AsyncTask源码分析

最近忙着做很多技术的积累,也很久没有研究android源码了,今天来分析下AsyncTask.java。后面可能会涉及一些比较实用的东西,ftp上传啊,百度地图api啊,语音啊,还有AR技术。有空我再写吧。
我们知道android 不允许我们在其他线程更新UI,否则会抛异常,这个异常是如何出现的,我们以后分析。
所以我们经常实用thread+handler 来更新UI,指导asynctask出现。首先我们来熟悉我们知道的函数
protected abstract Result doInBackground(Params... params);
这个是一个抽象函数,所以我们在继承 AsyncTask的子类中重写。

我们看 AsyncTask的构造函数,
public AsyncTask() {
mWorker = new WorkerRunnable() {
public Result call() throws Exception {
mTaskInvoked.set(true);

 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
            Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
            return postResult(doInBackground(mParams));
        }
    };

    mFuture = new FutureTask<Result>(mWorker) {
        @Override
        protected void done() {
            try {
                final Result result = get();

                postResultIfNotInvoked(result);
            } catch (InterruptedException e) {
                android.util.Log.w(LOG_TAG, e);
            } catch (ExecutionException e) {
                throw new RuntimeException("An error occured while executing doInBackground()",
                        e.getCause());
            } catch (CancellationException e) {
                postResultIfNotInvoked(null);
            } catch (Throwable t) {
                throw new RuntimeException("An error occured while executing "
                        + "doInBackground()", t);
            }
        }
    };
}

构造函数里面生成了2个对象, mWorker , mFuture 这个2个对象在什么时候被实用呢,我们看 AsyncTask的execute函数,也就是我们生成 AsyncTask子类对象之后调用的函数。
public final AsyncTask 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)");
}
}

1
2
3
4
5
6
7
8
9
    mStatus = Status.RUNNING;

    onPreExecute();

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

    return this;
}

这里看到参数中有个exec.execute(mFuture);这个是一个线程池的执行器。此时启动线程池,并且执行FutureTask 而mWorker是一个callback。总之就是执行 mWorker的call方法,java 线程池理解起来比较麻烦,我自己还是有一些的小疑问,尽管我看了线程池的实现代码,但是说实在的,代码很多,研究起来比较麻烦,我的理解是这样的,(当然可能是错误的),实现的目的就不细说了,就是在程序没有运行前先申请线程,但是不运行。我们知道线程是无法停止的,stop方法是@Deprecated的,所以论坛中经常有人这个问题,确实不知道如何回答。
另外见我对java 线程源码的分析,我们里面提到了为什么调用start方法,而不是run方法。根据操作系统原理,线程一旦运行起来,应用程序是无法知道他运行到什么位置,除非我们设置标志位,但是两个标志位之间,我们是无法知道的。所以我们认为线程是不可以预知的。
好了回过了说线程池,我们申请线程,其实首先是申请内存(见我的java 线程分析),其次是调用run方法。所以线程池就是申请了一堆的线程,但是不调用run方法,知道线程池满足一定的条件。这个网上都有,这样来说就存在以下的问题,我也没有解决掉,
因为预先申请的线程是有限的比如说5个,但是我们实际运行的时候,可能有很多请求,这个时候转化为task的概念,(我的理解),这样多个task公用一个线程。这样就有一个问题,线程是死循环,还不是死循环,如果不是,那么,一定时间之后,线程池就失去了作用。当然了,实际上不是的,源码实在太多,我未真正分析完。
抛砖引玉,我们回到 AsyncTask上面来,当我们通过线程池执行完后台的任务之后,需要更新UI 怎么办。我们重写了 protected void onPostExecute(Result result) {
}
这个是一个空方法,也就是说,默认是什么都不敢
private void finish(Result result) {
if (isCancelled()) {
onCancelled(result);
} else {
onPostExecute(result);
}
mStatus = Status.FINISHED;
}
方法调用了他,我们继续看谁调用了finish
private static class InternalHandler extends Handler {
@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;
}
}
}

这里,一个handler 通过接受到message,然后调用了他,我们看message = MESSAGE_POST_RESULT
return postResult(doInBackground(mParams));调用了 postResult, postResult方法调用了他。

至此,我们完全明白了。 其实 AsyncTask也是通过handler来通知主线程的。这里我们顺便说下handler,我相信还是有部分人不理解,(具体见我对handler源码分析),首先当一个程序起来之后,调用activitythread.main方法,这个时候去设点mainlooper,此后所有的在主线程生成的handler都共有这个looper。所以尽管我们new了很多的handler,但是looper却只有一个,所以,对于asynctaks有这样的说明The task instance must be created on the UI thread. 换句话说,这个task对象必须在ui线程里面new出来,否则他会因为没有looper,而抛异常,即便你调用了loop。prepare也会因为你使用的looper不是UI线程的looper而导致无法更新Ui线程。
至此,其实我们都明白了如何使用AsyncTask,其实我一直有一个问题,就是我们知道activitythread调用main函数之后是进入了loop的循环中,也就是说主线程其实是在死循环,那么我们UI是如何通过这个死循环的message机制更新的呢?后面我有时间分析了再写下来。

声明:eoe文章著作权属于作者,受法律保护,转载时请务必以超链接形式附带如下信息

原文作者: guzhijie1981

原文地址: http://my.eoe.cn/21517/archive/2925.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值