2012-01-31 12 views
14

Al usar AsyncTaskLoader, ¿cómo actualizarías una barra de progreso que muestra el estado a medida que se actualiza? Normalmente esperas a que la devolución de llamada se elimine cuando termine, pero ¿cómo se ejecutan las actualizaciones? ¿Dejarías que el hilo principal (ui) sondeara los datos tal como están siendo configurados o algo así?¿Desea actualizar la barra de progreso de AsyncTaskLoader?

Editar: Estoy hablando de AsyncTaskLoader, mire 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.

Respuesta

4

se puede hacer eso con los cargadores, pero hay que mantener y actualizar un 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) { 

    } 

} 
+2

creo la mayoría de las personas que llegan a esta pregunta usan un AsyncTaskLoader para leer algunos datos de la red. En ese caso, por favor, eche un vistazo a RoboSpice: es mucho más cerca de sus necesidades que un cargador cuando se trata de la creación de redes: https://github.com/octo-online/robospice – Snicolas

+1

no es lo que necesitamos sincronizar 'mActivity '¿accediendo? –

+3

Esto está mal. Loader se crea solo la primera vez que llamas a initLoader, por lo tanto si giras la actividad pierdes la referencia a ella y con eso cualquier progreso. La forma correcta de manejar esto es tener un método setActivity (...) en su cargador que cambie la referencia débil a la nueva actividad y use getSupportLoaderManager(). GetLoader (), transfiéralo a su cargador, compruébelo no nulo y llame al método setActivity() antes de llamar de nuevo a initLoader(). También en setActivity() debe asegurarse de que el cargador sincronice su estado con la vista de progreso. –

3

me transmitió una intención de la actividad (y es recibida por un BroadcastReceiver). No estoy muy contento con esta solución, pero funciona. AsynTask publishProgress es realmente más fácil de usar. ¿Encontraste alguna otra solución?

+1

no he encontrado ninguna solución, sin embargo, pero no he buscado dura eigther :) Hice esta pregunta porque yo estaba buscando en el AsyncTaskLoader y se encontró un área en la que le faltaba en comparación con AsyncTask – Warpzit

4

Puede utilizar manipulador, creo que será más ligero para el sistema de intención

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); 
      } 
     } 
    } 
}; 
} 

Conjunto mHandler al constructor del 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); 
+0

, pero cómo estará suceder en los cambios de orientación? el manejador se referirá al contexto anterior y se filtrará. Necesita actualizar el controlador de alguna manera. – Warpzit

+1

Es otra pregunta. Puede configurar android: configChanges = "orientation" en la configuración de la actividad. O defina manejador en onCreate y luego el manejador obtendrá nueva instancia en cada rotación. – garmax1

+0

Esta es la forma que yo esperaría que hacerlo yo mismo, sólo quería pasarlo alrededor stackoverflow para estar seguro :) – Warpzit

3

estoy usando esto con mi AsyncTaskLoader, en el interior de loadInBackground

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

Sin embargo, esto no funciona con un cambio de configuración (como cambio de orientación). No estoy seguro de que AsyncTaskLoader sea el mejor para usar si necesita actualizar la interfaz de usuario, pero funciona mejor cuando maneja los cambios de configuración. No sé por qué crearon tanto un AsyncTaskLoader como un AsyncTask cada uno con sus propias compensaciones. Solo frustra y confunde a los desarrolladores. Además de eso, AsyncTaskLoader tiene muy poca documentación.

+0

Otra posible solución, y vosotros los hedores de documentación (como tantas otras áreas de Android) :) – Warpzit

0

acabo de tener este problema. Usé 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 sondea y muestra el progreso.

En la devolución de llamada cargador onLoadFinished oculto mi panel de progreso, lo que hace que el bucle de sondeo para salir.

Por lo general yo evitaría estado estático, pero creo que en general es más simple que las alternativas. En mi caso, tengo un diseño diferente en el paisaje, así que estoy más feliz dejando 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()); 
} 
Cuestiones relacionadas