关于主ui线程的Android AsyncTask onPostExecute

fxf*_*mxf 7 multithreading android android-asynctask

我遇到了AsyncTask和onPostExecute的问题.我发现onPostExecute正在与主ui线程不同的线程上执行,这导致在修改任何视图时发生CalledFromWrongThreadException.

我进行了一些日志记录,以查看运行onPreExecute,doInBackground和onPostExecute的线程.我会看到这样的结果......

onPreExecute ThreadId: 1
doInBackground ThreadId: 25
onPostExecute ThreadId: 18
Run Code Online (Sandbox Code Playgroud)

我相信主ui线程id是1,我希望onPre和onPost都在线程1上执行.我确保创建并从ui线程调用execute方法(例如在Activity的onCreate中).

另外需要注意的是,我注意到以后的异步任务将在与先前异步任务onPostExecute方法相同的线程上运行其onPostExecute方法(在本例中为线程18).

现在,为了解决这个问题,我在调用runOnUiThread时将代码包装在我的onPostExecute方法中,但我认为这很麻烦,并且想要解决真正的问题.

我没有想法!任何人有任何见解?我很乐意回答任何可以帮助进一步调查的问题!

编辑:

有两种方法可以在代码中运行异步任务.我想知道这些例子中的后者是否会导致一些奇怪的事情发生?

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!!!
        }
    }
Run Code Online (Sandbox Code Playgroud)

}

以上看起来像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);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

也许这里发生的事情只是非常奇怪,而且根本不是如何使用异步任务,无论哪种方式都可以很好地解决问题的根源.

如果您需要更多上下文,请与我们联系.

Ofe*_*erR 4

我也遇到过同样的问题,结果发现问题出在使用 Flurry 3.2.1 上。然而,这个问题不仅限于 Flurry 库。

幕后的问题是从循环线程(不是主 UI 线程)进行第一次(首次加载应用程序时)AsyncTask 调用。此调用将 AsyncTask 中的 sHandler 静态变量初始化为错误的线程 ID,然后在所有后续 AsyncTask$onPostExecute() 调用中使用该 id。

为了解决这个问题,我在第一次应用程序加载时调用一个空的(不执行任何操作)AsyncTask,只是为了正确初始化 AsyncTask。