7

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);
        }
    }
}

おそらく、ここで起こっていることは非常に奇妙であり、非同期タスクがどのように使用されることを意図したものではないか、いずれにせよ、問題の根底に到達することは素晴らしいことです.

さらにコンテキストが必要な場合はお知らせください。

4

5 に答える 5

1

使用してみてください:

getBaseContext().runOnUiThread(new Runnable()
{
@override
public void run()
{

}
});

run関数内にコードを記述します

于 2013-01-16T23:36:10.633 に答える
1

AsyncTask は、メイン スレッドから使​​用するように設計されています。あなたの問題は 2 番目のケースで、バックグラウンド スレッドから SingleTask で execute を呼び出すことです。RunnerTask の doInBackground メソッドで呼び出します。onPostExecute は、RunnerTask の backgroundthread から実行されます。

あなたのための2つのオプション。

1: RunnerTask を破棄し、メイン スレッドから SingleTasks を実行します。それらはすべて並行して実行され、どちらが最初に終了するかわかりませんが、メイン スレッドで onPreExecute と onPostExecute が呼び出されます。

2: SingleTask を破棄して Runnables として定義すると、RunnerTask の doInBackground で順番に実行できます。それらはすべて、Run を呼び出した順序で、RunnerTask のバックグラウンド スレッドで実行されます。完了すると、RunnerTask の onPostExecute がメイン スレッドで実行されます。

于 2013-06-24T10:15:44.023 に答える
0

私はあなたのコードを試してみました.onPreExecuteとonPostExecuteは同じスレッドで実行されます.どのようにスレッドIDを出力しますか? 試す:

Log.d("THREADTEST","PRE"+Long.toString(Thread.currentThread().getId()));

Log.d("THREADTEST","BACKGROUND"+Long.toString(Thread.currentThread().getId()));

Log.d("THREADTEST","POST"+Long.toString(Thread.currentThread().getId()));

PSそれはあるべきです:

new SomeAsyncTask().execute();

private class SomeAsyncTask extends AsyncTask<String, Void, Integer> { ... }
于 2013-01-17T06:35:22.970 に答える
0

asynctask はメイン スレッドからのみ実行する必要があるため、実際には RunnerTask の doinbackground メソッドから SingleTask を実行していますが、これは正しくありません。RunnerTask から SingleTasks のセットを実行するロジックを再検討する必要があります。

于 2015-06-09T14:50:26.717 に答える