首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 更多程式語言 >> 程式設計疑難解答

Android AsyncTask 回調中更新 ListView:在 onPostExecute 設定 Adapter 或 notifyDataSetChanged

     編輯:程式設計疑難解答

新浪微博 SDK `userTimelineIds` 使用內部 `AsyncTask` 實現非同步回調,`onComplete(String result)` 執行於**背景執行緒**(或 SDK 內部執行緒池),**不能直接操作 UI**。需將資料傳遞到主執行緒(`runOnUiThread`、`Handler`、`LiveData`)後再設定 `ListView` Adapter。

問題代碼

mStatuseAPI.userTimelineIds(uid, ..., new RequestListener() {
    @Override
    public void onComplete(String result) {
        // ❌ 這裡可能在背景執行緒,直接操作 ListView 會崩潰或不生效
        getWbList(result);  // 內部可能呼叫 adapter.notifyDataSetChanged()
    }
});

解決方案對比

方案代碼範例優點缺點
runOnUiThread`runOnUiThread(() -> getWbList(result));`簡單、無額外依賴Activity 銷毀後可能洩漏
Handler (主執行緒 Looper)`new Handler(Looper.getMainLooper()).post(() -> getWbList(result));`可在非 Activity 類別使用需持有 Looper 參考
LiveData + ViewModel (推薦)ViewModel 持有 `MutableLiveData>`,Activity `observe` 更新 UI生命週期感知、配置變更安全、可測試需引入 Architecture Components
RxJava / Kotlin Coroutines`Single.fromCallable(...).subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread())`鏈式、背壓、取消支援學習曲線較高

快速修復:runOnUiThread

mStatuseAPI.userTimelineIds(uid, 0L, 0L, 50, 1, false, StatusesAPI.FEATURE_ALL,
    new RequestListener() {
        @Override
        public void onWeiboException(WeiboException e) { e.printStackTrace(); }

        @Override
        public void onComplete(String result) {
            if (TextUtils.isEmpty(result)) {
                Log.i(TAG, "無微博資料");
                return;
            }
            // ✅ 切回主執行緒更新 UI
            runOnUiThread(() -> {
                try {
                    getWbList(result);  // 解析 JSON、填充 List、adapter.notifyDataSetChanged()
                } catch (Exception e) {
                    e.printStackTrace();
                }
            });
        }
    });

getWbList 實作參考

private void getWbList(String json) {
    try {
        JSONObject obj = new JSONObject(json);
        JSONArray ids = obj.getJSONArray("ids");  // 視 API 實際結構
        List items = new ArrayList<>();
        for (int i = 0; i < ids.length(); i++) {
            String id = ids.getString(i);
            // 這裡可再發請求查詢微博詳情,或直接用 ID 佔位
            items.add(new WeiboItem(id, "內容載入中..."));
        }
        // 更新 Adapter
        if (adapter == null) {
            adapter = new WeiboAdapter(this, items);
            listView.setAdapter(adapter);
        } else {
            adapter.clear();
            adapter.addAll(items);
            adapter.notifyDataSetChanged();
        }
    } catch (JSONException e) { e.printStackTrace(); }
}

進階:封裝為 LiveData (Jetpack 標準)

// ViewModel
public class WeiboViewModel extends ViewModel {
    private final MutableLiveData> _weiboList = new MutableLiveData<>();
    public LiveData> weiboList = _weiboList;

    public void fetchWeiboIds(long uid) {
        mStatuseAPI.userTimelineIds(uid, ..., new RequestListener() {
            @Override public void onComplete(String result) {
                List list = parseResult(result);
                _weiboList.postValue(list);  // 自動切主執行緒
            }
            @Override public void onWeiboException(WeiboException e) {
                _weiboList.postValue(Collections.emptyList());
            }
        });
    }
}

// Activity/Fragement
viewModel.weiboList.observe(getViewLifecycleOwner(), items -> {
    adapter.submitList(items);  // ListAdapter / DiffUtil 自動動畫
});

核心原則

  • **SDK 回調不保證在主執行緒** → 永遠假設在背景執行緒
  • **UI 操作必須在主執行緒** → `runOnUiThread` / `Handler(Looper.getMainLooper())` / `LiveData.postValue`
  • **避免記憶體洩漏** → 用 `WeakReference` 或 `LifecycleObserver` 自動取消

在 `onComplete` 回調中用 `runOnUiThread(() -> getWbList(result))` 即可快速修復;長期專案建議遷移至 `ViewModel + LiveData` 或 `Kotlin Coroutines` 獲得完整生命週期管理。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved