Android线程和线程池(一)AsyncTask学习记录 使用+源码

线程和线程池

Android沿用了Java的线程模型,从Android3.0开始系统要求网络访问也必须在子线程中进行,否则网络访问将会失败并抛出NetworkOnMainThreadException异常。在Android里如果主线程被执行耗时任务导致阻塞后还会造成ANR的发生。

一、Java线程基本介绍

1.1 线程状态

  • 运行状态(Running)当CPU开始调度处于就绪状态的线程时,此时线程才得以真正执行,即进入到运行状态。
  • 阻塞状态(Blocked)处于运行状态中的线程由于某种原因,暂时放弃对CPU的使用权,停止执行,此时进入阻塞状态,阻塞状态后要再到运行状态,必须是先经过就绪状态。
  • 死亡状态(Dead)线程执行完了或者因异常退出了run()方法,该线程结束生命周期
  • 新建状态(New)线程对象创建后就会进入了新建状态,如:Thread t = new MyThread();
  • 可运行状态(Runnable)当调用线程对象的start()方法后,如:t.start();,线程进入可运行状态。此状态的线程只是明确做好了准备,随时等待CPU调度执行,不一定开始执行
  • 阻塞状态(Blocked)线程被锁阻塞,暂时放弃对CPU的使用权,停止执行,暂时不活动。
  • 等待状态(Waiting)线程暂时不活动,不运行任何代码,直到线程调度器重新激活它。
  • 超时等待状态(Timed waiting) 和等待状态不同的是,它是可以在指定的时间自行返回的。
  • 终止状态(Terminated)表示线程已经执行完毕,要么是run方法执行完正常退出,要么是一个没捕获的异常终止了run方法。
    在这里插入图片描述

线程创建后,调用Thread 的 start方法,开始进入运行状态,当线程执行wait方法后,线程进入等待状态,进入等待状态的线程需要其他线程通知才能返回运行状态。超时等待相当于在等待状态加上了时间限制,如果超过时间限制,则线程返回运行状态。当线程调用到同步方法时,如果线程没有获得锁则进入到阻塞状态,当阻塞状态的线程获取到锁时则重新回到运行状态。当线程执行完毕或者遇到意外异常终止时,都会进入终止状态。

1.2 为什么要使用多线程

  1. 多线程和进程相比,它是一种非常花销小,切换快,更"节俭"的多任务操作方式。
    • 在Linux系统下,启动一个新的进程必须分配给它独立的地址空间,建立众多的数据表来维护它的代码段、堆栈段和数据段,这是一种"昂贵"的多任务工作方式。
    • 而运行于一个进程中的多个线程,它们彼此之间使用相同的地址空间,共享大部分数据,启动一个线程所花费的空间远远小于启动一个进程所花费的空间,
    • 线程间彼此切换所需的时间也远远小于进程间切换所需要的时间。
    • 使用多线程能提高CPU利用率,多CPU或多核计算机本身具备执行多线程的能力,如果使用单个线程,无法重复利用计算机资源。
  2. 方便的通信机制。
    • 对不同进程来说,它们具有独立的数据空间,要进行数据的传递只能通过通信的方式进行,这种方式不仅费时,而且很不方便。
    • 线程则不然,由于同一进程下的线程之间共享数据空间,所以一个线程的数据可以直接为其它线程所用,快捷、方便。
    • 当然,数据的共享也带来其他一些问题,有的变量不能同时被两个线程所修改,有的子程序中声明为static的数据更有可能给多线程程序带来灾难性的打击,这些正是编写多线程程序时最需要注意的地方。
  3. 程序的角度
    • 使用多线程能简化程序的结构,使程序便于理解和维护。

小结

阻塞状态(Blocked)和等待状态(Waiting)区别是什么?
在这里插入图片描述

进入 waiting 状态是线程主动的,而进入 blocked 状态是被动的。更进一步的说,进入 blocked 状态是在同步(synchronized)代码之外,而进入 waiting 状态是在同步代码之内(然后马上退出同步)。

Entry Set中的线程处于阻塞状态,也就是线程还没有拿到锁。Wait Set中的线程处于等待状态,也就是拿到锁后暂时释放锁(等待条件成熟会再次获取锁)。

线程和其他线程抢锁没抢到,就处于阻塞状态了;(此时线程还没进同步代码块)

线程抢到了锁进了同步代码块,(由于某种业务需求)某些条件下Object.wait()了,就处于了等待状态。(此时线程已经进入了同步代码块)

除了Thread本身除外,在Android中可以扮演线程角色的的还有很多,比如AsyncTask和IntentService,同时HandlerThread也是一种特殊的线程。尽管他们的表现形式有别于传统的线程,但是他们的本质仍然是传统的线程。不同形式的线程虽然都是线程,但是它们仍然有不同的特性和使用场景。

二、AsyncTask

AsyncTask是一种轻量级的异步任务类可以在线程池中执行后台任务,然后把执行的进度和最终结果传递给主线程并在主线程中更新UI。从实现上来说,AsyncTask封装了Thread和Handler,但是AsyncTask并不适合进行特别耗时的后台任务,对于特别耗时的任务来说,建议使用线程池。AsyncTask本身是一个抽象类它提供了Params、Progress、Result 三个泛型参数,其类声明如下:public abstract class AsyncTask<Params, Progress, Result>
在这里插入图片描述

(1)onPreExecute(), 该方法在主线程中执行,将在execute(Params… params)被调用后执行,一般用来做一些UI的准备工作,如在界面上显示一个进度条。
(2)doInBackground(Params…params), 抽象方法,必须实现,该方法在线程池中执行,用于执行异步任务,将在onPreExecute方法执行后执行。其参数是一个可变类型,表示异步任务的输入参数,在该方法中还可通过publishProgress(Progress… values)来更新实时的任务进度,而publishProgress方法则会调用onProgressUpdate方法。此外doInBackground方法会将计算的返回结果传递给onPostExecute方法。
(3)onProgressUpdate(Progress…),在主线程中执行,该方法在publishProgress(Progress… values)方法被调用后执行,一般用于更新UI进度,如更新进度条的当前进度。
(4)onPostExecute(Result), 在主线程中执行,在doInBackground 执行完成后,onPostExecute 方法将被UI线程调用,doInBackground 方法的返回值将作为此方法的参数传递到UI线程中,并执行一些UI相关的操作,如更新UI视图。
(5)onCancelled(),在主线程中执行,当异步任务被取消时,该方法将被调用,要注意的是这个时onPostExecute将不会被执行。

  • AsyncTask的实例必须在主线程中创建
  • AsyncTask的execute方法必须在主线程中调用
  • 回调方法,Android会自动调用
  • 一个AsyncTack的实例,只能执行一次execute方法

2.1 应用例子

在这里插入图片描述

代码:https://github.com/zprjd/ServiceBestPractice

2.2 Callable

public interface Callable<V> {   
      V   call()   throws Exception;   
}   
Callable接口声明了一个名称为call()的方法,该方法可以有返回值V,也可以抛出异常。
Callable也是一个线程接口,它与Runnable的主要区别就是Callable在线程执行完成后可以有返回值
而Runnable没有返回值,Runnable接口声明如下:

public interface Runnable {
    public abstract void run();
}

2.3 Future

Future接口是用来获取异步计算结果的,
说白了就是对具体的Runnable或者Callable对象任务执行的结果进行获取(get()),取消(cancel()),
判断是否完成等操作。其方法如下:

public interface Future<V> {
    //取消任务
    boolean cancel(boolean mayInterruptIfRunning);

    //如果任务完成前被取消,则返回true。
    boolean isCancelled();

    //如果任务执行结束,无论是正常结束或是中途取消还是发生异常,都返回true。
    boolean isDone();

    //获取异步执行的结果,如果没有结果可用,此方法会阻塞直到异步计算完成。
    V get() throws InterruptedException, ExecutionException;

    // 获取异步执行结果,如果没有结果可用,此方法会阻塞,但是会有时间限制,
    //如果阻塞时间超过设定的timeout时间,该方法将返回null。
    V get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException;

}

总得来说Future有以下3点作用:

能够中断执行中的任务
判断任务是否执行完成
获取任务执行完成后额结果。
 但是Future只是接口,我们根本无法将其创建为对象,
