2012-01-31 2 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

+1

Не нужно ли нам синхронизировать 'mActivity 'доступ? –

+3

Это неправильно. Loader get создается только в первый раз, когда вы вызываете initLoader, поэтому, если вы поворачиваете действие, вы теряете ссылку на него и с этим каким-либо успехом. Правильный способ справиться с этим состоит в том, чтобы на вашем загрузчике был установлен метод setActivity (...), который меняет слабую ссылку на новую активность и использует getSupportLoaderManager(). GetLoader (), отсылайте его на загрузчик, проверяйте его non-null и вызвать метод setActivity(), прежде чем снова вызвать initLoader(). Также в setActivity() вы должны убедиться, что загрузчик синхронизирует свое состояние с представлением прогресса. –

3

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

+1

Я не нашел решение, но я не искал трудно eigther :) Я задал этот вопрос, потому что я смотрел в AsyncTaskLoader и нашел одну область, где не хватало по сравнению с AsyncTask – Warpzit

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

+1

Это еще один вопрос. Вы можете установить android: configChanges = «ориентация» в конфигурации активности. Или определите обработчик в onCreate, тогда обработчик получит новый экземпляр для каждого поворота. – garmax1

+0

Так я и рассчитывал сделать это сам, просто хотел бы передать его вокруг stackoverflow, чтобы быть уверенным :) – Warpzit

3

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

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

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

+0

Другое возможное решение, и вы документация воняет (как и многие другие области Android) :) – Warpzit

0

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

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

EDIT: Вот ссылка на ZIP, содержащий эту реализацию: http://www.2shared.com/file/VW68yhZ1/SampleTaskProgressDialogFragme.html

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()); 
} 
Смежные вопросы