2010-05-27 21 views
12

que tiene un hilo separado corriendo para obtener datos de internet. Después de eso, me gustaría actualizar el ListView en el hilo principal llamando a adapter.notifyDataSetChanged(). Pero no funciona. ¿Alguna solución para eso? Gracias.actualización ListView en el hilo principal desde otro hilo

+0

http://stackoverflow.com/a/33584826/1318946 –

Respuesta

12

buen consejo general es http://android-developers.blogspot.com/2009/05/painless-threading.html

Personalmente utilizo mi hilo a medida (A que se extiende la clase Thread), sino enviar la respuesta al hilo de interfaz de usuario a través de un mensaje. Por lo tanto, en la función run() del subproceso hay:

Message msg; 
msg = Message.obtain(); 
msg.what = MSG_IMG_SET;      
mExtHandler.sendMessage(msg); 

El subproceso de interfaz de usuario define un manejador de mensajes.

private Handler mImagesProgressHandler; 

public void onCreate(Bundle bundle) { 

    mImagesProgressHandler = new Handler() { 
     @Override 
     public void handleMessage(Message msg) { 
      switch (msg.what) {    
      case LoadImagesThread.MSG_IMG_SET: 
       mArrayAdapter.setBitmapList(mImagesList); 
       mArrayAdapter.notifyDataSetChanged(); 
       break; 
      case LoadImagesThread.MSG_ERROR: 
       break; 
      } 
      super.handleMessage(msg); 
     } 
    };     

Esto es realmente más fácil que AsyncTask.

+0

Prefiero este método también – Mark

+0

Olvidé mencionar: también puede agregar un objeto al mensaje como: msg.obj = someBitmap; y recibirlo en el controlador (que puede, por ejemplo, actualizar una matriz o lista con el mapa de bits recibido y notificar al adaptador que los datos subyacentes de la lista han cambiado: mArrayAdapter.notifyDataSetChanged();). En este caso, no pueden ocurrir condiciones de carrera. – Yar

+2

¡Cuidado - Aquí hay dragones! Esta clase interna de Handler tiene una referencia implícita a la clase externa 'this. Es mejor que ese controlador esté estático y tomar una WeakReference a la clase externa. –

9

O bien, enviar un mensaje a la cola de mensajes de la vista de lista (que ejecutar en el subproceso de interfaz de usuario):

list.post(new Runnable() {     
    @Override 
    public void run() { 
     adapter.notifyDataSetChanged(); 

    } 
}); 
2

Supongamos yourActivity es la actividad que el widget se ha colocado en él, yourView es el widget y adapter es adaptador del widget:

yourActivity.runOnUiThread(new Runnable() { 
public void run() {  
     try{ 
       adapter.notifyDataSetChanged(); 
     } 
     catch{} 
} 
} 
3

Se puede utilizar una combinación de RxJava y Retrofit para este propósito.

Así es como usted puede hacerlo. Usaré la API de GitHub para el ejemplo.

crear una interfaz Java para el API HTTP.

public interface GitHubService { 
    @GET("users/{user}/repos") 
    Observable<List<Repo>> listRepos(@Path("user") String user); 
} 

El uso de Observable convertirá la respuesta en una secuencia. Cada evento es una Lista de repos.

clase Uso de reequipamiento para generar una implementación de la interfaz GitHubService. Puede o no puede proporcionar un Cliente HTTP personalizado.

Retrofit retrofit = new Retrofit.Builder() 
      .baseUrl("https://api.github.com/") 
      .client(okHttpClient) // OkHttp Client 
      .addConverterFactory(GsonConverterFactory.create()) 
      .addCallAdapterFactory(RxJavaCallAdapterFactory.create()) 
      .build(); 

GitHubService service = retrofit.create(GitHubService.class); 

Ahora viene la parte Rx. Debe agregar un suscriptor para escuchar las respuestas enviadas por el servidor. En otras palabras, reaccionan a ella.

service.listRepos("octocat") 
.subscribeOn(Schedulers.io()) // 1 
.observeOn(AndroidSchedulers.mainThread()) // 2 
.flatMap(Observable::from) // 3 
.subscribe(repoList -> { // 4 
    // Update the list view 
    // notifyDataSetChanged 
}); 

Esto es lo que las líneas de comentarios con los números están haciendo -

1 - Se dice al sistema operativo que se enroscan a ser utilizado para realizar la llamada. Estamos eligiendo el hilo IO para eso.

2 - Indica al sistema operativo qué hilo se utilizará para escuchar la respuesta. Hacemos eso en el hilo principal y actualizamos la interfaz de usuario al recibir una respuesta.

3 - Esta línea demuestra la verdadera magia de Rx. Esta pequeña línea simple convierte una lista de respuestas a objetos individuales. Por lo tanto, estaremos reaccionando a todos los objetos en lugar de toda la lista por completo. Puede leer más al respecto here.

4 - Esta línea realmente define qué tipo de 'reacción' se mostrará al evento. Puedes actualizar el adaptador aquí.

Un suscriptor más elaborado es el siguiente -

new Subscriber<Repo>() { 
    @Override 
    public void onCompleted() { 

    } 

    @Override 
    public void onError(Throwable e) { 

    } 

    @Override 
    public void onNext(Repo repo) { 

    } 
} 

P. S. - He usado lambdas en los ejemplos de arriba. Puede agregar eso a través del here.

-1

El truco aquí es la posición donde se coloca la

mAdapter.notifyDataSetChanged();

Aquí un ejemplo sencillo:

mRecyclerView = (RecyclerView) rootView.findViewById(R.id.recycler_view); 
mAdapter = new myAdapter(......); 
mAdapter.notifyDataSetChanged(); 
mRecyclerView.setAdapter(mAdapter); 

este trabajo para mí perfectamente.

Cuestiones relacionadas