2010-05-27 21 views
12

Tôi có một luồng riêng chạy để lấy dữ liệu từ internet. Sau đó, tôi muốn cập nhật ListView trong thread chính bằng cách gọi adapter.notifyDataSetChanged(). Nhưng nó không hoạt động. Bất kỳ cách giải quyết nào cho điều đó? Cảm ơn.Cập nhật ListView trong chuỗi chính từ một chủ đề khác

+0

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

Trả lời

12

Nhìn chung lời khuyên tốt là http://android-developers.blogspot.com/2009/05/painless-threading.html

Cá nhân tôi sử dụng chủ đề tùy chỉnh của tôi (một lớp mở rộng chủ đề) nhưng gửi thư trả lời đến thread UI thông qua một tin nhắn. Vì vậy, trong hàm run() của luồng có:

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

Chuỗi giao diện người dùng xác định trình xử lý tin nhắn.

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

Điều này thực sự dễ dàng hơn so với AsyncTask.

+0

Tôi thích phương pháp này cũng như – Mark

+0

Tôi quên đề cập: bạn cũng có thể thêm đối tượng vào thông báo như: msg.obj = someBitmap; và nhận nó trong trình xử lý (ví dụ như có thể cập nhật một mảng hoặc danh sách với bitmap đã nhận và thông báo cho bộ điều hợp rằng dữ liệu cơ bản của danh sách đã thay đổi: mArrayAdapter.notifyDataSetChanged();). Trong trường hợp này, không có điều kiện chủng tộc nào có thể xảy ra. – Yar

+2

Hãy coi chừng - Đây là những con rồng! Lớp bên trong Handler này có một tham chiếu ngầm tới lớp bên ngoài 'this. Tốt hơn để làm cho Handler đó tĩnh và nhận một WeakReference đến lớp bên ngoài. –

9

Hoặc, gửi một thông điệp tới hàng đợi thông điệp của listview (trong đó sẽ thực hiện trên thread UI):

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

    } 
}); 
2

Giả yourActivity là hoạt động mà widget của bạn đã được đặt vào nó, yourView là The phụ tùng và adapter là bộ chuyển đổi của phụ tùng:

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

Bạn có thể sử dụng một sự kết hợp của RxJavaRetrofit cho mục đích này.

Đây là cách bạn có thể thực hiện. Tôi sẽ sử dụng API GitHub cho ví dụ.

Tạo giao diện Java cho API HTTP của bạn.

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

Sử dụng Observable sẽ chuyển đổi phản hồi thành luồng. Mỗi sự kiện là một Danh sách các Repos.

Sử dụng lớp Retrofit để tạo triển khai giao diện GitHubService. Bạn có thể hoặc có thể hoặc không thể cung cấp một HTTP Client tùy chỉnh.

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

Bây giờ đến phần Rx. Bạn phải thêm người đăng ký để nghe các phản hồi do máy chủ gửi lại. Nói cách khác, phản ứng với nó.

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

Đây là những gì các dòng chú giải với những con số đang làm -

1 - Nó nói với hệ điều hành mà thread được sử dụng để thực hiện cuộc gọi. Chúng tôi đang lựa chọn các thread IO cho điều đó.

2 - Nó cho biết hệ điều hành nào sẽ được sử dụng để nghe câu trả lời. Chúng tôi làm điều đó trên chuỗi chính và cập nhật giao diện người dùng khi nhận được phản hồi.

3 - Dòng này thể hiện sự kỳ diệu thực sự của Rx. Dòng đơn giản này chuyển đổi một danh sách các câu trả lời cho các đối tượng đơn lẻ. Do đó chúng tôi sẽ phản ứng với mọi đối tượng thay vì toàn bộ danh sách. Bạn có thể đọc thêm về nó here.

4 - Dòng này thực sự xác định loại 'phản ứng' nào sẽ được hiển thị cho sự kiện. Bạn có thể cập nhật bộ điều hợp tại đây.

Một thuê bao phức tạp hơn trông như thế này -

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

    } 

    @Override 
    public void onError(Throwable e) { 

    } 

    @Override 
    public void onNext(Repo repo) { 

    } 
} 

T.B. - Tôi đã sử dụng lambdas trong các ví dụ trên. Bạn có thể thêm điều đó thông qua here.

-1

Bí quyết ở đây là vị trí nơi bạn đặt các

mAdapter.notifyDataSetChanged();

Dưới đây là một ví dụ đơn giản:

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

tác phẩm này với tôi một cách hoàn hảo.

Các vấn đề liên quan