前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Asynctask那些事

Asynctask那些事

作者头像
用户1337002
发布2018-03-09 10:37:38
7130
发布2018-03-09 10:37:38
举报
文章被收录于专栏:猿份到

耗时操作?更新UI?这些都是我们经常听到的词汇了,最常用的方法就是Thread+Handler的方法,今天就来聊聊另一个熟悉的Asynctask,或许你没有听过,别着急,通过本次(API23)的源码进行讲解,你就明白了。

首先,通过一个简单的例子来看下Asynctask的写法:

代码语言:javascript
复制
public class MainActivity extends Activity {
    private static final String TAG = "MainActivity";
    private ProgressDialog mDialog;
    private TextView mTextView;
    @Override
    protected void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mTextView = (TextView) findViewById(R.id.id_tv);
        mDialog = new ProgressDialog(this);
        mDialog.setMax(100);
        mDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
        mDialog.setCancelable(false);
        new MyAsyncTask().execute();
    }
    private class MyAsyncTask extends AsyncTask<Void, Integer, Void>
    {
        @Override
        protected void onPreExecute()
        {
            mDialog.show();
            Log.e(TAG, Thread.currentThread().getName() + " onPreExecute ");
        }
        @Override
        protected Void doInBackground(Void... params)
        {
            // 模拟数据的加载,耗时的任务
            for (int i = 0; i < 100; i++)
            {
                try
                {
                    Thread.sleep(80);
                } catch (InterruptedException e)
                {
                    e.printStackTrace();
                }
                publishProgress(i);
            }
            Log.e(TAG, Thread.currentThread().getName() + " doInBackground ");
            return null;
        }
        @Override
        protected void onProgressUpdate(Integer... values)
        {
            mDialog.setProgress(values[0]);
            Log.e(TAG, Thread.currentThread().getName() + " onProgressUpdate ");
        }
        @Override
        protected void onPostExecute(Void result)
        {
            // 进行数据加载完成后的UI操作
            mDialog.dismiss();
            mTextView.setText("LOAD DATA SUCCESS ");
            Log.e(TAG, Thread.currentThread().getName() + " onPostExecute ");
        }
    }
}

进入某个Activity,Activity中需要的数据来自于网络或者其它耗时操作,可以在AsyncTask中onPreExecute完成一些准备操作。

比如上例中显示进度对话框;然后在doInBackground完成耗时操作,

在进行耗时操作时还能不时的通过publishProgress给onProgressUpdate中传递参数,然后在onProgressUpdate中可以进行UI操作。

比如上例更新进度条的进度;当耗时任务执行完成后,最后在onPostExecute进行设置控件数据更新UI等操作,例如隐藏进度对话框。

真正实现就是一个new MyAsyncTask().execute();通过execute方法实现。下面就从源码的角度聊聊AsyncTask。

既然我们调用的是execute方法,那就先从execute方法

代码语言:javascript
复制
@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;
}

在执行execute方法中,将status状态更改为running的状态。

mStatus = Status.RUNNING;设置当前AsyncTask的状态为RUNNING,上面的switch也可以看出,每个异步任务在完成前只能执行一次。

onPreExecute();执行了onPreExecute(),当前依然在UI线程,所以我们可以在其中做一些准备工作。

mWorker.mParams = params;将我们传入的参数赋值给了mWorker.mParams

exec.execute(mFuture);

相信大家会对mWorker,mFuture有疑问,别急,容我慢慢道来

代码语言:javascript
复制
private final WorkerRunnable<Params, Result> mWorker;
代码语言:javascript
复制
private static abstract class WorkerRunnable<Params, Result> implements Callable<Result> {
    Params[] mParams;
}

mworker可以看到是Callable的子类,且包含一个mParams用于保存我们传入的参数,

下面看初始化mWorker的代码:

代码语言:javascript
复制
public AsyncTask() {
    mWorker = new WorkerRunnable<Params, Result>() {
        public Result call() throws Exception {
            mTaskInvoked.set(true);

            Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
            //noinspection unchecked
            Result result = doInBackground(mParams);
            Binder.flushPendingCommands();
            return postResult(result);
        }
    };
}

构造方法中我们看到mworker的初始化操作,通过上面的代码我们知道一个抽象类,因此new了一个实现类,实现了call方法,call方法中设置mTaskInvoked=true,且最终调用doInBackground(mParams)方法,并返回Result值作为参数给postResult方法.可以看到我们的doInBackground出现了。

最后我们来看看postResult方法

代码语言:javascript
复制
private Result postResult(Result result) {
    @SuppressWarnings("unchecked")
    Message message = getHandler().obtainMessage(MESSAGE_POST_RESULT,
            new AsyncTaskResult<Result>(this, result));
    message.sendToTarget();
    return result;
}

