我有一個單獨的線程運行以從互聯網獲取數據。之後,我想通過調用adapter.notifyDataSetChanged()來更新主線程中的ListView。但它不起作用。任何解決方法?謝謝。從另一個線程更新主線程中的ListView
回答
使用AsyncTask(http://developer.android.com/reference/android/os/AsyncTask.html)。
調用adapter.notifyDataSetChanged()在onPostExecute(...)方法。
有關詳細信息,請仔細閱讀本:http://android-developers.blogspot.com/2009/05/painless-threading.html
總體不錯的建議是 http://android-developers.blogspot.com/2009/05/painless-threading.html
我個人使用我的自定義線程(一類擴展Thread),但通過消息發送響應到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更容易。
我更喜歡這種方法以及 – Mark 2011-02-14 01:47:04
我忘了提及:你也可以添加一個對象到消息,如:msg.obj = someBitmap;並在處理程序中接收它(例如,可以使用接收到的位圖更新數組或列表,並通知適配器列表的底層數據已更改:mArrayAdapter.notifyDataSetChanged();)。在這種情況下,不會出現競賽狀況。 – Yar 2011-02-16 09:09:21
當心 - 這裏是龍!這個內部Handler類對外部類有一個隱式引用。更好地使Handler靜態並將WeakReference引用到外部類。 – 2015-07-14 22:17:32
或者發佈消息ListView的消息隊列(這將在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{}
}
}
您可以使用RxJava和組合爲此目的。
下面介紹如何做到這一點。我將使用GitHub API作爲示例。
爲您的HTTP API創建一個Java接口。
public interface GitHubService {
@GET("users/{user}/repos")
Observable<List<Repo>> listRepos(@Path("user") String user);
}
使用Observable會將響應轉換爲流。每個事件都是回購列表。
使用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) {
}
}
附: - 我在上面的例子中使用過lambda表達式。您可以通過here添加。
這裏的技巧是,你把
mAdapter.notifyDataSetChanged()的位置;
這裏一個簡單的例子:
mRecyclerView = (RecyclerView) rootView.findViewById(R.id.recycler_view);
mAdapter = new myAdapter(......);
mAdapter.notifyDataSetChanged();
mRecyclerView.setAdapter(mAdapter);
這個工作對我來說很好。
- 1. 從C#中的另一個線程更新GUI - 切換回主線程?
- 2. 更新的JLabel從另一個線程
- 3. 從另一個線程更新UI(progressDialog)
- 4. 從另一個線程javafx更新ImageView
- 5. ProgressBar從另一個線程更新
- 6. 從另一個線程更新UI
- 7. 更新從另一個線程treeview
- 8. 從另一個線程的主線程中顯示錶格
- 9. 從另一個線程更新GUI線程
- 10. 從另一個線程foreach listview項目
- 11. 在另一個線程中更新CollectionView
- 12. 從另一個非主線程更新QGraphicsScene
- 13. 從另一個線程操作線程
- 14. 從另一個線程運行線程
- 15. 更新ListView控件從一個線程不是原來的線程在C#
- 16. 一個線程在iPhone應用程序中殺死另一個線程(兩個線程都是主線程)?
- 17. Winforms更新DataGridView在另一個線程
- 18. 更新而QListView從另一個線程(pyqt5)更新Python列表
- 19. 從另一個線程刷新UITableViewController
- 20. android UI從另一個線程更改
- 21. 如何更新線程中的listview?
- 22. 從android中的另一個線程更新ui
- 23. 從Java中的另一個線程更新JTextField
- 24. 從另一個線程更新petrel中的進度條
- 25. 從Visual C++ 2008中的另一個線程更新GUI
- 26. PySide:從另一個線程更新GUI更容易的方法
- 27. 從另一個線程DoDragDrop()
- 28. HttpWebRequests從另一個線程
- 29. 從另一個線程
- 30. 從另一個線程
http://stackoverflow.com/a/33584826/1318946 – 2015-11-07 16:12:54