AsyncTask使用及源码解析

AsyncTask介绍及使用

AsyncTask是什么?异步任务,在android中主线程不能做耗时的操作,否则很容易出现ANR异常,所以像访问网络,读取数据库等一些耗时的操作都放在子线程中,但是子线程是无法更新UI的,我们还需要把得到的结果发送到主线程中做更新UI的处理。这时我们就需要用到Handler或者AsnycTask,其实AsyncTask是对Handler和Thread做了封装,更加方便调用。

1. AsyncTask API介绍

  1. 构造方法
public abstract class AsyncTask<Params,Progress,Result>
//三个泛型分别表示: 启动任务执行的输入参数 , 后台任务执行的进度 , 后台任务执行结果
  1. 普通方法
(1). execute(Params... params)   
    // 调用该方法来启动执行异步方法

(2). onPreExecute() ;  
    // 在execute(Params... params)方法调用之后立即执行的方法,该方法在主线程中执行,

(3). doInBackground(Params... params); 
    // 在onPreExecute()执行之后执行的方法,该方法在子线程中执行,可以用来做一些耗时的操作;在该方法中可以调用publishProgress(Progress... vallues)来更新进度等,

(4). onProgressUpdate(Progress... values);
     // 在调用publishProgress(Progress... values),该方法在UI线程中执行,用来更新进度

(5). onPostExecute(Result result); 
    // 后台执行结束时,该方法调用,在UI线程中执行。后台计算结果被作为参数传递给该方法。

(6). onCancelled(); 
    // 当任务取消时调用该方法
  1. 使用时注意事项:
    (1). 异步任务的实例对象必须在主线程中创建;
    (2). execute(Params… params)方法必须在主线程中调用;
    (3). 不要手动调用onPreExecute(),doInBackground(Params… params),onPostExecute(Result result)这几个方法;
    (4). doInBackground(Params… params)方法是在子线程中执行的,所以不能做更新UI的操作;
    (5). 一个异步任务实例只能执行一次,如果 第二次就会抛出异常;

2. 使用实例

public class MainActivity extends Activity implements View.OnClickListener {

    private ProgressBar pb ;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        pb = (ProgressBar) findViewById(R.id.pb);
        pb.setMax(100);
        findViewById(R.id.btn1).setOnClickListener(this);
    }

    @Override
    public void onClick(View v) {
        asyncTask.execute(); // 调用execute()方法启动异步任务;
    }

    private AsyncTask<Void,Integer,String> asyncTask = new AsyncTask<Void, Integer, String>() {

        @Override
        protected void onPreExecute() {
            showToast("调用execute()方法执行异步任务,该方法立即在主线程中执行");
        }

        @Override
        protected String doInBackground(Void... v) {
            for(int i=0 ;i<=100;i++){
                SystemClock.sleep(500);    // 模拟耗时操作
                publishProgress(i);      //调用该方法更新进度
            }
            return "执行完成";
        }

        @Override  // 该方法在调用publishProgress()方法调用之后执行,执行在主线程接收publishProgress()传递的参数,用来更新UI界面
        protected void onProgressUpdate(Integer... values) {   
            pb.setProgress(values[0]);
        }

        @Override  // 该方法在doInBackground()方法执行结束后执行,接受其传递的参数,该方法在主线程中执行
        protected void onPostExecute(String s) {
            showToast(s);
        }
    };

    /**
     * 显示Toast
     * @param msg
     */
    private void showToast(String msg){
        Toast.makeText(this , msg , Toast.LENGTH_SHORT).show();
    }

}

3 . 仿AsyncTask

刚才说过AsyncTask其内部是对线程和Handler的封装,简化我们的使用。现在我们自己来实现一个AsyncTask,以便更好的了解其内部实现原理。
AsyncTask在使用过程中常用的那几个方法执行顺序以及是否执行在UI线程中我们已经做了了解,我们知道在调用execute()的时候开启异步任务,首先调用的就是onPreExecute()方法,然后在子线程中执行doInBackground()方法,在执行过程中调用publishProgress()方法将执行进度发送到主线程中,通过onProgressUpdate()方法来更新UI;在doInBackground()方法执行完毕以后,执行onPostExecute()方法,将执行结果作为参数传递给onPostExecute()。这就是AsyncTask执行流程,下面就是我们自己实现的MyAsyncTask

public abstract class MyAsyncTask<Params , Progress , Result> {

    private static InteranlHandler interHandler ;  // 内部封装Handler用来发送消息,在主线程中更新UI
    private static final int MSG_PROGRESS = 0 ;  // 发送更新UI进度类型的类型
    private static final int MSG_RESULT = 1 ;   // 发送执行结果的消息类型

