【发布时间】:2010-05-27 09:07:55
【问题描述】:
我有一个单独的线程正在运行以从 Internet 获取数据。之后,我想通过调用 adapter.notifyDataSetChanged() 来更新主线程中的 ListView。但它不起作用。有什么解决方法吗?谢谢。
【问题讨论】:
标签: android
我有一个单独的线程正在运行以从 Internet 获取数据。之后,我想通过调用 adapter.notifyDataSetChanged() 来更新主线程中的 ListView。但它不起作用。有什么解决方法吗?谢谢。
【问题讨论】:
标签: android
使用 AsyncTask (http://developer.android.com/reference/android/os/AsyncTask.html)。
在 onPostExecute(...) 方法中调用 adapter.notifyDataSetChanged()。
更多详情,请阅读:http://android-developers.blogspot.com/2009/05/painless-threading.html
【讨论】:
总体上好的建议是 http://android-developers.blogspot.com/2009/05/painless-threading.html
我个人使用我的自定义线程(扩展 Thread 的类),但通过 Message 向 UI 线程发送响应。所以在线程的run()函数中有:
Message msg;
msg = Message.obtain();
msg.what = MSG_IMG_SET;
mExtHandler.sendMessage(msg);
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);
}
};
这实际上比 AsyncTask 更容易。
【讨论】:
mImagesProgressHandler的引用
或者,将消息发布到列表视图的消息队列(将在 UI 线程上执行):
list.post(new Runnable() {
@Override
public void run() {
adapter.notifyDataSetChanged();
}
});
【讨论】:
假设
yourActivity 是您的小部件已放入其中的活动,
yourView 是小部件和
adapter 是小部件的适配器:
yourActivity.runOnUiThread(new Runnable() {
public void run() {
try{
adapter.notifyDataSetChanged();
}
catch{}
}
}
【讨论】:
您可以这样做。我将使用 GitHub API 作为示例。
为您的 HTTP API 创建一个 Java 接口。
public interface GitHubService {
@GET("users/{user}/repos")
Observable<List<Repo>> listRepos(@Path("user") String user);
}
使用 Observable 会将响应转换为流。每个事件都是一个 repos 列表。
使用 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);
现在是 Rx 部分。您必须添加订阅者才能收听服务器发回的响应。换句话说,做出反应。
service.listRepos("octocat")
.subscribeOn(Schedulers.io()) // 1
.observeOn(AndroidSchedulers.mainThread()) // 2
.flatMap(Observable::from) // 3
.subscribe(repoList -> { // 4
// Update the list view
// notifyDataSetChanged
});
这是用数字注释的行的作用 -
1 - 它告诉操作系统使用哪个线程进行调用。我们正在为此选择 IO 线程。
2 - 它告诉操作系统使用哪个线程来监听响应。我们在主线程上执行此操作,并在收到响应时更新 UI。
3 - 这行代码展示了 Rx 的真正魔力。这条简单的小线将响应列表转换为单个对象。因此,我们将对每个对象做出反应,而不是对整个列表做出反应。你可以阅读更多关于它的信息here。
4 - 这一行实际上定义了将对事件显示什么样的“反应”。您可以在此处更新适配器。
一个更复杂的订阅者看起来像这样 -
new Subscriber<Repo>() {
@Override
public void onCompleted() {
}
@Override
public void onError(Throwable e) {
}
@Override
public void onNext(Repo repo) {
}
}
附: - 我在上面的例子中使用了 lambdas。你可以通过here添加。
【讨论】:
这对我有用
this.runOnUiThread(() -> {
chatAdapter.notifyItemInserted(chatMessages.size()-1);
binding.chatMessages.scrollToPosition(chatMessages.size()-1);
});
其中this 指的是当前包含适配器和recyclerview 的Activity。
【讨论】:
这里的诀窍是你放的位置
mAdapter.notifyDataSetChanged();
这里是一个简单的例子:
mRecyclerView = (RecyclerView) rootView.findViewById(R.id.recycler_view);
mAdapter = new myAdapter(......);
mAdapter.notifyDataSetChanged();
mRecyclerView.setAdapter(mAdapter);
这对我来说非常适合。
【讨论】: