AsyncTask と onPostExecute に問題があります。onPostExecute がメインの UI スレッドとは異なるスレッドで実行されていることがわかりました。これにより、ビューを変更すると CalledFromWrongThreadException が発生します。
onPreExecute、doInBackground、および onPostExecute が実行されているスレッドを確認するために、いくつかのログを記録しました。私はこのような結果を見るでしょう...
onPreExecute ThreadId: 1
doInBackground ThreadId: 25
onPostExecute ThreadId: 18
メインの ui スレッド ID は 1 であり、onPre と onPost の両方がスレッド 1 で実行されることを期待します。ui スレッドから execute メソッドを作成して呼び出すようにしています (たとえば、アクティビティの onCreate で)。
私が気付いたもう 1 つの点は、後の非同期タスクが、前の非同期タスクの onPostExecute メソッドと同じスレッド (この場合はスレッド 18) で onPostExecute メソッドを実行することです。
現在、これを回避するために、runOnUiThread の呼び出しで onPostExecute メソッドのコードをラップしていますが、これはハッキーであり、実際の問題に取り組みたいと考えています。
私はアイデアがありません!誰にも洞察がありますか?今後の調査に役立つ質問があれば、喜んでお答えいたします。
編集:
コードで非同期タスクを実行する方法は 2 つあります。これらの例の後者が何か奇妙なことを引き起こしているのだろうか?
public class SomeActivity extends Activity {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main_layout);
new SomeAsyncTask().execute();
}
private class SomeAsyncTask extends AsyncTask<String, Void, Integer> {
@Override
public void onPreExecute() {
Thread.currentThread().getId() // 1
//Show a dialog
}
@Override
public Integer doInBackground(String... params) {
Thread.currentThread().getId() // 25
return 0;
}
@Override
public void onPostExecute(Integer result) {
Thread.currentThread().getId() // 18
//hide dialog
//update text view -> CalledFromWrongThreadException!!!
}
}
}
上記は AsyncTask の一般的な使用方法のように見えますが、このような単純なケースでもこの問題が発生していることがわかります。次の例では、非同期タスクを使用して他の非同期タスクを実行します。非同期タスクが構築されて奇妙な動作を引き起こしているときに何が起こるか、私にはわからないことがありますか?
public class SomeActivity extends Activity implements TaskRunner.OnFinishListener {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main_layout);
TaskRunner taskRunner = new TaskRunner();
taskRunner.setOnFinishListener(this);
taskRunner.addTask(new SingleTask());
taskRunner.addTask(new SingleTask());
taskRunner.execute();
}
@Override
public void onTaskFinish(List<Integer> results) {
//Thread id is 18 when it should be 1
//do something to a view - CalledFromWrongThreadException!!
}
}
//In a different file
public class SingleTask extends AsyncTask<String, Void, Integer> {
//This is a an async task so we can run it separately as an asynctask
//Or run it on whatever thread runnerExecute is called on
@Override
public Integer doInBackground(String... params) {
return runnerExecute(params);
}
//Can be called outside of doInBackground
public Integer runnerExecute(String... params) {
//some long running task
return 0;
}
}
//In a different file
public class TaskRunner {
private List<SingleTask> tasks;
private OnFinishListener onFinishListener;
public interface OnFinishListener {
public void onTaskFinish(List<Integer> results);
}
public TaskRunner() {
this.tasks = new ArrayList<SingleTask>();
}
public void setOnFinishListener(OnFinishListener listener) {
this.onFinishListener = listener;
}
public void addTask(SingleTask task) {
tasks.add(task);
}
public void executeTasks() {
new RunnerTask().execute((SingleTask[]) tasks.toArray());
}
//Calls the runnerExecute method on each SingleTask
private class RunnerTask extends AsyncTask<SingleTask, Integer, List<Integer>> {
@Override
public void onPreExecute() {
//Runs on thread 1
}
@Override
public List<Integer> doInBackground(SingleTask... params) {
//Runs on arbitrary thread
List<Integer> results = new ArrayList<Integer>();
for(SingleTask task : params) {
int result =task.runnerExecute(task.getParams());
results.add(result);
}
return results;
}
@Override
public void onPostExecute(List<Integer> results) {
//Runs on thread 18
onFinishListener.onTaskFinish(results);
}
}
}
おそらく、ここで起こっていることは非常に奇妙であり、非同期タスクがどのように使用されることを意図したものではないか、いずれにせよ、問題の根底に到達することは素晴らしいことです.
さらにコンテキストが必要な場合はお知らせください。