Android之AsyncTask源码学习

AsyncTask

1.定义,介绍:

  • asynctask是Android中的一个自带的轻量级异步类,通过他可以轻松的实现工作线程和UI线程之间的通信和线程切换(其实也只能在工作和ui线程之间切换,稍后会提到)
  • asynctask是一个抽象类,所以我们需要创建他的子类,一般重写他的四个方法即可:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    //这个就是要在后台做的工作,他将运行在后台工作线程上
    @WorkerThread
    protected abstract Result doInBackground(Params... params);

    //这个时开始执行前的操作,运行在主线程上
    @MainThread
    protected void onPreExecute() ;

    //doInBackground完成后调用
    @MainThread
    protected void onPostExecute(Result result)

    //实时更新,通过在doInBackground中调用publishProgress()方法
    @MainThread
    protected void onProgressUpdate(Progress... values)

2.源码

1.创建:

  • 问题:为什么说只能在工作线程和UI线程之间通信?我自己建一个looper线程也不行吗?(当然这种情况也很少)
    看他的三个构造函数:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
     public AsyncTask() {
    this((Looper) null);
    }

    /**
    * Creates a new asynchronous task. This constructor must be invoked on the UI thread.
    *
    * @hide
    */
    public AsyncTask(@Nullable Handler handler) {
    this(handler != null ? handler.getLooper() : null);
    }

    /**
    * Creates a new asynchronous task. This constructor must be invoked on the UI thread.
    *
    * @hide
    */
    public AsyncTask(@Nullable Looper callbackLooper) {
    mHandler = callbackLooper == null || callbackLooper == Looper.getMainLooper()
    ? getMainHandler()
    : new Handler(callbackLooper);

    ...
    ...
    ...
    }
    可以看出不管调用哪个都会指向第三个构造方法,关键代码
    `mHandler = callbackLooper == null || callbackLooper == Looper.getMainLooper()
    ? getMainHandler()
    : new Handler(callbackLooper);  `  
    所以,如果调用第一个构造函数,那么传入的Looper为null;如果调用第二个则传入handler.getLooper(),如果他为MainLooper的话,也将和第一个构造函数一样进入了 getMainHandler()方法:创建了一个拥有主线程的InternalHandler
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    private static Handler getMainHandler() {
    synchronized (AsyncTask.class) {
    if (sHandler == null) {
    sHandler = new InternalHandler(Looper.getMainLooper());
    }
    return sHandler;
    }
    }

    private static class InternalHandler extends Handler {
    public InternalHandler(Looper looper) {
    super(looper);
    }

    @SuppressWarnings({"unchecked", "RawUseOfParameterizedType"})
    @Override
    public void handleMessage(Message msg) {
    AsyncTaskResult<?> result = (AsyncTaskResult<?>) msg.obj;
    switch (msg.what) {
    case MESSAGE_POST_RESULT:
    // There is only one result
    result.mTask.finish(result.mData[0]);
    break;
    case MESSAGE_POST_PROGRESS:
    result.mTask.onProgressUpdate(result.mData);
    break;
    }
    }
    }
    那如果他不是mainlooper的话,就创建了一个new Handler(callbackLooper),然而这个handle既没有传入callback,也没有重写其handleMessage方法,其实是一个空的handle,但他可以调用msg的callback呀。就算这样,那我是不是仍然可以创建一个不与主线程(UI线程)相连的handle,那为啥还说只能用在ui与工作线程之前呢?
    哈哈,请再看一下上面贴上的三个构造函数的源码,我专门把第二个和第三个的注释也贴了上去,有一个很重要的注解@hide,也就是说google把第二个和第三个构造函数给隐藏起来了,不对开发者开放,我们根本访问不到(虽然能看到,而且时public,感兴趣可以查一下这个注解)。所以我们只能用第一个构造函数,传入空的looper,从而调用getMainHandler();
  • 顺便提一下handle 的执行顺序(dispatchMessage)
    1. msg的callback不为空,调用handleCallback方法(message.callback.run())
    2. mCallback不为空,调用mCallback.handleMessage(msg)
    3. 最后如果其他都为空,执行Handler自身的 handleMessage(msg) 方法

