我有一個AsyncTask從DoinBackground啓動DatabaseHelper類,它將SQLite數據庫從/ assets目錄複製到應用程序目錄(/ databases)。取消使用ProgressDialog的AsyncTask
在preExecute()中,我啓動了一個progressDialog。隨着DB幫助程序類的各個部分完成,DoinBackground進程將更新progressDialog。
當設備旋轉時,據我瞭解,我需要關閉對話框,取消AsyncTask,然後在旋轉完成後再次在onResume()中重新啓動。
第一個問題是當我調用AsyncTask.cancel()時,我的onCancel()事件觸發,但AsyncTask繼續運行。我知道,因爲LogCat在旋轉完成後很久才顯示來自我的數據庫幫助器的輸出。 UI在旋轉後可用,因爲progressDialog消失了,但數據庫似乎仍在複製,所以這不太好。
一條信息我googled說你不能取消一個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;
}
我已經玩了幾天了。我可以取消AsyncTask和progressDialog,但是如果您旋轉設備幾次,進度條開始瘋狂地來回跳動。我認爲發生的事情是同時運行多個AsyncTasks。如何在循環過程中保持AsyncTask的多個副本不會產卵?我用一個完整的工作示例編輯了上面的代碼。 – wufoo 2011-05-12 13:16:45