Android AsyncTask onPostExecute脱离主ui线程

Android AsyncTask onPostExecute脱离主ui线程,android,multithreading,android-asynctask,Android,Multithreading,Android Asynctask,我对AsyncTask和onPostExecute有问题。我发现onPostExecute在与主ui线程不同的线程上执行,这导致在修改任何视图时发生CalledFromErrorThreadException 我加入了一些日志,以查看在PreExecute、doInBackground和onPostExecute上运行的线程。我会看到这样的结果 onPreExecute ThreadId: 1 doInBackground ThreadId: 25 onPostExecute ThreadId:

我对AsyncTask和onPostExecute有问题。我发现onPostExecute在与主ui线程不同的线程上执行,这导致在修改任何视图时发生CalledFromErrorThreadException

我加入了一些日志,以查看在PreExecute、doInBackground和onPostExecute上运行的线程。我会看到这样的结果

onPreExecute ThreadId: 1
doInBackground ThreadId: 25
onPostExecute ThreadId: 18
我相信主ui线程id是1,我希望onPre和onPost都在线程1上执行。我要确保在ui线程中创建并调用execute方法(例如在活动的onCreate中)

我注意到的另一件事是,后面的异步任务将在与前面的异步任务onPostExecute方法(在本例中为线程18)相同的线程上运行其onPostExecute方法

现在为了解决这个问题,我在调用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!!!
        }
    }
公共类SomeActivity扩展活动{
@凌驾
创建时的公共void(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
setContentView(右布局、主布局);
新建SomeAsyncTask().execute();
}
私有类SomeAsyncTask扩展了AsyncTask{
@凌驾
公共无效onPreExecute(){
Thread.currentThread().getId()//1
//显示对话框
}
@凌驾
公共整数doInBackground(字符串…参数){
Thread.currentThread().getId()//25
返回0;
}
@凌驾
public void onPostExecute(整数结果){
Thread.currentThread().getId()//18
//隐藏对话框
//更新文本视图->CalledFromErrorThreadException!!!
}
}
}

上面的内容似乎是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);
        }
    }
}
公共类SomeActivity扩展活动实现TaskRunner.OnFinishListener{
@凌驾
创建时的公共void(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
setContentView(右布局、主布局);
TaskRunner TaskRunner=新的TaskRunner();
taskRunner.setOnFinishListener(此);
taskRunner.addTask(新的SingleTask());
taskRunner.addTask(新的SingleTask());
taskRunner.execute();
}
@凌驾
公共void onTaskFinish(列出结果){
//线程id应为1时为18
//对名为FromErrorThreadException的视图执行某些操作!!
}
}
//在另一个文件中
公共类SingleTask扩展了AsyncTask{
//这是一个异步任务,因此我们可以将其作为异步任务单独运行
//或者在调用runnerExecute的任何线程上运行它
@凌驾
公共整数doInBackground(字符串…参数){
返回runnerExecute(参数);
}
//可以在doInBackground之外调用
公共整数runnerExecute(字符串…参数){
//一些长时间运行的任务
返回0;
}
}
//在另一个文件中
公共类任务管理器{
私有列表任务;
私有OnFinishListener OnFinishListener;
公共接口侦听器{
公共void onTaskFinish(列出结果);
}
公共TaskRunner(){
this.tasks=new ArrayList();
}
public void setOnFinishListener(OnFinishListener侦听器){
this.onFinishListener=侦听器;
}
公共void addTask(单任务任务){
任务。添加(任务);
}
public void executeTasks(){
新建RunnerTask().execute((SingleTask[])tasks.toArray());
}
//对每个单任务调用runnerExecute方法
私有类RunnerTask扩展了AsyncTask{
@凌驾
公共无效onPreExecute(){
//在线程1上运行
}
@凌驾
公共列表doInBackground(单任务…参数){
//在任意线程上运行
列表结果=新建ArrayList();
for(单个任务:参数){
int result=task.runnerExecute(task.getParams());
结果。添加(结果);
}
返回结果;
}
@凌驾
public void onPostExecute(列出结果){
//在线程18上运行
onFinishListener.onTaskFinish(结果);
}
}
}
也许这里发生的事情非常奇怪,根本不知道异步任务是如何使用的,不管怎样,找到问题的根源都很好

如果需要更多上下文,请告诉我。

尝试使用:

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

}
});

run
函数中编写代码

我刚刚尝试了你的代码,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()));
另外,它应该是:

new SomeAsyncTask().execute();

私有类SomeAsyncTask扩展了AsyncTask{…}

异步任务设计为从主线程使用。您的问题是第二种情况,您从后台线程调用SingleTask上的execute。在RunnerTask的doInBackground方法中调用它。然后从RunnerTask的后台线程运行onPostExecute

你有两个选择

1:丢弃RunnerTask,并从主线程执行SingleTasks,它们都将并行运行,您不知道哪个先完成,而是onPreExecute和onPost
private class SomeAsyncTask extends AsyncTask<String, Void, Integer> { ... }