2011-06-17 100 views
4

我有一個方法public void writeEntry(Activity ctx, Entry entry)它獲得一些數據,必須調用本地方法,這需要更長的時間才能完成。
所以我創建了一個AsyncTask它處理ProgressDialog和本地方法。它在自己的活動很好測試它,在那活動我使用了一個回調接口等。等待與ProgressDialog執行AsyncTask

在我的情況下,我有上述方法,必須執行AsyncTask。執行不能在該方法,因爲它不停止進一步執行。
我需要從本地方法的結果之前,我可以與執行下去。
是否有任何可能性等待AsyncTask直到它完成?該方法wait()是不是一種選擇,因爲UI線程等待,太等的ProgressDialog感將會丟失。

我可以使用給定參數中的方法runOnUiThread()還是唯一可以啓動自己的解決方案活動

+0

那裏,在哪裏?我對活動描述感到困惑。你能寫一些名字,而不是使用「there」,所以我們知道我們正在查看多少不同的活動,謝謝其他人,只是在你的問題中轉儲相關的代碼:) – doNotCheckMyBlog

+0

我已經編輯過問。我希望現在清楚。通常只有主* Activity *,它調用writeEntry()方法。 – CSchulz

+0

我試圖理解它,所以基本上你有wrtieEntry方法執行AsyncTask但(writeEntry)代碼執行不斷。但是你希望代碼等到asynctask完成它的工作。我對嗎? – doNotCheckMyBlog

回答

3

我的第一個解決方案是使用具有接口實現的回調方法,請參閱示例https://stackoverflow.com/a/6396376/390177

在Android聊天中聊了一會之後,我聽說有一種更可行的解決方案。
您可以使用IntentService結合PendingIntent
通訊實現意圖's。
如果你想使用ProgressDialog,你需要爲它的自己的活動,其註冊例如BroadcastRecieverIntentService將它基於廣播的實際狀態。

但是讓我們現在就開始。
首先,我們創建了活動,其中包含ProgressDialog和註冊廣播接收器。該廣播接收器聽取有關更新和整理對話框消息。

對於活動我們需要佈局...

<?xml version="1.0" encoding="utf-8"?> 
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 
    android:layout_width="match_parent" android:layout_height="match_parent" 
    android:background="#80000000"> 
</LinearLayout> 

...和相關代碼:

public class ProgressActivity extends Activity { 
    /** 
    * ProgressDialog which is shown 
    */ 
    private ProgressDialog progessDialog_g; 

    /** 
    * Instance of the BroadcastReceiver 
    */ 
    private BroadcastReceiver receiver_g; 

    /** 
    * Identifier for the different settings of the ProgressDialog 
    */ 
    public static final String PROGRESS_DIALOG_BOOL_HORIZONTAL_BAR = "pbar_horizontal_bar"; 
    public static final String PROGRESS_DIALOG_BOOL_CANCELABLE = "pbar_horizontal_cancelable"; 
    public static final String PROGRESS_DIALOG_STR_MESSAGE = "pbar_message"; 
    public static final String PROGRESS_DIALOG_INT_MAX = "pbar_max_bar"; 
    public static final String PROGRESS_DIALOG_INT_VALUE = "pbar_value"; 
    protected static final int PROGRESS_DIALOG_INT_MAX_VALUE = 100; 

    @Override 
    protected void onCreate(Bundle savedInstanceState){ 
     super.onCreate(savedInstanceState); 

     setContentView(R.layout.progress); 

     progessDialog_g = new ProgressDialog(this); 

     // Reads and sets the settings for the ProgressDialog 
     Intent i = getIntent(); 
     progessDialog_g.setCancelable(i.getBooleanExtra(
       PROGRESS_DIALOG_BOOL_CANCELABLE, false)); 
     if (i.getBooleanExtra(
       PROGRESS_DIALOG_BOOL_HORIZONTAL_BAR, false)) { 
      progessDialog_g.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL); 
     } else { 
      progessDialog_g.setProgressStyle(ProgressDialog.STYLE_SPINNER); 
     } 
     progessDialog_g 
       .setMessage(i 
         .getStringExtra(PROGRESS_DIALOG_STR_MESSAGE)); 
     progessDialog_g.setMax(i.getIntExtra(
       PROGRESS_DIALOG_INT_MAX, 100)); 

     // Create the IntentFilter for the different broadcast messages 
     IntentFilter iFilter = 
       new IntentFilter(
         ExampleProgressService.PROGRESS_DIALOG_BROADCAST_INIT); 
     iFilter.addAction(ExampleProgressService.PROGRESS_DIALOG_BROADCAST_UPDATE); 
     iFilter.addAction(ExampleProgressService.PROGRESS_DIALOG_BROADCAST_FINISH); 

