AsyncTask简介

一、AsyncTask基本介绍:

Android要求主线程来更新UI,但是又不允许主线程在更新UI的过程中出现耗时的操作。那么这些耗时的操作一般会在子线程中去执行。当子线程将操作执行完后会反馈执行结果给UI主线程。Android一般使用Handler+Thread的方式实现上述需求。Handler的使用稍显复杂,需要继承Handler类,重写处理函数。还需要开发者自己开辟线程,在线程中完成操作以后再发送消息将结果更新到UI线程。Android为我们提供了AsyncTask这个工具类。AsyncTask对Handler+Thread开发框架进行了封装,AysncTask可以帮助我们创建后台线程,开发者只需要简单的重写几个回调函数,就可以完成后台子线程处理耗时操作,再将结果更新到UI线程的操作。  (摘抄自:https://blog.csdn.net/walk_and_think/article/details/50562066 )
 

二、AsyncTask抽象类定义:

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

三参数分别为:
    Params:需要执行任务的参数,一般是doInBackground中使用,数据来与是execute中的第一个参数。
    Progress:在onProgressUpdate中使用。
    Result:作为onPostExecute的参数被使用。
主要有下面的几个方法:
1. @MainThread protected void onPreExecute() { }
2. @WorkerThread protected abstract Result doInBackground(Params... params);
3. @MainThread protected void onProgressUpdate(Progress... values) { }
4. @MainThread protected void onPostExecute(Result result) { }
   
onPreExecute:运行于主线程。该方法是在UI主线程中于task创建前调用,一般用于创建task,比如在用户界面显示一个进度条(process bar)。
   

doInBackground:运行于子线程。在execute一结束,该方法就会在后台线程中执行比较耗时的工作。其参数来源于asynchronous task的Params。计算结果将被传给最后一步onPostExecute.该方法也可以被用于将结果publish给UI主线程。
  

onProgressUpdate:运行于主线程。该方法用于给用户界面展示后台线程正在运行的进展。举个列子:该方法可被用于进度条显示或者在文本框中显示日志。参数为Progress。
   

onPostExecute:运行于主线程。这个方法在doInBackground执行后去执行,用来通知UI线程,子线程的处理结果。参数来源于doInBackground的返回值。


一般来说,我们自己写的AsyncTask,必须继承AsyncTask这个类,然后实现方法doInBackground和onPostExecute(其实后面这个方法没有强调),使用异步机制的目的就是处理一些费时的操作,而费时的工作是在doInBackground中执行。至于onPreExecute(开始操作)/onProgressUpdate(操作过程)主要是为用户显示子线程的处理状态,可以不被重写。

 

三、实践:

创建一个Activity,有三个控件:一个button,一个进度条ProgressBar,一个文本框Textview。
要求在点击button的时候,文本框文字显示“Task start”,进度条以100ms的间隔更新5次,等更新完后,文本框文字变为“Task end”。
如下图所示:


代码如下:

package com.example.user.myapplication;

import android.os.AsyncTask;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.ProgressBar;
import android.widget.TextView;


public class MainActivity extends AppCompatActivity {
    private static final String TAG = "my_MainActivity";
    private static final int PROGRESS_BAR_MAX_VALUE = 5;//表示进度显示五次
    private static final int PORGRESS_UPDATE_TIME_GAP = 100;//每次进度的显示都隔100ms

    private Button mButton;//定义一个button
    private ProgressBar mProgressBar;//定义一个进度条
    private TextView mText;//定义一个文本框

    private MyAsyncTask mMyAsyncTask;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        mButton = (Button)findViewById(R.id.button);
        mProgressBar = (ProgressBar)findViewById(R.id.progressBar);
        mText = (TextView) findViewById(R.id.textView);

        mButton.setOnClickListener(new View.OnClickListener() {
            @Override//点击button的时候,文本框中显示Task start,同时进度条显示,当进度条结束后,文本框显示Task end.
            public void onClick(View view) {
                pressButton();
            }
        });

    }

    private void pressButton(){
        mMyAsyncTask = new MyAsyncTask();
        mMyAsyncTask.execute(PROGRESS_BAR_MAX_VALUE, PORGRESS_UPDATE_TIME_GAP);
    }
    //新定义的类继承AsyncTask,并实现了AsyncTask的四个方法。
    private class MyAsyncTask extends AsyncTask<Integer, Integer, String>{
        @Override
        protected void onPreExecute() {//该方法是运行在主线程中的
            Log.d(TAG, "onPreExecute was executed in " + Thread.currentThread().getName());
            mProgressBar.setProgress(0);
            mProgressBar.setMax(PROGRESS_BAR_MAX_VALUE);
            mText.setText("Task start");
        }

        @Override
        protected String doInBackground(Integer... params){//该方法运行于后台线程中
            Log.d(TAG, "doInBackgroud was executed in " + Thread.currentThread().getName());
            Log.d(TAG,"doInBackgroud: params = " + params);
            Log.d(TAG,"doInBackgroud: params[0] = " + params[0]);
            Log.d(TAG,"doInBackgroud: params[1] = " + params[1]);

            try {
                for (int i = 0; i <= params[0]; i++){
                    Thread.sleep(params[1]);//
                    this.publishProgress(i);
                    Log.d(TAG,"publishProgress was executed in : " + Thread.currentThread().getName());
                }
            }catch (InterruptedException e) {
                e.printStackTrace();
            }
            return new String("Task end");
        }

        @Override
        protected void onProgressUpdate(Integer... valus) {//运行于主进程,实时的为UI展示子线程的处理过程
            Log.d(TAG,"onProgressUpdate was executed in : " + Thread.currentThread().getName());
            Log.d(TAG,"onProgressUpdate: values = " + valus);
            Log.d(TAG,"onProgressUpdate: values[0] = " + valus[0]);
            mProgressBar.setProgress(valus[0]);
        }

        @Override
        protected void onPostExecute(String result) {//运行于主线程,任务完成,通知UI线程更新UI。
            Log.d(TAG,"onPostExecute was executed in : " + Thread.currentThread().getName());
            mText.setText(result);
        }
    }
}