    public MyAsyncTask(){
        interHandler = new InteranlHandler(); // 在创建实例时,内部创建Handler对象
    }

    /**
     * 调用execute方法,触发异步任务执行
     * @param params
     */
    public void execute(final Params... params){
        onPreExecute();             // 首先调用onProExecute()方法
        new Thread(){
            @Override
            public void run() {
                Result result = doInBackground(params);  // 在子线程中执行doInBackground方法,将获取的结果通过finish(Result)方法发送到主线程中
                finish(result);
            }
        }.start();
    }

    /**
    *通过AsyncTaskResult将数据封装起来发送到主线程中
    */
    private void finish(final Result result){
            AsyncTaskResult<Result> taskResult = new AsyncTaskResult<Result>(MyAsyncTask.this , result);
            Message msg = Message.obtain();
            msg.what = MSG_RESULT ;
            msg.obj = taskResult ;
            interHandler.sendMessage(msg);
        }


    /**
     * execute方法执行之前立即在mainTread中执行,
     */
    protected void onPreExecute(){

    }

    /**
     * 在子线程中执行
     * @param paramses
     * @return
     */
    protected abstract Result doInBackground(Params... paramses);

    /**
     * 更新UI,在主线程中执行
     * @param progress
     */
    protected void onProgressUpdate(Progress... progress){

    }

    /**
     * 调用该方法,将数据封装起来,发送到主线程中,触发onProgressUpdate方法在主线程中执行
     * @param progress
     */
    protected void publishProgress(final Progress... progress){
        AsyncTaskResult<Progress> result = new AsyncTaskResult<Progress>(MyAsyncTask.this , progress);
        Message msg = Message.obtain();
        msg.what = MSG_PROGRESS ;
        msg.obj = result ;
        interHandler.sendMessage(msg);
    }

    /**
     * doInBackground执行结束后,将结果作为参数传递给该方法,触发该方法在主线程中执行
     * @param result
     */
    protected void onPostExecute(Result result){

    }


    private static class InteranlHandler extends Handler{

        public InteranlHandler(){
            super(Looper.getMainLooper());
        }

        @Override
        public void handleMessage(Message msg) {
            AsyncTaskResult<?> result = (AsyncTaskResult<?>) msg.obj;
            switch (msg.what){
                case MSG_PROGRESS : // 在Handler中接受消息,调用onProgressUpdate()方法更新进度
                    result.asyncTask.onProgressUpdate(result.mData);
                    break;
                case MSG_RESULT : // 调用OnPostExecute()方法将将结果作为参数传递给OnPostExecute(Result)
                    result.asyncTask.onPostExecute(result.mData[0]);
                    break;
            }
        }
    };

    /**
     * 对数据进行封装
     * @param <Data>
     */
    private static class AsyncTaskResult<Data>{
        public MyAsyncTask asyncTask ;
        public Data[] mData ;
        public AsyncTaskResult(MyAsyncTask task , Data... datas){
            this.asyncTask = task ;
            this.mData = datas ;
        }
    }

}

这样就完成了我们自己的AsyncTask,使用方式和AsyncTask一样。

//创建实例,然后调用execute(Params... params)方法触发异步任务执行,
 private MyAsyncTask<Void , Integer , String> myAsyncTask = new MyAsyncTask<Void, Integer, String>() {

        @Override
        protected void onPreExecute() {
            showToast("MyAsyncTask  执行onPreExecute方法,在主线程中执行");
        }

        @Override
        protected String doInBackground(Void... voids) {
            for(int i=0;i<=100;i++){
                SystemClock.sleep(500);
                publishProgress(i);
            }
            return "MyAsycTask后台方法执行完毕";
        }

        @Override
        protected void onProgressUpdate(Integer... progress) {
            pb.setProgress(progress[0]);
        }

        @Override
        protected void onPostExecute(String result) {
            showToast(result);
        }
    };

4. AsyncTask源码解析

当我们完成了仿AsyncTask之后,我们对AsyncTask内部实现原理也就一目了然了。AsyncTask内部就是对线程池和Handler的封装,调用execute方法时,内部会调用executeOnExecutor()方法,该方法执行后,会先调用onPreExecute()方法;然后执行FutureTask任务,这个过程中doInBackground(Params… params)会被调用,如果我们在doInBackground方法中调用publishProgress(Progress… values)方法,内部会通过InternalHandler(继承Handler)实例来发送一条MESSAGE_POST_PROGRESS消息,更新进度,在InternalHandler中处理消息时,会调用onProgressUpdte(Progress… progress)方法,doInBackground()方法执行完毕后,会发送一条MESSAGE_POST_RESULT消息处理结果,InternalHandler在处理结果时,会调用onPostExecute()方法。

点击下载Demo

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值