于官方又给我们提供了其实现类FutureTask,这里我们要知道前面两个接口的介绍都只为此类做铺垫,
毕竟AsncyTask中使用到的对象是FutureTask

2.4 FutureTask

先来看看FutureTask的实现:

public class FutureTask<V> implements RunnableFuture<V> {  
显然FutureTask类实现了RunnableFuture接口,我们再看一下RunnableFuture接口的实现:

public interface RunnableFuture<V> extends Runnable, Future<V> {
    void run();
}
从接口实现可以看出,FutureTask除了实现了Future接口外还实现了Runnable接口,
因此FutureTask既可以当做Future对象也可是Runnable对象,
当然FutureTask也就可以直接提交给线程池来执行。接着我们最关心的是如何创建FutureTask对象,
实际上可以通过如下两个构造方法来构建FutureTask

public FutureTask(Callable<V> callable) {  
}  
public FutureTask(Runnable runnable, V result) {  
}  

FutureTask实现了Runnable接口,因此可以把他传给线程池Executor,让线程池执行ececute

// 获取异步执行结果,如果没有结果可用,此方法会阻塞直到异步计算完成,但是会有时间限制,
//如果阻塞时间超过设定的timeout时间,该方法将返回null。
public V get(long timeout, TimeUnit unit)
    throws InterruptedException, ExecutionException, TimeoutException {
    if (unit == null)
        throw new NullPointerException();
    int s = state;
    if (s <= COMPLETING &&
//阻塞式等待任务的返回值,等待call方法返回值,执行完立即返回执行结果
        (s = awaitDone(true, unit.toNanos(timeout))) <= COMPLETING)
        throw new TimeoutException();
    return report(s);
}

三、AsyncTask源码

AsyncTask实现原理=**线程池+Handler。**其中:线程池用于线程调度、复用&执行任务;Handler用于异步通信

AsyncTask内部封装了2个线程池+1个Handler,具体介绍如下:

onPreExecute方法先执行,接着是doInBackground方法,在doInBackground中如果调用了publishProgress方法,那么onProgressUpdate方法将会被执行

使用线程池可以维护固定数量的线程,轮训线程,避免不停的创建销毁等不必要的开销。

//CUP核数,
private static final int CPU_COUNT = Runtime.getRuntime().availableProcessors();
//核心线程数量,AsyncTask内部最大线程数100,手机CPU核数+1
private static final int CORE_POOL_SIZE = CPU_COUNT + 1;
//最大线程数量
private static final int MAXIMUM_POOL_SIZE = CPU_COUNT * 2 + 1;
//非核心线程的存活时间1s
private static final int KEEP_ALIVE = 1;

//线程工厂类,用来创建线程池
private static final ThreadFactory sThreadFactory = new ThreadFactory() {
//原子类型,为了确保mCount是线程安全的
    private final AtomicInteger mCount = new AtomicInteger(1);

    public Thread newThread(Runnable r) {
//将新增线程名字以AsyncTask #为标识
        return new Thread(r, "AsyncTask #" + mCount.getAndIncrement());
    }
};
//线程队列,核心线程不够用时,任务会添加到该队列中,队列满后,会去调用非核心线程执行任务
private static final BlockingQueue<Runnable> sPoolWorkQueue =
            new LinkedBlockingQueue<Runnable>(128);//阻塞队列大小128
/**
 * An {@link Executor} that can be used to execute tasks in parallel.
 */
//静态默认线程池,默认工作都由它完成
public static final Executor THREAD_POOL_EXECUTOR;
//用上面的参数实例化了THREAD_POOL_EXECUTOR
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;
}

/**
* An {@link Executor} that executes tasks one at a time in serial
* order.  This serialization is global to a particular process.
*/
public static final Executor SERIAL_EXECUTOR = new SerialExecutor();//调度线程池
/**
 * Indicates the current status of the task. Each status will be set only once
 * during the lifetime of a task.
 */