2.执行:

  • 包装doInBackground方法。
    创建完handle后,在第三个构造函数中可以看出,他接着创建了work(实现了callable)和futur(FutureTask对象其实就是更方便操作线程,Futrue可以监视目标线程调用call的情况,当你调用Future的get()方法以获得结果时,当前线程就开始阻塞,直接call方法结束返回结果。)其中很关键的代码就是在work中调用了,然后又将work用futuretask封装,在之后的调用中会最后提交给线程池
    result = doInBackground(mParams);
    mFuture = new FutureTask<Result>(mWorker) {......}
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    mWorker = new WorkerRunnable<Params, Result>() {
    public Result call() throws Exception {
    mTaskInvoked.set(true);
    Result result = null;
    try {
    Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
    //noinspection unchecked
    result = doInBackground(mParams);
    Binder.flushPendingCommands();
    } catch (Throwable tr) {
    mCancelled.set(true);
    throw tr;
    } finally {
    postResult(result);
    }
    return result;
    }
    };
    最后在finaly里调用postResult(result),将结果传递给handle,将调用handle(InternalHandler)的handleMessage,他处理两个,一个是执行结束finish(),从而调用了onPostExecute,另一个是在doInBackground里用户调用的publishProgress像handle发送消息,从而调用onProgressUpdate
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
public void handleMessage(Message msg) {
AsyncTaskResult<?> result = (AsyncTaskResult<?>) msg.obj;
switch (msg.what) {
case MESSAGE_POST_RESULT:
// There is only one result
result.mTask.finish(result.mData[0]);
break;
case MESSAGE_POST_PROGRESS:
result.mTask.onProgressUpdate(result.mData);
break;
}
}

protected final void publishProgress(Progress... values) {
if (!isCancelled()) {
getHandler().obtainMessage(MESSAGE_POST_PROGRESS,
new AsyncTaskResult<Progress>(this, values)).sendToTarget();
}
}

private void finish(Result result) {
if (isCancelled()) {
onCancelled(result);
} else {
onPostExecute(result);
}
mStatus = Status.FINISHED;
}

asynctask的两个线程池:

- `public static final Executor THREAD_POOL_EXECUTOR`:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
private static final BlockingQueue<Runnable> sPoolWorkQueue =
new LinkedBlockingQueue<Runnable>(128);


/**
* An {@link Executor} that can be used to execute tasks in parallel.
*/
public static final Executor THREAD_POOL_EXECUTOR;

static {
ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(
CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE_SECONDS, TimeUnit.SECONDS,
sPoolWorkQueue, sThreadFactory);
threadPoolExecutor.allowCoreThreadTimeOut(true);
THREAD_POOL_EXECUTOR = threadPoolExecutor;
}

可以看出,这是一个核心线程数最小为2的线程池,它是用来并行执行task的,但当达到核心线程最大值后,依旧会在阻塞队列里等待

  • public static final Executor SERIAL_EXECUTOR = new SerialExecutor()

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    private static class SerialExecutor implements Executor {
    final ArrayDeque<Runnable> mTasks = new ArrayDeque<Runnable>();
    Runnable mActive;

    public synchronized void execute(final Runnable r) {
    mTasks.offer(new Runnable() {
    public void run() {
    try {
    r.run();
    } finally {
    scheduleNext();
    }
    }
    });
    if (mActive == null) {
    scheduleNext();
    }
    }

    protected synchronized void scheduleNext() {
    if ((mActive = mTasks.poll()) != null) {
    THREAD_POOL_EXECUTOR.execute(mActive);
    }
    }
    }

    所以第二个 是一个顺序串行执行的Executor:每次将任务提交到数组双向队列里,execute后会依次执行,然后scheduleNext获取下一个任务。

  • AsyncTask中默认时使用的第二个,SERIAL_EXECUTOR,串行执行,
    private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;
    当然你也可以修改

    1
    2
    3
    4
    /** @hide */
    public static void setDefaultExecutor(Executor exec) {
    sDefaultExecutor = exec;
    }

    然而很不幸,他也被hide起来了…但是可以在接下来的入口处,直接调用executeOnExecutor(Executor exec,Params... params)方法传入指定的Executor

开始执行的入口:

