Android AsyncTask源码解析

AsyncTask 在android中是一个轻量级的异步线程,我们使用也比较多,今天就从源码的角度来解析一下AsyncTask。

首先我们看一下怎么使用:

我们从网络上下载一张图片,显示下载的进度:

先把代码贴出来

/**
 * Created by xxnan on 2016/6/3.
 */
public class TestAsyncTaskActivity extends AppCompatActivity {
    private Button begin;
    private ProgressDialog progressDialog;
    private MyAsyncTask myAsyncTask;
    String url="http://f.hiphotos.baidu.com/image/h%3D300/sign=b4b02e92ce177f3e0f34fa0d40cf3bb9/4afbfbedab64034f1d887e22a8c379310a551d48.jpg";
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.async);
        begin=(Button)findViewById(R.id.begindown);

        begin.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                myAsyncTask = new MyAsyncTask(TestAsyncTaskActivity.this, progressDialog);
                myAsyncTask.execute(url);
            }
        });

    }
}

MyAsyncTask.java类:

/**
 * Created by xxnan on 2016/6/3.
 */
public class MyAsyncTask extends AsyncTask<String,Integer,Boolean> {
    private ProgressDialog progressDialog;
    private Context mContext;
    public MyAsyncTask(Context context,ProgressDialog progressDialog)
    {
        this.progressDialog=progressDialog;
        mContext=context;
    }
    @Override
    protected void onPreExecute() {
        super.onPreExecute();
        progressDialog=new ProgressDialog(mContext);
        progressDialog.setTitle("下载进度");
        progressDialog.setProgress(0);
        progressDialog.setMax(100);
        progressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
        progressDialog.show();
    }

    @Override
    protected Boolean doInBackground(String... params) {
        HttpURLConnection httpURLConnection=null;
        try{
            URL url=new URL(params[0]);
            httpURLConnection=(HttpURLConnection)url.openConnection();
            httpURLConnection.setConnectTimeout(3000);
            httpURLConnection.setRequestMethod("GET");

            httpURLConnection.setReadTimeout(3000);
            int filelegth=0;
            if(httpURLConnection.getResponseCode()==200)
            {
                filelegth=httpURLConnection.getContentLength();
                File file=new File("/mnt/sdcard/async/");
                if(!file.exists())
                    file.mkdir();
                File f=new File(file.getAbsolutePath(),"qiaoen.jpg");
                InputStream inputStream=null;
                FileOutputStream fileOutputStream=new FileOutputStream(f);
                inputStream=httpURLConnection.getInputStream();
                int len=0;
                long totalsize=0;
                byte[] bytes=new byte[1024];
                while((len=inputStream.read(bytes))!=-1)
                {
                    fileOutputStream.write(bytes,0,len);
                    totalsize+=len*100;
                    int progress=(int)(totalsize/filelegth);
                    publishProgress(progress);
                }
            }
        }
        catch (Exception e)
        {
            e.printStackTrace();
            return false;
        }finally {
            httpURLConnection=null;
        }

        return true;
    }

    @Override
    protected void onProgressUpdate(Integer... values) {
        super.onProgressUpdate(values);
        progressDialog.setProgress(values[0]);
    }

    @Override
    protected void onPostExecute(Boolean aBoolean) {
        super.onPostExecute(aBoolean);
        progressDialog.dismiss();
        if (aBoolean)
        {
            ToastUtil.getInstance().showToast(mContext, "下载成功!");
        }else
            ToastUtil.getInstance().showToast(mContext, "下载失败!");
    }
}

 

我们看怎么启动一个AsyncTask:

myAsyncTask = new MyAsyncTask(TestAsyncTaskActivity.this, progressDialog);
                myAsyncTask.execute(url);

记住启动 AsyncTask必须在主线程,这一点我们也可以从 AsyncTask.java的注解可以看出
我们new了一个MyAsyncTask 继承与AsyncTask并传入了一个字符串,我们来看一下AsyncTask的构造方法:
/**
     * Creates a new asynchronous task. This constructor must be invoked on the UI thread.
     */
    public AsyncTask() {
        mWorker = new WorkerRunnable<Params, Result>() {
            public Result call() throws Exception {
                mTaskInvoked.set(true);

                Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
                //noinspection unchecked
                Result result = doInBackground(mParams);
                Binder.flushPendingCommands();
                return postResult(result);
            }
        };

        mFuture = new FutureTask<Result>(mWorker) {
            @Override
            protected void done() {
                try {
                    postResultIfNotInvoked(get());
                } catch (InterruptedException e) {
                    android.util.Log.w(LOG_TAG, e);
                } catch (ExecutionException e) {
                    throw new RuntimeException("An error occurred while executing doInBackground()",
                            e.getCause());
                } catch (CancellationException e) {
                    postResultIfNotInvoked(null);
                }
            }
        };
    }
AsyncTask构造方法总初始化了两个类,一个 WorkerRunnable一个FutureTask,WorkerRunnable简单实现了Callable接口
/**
 * Creates a new asynchronous task. This constructor must be invoked on the UI thread.
 */
