Android的AsyncTask onPostExecuteclosures主要的UI线程

我有一个与AsyncTask和onPostExecute问题。 我发现onPostExecute执行在不同于主ui线程的线程上,当我修改任何视图时,会导致发生CalledFromWrongThreadException。

我把一些日志logging,看看哪些线程onPreExecute,doInBackground和onPostExecute正在运行。 我会看到像这样的结果…

onPreExecute ThreadId: 1 doInBackground ThreadId: 25 onPostExecute ThreadId: 18 

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

另外需要注意的是,后来的asynchronous任务将在与之前的asynchronous任务onPostExecute方法(本例中为线程18)相同的线程上运行onPostExecute方法。

现在为了解决这个问题,我在调用runOnUiThread的时候将代码封装在onPostExecute方法中,但是我认为这很冒充,希望能够解决真正的问题。

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

编辑:

asynchronous任务在代码中运行有两种方法。 我想知道这些例子中的后者是否会造成奇怪的事情发生?

 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,但我仍然看到这个问题发生即使在这样的简单情况。 下一个示例使用asynchronous任务来运行其他asynchronous任务。 也许有什么我不知道什么时候asynchronous任务构造,造成一些奇怪的行为会发生什么?

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

也许这里发生的事情只是超级怪异,而不是如何使用asynchronous任务,无论哪种方式,这将是很好的底部问题。

让我知道你是否需要更多的上下文。

我一直在遇到同样的问题,事实certificate这个问题是使用Flurry 3.2.1。 但是,这个问题不仅限于Flurry库。

幕后的问题是有史以来第一次(当应用程序加载第一次)从不是主UI线程的循环线程的AsyncTask调用。 此调用将AsyncTask中的sHandler静态variables初始化为错误的线程ID,然后在随后的所有AsyncTask $ onPostExecute()调用中使用此ID。

为了解决这个问题,我在第一个应用程序加载时调用了一个空的(无所事事)AsyncTask,只是为了正确地初始化AsyncTask。

尝试使用:

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

并在run函数中写入你的代码

AsyncTask被devise为在主线程中使用。 你的问题是第二种情况,是你从后台线程的SingleTask调用执行。 你可以在RunnerTask的doInBackground方法中调用它。 然后onPostExecute从RunnerTask的后台运行

两个选项给你。

1:Trash RunnerTask,并从你的主线程执行SingleTasks,它们将全部并行运行,你不会知道哪一个先完成,但是在主线程上调用PreExecute和onPostExecute

2:清理SingleTask并将它们定义为Runnables,然后在RunnerTask的doInBackground中依次运行它们。 他们将全部运行在RunnerTask的后台线程中,按照您调用Run的顺序运行。 完成后,RunnerTask的onPostExecute在主线程上运行。

我只是试过你的代码和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> { ... } 

你实际上是从RunnerTask的doinbackground方法执行SingleTask,这是不正确的,因为asynctask只能从主线程执行。 您需要重新查看从RunnerTask运行SingleTasks集合的逻辑。