     // Creates the BroadcastReceiver 
     receiver_g = new BroadcastReceiver() { 
      @Override 
      public void onReceive(Context context, Intent intent){ 
       Log.d(DefaultPreferences.DEBUG_PREFIX + "ProgressActivity", 
         intent.getAction()); 

       if (ExampleProgressService.PROGRESS_DIALOG_BROADCAST_INIT 
         .equals(intent.getAction())) { 
        // Sets the ProgressDialog style 
        if (intent 
          .getBooleanExtra(
            PROGRESS_DIALOG_BOOL_HORIZONTAL_BAR, 
            false)) { 
         progessDialog_g 
           .setProgressStyle(ProgressDialog.STYLE_HORIZONTAL); 
        } else { 
         progessDialog_g 
           .setProgressStyle(ProgressDialog.STYLE_SPINNER); 
        } 

        // Shows the ProgressDialog  
        progessDialog_g.show(); 
       } else if (ExampleProgressService.PROGRESS_DIALOG_BROADCAST_UPDATE 
         .equals(intent.getAction())) { 
        // Updates the ProgressDialog 
        int value = 
          intent.getIntExtra(
            PROGRESS_DIALOG_INT_VALUE, 
            -1); 
        if (value != -1) { 
         progessDialog_g.setProgress(value); 
        } 
       } else if (ExampleProgressService.PROGRESS_DIALOG_BROADCAST_FINISH 
         .equals(intent.getAction())) { 
        // Finishs the ProgressDialog 
        progessDialog_g.cancel(); 
        finish(); 
       } 
      } 
     }; 

     // Registers the BroadcastReceiver 
     registerReceiver(receiver_g, iFilter); 
    } 

    @Override 
    protected void onDestroy(){ 
     unregisterReceiver(receiver_g); 
     super.onDestroy(); 
    } 
} 

現在,我們要使用的活動,所以讓從調用它開始:

final Intent i = new Intent(parentActivity, <packages>.ProgressActivity); 
i.putExtra(ProgressActivity.PROGRESS_DIALOG_BOOL_CANCELABLE, cancelable_g); 
i.putExtra(ProgressActivity.PROGRESS_DIALOG_BOOL_HORIZONTAL_BAR, showProgress_g); 
i.putExtra(ProgressActivity.PROGRESS_DIALOG_STR_MESSAGE, message_g); 
i.putExtra(ProgressActivity.PROGRESS_DIALOG_INT_MAX, ProgressActivity.PROGRESS_DIALOG_INT_MAX_VALUE); 

parentActivity.startActivity(i); 

所以我們需要一個正在運行的ProgressActivity,它等待不同的廣播。但首先我們需要發送廣播的IntentService
所以讓我們去:

public class ExampleProgressService extends IntentService { 
    /** 
    * PendingIntent for callback. 
    */ 
    protected PendingIntent pi_g = null; 

    private static final String DEBUG_TAG = "ExampleProgressService"; 

    /** 
    * Message identifier for ProgressDialog init 
    */ 
    public static final String PROGRESS_DIALOG_BROADCAST_INIT = "Dialog.Progress.Init"; 
    /** 
    * Message identifier for ProgressDialog finish 
    */ 
    public static final String PROGRESS_DIALOG_BROADCAST_FINISH = "Dialog.Progress.Finish"; 
    /** 
    * Message identifier for ProgressDialog update 
    */ 
    public static final String PROGRESS_DIALOG_BROADCAST_UPDATE = "Dialog.Progress.Update"; 

    /** 
    * Identifier of the result for intent content 
    */ 
    public static final String PROGRESS_DATA_RESULT = "Result"; 
    /** 
    * Identifier of the result error for intent content 
    */ 
    public static final String PROGRESS_DATA_RESULT_ERROR_MESSAGE = "Result.Error.Message"; 
    /** 
    * Identifier of the result error exception for intent content 
    */ 
    public static final String PROGRESS_DATA_RESULT_ERROR_EXCEPTION = "Result.Error.Exception"; 
    /** 
    * Identifier of the result status for intent content 
    */ 
    public static final String PROGRESS_DATA_RESULT_STATUS_BOOL = "Result.Status.boolean"; 

    /** 
    * Identifier of the pending intent for intent content 
    */ 
    public static final String PROGRESS_DATA_PENDING_RESULT = "PendingResult"; 

    public ExampleProgressService() { 
     super("ExampleProgressService"); 
    } 

    /** 
    * Send the finish message. 
    */ 
    private void closeProgressActivity() { 
     Intent intent = new Intent(PROGRESS_DIALOG_BROADCAST_FINISH); 

     sendBroadcast(intent); 
    } 

