2012-01-31 98 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()); 
}