Обновить контрольную панель из AsyncTaskLoader?
При использовании AsyncTaskLoader, как бы вы обновили индикатор прогресса, показывающий статус при его обновлении? Обычно вы ожидаете, когда обратный вызов будет удален, когда будет выполнен, но как выполнять обновления?
Разрешите ли основной поток (ui) опросить данные по мере их установки или что-то еще?
Изменить: я говорю о AsyncTaskLoader, посмотрите на часть загрузчика. Вот ссылка на класс: http://developer.android.com/reference/android/content/AsyncTaskLoader.html
Я хочу использовать его, потому что это будущее:), я знаю, как это сделать с помощью AsyncTask.
Ответы
Ответ 1
Вы можете сделать это с помощью загрузчиков, но вам нужно сохранить и обновить 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
Вы можете использовать обработчик, я думаю, что он будет легче для системы, чем намерение
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);
Ответ 3
Я транслировал намерение в действие (и получил его BroadcastReceiver). Я не очень доволен этим решением, но он работает. AsynTask publishProgress действительно проще в использовании. Вы нашли другое решение?
Ответ 4
Я использую это с моим AsyncTaskLoader
, внутри loadInBackground
runOnUiThread(new Runnable() {
public void run() {
//UI code
}
});
Однако это не работает с изменением конфигурации (например, смены ориентации). Я не уверен, что AsyncTaskLoader
лучше всего использовать, если вам нужно обновить интерфейс, но он работает лучше всего при обработке изменений конфигурации. Я не знаю, почему они создали как AsyncTaskLoader
, так и AsyncTask
, каждый из которых имеет свои собственные компромиссы. Просто расстраивает и смущает разработчиков. Кроме того, AsyncTaskLoader
имеет очень мало документации.
Ответ 5
Отключив ответ @garmax, я нашел сайт, в котором показано, как объединить AsyncTaskLoader
с фрагментами: http://habrahabr.ru/post/131560/
Это по-русски, но я мог бы опубликовать мою версию позже.
EDIT: здесь ссылка на ZIP, содержащую эту реализацию: http://www.2shared.com/file/VW68yhZ1/SampleTaskProgressDialogFragme.html
Ответ 6
У меня была эта проблема. Я использовал статическую 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());
}