2012-01-31 122 views
14

使用AsyncTaskLoader時,如何更新進度條以顯示更新狀態?通常,等待回調完成後刪除,但如何執行更新? 您是否讓主線程(ui)在設置數據時輪詢數據?從AsyncTaskLoader更新進度條?

編輯:我說的是AsyncTaskLoader,看看裝載機部分。這裏是鏈接到類:http://developer.android.com/reference/android/content/AsyncTaskLoader.html

我想使用它,因爲它的未來:),我知道如何用AsyncTask做到這一點。

回答

4

你可以做到這一點與裝載機,但你需要保持和更新的WeakReference你的活動:

public class LoaderTestActivity extends FragmentActivity implements LoaderCallbacks<Void> { 
    private static final int MAX_COUNT = 100; 

    private ProgressBar progressBar; 

    @Override 
    public void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 
     setContentView(R.layout.activity_async_task_test); 

     progressBar = (ProgressBar) findViewById(R.id.progressBar1); 
     progressBar.setMax(MAX_COUNT); 
     AsyncTaskCounter.mActivity = new WeakReference<LoaderTestActivity>(this); 
    } 

    @Override 
    public boolean onCreateOptionsMenu(Menu menu) { 
     getMenuInflater().inflate(R.menu.activity_async_task_test, menu); 
     return true; 
    } 

    public void onStartButtonClick(View v) { 
     startWork(); 
    } 

    void startWork() { 
     getSupportLoaderManager().initLoader(0, (Bundle) null, this); 
    } 

    static class AsyncTaskCounter extends AsyncTaskLoader<Void> { 
     static WeakReference<LoaderTestActivity> mActivity; 

     AsyncTaskCounter(LoaderTestActivity activity) { 
      super(activity); 
      mActivity = new WeakReference<LoaderTestActivity>(activity); 
     } 

     private static final int SLEEP_TIME = 200; 

     @Override 
     public Void loadInBackground() { 
      for (int i = 0; i < MAX_COUNT; i++) { 
       try { 
        Thread.sleep(SLEEP_TIME); 
       } catch (InterruptedException e) { 
        e.printStackTrace(); 
       } 
       Log.d(getClass().getSimpleName(), "Progress value is " + i); 
       Log.d(getClass().getSimpleName(), "getActivity is " + getContext()); 
       Log.d(getClass().getSimpleName(), "this is " + this); 

       final int progress = i; 
       if (mActivity.get() != null) { 
        mActivity.get().runOnUiThread(new Runnable() { 

         @Override 
         public void run() { 
          mActivity.get().progressBar.setProgress(progress); 
         } 
        }); 
       } 
      } 
      return null; 
     } 

    } 

    @Override 
    public Loader<Void> onCreateLoader(int id, Bundle args) { 
     AsyncTaskLoader<Void> asyncTaskLoader = new AsyncTaskCounter(this); 
     asyncTaskLoader.forceLoad(); 
     return asyncTaskLoader; 
    } 

    @Override 
    public void onLoadFinished(Loader<Void> arg0, Void arg1) { 

    } 

    @Override 
    public void onLoaderReset(Loader<Void> arg0) { 

    } 

} 
+2

我認爲大多數遇到此問題的人都使用AsyncTaskLoader從網絡中讀取一些數據。在這種情況下,請查看RoboSpice:在網絡方面,它比裝載程序更接近您的需求:https://github.com/octo-online/robospice – Snicolas 2012-11-08 15:17:57

+1

我們不需要同步'mActivity 「訪問? – 2013-03-22 07:28:55

+3

這是錯誤的。只有在第一次調用initLoader時纔會創建Loader,因此如果您旋轉活動,則失去了對它的引用以及任何進度。 來處理這個正確的方法是有你的加載器setActivity(...)方法,改變弱引用新的活動,並使用getSupportLoaderManager()。getLoader(),將其轉換爲您的裝載機,檢查非空並在再次調用initLoader()之前調用它的setActivity()方法。同樣在setActivity()中,您應該確保加載器將其狀態與進度視圖同步。 – 2014-03-18 16:43:05

3