log:

10-25 14:08:05.526 D/my_MainActivity(23538): onPreExecute was executed in main
10-25 14:08:05.530 D/my_MainActivity(23538): doInBackgroud was executed in AsyncTask #1
10-25 14:08:05.530 D/my_MainActivity(23538): doInBackgroud: params = [Ljava.lang.Integer;@7416a7
10-25 14:08:05.530 D/my_MainActivity(23538): doInBackgroud: params[0] = 5
10-25 14:08:05.530 D/my_MainActivity(23538): doInBackgroud: params[1] = 100
10-25 14:08:05.668 D/my_MainActivity(23538): onProgressUpdate was executed in : main
10-25 14:08:05.669 D/my_MainActivity(23538): onProgressUpdate: values = [Ljava.lang.Integer;@c7eb754
10-25 14:08:05.669 D/my_MainActivity(23538): onProgressUpdate: values[0] = 0
10-25 14:08:05.668 D/my_MainActivity(23538): publishProgress was executed in : AsyncTask #1
10-25 14:08:05.800 D/my_MainActivity(23538): onProgressUpdate was executed in : main
10-25 14:08:05.800 D/my_MainActivity(23538): onProgressUpdate: values = [Ljava.lang.Integer;@cc7d6fd
10-25 14:08:05.800 D/my_MainActivity(23538): onProgressUpdate: values[0] = 1
10-25 14:08:05.802 D/my_MainActivity(23538): publishProgress was executed in : AsyncTask #1
10-25 14:08:05.940 D/my_MainActivity(23538): onProgressUpdate was executed in : main
10-25 14:08:05.941 D/my_MainActivity(23538): onProgressUpdate: values = [Ljava.lang.Integer;@945cff2
10-25 14:08:05.941 D/my_MainActivity(23538): onProgressUpdate: values[0] = 2
10-25 14:08:05.943 D/my_MainActivity(23538): publishProgress was executed in : AsyncTask #1
10-25 14:08:06.050 D/my_MainActivity(23538): onProgressUpdate was executed in : main
10-25 14:08:06.050 D/my_MainActivity(23538): publishProgress was executed in : AsyncTask #1
10-25 14:08:06.051 D/my_MainActivity(23538): onProgressUpdate: values = [Ljava.lang.Integer;@f417643
10-25 14:08:06.051 D/my_MainActivity(23538): onProgressUpdate: values[0] = 3
10-25 14:08:06.162 D/my_MainActivity(23538): onProgressUpdate was executed in : main
10-25 14:08:06.162 D/my_MainActivity(23538): onProgressUpdate: values = [Ljava.lang.Integer;@bb9f4c0
10-25 14:08:06.162 D/my_MainActivity(23538): onProgressUpdate: values[0] = 4
10-25 14:08:06.163 D/my_MainActivity(23538): publishProgress was executed in : AsyncTask #1
10-25 14:08:06.279 D/my_MainActivity(23538): onProgressUpdate was executed in : main
10-25 14:08:06.279 D/my_MainActivity(23538): publishProgress was executed in : AsyncTask #1
10-25 14:08:06.280 D/my_MainActivity(23538): onProgressUpdate: values = [Ljava.lang.Integer;@33fe5f9
10-25 14:08:06.280 D/my_MainActivity(23538): onProgressUpdate: values[0] = 5
10-25 14:08:06.283 D/my_MainActivity(23538): onPostExecute was executed in : main

盗了一张大牛的图,该图很好的说明了AsyncTask task执行的过程:

上图中,需要注意的是:
1. execute的调用,只能在主线程。
2. 主线程中运行的方法,只有execute需要被调用,其余的方法onPreExecute/onProgressUpdate/onPostExecute 都是不需要主动去调用的。会被自动执行。
3. 重写AsyncTask中的方法时,只有doInBackground必须要被重写,其余的可以忽略。
4. AsyncTask适用于轻量级的操作中。
5. AsyncTask的执行是同步的。

 

问题:

1. 为什么除了调用execute后,AsyncTask的四个方法会被顺序执行?
2. 为什么AsyncTask只能适用于比较轻量级的操作中?
3. AsyncTask同步的原因是啥?

至于第二个问题,AnsycTask执行任务时,内部会创建一个进程作用域的线程池来管理要运行的任务,也就就是说当你调用了AsyncTask.execute()后,AsyncTask会把任务交给线程池,由线程池来管理创建Thread和运行Therad。但是对于线程池的大小及其可运行的线程数都是规定的,若是任务量比较大,要么耗时比较长,要么程序崩溃的:

在Android3.0之前规定一个线程池大小为128,同一时刻可以运行的任务数有5。当有第6个任务想要运行的时候,只能先等待;如果要放进去第129个线程,那么程序就会崩溃。

在Android3.0之后的版本上规定,线程池大小根据CPU的数量来定。对于仅有一个CPU的主机,可同时运行的线程数2,可以容纳的最大线程数量为3。但是从HONEYCOMB开始,AsyncTask只允许一个线程执行,来防止多线程同时运行时出现的错误。如果用户向并行执行多线程,可以自定义THREAD_POOL_EXECUTOR重新去定义线程池。
如下所示:
Executor exec = new ThreadPoolExecutor(15, 200, 10, TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>());
这样就可以使用我们自定义的一个Executor来执行任务,而不是使用默认的SerialExecutor。上述代码的效果允许在同一时刻有15个任务正在执行,并且最多能够存储200个任务。

 
 

总结:

如若想异步处理一些轻量级的操作,AsyncTask是个不错的选择,他封装了Thread和Handler,不需要用户再去自定义handler和Thread。AsyncTask是个抽象类,使用的时候需要继承他,调用其execute方法,并在实现类中重写上面的doInBackground的方法。如果想要将执行结果反馈到UI,则需要将剩余的三(可选择)个方法重写。

 

##首次写博客,边抄边学习边总结。给自己加油,希望可以坚持下去!!!

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值