public enum Status {
    /**
     * Indicates that the task has not been executed yet.
     */
    PENDING,//还没开始执行
    /**
     * Indicates that the task is running.
     */
    RUNNING,//已经开始执行
    /**
     * Indicates that {@link AsyncTask#onPostExecute} has finished.
     */
    FINISHED,//任务已经执行完成,或取消了
}//枚举内部类
/**
 * Creates a new asynchronous task. This constructor must be invoked on the UI thread.
 *
 * @hide
 */
public AsyncTask(@Nullable Looper callbackLooper) {
//如果是主线程looper就创建主线程handler,如果不是就用传入looper创建handler,默认是主线程handler
    mHandler = callbackLooper == null || callbackLooper == Looper.getMainLooper()
        ? getMainHandler()
        : new Handler(callbackLooper);
//创建WorkerRunnable mWorker,本质上就是一个实现了Callable接口对象
    mWorker = new WorkerRunnable<Params, Result>() {
        public Result call() throws Exception {//在线程池中某个线程执行的
            mTaskInvoked.set(true);//表示任务已经开始执行了
            Result result = null;
            try {
                Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);//将call方法设置为后台线程
                //noinspection unchecked
                result = doInBackground(mParams);//后台耗时操作,将返回值给result
                Binder.flushPendingCommands();
            } catch (Throwable tr) {
                mCancelled.set(true);
                throw tr;
            } finally {
                postResult(result);//执行完的result传给postResult
            }
            return result;
        }
    };

//初始化mFuture的时候将mWorker作为参数传入
//mWorker是一个Callable对象,mFuture是一个FutureTask对象
//把mWorker(即Callable实现类)封装成FutureTask实例
//最终执行结果也就封装在FutureTask中
    mFuture = new FutureTask<Result>(mWorker) {
//任务执行完成后被调用
        @Override
        protected void done() {
            try {
//如果还没更新结果通知就执行postResultIfNotInvoked
                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);//抛异常
            }
        }
    };
}

private static abstract class WorkerRunnable<Params, Result> implements Callable<Result> {
    Params[] mParams;
}//实现了Callable
@FunctionalInterface
public interface Callable<V> {
    /**
     * Computes a result, or throws an exception if unable to do so.
     *
     * @return computed result
     * @throws Exception if unable to compute a result
     */
    V call() throws Exception;//Runnable的call方法没有返回值,Callable的call方法有返回值
}

接下来看一下execute()方法。

public final AsyncTask<Params, Progress, Result> execute(Params... params) {
//传入了DefaultExecutor,DefaultExecutor就是默认执行任务的线程池
	 return executeOnExecutor(sDefaultExecutor, params);
}

public final AsyncTask<Params, Progress, Result> executeOnExecutor(Executor exec,
        Params... params) {
    if (mStatus != Status.PENDING) {//判断必须是PENDING状态才能向下执行
        switch (mStatus) {//保证一个AsyncTask**只执行一次**任务
            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)");
        }//AsyncTask的execute方法只能执行一次,想执行多次需要多个AsyncTask
    }

    mStatus = Status.RUNNING;//从PENDING改变为RUNNING状态

//在开始前先做初始化工作
//execute方法在主线程中进行,onPreExecute()方法也在主线程中运行,所以可以做UI的改变
    onPreExecute();

//参数传递给了mWorker.mParams
    mWorker.mParams = params;//保存了方法中的参数params

//执行mFuture任务,其中exec就是传递进来的sDefaultExecutor
 //把mFuture交给线程池去执行任务
    exec.execute(mFuture);//mFuture实现了Runnable接口
    return this;
}

onPreExecute()方法会第一个得到执行。在之后两行调用了Executor.execute()方法,并将前面初始化的mFuture对象传了进去。这个Executor对象是传入的sDefaultExecutor变量,接着找一下这个sDefaultExecutor变量,源码如下所示:

private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;
//一个静态内部类,绑定了主线程的looper与消息队列,处理子线程中的消息在主线程中回显
private static InternalHandler sHandler;

private volatile Status mStatus = Status.PENDING;//初始状态为是PENDING

刚才在executeOnExecutor()方法中调用的execute()方法,其实也就是调用的SerialExecutor类中的execute()方法。来看看SerialExecutor,他是AsyncTask的内部类:

private static class SerialExecutor implements Executor {//内部类
		//串行执行任务,没有容量上限
    final ArrayDeque<Runnable> mTasks = new ArrayDeque<Runnable>();{
    Runnable mActive;//正在执行的任务

    public synchronized void execute(final Runnable r) {
//add() 和 offer()都是用来向队列添加一个元素。
在容量已满的情况下,add() 方法会抛出IllegalStateException异常,offer() 方法只会返回 false//通过调用offer将封装后的runnable添加到队尾
        mTasks.offer(new Runnable() //匿名内部类
            public void run() {
                try {
                    r.run();//线程池中执行
                } finally {
                    scheduleNext();//执行下一个任务的Runnable
                }
            }
        });
        if (mActive == null) {
            scheduleNext();//没有任务就执行下一个任务
        }
    }

调用ArrayDequeoffer()方法将传入的Runnable对象添加到队列的尾部,
然后判断mActive对象是不是等于null,第一次运行当然是等于null了,
于是会调用scheduleNext()方法。在这个方法中会从队列的头部取值,
并赋值给mActive对象,然后调用THREAD_POOL_EXECUTOR去执行取出的取出的Runnable对象。
之后如何又有新的任务被执行,同样还会调用offer()方法将传入的Runnable添加到队列的尾部,
但是再去给mActive对象做非空检查的时候就会发现mActive对象已经不再是null了,
于是就不会再调用scheduleNext()方法。
r.run()执行完后面添加的任务岂不是永远得不到处理了?
当然不是,看一看offer()方法里传入的Runnable匿名类,
这里使用了一个try finally代码块,并在finally中调用了scheduleNext()方法,
保证无论发生什么情况,这个方法都会被调用。也就是说,每次当一个任务执行完毕后,
下一个任务才会得到执行,SerialExecutor模仿的是单一线程池的效果,如果我们快速地启动了很多任务,
同一时刻只会有一个线程正在执行,其余的均处于等待状态。
ArrayDeque是一个存放任务队列的容器(mTasks),任务Runnable传递进来后交给SerialExecutor
的execute方法处理,SerialExecutor会把任务Runnable插入到任务队列mTasks尾部,
接着会判断是否有Runnable在执行,没有就调用scheduleNext方法去执行下一个任务,
接着交给THREAD_POOL_EXECUTOR线程池中执行,由此可见SerialExecutor并不是真正的线程执行者,
它只是是保证传递进来的任务Runnable(实例是一个FutureTask)串行执行,
而真正执行任务的是THREAD_POOL_EXECUTOR线程池,
当然该逻辑也体现AsyncTask内部的任务是默认串行进行的。

    protected synchronized void scheduleNext() {
//从任务队列mTasks中通过poll()出队然后判断是否为空,并放到THREAD_POOL_EXECUTOR线程池中执行.
//由此也可见任务是串行进行的。
        if ((mActive = mTasks.poll()) != null) {
            THREAD_POOL_EXECUTOR.execute(mActive);
        }
    }
}

SerialExecutor类中也有一个execute()方法,这个方法里的所有逻辑在子线程中执行,有一个Runnable参数,那么目前这个参数的值是就是mFuture对象,也就是说r.run调用的实际是FutureTask类的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);
    }
}
public FutureTask(Callable<V> callable) {
    if (callable == null)
        throw new NullPointerException();
    this.callable = callable;
    this.state = NEW;       // ensure visibility of callable
}
传入的是mWorker,看mWorker的call方法

public Result call() throws Exception {//在线程池中某个线程执行的
    mTaskInvoked.set(true);//表示任务已经开始执行了
    Result result = null;
    try {
//将call方法设置为后台线程
        Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);/
        //noinspection unchecked
//后台耗时操作,将返回值给result
        result = doInBackground(mParams);//执行doInBackground,并传递mParams参数
        Binder.flushPendingCommands();
    } catch (Throwable tr) {
        mCancelled.set(true);
        throw tr;
    } finally {
        postResult(result);//执行完的result传给postResult
    }
    return result;
}

小结