我向活動廣播了一個Intent(它由BroadcastReceiver接收)。我對這個解決方案並不滿意,但它很有用。 AsynTask publishProgress真的更容易使用。你有沒有找到其他解決方案?

+1

我還沒有找到任何解決辦法,但我還沒有搜查硬eigther :)我問這個問題,因爲我一直在尋找進入AsyncTaskLoader,發現它缺乏比較的AsyncTask – Warpzit 2012-03-27 15:38:10

4

您可以使用處理程序,我認爲它會爲系統是輕於意圖

public class MyFragmentActivity extends FragmentActivity{ 
private final static int MSGCODE_PROGRESS = 1; 
private final static int MSGCODE_SIZE = 2; 

    private final Handler mHandler = new Handler() { 
    public void handleMessage(Message msg) { 
     Bundle bundle = msg.getData(); 
     if(null != bundle){ 
      int data = msg.getData().getInt(BUNDLE_PROGRESS); 
      if(msg.what == MSGCODE_SIZE){ 
       mProgressBar.setMax(data); 
      } else if(msg.what == MSGCODE_PROGRESS){ 
       mProgressBar.setProgress(data); 
      } 
     } 
    } 
}; 
} 

設置mHandler到AsyncTaskLoader的構造和loadInBackground您可以更新進度

Bundle bundle = new Bundle(); 
bundle.putInt(BUNDLE_PROGRESS, lenghtOfFile); 
Message msg = new Message(); 
msg.setData(bundle); 
msg.what = MSGCODE_SIZE; 
mHandler.sendMessage(msg); 
+0

一個區域,但會出現什麼發生取向變化?處理程序將引用舊的上下文,你會泄漏。你需要以某種方式更新處理程序。 – Warpzit 2012-04-14 18:07:16

+1

這是另一個問題。您可以在活動配置中設置android:configChanges =「orientation」。或者在onCreate中定義處理程序,然後處理程序將在每次循環中獲得新的實例。 – garmax1 2012-04-14 18:43:14

+0

這是我期望自己做的方式,只是想將它傳遞給計算器,以確保:) – Warpzit 2012-04-14 19:14:59

3

我使用這與我AsyncTaskLoader,內loadInBackground

runOnUiThread(new Runnable() { 
    public void run() { 
     //UI code 
    } 
}); 

但是,這不適用於配置更改(如方向更改)。我不確信AsyncTaskLoader是最好的使用,如果你需要更新用戶界面,但它處理配置更改時效果最好。我不知道他們爲什麼創建了一個AsyncTaskLoaderAsyncTask,每個人都有自己的權衡。只是挫敗和迷惑開發人員。最重要的是,AsyncTaskLoader幾乎沒有文檔。

+0

另一種可能的解決方案,你是文檔惡臭(像Android的其他領域):) – Warpzit 2012-04-17 06:27:25

0

我只是有這個問題。我在我的活動中使用了一個靜態的AtomicInteger來存儲進度。加載器通過回調來更新它,活動輪詢它並顯示進度。

在加載器回調onLoadFinished我隱藏我的進度面板,導致輪詢循環退出。

通常我會避免靜態,但我認爲總體上這比替代方案更簡單。就我而言,我在景觀中有不同的佈局,所以我更高興地讓方向變化像平常一樣行事。

private Handler progressHandler; // init with new Handler(getMainLooper()) 
private static AtomicInteger progress = new AtomicInteger(0); 

... 

private void beginProgressUiUpdates() { 
    progress.set(0); 
    displayProgress(); 
    progressHandler.postDelayed(pollProgress, PROGRESS_POLL_PERIOD_MILLIS); 
} 

private Runnable pollProgress = new Runnable() { 
    public void run() { 
     if (findViewById(R.id.progressPanel).getVisibility() == View.VISIBLE) { 
      displayProgress(); 
      progressHandler.postDelayed(pollProgress, PROGRESS_POLL_PERIOD_MILLIS); 
     } 
    } 
}; 

private void displayProgress() { 
    ((ProgressBar)findViewById(R.id.progressBar)).setProgress(progress.get()); 
}