欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Android之AsynTask

程序员文章站 2022-04-25 16:07:39
...

 

1.asynctask是Android为我们封装的一个异步线程调用的类;首先我们看一下它的简单使用

public class HandleActivity extends AppCompatActivity {
    public static final int MSG_CODE = 0;
    public static final int MSG_CODE2 = 1;
    public static final String TAG = "HandleActivity";
    private TextView tv;

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        tv = findViewById(R.id.tv1);
        asyncTask.execute();
        tv.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                asyncTask.cancel(false);
            }
        });
    }

    private AsyncTask asyncTask = new AsyncTask() {
        @Override
        protected void onPreExecute() {
            super.onPreExecute();
            Log.d(TAG, "onPreExecute调用了");
            tv.setText("准备加载");
        }

        @Override
        protected Object doInBackground(Object[] objects) {
            Log.d(TAG, "doInBackground调用了");
            try {
                int count = 0;
                int length = 1;
                while (count < 99) {

                    count += length;
                    // 可调用publishProgress()显示进度, 之后将执行onProgressUpdate()
                    publishProgress(count);
                    // 模拟耗时任务
                    Thread.sleep(50);
                }
            }catch (InterruptedException e) {
                e.printStackTrace();
            }
            return null;
        }

        @Override
        protected void onProgressUpdate(Object[] values) {
            super.onProgressUpdate(values);
            Log.d(TAG, "onProgressUpdate调用了");
            tv.setText("loading..." + values[0] + "%");
        }

        @Override
        protected void onPostExecute(Object o) {
            super.onPostExecute(o);
            Log.d(TAG, "onPostExecute调用了");
            tv.setText("加载完成");
        }

        @Override
        protected void onCancelled() {
            super.onCancelled();
            Log.d(TAG, "onCancelled调用了");
            tv.setText("取消加载");
        }

    };
}

我这里是直接new了一个asynctask对象,当然你也可以写一个类专门继承自Async task,使用的时候new出来即可;

我们可以看到,这里面重写了几个方法,这几个方法都是我们有可能用到的;其中doInBackground是在子线程中运行的,其他的方法都是在主线程中运行的,也就是都可以用来更新ui操作。调用方法asyncTask.execute()必须在主线程中调用。

2.源码分析

2.1,首先看构造方法:

public AsyncTask() {
        this((Looper) null);
    }

 我们接着往下追踪:

public AsyncTask(@Nullable Looper callbackLooper) {
        //1.初始化handler;我们一般传进来是空,就会调用getMainHandler(),获取到主线程的handler
        mHandler = callbackLooper == null || callbackLooper == Looper.getMainLooper()
            ? getMainHandler()
            : new Handler(callbackLooper);

        //2.workerrunnable其实就是一个callback,里面就执行了doInBackground方法
        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;
            }
        };
        //3.futuretask其实就是一个runnable
        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);
                }
            }
        };
    }

其实构造方法里面就是做了一些初始化工作:初始化handler、一个callback对象、一个runnable对象;

接下来,我们再来看调用:

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

注意:@MainThread 源码中已经标记好了,此方法必须在主线程中调用。

executeOnExecutor(sDefaultExecutor, params);这个sDefaultExecutor是什么呢?
public static final Executor SERIAL_EXECUTOR = new SerialExecutor();

private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;

可以看到就是一个serialExecutor:

private static class SerialExecutor implements Executor {
        final ArrayDeque<Runnable> mTasks = new ArrayDeque<Runnable>();//双向队列
        Runnable mActive;//当前正在执行的runnable

        public synchronized void execute(final Runnable r) {
            //把runnable任务加入队列
            mTasks.offer(new Runnable() {
                public void run() {
                    try {
                        r.run();
                    } finally {
                        scheduleNext();
                    }
                }
            });
            //没有正在运行的任务时,就处理下一个任务
            if (mActive == null) {
                scheduleNext();
            }
        }

        protected synchronized void scheduleNext() {
            if ((mActive = mTasks.poll()) != null) {
                THREAD_POOL_EXECUTOR.execute(mActive);//把任务交给线程池去执行
            }
        }
    }

可以看到serialExecutor中重写了excute方法;通过上面的注释,可以知道任务在向队列中添加时,是串行的;并且任务被线程池来执行了;那我们去看看这个线程池是什么:

private static final int CPU_COUNT = Runtime.getRuntime().availableProcessors();
    // We want at least 2 threads and at most 4 threads in the core pool,
    // preferring to have 1 less than the CPU count to avoid saturating
    // the CPU with background work
    private static final int CORE_POOL_SIZE = Math.max(2, Math.min(CPU_COUNT - 1, 4));
    private static final int MAXIMUM_POOL_SIZE = CPU_COUNT * 2 + 1;
    private static final int KEEP_ALIVE_SECONDS = 30;

private static final ThreadFactory sThreadFactory = new ThreadFactory() {
        private final AtomicInteger mCount = new AtomicInteger(1);

        public Thread newThread(Runnable r) {
            return new Thread(r, "AsyncTask #" + mCount.getAndIncrement());
        }
    };

    private static final BlockingQueue<Runnable> sPoolWorkQueue =
            new LinkedBlockingQueue<Runnable>(128);

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核心数,规定了线程池核心线程数,最大线程数,空闲线程存活时间等等。

也就是说明了,我们的异步任务最终是交由这个静态线程池来处理的。

3.我们来过一下这个流程:

asyncTask.execute();------>
executeOnExecutor(sDefaultExecutor, params);----------->
onPreExecute();//开始异步任务之前的准备工作,我们会重写这个方法
exec.execute(mFuture);mFuture就是构造方法中封装了mworker对象的实例------------------>
THREAD_POOL_EXECUTOR.execute(mActive);mActive就是上面的mFuture;mFuture里面装配的是mworker;也就是会执行mworker里面的call方法--------------------->
result = doInBackground(mParams);//开始执行异步任务,有返回结果
postResult(result);----------------->
Message message = getHandler().obtainMessage(MESSAGE_POST_RESULT,
        new AsyncTaskResult<Result>(this, result));
message.sendToTarget();//其实就是调用了handler发送消息--------------->
switch (msg.what) { 
case MESSAGE_POST_RESULT: 
 result.mTask.finish(result.mData[0]); //finish方法,
break; 
case MESSAGE_POST_PROGRESS: 
result.mTask.onProgressUpdate(result.mData); //更新进度就是在这里调用的
break; 
}------------>
finish方法:
if (isCancelled()) {
    onCancelled(result);//取消任务
} else {
    onPostExecute(result);//任务完成
}

我们可以看到重写的方法都一步步调用完成;之所以onProgressUpdate、onCancelled、onPostExecute可以直接更新ui,就是因为内部使用了handler机制;

此外,如果我们想使用onProgressUpdate来更新进度,必须要手都调用一个方法:

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

可以看到上面的注解:@WorkerThread  需要在工作线程调用即可,也就是通常会写到doInBackground方法中;它也是使用的handler发送消息,可以让我们在onProgressUpdate中直接更新ui;

4.总结

asynctask使用的是:一个SerialExecutor,一个ThreadPoolExecutor,一个内部的InternalHandler。执行任务也使用到了Callable

和FutureTask(FutureTask<V> implements RunnableFuture<V>)。

注意:asynctask内部把任务添加到任务队列是串行的,然后再把任务从队列中取出来执行;

相关标签: AsyncTask