public AsyncTask() {
    mWorker = new WorkerRunnable<Params, Result>() {
        public Result call() throws Exception {
            mTaskInvoked.set(true);

            Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
            //noinspection unchecked
            Result result = doInBackground(mParams);
            Binder.flushPendingCommands();
            return postResult(result);
        }
    };

    mFuture = new FutureTask<Result>(mWorker) {
        @Override
        protected void done() {
            try {
                postResultIfNotInvoked(get());
            } catch (InterruptedException e) {
                android.util.Log.w(LOG_TAG, e);
            } catch (ExecutionException e) {
                throw new RuntimeException("An error occurred while executing doInBackground()",
                        e.getCause());
            } catch (CancellationException e) {
                postResultIfNotInvoked(null);
            }
        }
    };
}
 FutureTask初始化的时候把初始化的WorkerRunnable传进去了构造方法如下: 
public FutureTask(Callable<V> callable) {
    if (callable == null)
        throw new NullPointerException();
    this.callable = callable;
    this.state = NEW;       // ensure visibility of callable
}

new完MyAsyncTask然后就执行myAsyncTask.execute(url);,执行的是execute()方法,我们在AsyncTask中找到execute()

如下:

public final AsyncTask<Params, Progress, Result> execute(Params... params) {
    return executeOnExecutor(sDefaultExecutor, params);
}

 

继续跟踪executeOnExecutor方法:

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是个空方法,等我们重写。这也是我们熟知的AsyncTask先执行 onPreExecute()方法,此方法还是跑在主线程。
 
把execute(url)的参数赋给WorkerRunnable实例的Params[]成员变量,再执行exec.execute(mFuture)

也就是mFuture的run方法
public void run() {
    if (state != NEW ||
        !U.compareAndSwapObject(this, RUNNER, null, Thread.currentThread()))
        return;
    try {
        Callable<V> c = callable;
        if (c != null && state == NEW) {
            V result;
            boolean ran;
            try {
                result = c.call();
                ran = true;
            } catch (Throwable ex) {
                result = null;
                ran = false;
                setException(ex);
            }
            if (ran)
                set(result);
        }
    } finally {
        // runner must be non-null until state is settled to
        // prevent concurrent calls to run()
        runner = null;
        // state must be re-read after nulling runner to prevent
        // leaked interrupts
        int s = state;
        if (s >= INTERRUPTING)
            handlePossibleCancellationInterrupt(s);
    }
}

初始化mFuture的时候将mWorker传入赋值给 mFuture的callable,然后执行callable的call()方法,call()的实现在mworker的初始化中
public Result call() throws Exception {
    mTaskInvoked.set(true);

    Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
    //noinspection unchecked
    Result result = doInBackground(mParams);
    Binder.flushPendingCommands();
    return postResult(result);
}

call()方法里面我们又可看到了我们熟悉的doInBackground()方法,此方法是一个抽象方法在子类中我们实现,再执行postResult方法将结果Result传递给主线程
private Result postResult(Result result) {
    @SuppressWarnings("unchecked")
    Message message = getHandler().obtainMessage(MESSAGE_POST_RESULT,
            new AsyncTaskResult<Result>(this, result));
    message.sendToTarget();
    return result;
}

主线程处理
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;
    }
}
跟着finish方法走,执行
如下:
<pre style="background-color:#2b2b2b;color:#a9b7c6;font-family:'宋体';font-size:12.0pt;"><span style="color:#cc7832;">private void </span><span style="color:#ffc66d;">finish</span>(<span style="color:#507874;">Result </span>result) {
    <span style="color:#cc7832;">if </span>(isCancelled()) {
        onCancelled(result)<span style="color:#cc7832;">;
</span><span style="color:#cc7832;">    </span>} <span style="color:#cc7832;">else </span>{
        onPostExecute(result)<span style="color:#cc7832;">;
</span><span style="color:#cc7832;">    </span>}
    <span style="color:#9876aa;">mStatus </span>= Status.<span style="color:#9876aa;"><em>FINISHED</em></span><span style="color:#cc7832;">;
</span>}

 
 
 如果当前的task已经取消了,那么就不返回结果,否则则执行我们熟悉的onPostExecute方法,此方法也是一个空方法,需要我们在子类中重写。 
 
这里还有两个方法没有讲到那就是publishProgress和onProgressUpdate方法,
我们看一下这两个方法
<pre style="background-color:#2b2b2b;color:#a9b7c6;font-family:'宋体';font-size:12.0pt;"><span style="color:#cc7832;">protected final void </span><span style="color:#ffc66d;">publishProgress</span>(<span style="color:#507874;">Progress</span>... values) {
    <span style="color:#cc7832;">if </span>(!isCancelled()) {
        <span style="font-style:italic;">getHandler</span>().obtainMessage(<span style="color:#9876aa;"><em>MESSAGE_POST_PROGRESS</em></span><span style="color:#cc7832;">,
</span><span style="color:#cc7832;">                new </span>AsyncTaskResult<<span style="color:#507874;">Progress</span>>(<span style="color:#cc7832;">this, </span>values)).sendToTarget()<span style="color:#cc7832;">;
</span><span style="color:#cc7832;">    </span>}
}

 
 publishProgress方法可以在子线程中调用发送进度条的值给主线程去更新UI,因而我们可以在 
doInBackground()中调用 
publishProgress()去更新UI。 
case MESSAGE_POST_PROGRESS:
    result.mTask.onProgressUpdate(result.mData);
    break;

最终调用到
onProgressUpdate()
方法,(一个空的方法,我们在子类中去重写)也是我们熟悉的方法去更新进度条。
 
到这里就把整个Asynctask类的思路理清楚了,当然里面还有很多东西,有兴趣的可以跟着我这个思路去理一理,有不正确的地方请多多指出,谢谢!
 

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值