Android中AsyncTask的使用和源码分析

前言: 在上一篇Android中的线程和线程池的分析中我们可以看到,异步任务的线程池的一些配置.

连接地址:Android中的线程和线程池

一.在Android中AsyncTask的使用

首先: AsyncTask类是一个轻量级的异步任务类,他可以在线程池中执行后台任务;将执行的进度和任务传递到主线程中来更新UI.

缺点: 是一个轻量级的异步任务类,并不适合与特别耗时的后台操作.

AsyncTask使用的注意事项:

  1. AsyncTask类必须在主线程中加载,也就是第一次访问AsyncTask必须发生在主线程中,在Android4.1版本以上,主线程的main方法中调用了AsyncTask的init()方法,也就是替我们在主线程中加载了异步任务类.这一点不需要注意.
  2. 我们在主线程中创建异步任务的对象
  3. 异步任务的execute()方法必须在UI线程中调用
  4. 一个异步任务对象只能执行一次execute()方法,执行多次会报运行时错误.
  5. 不要直接调用异步任务中的方法,例如 onPreExecute()等方法
  6. 我们也可以使用 executeOnExecute()方法来并行的执行任务,默认异步任务类是串行执行任务的.

AsyncTask的几个参数:

由于AsyncTask是一个抽象类,所以如果我们想使用它,就必须要创建一个子类去继承它。在继承时我们可以为AsyncTask类指定三个泛型参数,这三个参数的用途如下:

1. Params

在执行AsyncTask时需要传入的参数,可用于在后台任务中使用。

2. Progress

后台任务执行时,如果需要在界面上显示当前的进度,则使用这里指定的泛型作为进度单位。

3. Result

当任务执行完毕后,如果需要对结果进行返回,则使用这里指定的泛型作为返回值类型。

AsyncTask的几个方法:

1. onPreExecute()

这个方法会在后台任务开始执行之间调用,用于进行一些界面上的初始化操作,比如显示一个进度条对话框等。

2. doInBackground(Params...)

这 个方法中的所有代码都会在子线程中运行,我们应该在这里去处理所有的耗时任务。

任务一旦完成就可以通过return语句来将任务的执行结果进行返回,如果 AsyncTask的第三个泛型参数指定的是Void

,就可以不返回任务执行结果。

注意,在这个方法中是不可以进行UI操作的,如果需要更新UI元素,比 如说反馈当前任务的执行进度,可以调用

publishProgress(Progress...)方法来完成。

3. onProgressUpdate(Progress...)

当在后台任务中调用了publishProgress(Progress...)方法后,这个方法就很快会被调用,方法中携带的参数就是在

后台任务中传递过来的。在这个方法中可以对UI进行操作,利用参数中的数值就可以对界面元素进行相应的更新。

4. onPostExecute(Result)

当后台任务执行完毕并通过return语句进行返回时,这个方法就很快会被调用。返回的数据会作为参数传递到此方法

中,可以利用返回的数据来进行一些UI操作,比如说提醒任务执行的结果,以及关闭掉进度条对话框等。

我们根据注意事项来写一个异步任务使用:

public class MainActivity extends AppCompatActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        //  创建异步任务对象
        DownFileTask downFileTask = null;
        downFileTask = new DownFileTask();
        //启动异步任务
        downFileTask.execute();
    }
    
    //  三个参数:
    //  第一个参数是指: doInBackground执行时候的输入参数
    // 第二个参数; 异步任务在执行的时候的进度的类型
    //第三个参数: 是结束后返回给 onPostExectue()的结果
    private class DownFileTask extends AsyncTask<URL, Integer, Long> {
        //运行在主线程中,主要是异步任务之前的一些准备工作
        @Override
        protected void onPreExecute() {
            super.onPreExecute();
        }

      // 主要是用来执行异步任务的,运行在子线程中
        //三个省略号标识的是可变参数
        //在线程池中调用
        @Override
        protected Long doInBackground(URL... urls) {
            int count = urls.length;
            long totalSize = 0;
            for (int i = 0; i < count; i++) {
                //totalSize += Downloader.downloadFile(urls[i]);
                // 在doInBackgroun中会通过 publishProcess()来调用onProgressUpdate()方法
                publishProgress((int) ((i / (float) count) * 100));
                // Escape early if cancel() is called
                if (isCancelled())
                    break;
            }
            return totalSize;
        }

        //运行在主线程中,用于展示异步任务的进度;比如下载的进度

        @Override
        protected void onProgressUpdate(Integer... values) {
            //在主线程中代用,来更新进度
            super.onProgressUpdate(values);
        }

        //在异步任务完成之后会被调用,主要是返回的结果
        // 在主线程中调用
        @Override
        protected void onPostExecute(Long aLong) {
            super.onPostExecute(aLong);
        }
    }


}

