[英]AsyncTask is still blocking UI thread
I my main activity I want to autosave whenever the user leaves the app or changes to another activity. 我的主要活动是我想在用户离开应用程序或更改为其他活动时自动保存。 So I implemented the save function in the activity's OnPause method, which works fine.
因此,我在活动的OnPause方法中实现了保存功能,效果很好。 Problem is the save process can take a few seconds, so I wanted a progressdialog while it happens.
问题是保存过程可能需要几秒钟,因此我希望在发生过程时进行进度对话框。 So I implenmeted that with an ASyncTask like this:
所以我用这样的ASyncTask来实现:
@Override
public void onPause()
{
super.onPause();
// save sheet when user is leaving activity
SaveTask task = new SaveTask(PlayCharacterActivity.this);
task.execute();
}
private class SaveTask extends AsyncTask <Void, Void, Void> {
private ProgressDialog dialog;
public SaveTask(PlayCharacterActivity activity) {
}
@Override
protected void onPreExecute() {
super.onPreExecute();
dialog = new ProgressDialog(PlayCharacterActivity.this);
dialog.setMessage("Saving...");
dialog.show();
dialog.setIndeterminate(true);
dialog.setCancelable(false);
}
@Override
protected void onPostExecute(Void result) {
if (dialog.isShowing()) {
dialog.dismiss();
}
super.onPostExecute(result);
}
@Override
protected Void doInBackground(Void... params) {
try {
//Log.d("plch:OnPause", "starting save");
Sheet.getInstance().Save();
//Log.d("plch:OnPause", "finished save");
} catch (RuntimeException e) {
e.printStackTrace();
}
return null;
}
}
Problem is, the dialog doesn't appear until after the background task has completed. 问题是,直到后台任务完成后对话框才出现。 And I can see in logcat that the main thread is still being blocked.
而且我可以在logcat中看到主线程仍在被阻塞。 I believe it happens in the middle of the save function when it does the serialisation.
我相信它发生在序列化时保存功能的中间。
Save is like this: 保存是这样的:
public void Save()
{
long dtMili = System.currentTimeMillis();
Date d = new Date(dtMili);
CharSequence s = DateFormat.format("hh:mm:ss", d.getTime());
// use this flag to know whether to back up the saved file or not
boolean saveSuccessful = false;
//_xml = new String("");
dtMili = System.currentTimeMillis();
d = new Date(dtMili);
Log.d("Load/Save", "started serialising: " + DateFormat.format("hh:mm:ss", d.getTime()));
_xml = _instance.Serialise();
dtMili = System.currentTimeMillis();
d = new Date(dtMili);
Log.d("Load/Save", "finished serialising: " + DateFormat.format("hh:mm:ss", d.getTime()));
try
{
//---SD Card Storage---
File sdCard = Environment.getExternalStorageDirectory();
File directory = new File (sdCard.getAbsolutePath() + "/RPGenius");
directory.mkdirs();
File file = new File(directory, _name + ".rpg");
FileOutputStream fOut = new FileOutputStream(file);
Log.d("Saving to: ", file.getAbsolutePath());
//---write the string to the file---
OutputStreamWriter osw = new OutputStreamWriter(fOut);
//DebugHelper.DebugMessage("File contents: " + _xml);
dtMili = System.currentTimeMillis();
d = new Date(dtMili);
Log.d("Load/Save", "started writing file: " + DateFormat.format("hh:mm:ss", d.getTime()));
osw.write(_xml);
osw.flush();
osw.close();
dtMili = System.currentTimeMillis();
d = new Date(dtMili);
Log.d("Load/Save", "finished writing file: " + DateFormat.format("hh:mm:ss", d.getTime()));
saveSuccessful = true;
}
catch (NullPointerException npe)
{
npe.printStackTrace();
}
catch (IOException ioe)
{
ioe.printStackTrace();
}
// if the save was completely successfully, back it up
if (saveSuccessful)
{
File sdCard = Environment.getExternalStorageDirectory();
File directory = new File (sdCard.getAbsolutePath() + "/RPGenius");
File file = new File(directory, _name + ".rpg");
if (file.exists())
{
// locate backup directory and create if not present
File backupDirectory = new File (sdCard.getAbsolutePath() + "/RPGenius/Backups");
backupDirectory.mkdirs();
// create target file location/name
File backupFile = new File(backupDirectory, _name + ".rpg");
// attempt to copy file
try {
FileInputStream inStream = new FileInputStream(file);
FileOutputStream outStream = new FileOutputStream(backupFile);
FileChannel inChannel = inStream.getChannel();
FileChannel outChannel = outStream.getChannel();
inChannel.transferTo(0, inChannel.size(), outChannel);
inStream.close();
outStream.close();
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
Serialise is like this: 序列化是这样的:
@Override
public String Serialise() {
// produce xml string to represent this object
_indents = 0;
_xml = new String("");
StartXmlItem("Sheet");
//AddSimpleXmlItem("Name", _name);
StartXmlItem("Stats");
for (XmlSerialisable stat: _stats)
{
AddComplexXmlItem(stat);
}
EndXmlItem("Stats");
StartXmlItem("Effects");
for (XmlSerialisable effect: _effects)
{
AddComplexXmlItem(effect);
}
EndXmlItem("Effects");
StartXmlItem("Pages");
for (XmlSerialisable page: _pages)
{
AddComplexXmlItem(page);
}
EndXmlItem("Pages");
EndXmlItem("Sheet");
return _xml;
}
I'm not immediately interested in improvements to the save/serialise methods unless they are relevant to the progressdialog problem. 除非它们与progressdialog问题相关,否则我不会立即对保存/序列化方法的改进感兴趣。 Can anyone help?
有人可以帮忙吗?
I propose the following change of your AsyncTask
: 我建议对
AsyncTask
进行以下更改:
First of all remove the progressbar field and the useless constructor from the AsyncTask
: 首先,从
AsyncTask
删除progressbar字段和无用的构造函数:
private ProgressDialog dialog; //should be declared as field in Activity
public SaveTask(PlayCharacterActivity activity) { //don't pass the activity to AsyncTask
}
Then in the onPreExecute() just do: 然后在onPreExecute()中执行以下操作:
@Override
protected void onPreExecute() {
showDialog(); //call a method in your Activity that shows your dialog as you want
}
Remember that AsyncTask's onPreExecute method is run in the UI thread so you can deal with views from the Activity here. 请记住,AsyncTask的onPreExecute方法在UI线程中运行,因此您可以在此处处理Activity中的视图。 See documentation: http://developer.android.com/reference/android/os/AsyncTask.html#onPreExecute()
请参阅文档: http : //developer.android.com/reference/android/os/AsyncTask.html#onPreExecute()
Try moving the dialog to the outer class and opening it outside the AsyncTask and by the static method 尝试将对话框移到外部类,然后在AsyncTask外部并通过静态方法将其打开
dialog = ProgressDialog.show(...)
just before 就在之前
task.execute();
It should be possible to close it from onPostExecute 应该可以从onPostExecute关闭它
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.