    /** 
    * Do some magic with the intent content 
    */ 
    private void extractVariablesFromIntentAndPrepare(Intent intent) 
      throws Exception { 
     pi_g = (PendingIntent) intent 
       .getParcelableExtra(PROGRESS_DATA_PENDING_RESULT); 

     if (pi_g == null) { 
      throw new Exception("There is no pending intent!"); 
    } 

    /** 
    * Sends an error message. 
    */ 
    private void failed(Exception e, String message) { 
     Intent i = new Intent(); 
     i.putExtra(PROGRESS_DATA_RESULT_ERROR_EXCEPTION, e); 
     i.putExtra(PROGRESS_DATA_RESULT_ERROR_MESSAGE, message); 

     send(i, false); 
    } 

    /** 
    * Sends the init message. 
    */ 
    private void initProgressActivity() { 
     Intent intent = new Intent(PROGRESS_DIALOG_BROADCAST_INIT); 

     intent.putExtra(PROGRESS_DIALOG_BOOL_HORIZONTAL_BAR, 
       multipart_g); 

     sendBroadcast(intent); 
    } 

    /** 
    * (non-Javadoc) 
    * 
    * @see android.app.IntentService#onHandleIntent(android.content.Intent) 
    */ 
    @Override 
    protected void onHandleIntent(Intent intent) { 
     extractVariablesFromIntentAndPrepare(intent); 

     initProgressActivity(); 

     // do your calculation here and implements following code 
     Intent intent = new Intent(PROGRESS_DIALOG_BROADCAST_UPDATE); 

     intent.putExtra(PROGRESS_DIALOG_INT_VALUE, progressValue); 

     sendBroadcast(intent); 

     // If you finished, use one of the two methods to send the result or an error 
     success(result); 
     failed(exception, optionalMessage); 
    } 

    /** 
    * Sends the data to the calling Activity 
    */ 
    private void send(Intent resultData, boolean status) { 
     resultData.putExtra(PROGRESS_DATA_RESULT_STATUS_BOOL, status); 

     closeProgressActivity(); 

     try { 
      pi_g.send(this, Activity.RESULT_OK, resultData); 
     } catch (PendingIntent.CanceledException e) { 
      Log.e(DEBUG_TAG, 
        "There is something wrong with the pending intent", e); 
     } 
    } 

    /** 
    * Sends the result message. 
    */ 
    private void success(String result) { 
     Intent i = new Intent(); 
     i.putExtra(PROGRESS_DATA_RESULT, result); 

     send(i, true); 
    } 
} 

的計算進步的結果應是在parentActivity可用的,所以我們在活動創建的PendingIntent並調用IntentService

// Some identifier for the call 
int requestCode = 12345; 

final Intent sI = new Intent(ExampleProgressService.PROGRESS_SERVICE_ACTION); 

// Callback 
sI.putExtra(ExampleProgressService.PROGRESS_DATA_PENDING_RESULT, parentActivity 
     .createPendingResult(requestCode, null, 
       PendingIntent.FLAG_CANCEL_CURRENT)); 

// Service start 
parentActivity.startService(sI); 

對於接收結果,我們必須重寫方法onActivityResult(int requestCode, int resultCode, Intent data)

@Override 
protected void onActivityResult(int requestCode, int resultCode, Intent data){ 
    // Compares the requestCode with the requestCode from above 
    if (requestCode == ...) { 
     if (data.getBooleanExtra(ExampleProgressService.PROGRESS_DATA_RESULT_STATUS_BOOL, false)) { 
      // Calculation was success 
      data.getStringExtra(ExampleProgressService.PROGRESS_DATA_RESULT); 
     } else 
     { 
      // Calculation is failed 
      data.getStringExtra(ExampleProgressService.PROGRESS_DATA_RESULT_ERROR_MESSAGE); 
      ((Exception) data.getSerializableExtra(ExampleProgressService.PROGRESS_DATA_RESULT_ERROR_EXCEPTION)); 
     } 
    } 
} 

這是神奇的,我希望它會幫助你。

4

,所以我會盡量解釋,就像我可以

啓動一個的AsyncTask裏面你沉重的過程,但你想的AsyncTask完成後執行任何代碼把它放在一個單獨的公共方法。現在,一旦你完成與分別在onPostExecute()創建方法您重過程調用。

所以psuuedo代碼看起來像這樣,

class main extends Activity { 

    class Something extends AsyncTask<String, Integer, String> { 

     protected void onPreExecute() { 
      // Start your progress bar... 
     } 

     protected String doInBackground(String... params) { 
      // Do your heavy stuff... 
      return null; 
     } 

     protected void onPostExecute(String result) { 
      // close your progress dialog and than call method which has 
      // code you are wishing to execute after AsyncTask. 
     } 
    } 

} 

希望這將幫助,

祝您好運!

+0

如何等待該代碼片段的* AsyncTask *的結果,而不凍結UI線程? – CSchulz