二 .根据执行过程进行源码分析:

首先是异步任务的execute()来启动的,我们开看看源码:

  便于看的明白,明白几个参数的类型:

   第一个用于任务排队的一个线程池

 public static final Executor SERIAL_EXECUTOR = new SerialExecutor();
  第二个是sDefaultExecutor指的就是这个线程池(串行线程池)

private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;

具体的开启的方法:

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

在看几个参数的类型:

private final FutureTask<Result> mFuture;
首先FutureTask是一个并发类,最后追查到,这个类继承了Runable和Future两个接口,用来将传递进来的参数params封装为FutureTask对象,之后见mFuture交给SerialExector的exectue()处理.

@MainThread
    public final AsyncTask<Params, Progress, Result> executeOnExecutor(Executor exec,
            Params... params) {
        if (mStatus != Status.PENDING) {
            switch (mStatus) {
                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)");
            }
        }

        mStatus = Status.RUNNING;

        onPreExecute();

        mWorker.mParams = params;
        exec.execute(mFuture);

        return this;
    }
观看上面的代码,我们看到了一个非常熟悉的方法,对就是onPreExecute(),他首先会被调用,所以我们可以在onPreExecute()完成异步任务的一些准备工作.

  再看一下子串行线程池源码:

public static final Executor SERIAL_EXECUTOR = new SerialExecutor();

    private static final int MESSAGE_POST_RESULT = 0x1;
    private static final int MESSAGE_POST_PROGRESS = 0x2;

    private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;
    private static InternalHandler sHandler;

    private final WorkerRunnable<Params, Result> mWorker;
    private final FutureTask<Result> mFuture;

    private volatile Status mStatus = Status.PENDING;
    
    private final AtomicBoolean mCancelled = new AtomicBoolean();
    private final AtomicBoolean mTaskInvoked = new AtomicBoolean();

    private static class SerialExecutor implements Executor {
          // 任务队列 mTask中会
       final ArrayDeque<Runnable> mTasks = new ArrayDeque<Runnable>();
        Runnable mActive;

        public synchronized void execute(final Runnable r) {
            mTasks.offer(new Runnable() {
                public void run() {
                    try {
                        r.run();
                    } finally {
                        scheduleNext();
                    }
                }
            });
          // 判断有没有正在活动的异步任务,没有会调用scheduleNext()
      if (mActive == null) {
                scheduleNext();
            }
        }

        protected synchronized void scheduleNext() {
            if ((mActive = mTasks.poll()) != null) {
                THREAD_POOL_EXECUTOR.execute(mActive);
            }
        }
    }
将FutureTask插入到任务队列中,mTask,接着判断有没有活动的异步任务,没有调用schueduleNext(),也就是说异步任务执行完毕后,才会继续执行其他任务,也就是为什么说异步任务是串行执行的.
    上面的线程池只是对异步任务进行排队,真正处理任务的线程池是 THREAD_POOL_EXECUTOR中执行的,我们来看看这个线程池的源码:

     

 /**
     * An {@link Executor} that can be used to execute tasks in parallel.
     */
    public static final Executor THREAD_POOL_EXECUTOR;

    static {
        ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(
                CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE_SECONDS, TimeUnit.SECONDS,
                sPoolWorkQueue, sThreadFactory);
        threadPoolExecutor.allowCoreThreadTimeOut(true);
        THREAD_POOL_EXECUTOR = threadPoolExecutor;
    }

我们可以看出来,在上一篇中都有很详细的说明,核心线程数是cpu数量+1;非核心线程是cpu核心线程数的2倍+1;

核心线程没有超时策略,非核心线程有超时策略.

 /**
     * Creates a new asynchronous task. This constructor must be invoked on the UI thread.
     */
    public AsyncTask() {
        mWorker = new WorkerRunnable<Params, Result>() {
            public Result call() throws Exception {
                mTaskInvoked.set(true);
                Result result = null;
                try {
                    Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
                    //noinspection unchecked
                    result = doInBackground(mParams);
                    Binder.flushPendingCommands();
                } catch (Throwable tr) {
                    mCancelled.set(true);
                    throw tr;
                } finally {
                    postResult(result);
                }
                return result;
            }
        };

        mFuture = new FutureTask<Result>(mWorker) {
            @Override
            protected void done() {
                try {
                    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);
                }
            }
        };
    }

mWorker实际上是一个Callable对象,会调用他的call()方法;在望下面看.

