2011-05-10 125 views
2

我有一个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; 
} 

回答

1

我试着取消这个asynctask,但是当我创建一个新的实例并执行它时遇到了麻烦。之前的AsyncTask似乎在整个轮换过程中生存下来,只要启动任务就开始更新progressDialog。

想到我只是让android管理AsyncTask本身,因为它似乎想保持它在后台运行。所以,我最终做的只是关闭旋转过程中的progressDialog,然后再次在onResume()中弹出它。 AsyncTask似乎只是从中断的地方继续。

我会更新上面的代码 - 希望它可以帮助别人。

0

通常你会设置一个标志(例如boolean mIsRunning;)您doInBackground()方法周期性地检查。如果清除,请停止处理。当您希望取消该任务时,将该标志设置为false。

+0

我已经玩了几天了。我可以取消AsyncTask和progressDialog,但是如果您旋转设备几次,进度条开始疯狂地来回跳动。我认为发生的事情是同时运行多个AsyncTasks。如何在循环过程中保持AsyncTask的多个副本不会产卵?我用一个完整的工作示例编辑了上面的代码。 – wufoo 2011-05-12 13:16:45