gau*_*ain 21 android android-asynctask
这是在一次Android采访中被问到的.我被问到是否可以从异步任务1的doInBackground()方法启动另一个异步任务(让它成为Task2)(让它成为Task1).我已经阅读了以下文档:
必须在UI线程上创建任务实例.
必须在UI线程上调用execute(Params ...).
根据这些陈述,我认为不应该从另一个任务的后台方法启动任务.此外,异步任务有UI方法(不能在后台线程上使用),所以加强了我的论点,我回答它是不可能的.
在检查一个简单的演示应用程序时,我看到它确实可以这样做.一些演示代码:
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mContext = this;
init();
Log.v ("gaurav", "Thread is : " + Thread.currentThread().getName());
Task1 task = new Task1();
task.execute();
}
class Task1 extends AsyncTask {
@Override
protected Object doInBackground(Object... params) {
// TODO Auto-generated method stub
Log.v ("gaurav", "Thread task 1 is : " + Thread.currentThread().getName());
Task2 task = new Task2();
task.execute();
return null;
}
}
class Task2 extends AsyncTask {
@Override
protected Object doInBackground(Object... params) {
// TODO Auto-generated method stub
Log.v ("gaurav", "Thread task 2 is : " + Thread.currentThread().getName());
Log.v ("gaurav", "Task 2 started");
return null;
}
}
Run Code Online (Sandbox Code Playgroud)
我得到以下日志表明执行成功:
> 08-07 09:46:25.564: V/gaurav(2100): Thread is : main 08-07
> 09:46:25.564: V/gaurav(2100): Thread task 1 is : AsyncTask #3 08-07
> 09:46:25.564: V/gaurav(2100): Thread task 2 is : AsyncTask #4 08-07
> 09:46:25.564: V/gaurav(2100): Task 2 started
Run Code Online (Sandbox Code Playgroud)
我在ICS,KK和L设备上检查了这个,它适用于所有人.
我能想到的一个原因是我没有覆盖任何UI方法并在我的第二个任务中进行任何UI更新,因此它不会导致任何问题,但我不确定.即使是这种情况,也违反了开发者指南中提到的线程规则.
作为参考,我也检查了这个链接:从另一个AsyncTask doInBackground()启动AsyncTask但是答案表明使用doInBackground()内部的runOnUiThread()方法启动第二个任务.我想对这里发生的事情提供一些帮助.谢谢.
小智 15
我们将您的代码更改为以下内容:
class Task1 extends AsyncTask {
@Override
protected Object doInBackground(Object... params) {
// TODO Auto-generated method stub
Log.v ("gaurav", "Thread task 1 is : " + Thread.currentThread().getName());
Task2 task = new Task2();
task.execute();
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
Log.v ("gaurav", "Log after sleeping");
return null;
}
}
class Task2 extends AsyncTask {
@Override
protected Object doInBackground(Object... params) {
// TODO Auto-generated method stub
Log.v ("gaurav", "Thread task 2 is : " + Thread.currentThread().getName());
Log.v ("gaurav", "Task 2 Started");
return null;
}
}
Run Code Online (Sandbox Code Playgroud)
现在LogCat返回:
08-07 06:13:44.208 3073-3073/testapplication V/gaurav? Thread is : main
08-07 06:13:44.209 3073-3091/testapplication V/gaurav? Thread task 1 is : AsyncTask #1
08-07 06:13:49.211 3073-3091/testapplication V/gaurav? Log after sleeping
08-07 06:13:49.213 3073-3095/testapplication V/gaurav? Thread task 2 is : AsyncTask #2
08-07 06:13:49.213 3073-3095/testapplication V/gaurav? Task 2 Started
Run Code Online (Sandbox Code Playgroud)
正如您所看到的Task 2,在Task 1执行结束后执行(即使在睡眠5秒后).这意味着第二个任务在完成第一个任务之前不会启动.
为什么?
原因是AsyncTask的源代码背后.请考虑以下execute()方法:
public synchronized void execute(final Runnable r) {
mTasks.offer(new Runnable() {
public void run() {
try {
r.run();
} finally {
scheduleNext();
}
}
});
if (mActive == null) {
scheduleNext();
}
}
Run Code Online (Sandbox Code Playgroud)
和scheduleNext()方法:
protected synchronized void scheduleNext() {
if ((mActive = mTasks.poll()) != null) {
THREAD_POOL_EXECUTOR.execute(mActive);
}
}
Run Code Online (Sandbox Code Playgroud)
这些方法中最重要的关键字是synchronized确保这些方法只能在一个线程中同时运行.当调用execute方法,它提供了一个新的Runnable来mTask这是一个实例ArrayDeque<Runnable>类的工作将在不同的线程不同要求的串行[详细信息].如果没有执行Runnable(即if (mActive == null)),scheduleNext()则将调用,否则,将scheduleNext()在finally(由于任何原因)当前执行结束之后调用块中的块Runnable.所有Runnables都在一个单独的线程上执行THREAD_POOL_EXECUTOR.
从其他线程执行AsyncTask有什么问题?从Jelly Bean AsyncTask开始,在UI线程的应用程序启动时加载类,以便保证在UI线程上发生回调,但是,在Jelly Bean发布之前,如果另一个线程创建AsyncTask回调可能不会发生在正确的线程上.
因此,AsyncTask应该仅在Jelly Bean(+和+)之前的平台上从UI线程调用实现.
澄清:请考虑以下示例,它只是澄清了Android不同平台版本之间的差异:
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main2);
new Thread() {
@Override
public void run() {
Task1 task = new Task1();
task.execute();
}
}.start();
}
class Task1 extends AsyncTask {
@Override
protected Object doInBackground(Object... params) {
return null;
}
}
Run Code Online (Sandbox Code Playgroud)
它在Android 5.1上工作正常,但在Android 2.3上崩溃时出现以下异常:
08-07 12:05:20.736 584-591/github.yaa110.testapplication E/AndroidRuntime? FATAL EXCEPTION: Thread-8
java.lang.ExceptionInInitializerError
at github.yaa110.testapplication.Main2Activity$1.run(Main2Activity.java:21)
Caused by: java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare()
at android.os.Handler.<init>(Handler.java:121)
at android.os.AsyncTask$InternalHandler.<init>(AsyncTask.java:421)
at android.os.AsyncTask$InternalHandler.<init>(AsyncTask.java:421)
at android.os.AsyncTask.<clinit>(AsyncTask.java:152)
at github.yaa110.testapplication.Main2Activity$1.run(Main2Activity.java:21)
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
14806 次 |
| 最近记录: |