当前位置: 首页 > 工具软件 > AsynTask > 使用案例 >

Android之AsynTask

郭修平
2023-12-01

 

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内部把任务添加到任务队列是串行的,然后再把任务从队列中取出来执行;

 类似资料: