2011-05-10 85 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