到此我们看到了一个熟悉的东东,Handler,Handler,Handler,?,重要的事情说三遍。

postResult中出现了我们熟悉的异步消息机制,传递了 message.what为MESSAGE_POST_RESULT的消息;

message.object= new AsyncTaskResult(this,result);

AsyncTaskResult实际上就是一个携带参数的对象而已

代码语言:javascript
复制
private static class AsyncTaskResult<Data> {
    final AsyncTask mTask;
    final Data[] mData;

    AsyncTaskResult(AsyncTask task, Data... data) {
        mTask = task;
        mData = data;
    }
}

现在让我们找找handler相关的代码,可以看到,在接收到MESSAGE_POST_RESULT消息时,执行了result.mTask.finish(result.mData[0]);其实就是我们的AsyncTask.this.finish(result)

代码语言:javascript
复制
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;
        }
    }
}

下面了解下finish方法

代码语言:javascript
复制
private void finish(Result result) {
    if (isCancelled()) {
        onCancelled(result);
    } else {
        onPostExecute(result);
    }
    mStatus = Status.FINISHED;
}

可以看到,如果我们调用了cancel(),则执行onCancelled回调;

正常执行的情况下调用我们的onPostExecute(result);

主要这里的调用是在handler的handleMessage中,所以是在UI线程中。最后将status的状态改为finished。

mworker聊的差不多了,现在我们来聊聊下一个东西mFuture,同样的,mFuture也是在构造方法中完成初始化的

代码语言:javascript
复制
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);
        }
    }
};

如果mTaskInvoked不为true,则执行postResult; 但是在mWorer初始化时就已经将mTaskInvoked为true,所以一般这个postResult执行不到

代码语言:javascript
复制
private void postResultIfNotInvoked(Result result) {
    final boolean wasTaskInvoked = mTaskInvoked.get();
    if (!wasTaskInvoked) {
        postResult(result);
    }
}

private Result postResult(Result result) {
    @SuppressWarnings("unchecked")
    Message message = getHandler().obtainMessage(MESSAGE_POST_RESULT,
            new AsyncTaskResult<Result>(this, result));
    message.sendToTarget();
    return result;
}

其实执行到最后都是Handler身影的存在。到目前为止都只是介绍了这mWorker和mFuture的实例化而已。

下面说说真正的调用

exec.execute(mFuture);

代码语言:javascript
复制
@MainThread
public final AsyncTask<Params, Progress, Result> execute(Params... params) {
    return executeOnExecutor(sDefaultExecutor, params);
}

sDefaultExecutor的本质是

代码语言:javascript
复制
private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;
代码语言:javascript
复制
private static class SerialExecutor implements Executor {
    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();
                }
            }
        });
        if (mActive == null) {
            scheduleNext();
        }
    }

    protected synchronized void scheduleNext() {
        if ((mActive = mTasks.poll()) != null) {
            THREAD_POOL_EXECUTOR.execute(mActive);
        }
    }
}

可以看到sDefaultExecutor其实为SerialExecutor的一个实例,其内部维持一个任务队列;

直接看其execute(Runnable runnable)方法,将runnable放入mTasks队尾; 判断当前mActive是否为空,为空则调用scheduleNext方法 scheduleNext,则直接取出任务队列中的队首任务,如果不为null则传入THREAD_POOL_EXECUTOR进行执行。

看看THREAD_POOL_EXECUTOR是何方神圣?

代码语言:javascript
复制
/**
 * An {@link Executor} that can be used to execute tasks in parallel.
 */
public static final Executor THREAD_POOL_EXECUTOR
        = new ThreadPoolExecutor(CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE,
                TimeUnit.SECONDS, sPoolWorkQueue, sThreadFactory);

其实就是一个可自定义的线程池。源码中配置的参数如下:

代码语言:javascript
复制
private static final int CPU_COUNT = Runtime.getRuntime().availableProcessors();
private static final int CORE_POOL_SIZE = CPU_COUNT + 1;
private static final int MAXIMUM_POOL_SIZE = CPU_COUNT * 2 + 1;
private static final int KEEP_ALIVE = 1;

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);

看到这里,大家就会知道背后原来有一个线程池,且最大支持CPU_COUNT * 2 + 1的线程并发,加上长度为128的阻塞队列,可能会觉得就是在快速调用MAXIMUM_POOL_SIZE+128个以内的AsyncTask子类的execute方法不会出现问题,而大于MAXIMUM_POOL_SIZE+128则会抛出异常。

到此为止,源码分析讲解已经结束,希望大家能对Asynctask有更好的了解。如果你有更好的想法欢迎留言

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2017-10-20,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 猿份到 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档