Update ListView in the main thread from another thread

前端 未结 6 794
北恋
北恋 2020-12-08 08:34

I have a separate thread running to get data from the internet. After that, I would like to update the ListView in the main thread by calling adapter.notifyDataSetChanged().

相关标签:
6条回答
  • 2020-12-08 09:03

    The trick here is the position where you put the

    mAdapter.notifyDataSetChanged();

    Here a simple example :

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

    this work for me perfectly.

    0 讨论(0)
  • Assume yourActivity is the activity that your widget has been placed into it, yourView is The widget and adapter is The widget's adapter:

    yourActivity.runOnUiThread(new Runnable() {
     public void run() {    
             try{
                    adapter.notifyDataSetChanged();
             }
             catch{}
     }
    }
    
    0 讨论(0)
  • 2020-12-08 09:11

    Or, post a message to the listview's message queue (which would execute on the UI thread):

    list.post(new Runnable() {                  
        @Override
        public void run() {
           adapter.notifyDataSetChanged();
    
        }
    }); 
    
    0 讨论(0)
  • 2020-12-08 09:18

    Use AsyncTask ( http://developer.android.com/reference/android/os/AsyncTask.html ).

    Invoke adapter.notifyDataSetChanged() in onPostExecute(...) method.

    For more details, please read this: http://android-developers.blogspot.com/2009/05/painless-threading.html

    0 讨论(0)
  • 2020-12-08 09:18

    Overall good advice is http://android-developers.blogspot.com/2009/05/painless-threading.html

    Personally I use my custom thread (a class extending Thread ) but send response to the UI thread through a Message. So in the thread's run() function there is:

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

    The UI thread defines a message handler.

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

    This is actually easier than AsyncTask.

    0 讨论(0)
  • 2020-12-08 09:22

    You can use a combination of RxJava and Retrofit for this purpose.

    Here's how you can do it. I will be using the GitHub API for the example.

    Create a Java interface for your HTTP API.

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

    Using Observable will convert the response into a stream. Every event being a List of repos.

    Use Retrofit class to generate an implementation of the GitHubService interface. You may or may or may not provide a custom HTTP Client.

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

    Now comes the Rx part. You have to add a subscriber to listen to the responses sent back by the server. In other words, react to it.

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

    Here's what the lines commented with numbers are doing -

    1 - It tells the OS which thread to be used to make the call. We are choosing the IO thread for that.

    2 - It tells the OS which thread to be used to listen for the response. We do that on the main thread, and update the UI on receiving a response.

    3 - This line demonstrates the true magic of Rx. This simple little line converts a list of responses to single objects. Hence we will be reacting to every object instead of the whole list altogether. You can read more about it here.

    4 - This line actually defines what kind of 'reaction' will be shown to the event. You can update the adapter here.

    A more elaborate subscriber looks like this -

    new Subscriber<Repo>() {
        @Override
        public void onCompleted() {
    
        }
    
        @Override
        public void onError(Throwable e) {
    
        }
    
        @Override
        public void onNext(Repo repo) {
    
        }
    }
    

    P.S. - I have used lambdas in the examples above. You can add that through here.

    0 讨论(0)
提交回复
热议问题