当创建完asynctask后,调用asynctask.execute(Params… params)就可开始执行,然后其实是调用了executeOnExecutor(Executor exec,Params... params)这个方法,传入 sDefaultExecutor和doInbackgroud方法的参数:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
public final AsyncTask<Params, Progress, Result> executeOnExecutor(Executor exec,
Params... params) {
if (mStatus != Status.PENDING) {
switch (mStatus) {
case RUNNING:
throw new IllegalStateException("Cannot execute task:"
+ " the task is already running.");
case FINISHED:
throw new IllegalStateException("Cannot execute task:"
+ " the task has already been executed "
+ "(a task can be executed only once)");
}
}

mStatus = Status.RUNNING;

onPreExecute();

mWorker.mParams = params;
exec.execute(mFuture);

return this;
}

四个回调执行的线程

- `onPreExecute()`:

从上面代码我们可以看到在这里执行了 onPreExecute(),所以,在哪个线程执行了asynctask.execute(Params… params), onPreExecute()他就在哪个线程执行
- doInBackGround():被放到了asynctask的线程池里执行
- onProgressUpdate()和onPostExecute()这两个都是在handler的回调handleMessage里被调用的,所以关键就在handler里的Looper是哪个线程的,他们俩就在哪个线程执行(注意,这里其实跟handler在哪个线程创建没关系,可以在子线程创建handler而传入主线程的Looper)而我们之前也分析了,现在handler的looper只能是主线程的 ,所以这两个方法也是在主线程执行的
如:

1
2
3
4
5
6
7
8
Handler handler=new Handler(getMainLooper(), new Handler.Callback() {
@Override
public boolean handleMessage(Message msg) {
Log.i(TAG, "handleMessage: "+Thread.currentThread());
titleBar.setTitle("hahahah");
return false;
}
});

下面是我的测试例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40

public class AsyncTest extends AsyncTask<String,Integer,String> {
public static final String TAG="AsyncTask";

public AsyncTest(){
super();
}
@Override
protected String doInBackground(String... strings) {
Log.i(TAG, "doinbackground: "+Thread.currentThread()+strings);
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
publishProgress(2);

return "finish";
}

@Override
protected void onPreExecute() {
Log.i(TAG, "onPreExecute: start");
Log.i(TAG, "onPreExecute: "+Thread.currentThread());
}

@Override
protected void onPostExecute(String s) {
Log.i(TAG, "onPostExecute: "+s);
Log.i(TAG, "onpostexecute: "+Thread.currentThread());

}

@Override
protected void onProgressUpdate(Integer... values) {
Log.i(TAG, "onProgressUpdate: "+values[0]);
Log.i(TAG, "onprogressupdate: "+Thread.currentThread());

}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
Activity里:

protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.acitivty_view_test);

new Thread(new Runnable() {
@Override
public void run() {
AsyncTest test=new AsyncTest();
test.execute("aaa");
}
}).start();

}

结果:
asynctask.png
所以,asynctask也不一定非得在主线程创建和执行

最后一问:为啥一个任务只能执行一次?

当我第一次看到这个规则时,我也很奇怪,好不容易创建了,就执行一次就完了?我不信,结果看一下源码确实发现了那个异常,如果是同一个任务就会抛出“通一个任务只能执行一次”,那意义何在呢?
在仔细看一下源码发现他的线程池都是静态的,所以这样更好诠释了asynctask是一个轻量的线程框架的含义,每次没给他其实就代表一次任务,提交给统一的线程池去管理运行。

1
2


为什么 AsyncTask 的对象只能被调用一次,否则会出错?(每个状态只能执行一次)
从上面我们知道,AsyncTask 有 3 个状态,分别为 PENDING、RUNNING、FINSHED,而且每个状态在 AsyncTask 的生命周期中有且只执行一次。由于在执行完 execute 方法的时候会先对 AsyncTask 的状态进行判断,如果是 PENDING(等待中)的状态,就会往下执行并将 AsyncTask 的状态设置为 RUNNING(运行中)的状态;否则会抛出错误。AsyncTask finish 的时候,AsyncTask 的状态会被设置为 FINSHED 状态。

if (mStatus != Status.PENDING) {
switch (mStatus) {
case RUNNING:
throw new IllegalStateException(“Cannot execute task:”
+ “ the task is already running.”);
case FINISHED:
throw new IllegalStateException(“Cannot execute task:”
+ “ the task has already been executed “
+ “(a task can be executed only once)”);
}
}

© 2020 WPY's Android Tour All Rights Reserved. 本站访客数人次 本站总访问量
Theme by hiero