android - ¿Deseas actualizar la barra de progreso de AsyncTaskLoader?
progress-bar (6)
Al usar un AsyncTaskLoader, ¿cómo actualizaría una barra de progreso que muestra el estado a medida que se actualiza? Normalmente, esperas a que se elimine la devolución de llamada cuando hayas terminado, pero ¿cómo se ejecutan las actualizaciones? ¿Permitiría que el hilo principal (ui) sondea los datos a medida que se configuran o algo así?
Edición: estoy hablando de AsyncTaskLoader , mira la parte del cargador. Aquí está el enlace a la clase: http://developer.android.com/reference/android/content/AsyncTaskLoader.html
Quiero usarlo porque es el futuro :), sé cómo hacerlo con AsyncTask.
Estoy usando esto con mi AsyncTaskLoader
, dentro de loadInBackground
runOnUiThread(new Runnable() {
public void run() {
//UI code
}
});
Sin embargo, esto no funciona con un cambio de configuración (como el cambio de orientación). No estoy convencido de que AsyncTaskLoader
sea el mejor para usar si necesita actualizar la interfaz de usuario, pero funciona mejor cuando se manejan cambios de configuración. No sé por qué crearon tanto un AsyncTaskLoader
como una AsyncTask
cada uno con sus propias compensaciones. Solo frustra y confunde a los desarrolladores. Además de eso, AsyncTaskLoader
tiene muy poca documentación.
Puede hacer eso con los cargadores, pero necesita mantener y actualizar una WeakReference en su actividad:
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) {
}
}
Puedes usar el controlador, creo que será más ligero para el sistema que para el intento
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);
}
}
}
};
}
Configure mHandler como constructor de AsyncTaskLoader y desde loadInBackground puede actualizar el progreso
Bundle bundle = new Bundle();
bundle.putInt(BUNDLE_PROGRESS, lenghtOfFile);
Message msg = new Message();
msg.setData(bundle);
msg.what = MSGCODE_SIZE;
mHandler.sendMessage(msg);
Saliendo de la respuesta de @garmax, encontré un sitio que mostraba cómo combinar AsyncTaskLoader
s con Fragments en: http://habrahabr.ru/post/131560/
Está en ruso, pero podría publicar mi implementación más tarde.
EDITAR : aquí hay un enlace al ZIP que contiene esa implementación: http://www.2shared.com/file/VW68yhZ1/SampleTaskProgressDialogFragme.html
Transmito una Intención a la Actividad (y es recibida por un BroadcastReceiver). No estoy muy contento con esta solución pero funciona. El AsynTask publishProgress es realmente más fácil de usar. ¿Encontraste alguna otra solución?
acabo de tener este problema. Utilicé un AtomicInteger estático en mi actividad para almacenar el progreso. El cargador lo actualiza a través de una devolución de llamada y la actividad lo encuesta y muestra el progreso.
En la devolución de llamada del cargador onLoadFinished
, onLoadFinished
mi panel de progreso, lo que hace que el bucle de sondeo salga.
Por lo general, evitaría el estado estático, pero en general creo que esto es más simple que las alternativas. En mi caso, tengo un diseño diferente en el paisaje, así que estoy más feliz de dejar que los cambios de orientación se comporten normalmente.
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());
}