AsyncTask:异步任务

QuibblerQuibbler 2020-01-23 约 14 分钟 1734 次阅读

AsyncTask:异步任务

多线程开发在Android中很常见,网络请求,图片加载,JSON解析等等。而且Android也提供了非常丰富的多线程方法,Thread、Runnable、Handler等等。

AsyncTask更进一步做了封装,直接开启一个任务,内部在子线程中处理耗时任务。还能在UI线程中更新界面。关于AsyncTask的原理参考《源码颇析AsyncTask工作原理》。

1、AsyncTask类

AsyncTask内部已经做了大量的封装,是一个抽象类。

1.1、doInBackground()

AsyncTask只有一个抽象方法doInBackground()。该方法返回的类型是泛型Result,定义AsyncTask时指定的返回结果类型。参数就是调用AsyncTask.execute(...)所传入的参数params。后面再详细的说明。

protected abstract Result doInBackground(Params... params);

方法名就可以看出来这个方法是运行在后台子线程中,专门用来执行耗时任务的,官方文档的说明是:

/*
     * 重写此方法以在后台线程上执行计算。 指定的参数是此任务的调用者传递给{@link #execute}的参数。
     *
     * 这部分代码将会运行在后台线程中. 
     * 为了更好的支持测试框架,推荐在前台(UI线程)调用execute()方法。
     *
     * 可以在该方法中调用{@link #publishProgress}去更新U进度,
     * 上面的方法会择机调用onProgressUpdate,可以在其中去更新UI界面上的进度
     */

1.2、重写方法

继承AsyncTask自定义自己的异步任务,除了实现唯一的抽象方法doInBackground(),一般还需要重写其它几个重要的方法:onPreExecute()、onPostExecute()、onProgressUpdate()。

public class TaskAsyncTask extends AsyncTask<String, Integer, Boolean> {
    
        @Override
        protected void onPreExecute() {
            super.onPreExecute();
        }
        
        @Override
        protected Boolean doInBackground(String[] objects) {
            return null;
        }
        
        @Override
        protected void onPostExecute(Boolean o) {
            super.onPostExecute(o);
        }
        
        @Override
        protected void onProgressUpdate(Integer[] values) {
            super.onProgressUpdate(values);
        }
    }

1.3、其它方法

此外还有几个方法:onCancle(Boolean )、onCancle()。取消任务,最好在生命周期的onDestory()调用,取消后台任务的执行。

/**
     * <p>Runs on the UI thread after {@link #cancel(boolean)} is invoked and
     * {@link #doInBackground(Object[])} has finished.</p>
     * 
     * <p>The default implementation simply invokes {@link #onCancelled()} and
     * ignores the result. If you write your own implementation, do not call
     * <code>super.onCancelled(result)</code>.</p>
     *
     * @param result The result, if any, computed in
     *               {@link #doInBackground(Object[])}, can be nul
     */
    @SuppressWarnings({"UnusedParameters"})
    @MainThread
    protected void onCancelled(Result result) {
        onCancelled();
    }

这些方法根据业务需求,按需重写。按照AsyncTask内部设定的顺序依次执行。


2、AsyncTask中的泛型

AsyncTask中有三个泛型,第一个泛型是传入参数的类型Params,第二个泛型是任务执行的进度Progress,一般为Integer或者Void;第三个泛型是任务执行的结果Result,可以为Boolean值表示是否执行成功,也可以是Bitmap等获取的数据。

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

注意:三个泛型不能为基本数据类型,要是是int就用Integer,bool就用Boolean,void就用Void类型,使用包装器类型替代基本类型。

2.1、方法中的泛型参数

仔细看可以看到前面几个方法的参数和返回值与这几个泛型密切相关。

doInBackground()传入的参数类型是第一个泛型Params,该类型也是AsyncTask的execute()方法的参数类型。返回结果类型是第三个泛型Result

@Override
    protected Boolean doInBackground(String[] objects) {
        return null;
    }

onPostExecute()方法在执行完后台任务doInBackground()之后执行,发布执行结果,方法参数就是第三个泛型Result。这里定义的是Boolean类型。

@Override
    protected void onPostExecute(Boolean o) {
       super.onPostExecute(o);
    }

onProgressUpdate()方法的参数类型是第二个泛型Progress,任务执行的进度,一般为Integer表示下载进度等。或者直接为Void类型,不需要知道进度。

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

3、创建AsyncTask

继承AsyncTask的类提供构造方法,可以有默认的无参构造函数:

AsyncTask asyncTask = new TaskAsyncTask();

一般还会通过有参构造函数传入一些数据,初始化AsyncTask中的成员变量。比如从Activity中传入一个回调接口,用于在onPostExecute()、onProgressUpdate()中调用更新数据。

