Android 从另一个线程更新主线程中的 ListView

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/2919778/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-20 07:54:32  来源:igfitidea点击:

Update ListView in the main thread from another thread

android

提问by Wilson

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(). But it does not work. Any workaround for that? Thanks.

我有一个单独的线程正在运行以从 Internet 获取数据。之后,我想通过调用adapter.notifyDataSetChanged() 来更新主线程中的ListView。但它不起作用。有什么解决方法吗?谢谢。

回答by Damian Ko?akowski

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

使用 AsyncTask ( http://developer.android.com/reference/android/os/AsyncTask.html)。

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

onPostExecute(...)方法中调用adapter.notifyDataSetChanged()

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

更多详情,请阅读:http: //android-developers.blogspot.com/2009/05/painless-threading.html

回答by Yar

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

总体上很好的建议是 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:

我个人使用我的自定义线程(一个扩展 Thread 的类),但通过消息向 UI 线程发送响应。所以在线程的 run() 函数中有:

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

The UI thread defines a message handler.

UI 线程定义了一个消息处理程序。

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.

这实际上比 AsyncTask 更容易。

回答by Jay Sidri

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

或者,将消息发布到列表视图的消息队列(将在 UI 线程上执行):

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

    }
}); 

回答by padfoot27

You can use a combination of RxJavaand Retrofitfor this purpose.

为此,您可以结合使用RxJavaRetrofit

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

这是您如何做到的。我将使用 GitHub API 作为示例。

Create a Java interface for your HTTP API.

为您的 HTTP API 创建一个 Java 接口。

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.

使用 Observable 会将响应转换为流。每个事件都是一个回购列表。

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

使用 Retrofit 类生成 GitHubService 接口的实现。您可能会或可能不会提供自定义 HTTP 客户端。

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, reactto it.

现在是 Rx 部分。你必须添加一个订阅者来监听服务器发回的响应。换句话说,对它做出反应

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.

1 - 它告诉操作系统使用哪个线程来进行调用。我们为此选择 IO 线程。

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.

2 - 它告诉操作系统使用哪个线程来监听响应。我们在主线程上执行此操作,并在收到响应时更新 UI。

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.

3 - 这一行展示了 Rx 的真正魔力。这个简单的小行将响应列表转换为单个对象。因此,我们将对每个对象而不是整个列表做出反应。您可以在此处阅读更多相关信息。

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

4 - 这一行实际上定义了将向事件显示什么样的“反应”。您可以在此处更新适配器。

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.

PS - 我在上面的例子中使用了 lambdas。你可以通过这里添加。

回答by Mostafa Lavaei

Assume yourActivityis the activity that your widget has been placed into it, yourViewis The widget and adapteris The widget's adapter:

假设 yourActivity是您的小部件已放入其中的活动, yourView是小部件, adapter是小部件的适配器:

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

回答by Samir Thebti

The trick here is the position where you put the

这里的诀窍是你把

mAdapter.notifyDataSetChanged();

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.

这对我来说很完美。