錯誤程式碼片段
class UpdateTask implements Runnable {
@Override
public void run() {
// 非 UI 執行緒
setContentView(R.layout.activity_messages); // 錯誤:只能在 UI 執行緒呼叫
ListView lm = (ListView) findViewById(R.id.listView1);
ArrayAdapter<String> adpt = new ArrayAdapter<String>(this,
android.R.layout.simple_list_item_1, lst); // 錯誤:this 非 Context
lm.setAdapter(adpt);
handler.postDelayed(this, 500);
}
}
兩大核心問題
- Context 傳遞錯誤:
ArrayAdapter 建構子第一個參數需為 Context,匿名內部類別中的 this 指向 Runnable 實例,而非 Activity。應改為 YourActivity.this 或 getApplicationContext()。
- 非 UI 執行緒操作 View:
run() 在背景執行緒執行,直接呼叫 setContentView、findViewById、setAdapter 會拋出 CalledFromWrongThreadException。
正確做法
class UpdateTask implements Runnable {
@Override
public void run() {
// 1. 背景執行緒只做資料查詢
final List<String> data = cs.GetMessage(id);
// 2. 切回 UI 執行緒更新介面
runOnUiThread(new Runnable() {
@Override
public void run() {
ListView lm = (ListView) findViewById(R.id.listView1);
ArrayAdapter<String> adpt = new ArrayAdapter<>(
MainActivity.this,
android.R.layout.simple_list_item_1,
data);
lm.setAdapter(adpt);
}
});
// 3. 排程下一次輪詢
handler.postDelayed(this, 500);
}
}
關鍵點總結
- 資料查詢(網路、資料庫)放在背景執行緒。
- 所有 View 操作必須在 UI 執行緒(
runOnUiThread、Handler.post、AsyncTask.onPostExecute)。
- 建構
ArrayAdapter 時傳入 Activity.this 或 getContext()。