AsyncTask asyncTask = new TaskAsyncTask(listener);

4、执行AsyncTask

创建好AsyncTask对象之后,就可以开始执行任务了,有两种执行方法供调用。

4.1、execute()

直接调用execute()

asyncTask.execute();

使用该种方法使用的是默认线程池,查看源码可以发现,内部调用的是第二种方法,只不过传入的线程池是默认的AsyncTask.SERIAL_EXECUTOR

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

而这个AsyncTask中的sDefaultExecutor定义如下:

private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;
    
    ...
    public static final Executor SERIAL_EXECUTOR = new SerialExecutor();

4.2、executeOnExecutor()

指定线程池执行任务,AsyncTask中默认定义了两种线程池:

①SERIAL_EXECUTOR中的任务按照“先进先执行,依次执行”的原则,后续任务要等先前的任务执行完毕后才会执行,顺次执行。也是默认的执行器。

asyncTask.executeOnExecutor(AsyncTask.SERIAL_EXECUTOR, params...);

②THREAD_POOL_EXECUTOR被加入线程池的任务会立刻执行,也就是所有任务并发执行。

asyncTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, params...);

但是有个前提,THREAD_POOL_EXECUTOR中一起执行的任务超过了线程池数量个,那么新加入的任务会等线程执行完毕了再执行。这个线程池最大定义目前是20,查看以前的博客的文档说的是(CPU*2+1)。在AsyncTask类静态初始化:

private static final int CORE_POOL_SIZE = 1;
    private static final int MAXIMUM_POOL_SIZE = 20;
    private static final int BACKUP_POOL_SIZE = 5;
    private static final int KEEP_ALIVE_SECONDS = 3;
    ... 
    static {
        ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(
                CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE_SECONDS, TimeUnit.SECONDS,
                new SynchronousQueue<Runnable>(), sThreadFactory);
        threadPoolExecutor.setRejectedExecutionHandler(sRunOnSerialPolicy);
        THREAD_POOL_EXECUTOR = threadPoolExecutor;
    }

5、AsyncTask注意点

①Task的实例必须在UI线程中创建

②execute方法必须在UI线程中调用

③不要手动的调用onPreExecute(), onPostExecute(Result),doInBackground(Params…), onProgressUpdate(Progress…)这几个方法

④该task只能被执行一次,否则多次调用时将会出现异常

        ⑤AsyncTask不与任何组件绑定生命周期。使用建议:在Activity 或 Fragment中使用 AsyncTask时,最好在Activity 或 Fragment的onDestory()调用 cancel(boolean);

⑥AsyncTask应被声明为Activity的静态内部类。或者单独继承AsyncTask定义一个类。否则,当Activity需销毁时,会因AsyncTask保留对Activity的引用 而导致Activity无法被回收,最终引起内存泄露。

参考博客:

        别再傻傻得认为AsyncTask只可以在主线程中创建实例和调用execute方法

        Android 多线程:AsyncTask的原理 及其源码分析

        Android 多线程:手把手教你使用AsyncTask

        AsyncTask坑:多个task是串行执行还是并行的

相关推荐

精选
ViewPager和PagerAdapter、FragmentPagerAdapter、FragmentStatePager
Android

ViewPager和PagerAdapter、FragmentPagerAdapter、FragmentStatePager

ViewPager1、ViewPagerandroidx.viewpager.widget.ViewPager,Android中使用非常广泛的控件,可以说是APP必备:首次打开引导页、页面Banner广告等。常用方法:setAdapter() 设置适配器setOffscreenPageLimit() 设置缓存的页面个数,默认是 1setCurrentItem() 跳转到特定的页面setOnPage

1.1k
获取Android内置WebView内核版本
Android

获取Android内置WebView内核版本

获取Android内置WebView内核版本竟然能遇到这样奇葩的事情,网页用的技术过于新颖,以至于只支持高版本Chromium内核的,低版本安卓系统中内置的内核版本较低,无法加载前端页面。1、设置查看在系统设置里 > 应用 > 应用管理 > 显示系统应用,查看WebView组件:2、页面查看通过WebView发起的网络请求,都会带上浏览器的UA,通常页面都可以通过UA判断浏览器的内核版本。这里有两

1.1w
Android 14适配总结
Android

Android 14适配总结

Android 14适配总结毕业工作至今已经适配了三个Android大版本,从Android 11到Android 12、再到Android 13。2023年,Google即将推出的Android 14,上半年已经开始第一批适配。现在,第四个Android版本已经适配完,总结记录一下。1、Android 14计划Google一般会在2月份对外发布预告,同时放出开发者预览版。“拉通”各大平台、厂商以

1.1w