Android 之 AsyncTask

前言:

本文纯粹个人见解,如有错误或不正确的地方,请指出,多谢。

AsyncTask是Android对 线程池 的一个轻量级封装。

介绍:

线程池:
管理线程的地方。

核心线程:CORE_POOL_SIZE,
api19是 CPU核数+1
api27是 Math.max(2, Math.min(核数 - 1, 4)),即2到4。

任务队列:最大存放128个任务
private static final BlockingQueue<Runnable> sPoolWorkQueue =
           new LinkedBlockingQueue<Runnable>(128);

最大线程数:核心线程+额外线程:MAXIMUM_POOL_SIZE = 核数*2+1

额外线程空闲后的存活时间:KEEP_ALIVE_SECONDS = 30; 即存活30秒。

现在假设新建AsyncTask,一直往里添加任务。

1.新建AsyncTask时,线程池为空,添加任务时,

            会将任务交给任务队列,核心线程空闲就会从任务队列提取任务执行。

2.当全部核心线程都在工作,任务就会继续往任务队列放,

            超过最大值128个任务时,就会新开额外线程来处理,直到最大线程数。

        3.然后额外线程全部在工作的时候,还往里添加任务,

            就会使用handler抛出拒绝任务的异常Exception。


自带的Executor:
控制AsyncTask是串行执行任务还是并行执行任务。

Handler

负责线程间的通讯和更新UI界面。可以看看我之前的 博文 或 查阅其他相关资料。


生命周期

onPreExecute → doInBackground → onPostExecute

其中通过手动调用publishProgress()来调用onProgressUpdate。

还可以调用onCancelled()来取消任务。




如何使用:

第一步:新建一个类继承AsyncTask<Parms,Progress,Result>,重写需要的方法。
Parms:执行异步操作前输入的值。
Progress:执行中任务进度的值。
Result:执行后反馈结果的值。
三个都是泛类,可以任意改动类型。

第二步:实例化对象,在主线程上使用execute()即可。


举个简单的例子:模拟下载更新progressbar

class DownloadAsyncTask extends AsyncTask<Void, Integer, Boolean> {

	//执行后台任务前,调用该方法
        @Override
        protected void onPreExecute() {
            super.onPreExecute();
            mProgressBar.setProgress(0);
            mTextView.setText("0 %");
            isDownload = true;
        }

	//顾名思义,就是后台子线程执行任务的方法
        @Override
        protected Boolean doInBackground(Void... voids) {
            for (int i = 0; i < 101; i++) {
                try {
                    //睡眠模拟网络下载//
                    Thread.sleep(80);

                    //调用这个才能更新UI进度
                    publishProgress(i);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                    
                    //下载出错
                    return false;
                }
            }

            //下载成功
            return true;
        }

	//子线程更新UI进度的方法
	//调用publishProgress会触发该方法
        @Override
        protected void onProgressUpdate(Integer... values) {
            super.onProgressUpdate(values);
            mProgressBar.setProgress(values[0]);
            mTextView.setText(values[0] + " %");
        }

	//执行完后台任务后会执行的方法
        @Override
        protected void onPostExecute(Boolean aBoolean) {
            super.onPostExecute(aBoolean);
            if (aBoolean) {
                mTextView.setText("下载完成");
            } else {
                mTextView.setText("下载出错");
            }
    	    isDownload = false;
        }
    }

新建好内部类,就看看onCreate这边

public class SampleActivity extends AppCompatActivity {

    private TextView mTextView;
    private ProgressBar mProgressBar;
    private Button mButton;

    private boolean isDownload;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_sample);
        isDolwoad = false;

        mTextView = findViewById(R.id.sam_btn);
        mProgressBar = findViewById(R.id.sam_progressBar);
        mButton = findViewById(R.id.sam_btn);

        mButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if (isDownload) {
                    Toast.makeText(v.getContext(), "正在下载...", Toast.LENGTH_SHORT).show();
                } else {
                    new DownloadAsyncTask().execute();  //这是执行AsyncTask,相当于添加任务
                }
            }
        });
    }

    class DownloadAsyncTask extends AsyncTask<Void, Integer, Boolean> {/*请看上面的*/}

}

效果图:



从例子可以看出,内部类DownloadAsyncTask继承了AsyncTask<Void, Integer, Boolean>

Parms 就是 Void, 所以new DownloadAsyncTask().execute();没有传入参数。

Progress 就是 Integer ,用来更新progressBar 和 TextVIew

Results 就是Boolean ,最后执行完毕反馈的结果


例子中重写了的方法有

onPreExecute();

doInBackground(Void... void);

onProgressUpdate(Integer... values);

onPostExecute(Boolean aBoolean):


其中只有doInBackground是必须重写的,而且在后台子线程运行。

其他都是在主线程执行的。

细心的朋友会留意到方法里的参数,跟继承时的泛类值一样。

没错,doInBackground的参数就是传入的Parms,

onProgressUpdate的参数就是中间的Progress,

onPostExecute的参数就是最后的Results,即doInBackground执行完反馈的值。


优点:

        简单,结构清晰。

        方法已经给好,直接在里面写动作就好了。

缺点:一大堆...

        1.生命周期

            因为AsyncTask不会随Activity销毁而销毁。

            doInBackground会一直执行完为止。然后执行onPostExecute或onCancelled.


         2.内存泄漏

            Activity中使用非静态匿名内部AsyncTask类,AsyncTask会保留一个对Activity的引用。

            Activity被销毁,AsyncTask还有保留,系统无法收回Activity,导致内存泄漏。


         3.结果丢失

            Activity被销毁,AsyncTask还有保留的旧Activity的引用,

            那么onProgressUpdate和onPostExecute将不起作用。


          4.onCancel()不一定起作用

               doInBackground()有不可打断的方法会失效,比如这个BitmapFactory.decodeStream() IO操作。


          5.并行的隐患

                因为所有AsyncTask都是用同一个线程池,如果并行的doInBackground访问到相同的资源,但没有处理同步问题,就会报错甚至崩溃。


          6.局限性

            AsyncTask对象必须在主线程中创建

            AsyncTask对象的execute方法必须在主线程中调用

            一个AsyncTask对象只能调用一次execute方法

            .不要在你的程序中去直接调用onPreExecute(), onPostExecute, 

                                        doInBackground, onProgressUpdate方法


Thanks:

        以上内容部分来自以下网站

             AsyncTask(一)AsyncTask的使用

            你真的了解AsyncTask?

            深入理解AsyncTask的工作原理

        

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值