private static abstract class WorkerRunnable<Params, Result> implements Callable<Result> {
    Params[] mParams;
}

private final WorkerRunnable<Params, Result> mWorker;
我们突然看到了一个熟悉的方法,就是后台任务doInBackground()方法,并且获取了结果result,并将这个结果作为postResult()的参数传递,并且设置一个参数的为true就是mTaskInvoked,表示的就是当前的线程已经调用过了!
mTaskInvoked.set(true);

我们接着postResult(参数结果后台任务的)

private Result postResult(Result result) {
    @SuppressWarnings("unchecked")
    Message message = getHandler().obtainMessage(MESSAGE_POST_RESULT,
            new AsyncTaskResult<Result>(this, result));
    message.sendToTarget();
    return result;
}
看到了什么?对的就是一个getHandler(),并且使用它发送了一个消息,再看看这个消息就是message_post_result这个方法;

继续看看,这个Handler,异步任务是封装了两线程池和一个Handler,我们需要看看这个Handler;

private static Handler getHandler() {
    synchronized (AsyncTask.class) {
        if (sHandler == null) {
            sHandler = new InternalHandler();
        }
        return sHandler;
    }
}
看到一个InternalHnadler对象.

private static class InternalHandler extends Handler {
    public InternalHandler() {
        super(Looper.getMainLooper());
    }
这个就是我们所谓的Handler,发送了一个消息

private static class InternalHandler extends Handler {
    public InternalHandler() {
        super(Looper.getMainLooper());
    }

    @SuppressWarnings({"unchecked", "RawUseOfParameterizedType"})
    @Override
    public void handleMessage(Message msg) {
        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:
                result.mTask.onProgressUpdate(result.mData);
                break;
        }
    }
}
这个类是在异步任务中创建好的一个Handler,也就是说 handlerMessage()是在主线程中执行的,我们在细看这个Handler这个类,我们看到是一个static 修饰是一个静态的变量,sHandler是 static final修饰会在加载类的时候初始化.结果会发送到主线程中,再次做了一个判断; 如果是异步执行的进度等对ui的更新,会调用
onProgressUpdate()方法
如果是message_post_result的话,会执行finish()方法

private void finish(Result result) {
    if (isCancelled()) {
        onCancelled(result);
    } else {
        onPostExecute(result);
    }
    mStatus = Status.FINISHED;
}
如果是取消(isCancelled)会执行onCancelled(),附则执行onPostExecute(),状态设置为完成状态.

注意点: mWorker的call()会调用异步任务的后台任务的方法,之后获取任务的返回值,作为参数传递给postResult(),在这个方法里面使用sHandler发送了一条消息,也就是发送到InternalHnadler的handlerMessage()中处理这个消息,完成了线程池切换到主线程的操作.








  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
AsyncTaskAndroid 开发用于在后台执行耗时操作的一个类,可以进行异步操作以避免在主线程上执行耗时操作导致界面卡顿的情况。在 Kotlin 使用 AsyncTask 的用法与 Java 基本一致。 使用 AsyncTask 需要创建一个继承于 AsyncTask 的子类来进行异步操作。在 Kotlin ,可以使用 object 关键字创建一个匿名内部类来实现 AsyncTask 的子类。下面是一个基本的 AsyncTask 使用示例: ```kotlin // 创建一个继承自 AsyncTask 的子类 val task = object : AsyncTask<Void, Void, String>() { // 在后台线程执行耗时操作 override fun doInBackground(vararg params: Void): String { // 执行耗时操作,例如网络请求或数据库查询 return "AsyncTask 执行完毕" } // 在耗时操作结束后更新 UI override fun onPostExecute(result: String) { // 在这里更新 UI,例如更新 TextView 的内容 } } // 执行 AsyncTask task.execute() ``` 在上面的示例,首先创建了一个继承于 AsyncTask 的子类,并实现了三个方法:doInBackground、onPostExecute 和 onPostExecute。doInBackground 方法用于在后台线程执行耗时操作,例如网络请求或数据库查询,并返回结果给 onPostExecute 方法。onPostExecute 方法在耗时操作结束后会被调用,你可以在这个方法更新 UI。 最后,通过调用 AsyncTask 的 execute 方法来执行异步操作。 需要注意的是,Kotlin 推荐使用更现代化的异步操作方式,例如使用 Kotlin 协程来替代 AsyncTask。Kotlin 协程提供了更简洁、可读性更高的代码,且在处理异步操作上更加灵活和强大。因此,如果在新的项目,可以考虑使用 Kotlin 协程来替代 AsyncTask

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值