我有一个AsyncTask,它从DoinBackground启动DatabaseHelper类,它将SQLite数据库从/ assets目录复制到应用程序目录(/ databases)。
在preExecute()中,我启动了progressDialog。随着DB帮助程序类的各个部分的完成,DoinBackground进程会更新progressDialog。
根据我的理解旋转设备时,我需要关闭对话框,取消AsyncTask,然后在轮换完成后再次在onResume()中重新启动。
第一个问题是当我调用AsyncTask.cancel()时,我的onCancel()事件会触发,但AsyncTask会继续运行。我知道因为LogCat在轮换完成后很长时间显示了我的DB Helper的输出。在旋转之后UI是可用的,因为progressDialog已经消失但数据库仍然似乎在复制,所以这不好。
我用Google搜索的一条信息说你无法取消AsyncTask,所以我只是让事情在后台运行而不用担心吗?有没有办法再次将(仍然执行的)DoinBackground进程连接到progressDialog?
由于
package com.test.helloasync;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import android.app.Activity;
import android.app.ProgressDialog;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.SystemClock;
import android.util.Log;
public class HelloAsync extends Activity
{
myVars v;
protected fileCopyTask fct;
private final String TAG = "** HelloAsync **";
private final String DBNAME = "foo.png"; // need png extension: Data exceeds UNCOMPRESS_DATA_MAX (5242880 vs 1048576)
@Override
public void onCreate (Bundle savedInstanceState)
{
super.onCreate (savedInstanceState);
setContentView (R.layout.main);
restoreFromObject ();
}
/* (non-Javadoc)
* @see android.app.Activity#onResume()
*/
@Override
protected void onResume ()
{
// TODO Auto-generated method stub
Log.d (TAG, "onResume()");
// only start NEW task if not cancelled and file has not been copied yet
if ((v.taskCancelled == false) && (v.fileCopied == false))
{
fct = new fileCopyTask ();
fct.execute ();
}
// show progressdialog if we were cancelled becuase asynctask will continue by itself
if ((v.taskCancelled == true) && (v.fileCopied == false))
{
Log.d (TAG, "onAttachedToWindow(): launching fct");
v.pd.show ();
// may need to check status here to make sure it was cancelled and not something else...
Log.d (TAG, "fct cancel status is " + fct.isCancelled ());
}
super.onResume ();
}
/**
* saves myVars class during rotation
*/
@Override
public Object onRetainNonConfigurationInstance ()
{
Log.d (TAG, "onRetainNonConfigurationInstance(): saving myVars objects");
// close db transfer dialogs if showing so we don't cause a UI error
if (v.pd != null)
if (v.pd.isShowing ())
{
v.taskCancelled = true;
v.pd.cancel ();
}
// save task to myVars so we can use it onRestoreInstanceState
v.fct = fct;
return (v);
}
/*
* restores myVars class after rotation
*/
private void restoreFromObject ()
{
Log.d (TAG, "restoreFromObject(): retrieving myVars object");
v = (myVars) getLastNonConfigurationInstance ();
// initialize myVars object (v) first time program starts
if (v == null)
v = new myVars ();
else
{
Log.d (TAG, "myVars already initialized");
fct = (fileCopyTask) v.fct;
}
}
/**
*
* copy a file from /assets to /data/data/com.blah.blah/databases
*
*/
private class fileCopyTask extends AsyncTask<Integer, Void, Void>
{
// on UI thread here
protected void onPreExecute ()
{
Log.d (TAG, "onPreExecute()" );
// only show this when db has not been copied
// set initDbDone to false prir to call if downloading a new DB
v.pd = new ProgressDialog (HelloAsync.this);
v.pd.setProgressStyle (ProgressDialog.STYLE_HORIZONTAL);
v.pd.setMessage ("Initializing Database");
v.pd.show ();
}
/**
* opens file in assets/ directory and counts the bytes in it so we can have an actual progress bar
*
* @return size
*/
private int getAssetSize ()
{
int size = 0;
try
{
InputStream fin = getBaseContext ().getAssets ().open (DBNAME);
byte [] buffer = new byte [1024];
int length = 0;
while ((length = fin.read (buffer)) > 0)
size += length;
fin.close ();
}
catch (IOException ioe)
{
Log.d (TAG, "fileCopyTask(): asset size failed: ioex :" + ioe);
size = 0;
}
Log.d (TAG, " fileCopyTask(): asset size is " + size);
return (size);
}
@Override
protected Void doInBackground (Integer... params)
{
Log.d (TAG, "doInBackground: +++++++++++++++++++++++++++++++++");
try
{
int inputsize = getAssetSize ();
// this is the input file in the assets directory. We have no idea how big it is.
InputStream fin = getBaseContext ().getAssets ().open (DBNAME);
// this is the destination database file on the android device
File dbFile = getBaseContext ().getDatabasePath (DBNAME);
// check if destination directory exists
String parent = dbFile.getParent ();
// create the desitination directory if it does not exist in /data/data/blah.. (on device)
if (dbFile.exists () == false)
{
boolean result = new File (parent).mkdir ();
Log.d (TAG, " fileCopyTask(): mkdir() result is " + result);
}
// this is the output file in the databases/ subdirectory of the app directory (on device)
OutputStream fout = new FileOutputStream (dbFile);
// transfer bytes from the inputfile to the outputfile
byte [] buffer = new byte [4096];
int length;
int bytesCopied = 0;
while ((length = fin.read (buffer)) > 0)
{
fout.write (buffer, 0, length);
bytesCopied += length;
float b = (float) (bytesCopied * 1.0);
float i = (float) (inputsize * 1.0);
float pctdone = (float) ((b / i) * 100.0);
int pct = (int) (pctdone);
// updating every 4k seems to really slow things down so do it every 5 chunks
if ((pct % 5) == 0)
v.pd.setProgress ((int) pctdone);
}
fout.flush ();
fin.close ();
fout.close ();
}
catch (IOException e)
{
Log.d (TAG, "fileCopyTask(): DB copy blew up. IOE: " + e.getMessage ());
// just in case, attempt to cancel the process in event of cataclysm
this.cancel (true);
e.printStackTrace ();
}
return null;
}
// can use UI thread here
protected void onPostExecute (final Void unused)
{
Log.d (TAG, "fileCopyTask():onPostExecute()");
// set progress bar to 100% when done.
v.pd.setProgress (100);
v.pd.dismiss ();
// set the state flags to show a succesful completion
v.taskCancelled = false;
v.fileCopied = true;
}// onPostExecute()
}// fileCopyTask()
}
///////////////////////////////////////
// myVars.java
//////////////////////////////////////
/**
*
*/
package com.test.helloasync;
import android.app.AlertDialog;
import android.app.AlertDialog.Builder;
import android.app.ProgressDialog;
import android.content.DialogInterface;
public class myVars
{
ProgressDialog pd;
boolean taskCancelled = false;
boolean fileCopied = false;
Object fct;
}
答案 0 :(得分:1)
我尝试取消asynctask,但是当我创建一个新实例并执行它时遇到了麻烦。之前的AsyncTask似乎在轮换期间存活,并且在 NEW 任务被激活后立即开始更新progressDialog。
以为我只是让android管理AsyncTask本身,因为它似乎想让它在后台运行。所以,我最终做的只是在旋转时关闭progressDialog,然后在onResume()中再次弹出它。 AsyncTask似乎只是从它停止的地方开始。
我将更新上面的代码 - 希望它可以帮助其他人。
答案 1 :(得分:0)
通常,您设置了boolean mIsRunning;
方法定期检查的标记(例如doInBackground()
)。如果已清除,请停止处理。如果要取消该任务,请将该标志设置为false。