Обновить прогрессбар от AsyncTaskLoader? - PullRequest
16 голосов
/ 31 января 2012

При использовании AsyncTaskLoader как бы вы обновили индикатор выполнения, отображающий состояние по мере его обновления? Обычно вы ждете, когда обратный вызов удалится, когда закончите, но как сделать запуск обновлений? Вы позволите основному потоку (пользовательскому интерфейсу) опрашивать данные во время их установки или что-то в этом роде?

Редактировать: я говорю о AsyncTaskLoader , посмотрите на часть загрузчика. Вот ссылка на класс: http://developer.android.com/reference/android/content/AsyncTaskLoader.html

Я хочу использовать его, потому что это будущее :), я знаю, как это сделать с помощью AsyncTask.

Ответы [ 6 ]

4 голосов
/ 21 сентября 2012

Вы можете сделать это с загрузчиками, но вам нужно сохранить и обновить 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) {

    }

}
4 голосов
/ 14 апреля 2012

Вы можете использовать обработчик, я думаю, он будет легче для системы, чем намерение

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 голосов
/ 17 апреля 2012

Я использую это с моим AsyncTaskLoader, внутри loadInBackground

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

Однако это не работает с изменением конфигурации (например, с изменением ориентации). Я не уверен, что AsyncTaskLoader лучше всего использовать, если вам нужно обновить интерфейс, но он лучше всего работает при обработке изменений конфигурации. Я не знаю, почему они создали AsyncTaskLoader и AsyncTask каждый со своими собственными компромиссами. Просто расстраивает и смущает разработчиков. Вдобавок к этому AsyncTaskLoader имеет очень мало документации.

3 голосов
/ 27 марта 2012

Я передаю Намерение для Действия (и оно получено BroadcastReceiver). Я не очень доволен этим решением, но оно работает. AsynTask publishProgress действительно проще в использовании. Вы нашли другое решение?

1 голос
/ 07 февраля 2015

У меня просто была эта проблема.Я использовал статический 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());
}
0 голосов
/ 19 апреля 2012

Исходя из ответа @ garmax, я нашел сайт, который показал, как объединить AsyncTaskLoader s с фрагментами: http://habrahabr.ru/post/131560/

Это на русском языке, но я мог бы опубликовать свою реализацию этого позже.

РЕДАКТИРОВАТЬ : Вот ссылка на ZIP, содержащий эту реализацию: http://www.2shared.com/file/VW68yhZ1/SampleTaskProgressDialogFragme.html

...