AsynTask在初始化时会创建mWorker实例对象和FutureTask实例对象,mWorker是一个实现了Callable线程接口并封装了传递参数的实例对象,然后mWorker实例会被封装成FutureTask实例中。在AsynTask创建后,我们调用execute方法去执行异步线程,其内部又直接调用了executeOnExecutor方法,并传递了线程池exec对象和执行参数,该方法内部通过线程池exec对象去执行mFuture实例,
这时mWorker内部的call方法将被执行并调用doInBackground方法,最终通过postResult去通知更结果。


private Result postResult(Result result) {
    @SuppressWarnings("unchecked")
//把result封装到一个AsyncTaskResult对象中,
//最后把MESSAGE_POST_RESULT标示和AsyncTaskResult存放到Message中并发送给Handler去处理,
    Message message = getHandler().obtainMessage(MESSAGE_POST_RESULT,//获取主线程Handler
            new AsyncTaskResult<Result>(this, result));
    message.sendToTarget();//将message发送给handler
    return result;
}

通过Handler去执行结果更新的,在执行结果成返回后,把result封装到一个AsyncTaskResult对象中,
最后把MESSAGE_POST_RESULT标示和AsyncTaskResult存放到Message中并发送给Handler去处理,
这里我们先看看AsyncTaskResult的源码:
private static class AsyncTaskResult<Data> {
    final AsyncTask mTask;
    final Data[] mData;

    AsyncTaskResult(AsyncTask task, Data... data) {
        mTask = task;
        mData = data;
    }
}
AsyncTaskResult封装了执行结果的数组以及AsyncTask本身
接着看看AsyncTaskResult被发送到handler后如何处理的。
private static class InternalHandler extends Handler {
    public InternalHandler(Looper looper) {
        super(looper);
    }

    @SuppressWarnings({"unchecked", "RawUseOfParameterizedType"})
    @Override
    public void handleMessage(Message msg) {
//获取AsyncTaskResult
        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://更新进度条的标志
//调用asynctask的onProgressUpdate
                result.mTask.onProgressUpdate(result.mData);
                break;
        }
    }
}

如果这是一条MESSAGE_POST_RESULT消息,就会去执行finish()方法,如果这是一条MESSAGE_POST_PROGRESS消息,就会去执行onProgressUpdate()方法。那么finish()方法的源码如下所示:

private void finish(Result result) {//在主线程中执行的
    if (isCancelled()) {
        onCancelled(result);
    } else {
        onPostExecute(result);//后台计算结果后的显现工作
    }
    mStatus = Status.FINISHED;//改变状态表示任务执行完毕
}

该方法先判断任务是否被取消,如果没有被取消则去执行onPostExecute(result)方法,外部通过onPostExecute方法去更新相关信息,如UI,消息通知等。最后更改AsyncTask的状态为已完成。到此AsyncTask的全部流程执行完。
MESSAGE_POST_PROGRESS是我们在doInBackground方法中调用publishProgress方法时发出的,该方法如下:

protected final void publishProgress(Progress... values) {
    if (!isCancelled()) {
        getHandler().obtainMessage(MESSAGE_POST_PROGRESS,
                new AsyncTaskResult<Progress>(this, values)).sendToTarget();
    }
}

小结

AsyncTask的方法中,除了doInBackground()方法是后台线程之外,其余方法都处于主线程,因此在其余方法中是可以调用UI工具包的

它主要用于执行一些不太长的异步任务。但由于context泄露,回调遗漏,configuration变化导致崩溃,平台差异性等原因,在api 30(Android 11)中AsyncTask被正式废弃:被弃用后,Android给出了两个替代的建议:java.util.concurrent包下的相关类,如Executor,ThreadPoolExecutor,FutureTask。kotlin并发工具,那就是协程了。

参考资料

https://blog.csdn.net/guolin_blog/article/details/11711405?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522159594993219195162550355%2522%252C%2522scm%2522%253A%252220140713.130102334.pc%255Fblog.%2522%257D&request_id=159594993219195162550355&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2blogfirst_rank_v2~rank_blog_v1-1-11711405.pc_v2_rank_blog_v1&utm_term=AsyncTask&spm=1018.2118.3001.4187

https://blog.csdn.net/javazejian/article/details/52464139
Android开发艺术探索

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值