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
Update ListView in the main thread from another thread
提问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.
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
yourActivity
is the activity that your widget has been placed into it,
yourView
is The widget and
adapter
is 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.
这对我来说很完美。