zoukankan      html  css  js  c++  java
  • AsnycTask的内部的实现机制

    AsnycTask的内部的实现机制

    写在前面

    我们为什么要用AsnycTask。 在Android程序开始运行的时候会单独启动一个进程,默认情况下所有 这个程序操作都在这个进程中进行。一个Android程序默认情况下只有 一个进程,但是一个进程却是可以有许线程的。

    我们通常会把一些比较耗时的操作,例如网络请求、数据库操作、复杂计算等逻辑都封装到单独的线程,这样就可以避免阻塞主线程。

    内部机制

    主要分为两大部分:

    1、与主线的交互,它内部实例化了一个静态的自定义类InternalHand- ler,这个类是继承自Handler的,在这个自定义类中绑定了一个叫做 AsyncTaskResult的对象,每次子线程需要通知主线程,就调用send- ToTarget发送消息给handler。然后在handler的handleMessage 中AsyncTaskResult根据消息的类型不同(例如MESSAGE POST- PROGRESS会更新进度条 , MESSAGEPOST CANCEL取消任务)而 做不同的操作,值得一提的是,这些操作都是在UI线程进行的,意味着, 从子线程一旦需要和UI线程交互,内部自动调用了handler对象把消息 放在了主线程了。

    mFuture = new FutureTask<Result>(mWorker) {
    @Override
    protected void More ...done() {
    Message message;
    Result result = null;
    try {
    result = get();
    } catch (InterruptedException e) {
    android.util.Log.w(LOG_TAG, e);
    } catch (ExecutionException e) {
    throw new RuntimeException("An error occured while executing
    doInBackground()",
    e.getCause());
    } catch (CancellationException e) {
    message = sHandler.obtainMessage(MESSAGE_POST_CANCEL,
    new AsyncTaskResult<Result>(AsyncTask.this, (Result[]) null));
    message.sendToTarget();
    return;
    } catch (Throwable t) {
    throw new RuntimeException("An error occured while executing "
    `+ "doInBackground()", t);`
    }
    message = sHandler.obtainMessage(MESSAGE_POST_RESULT,
    new AsyncTaskResult<Result>(AsyncTask.this, result));
    message.sendToTarget();
    }
    };
    private static class InternalHandler extends Handler {
    @SuppressWarnings({"unchecked", "RawUseOfParameterizedType"})
    @Override
    public void More ...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;
    case MESSAGE_POST_CANCEL:
    result.mTask.onCancelled();
    break;
    }
    }
    }
    

    2、AsyncTask内部调度,虽然可以新建多个AsyncTask的子类的实例, 但是AsyncTask的内部Handler和ThreadPoolExecutor都是static 的,这么定义的变量属于类的,是进程范围内共享的,所以AsyncTask 控制着进程范围内所有的子类实例,而且该类的所有实例都共用一个线 程池和Handler。

    public abstract class AsyncTask<Params, Progress, Result> {
    private static final String LOG_TAG = "AsyncTask";
    private static final int CORE_POOL_SIZE = 5;
    private static final int MAXIMUM_POOL_SIZE = 128;
    private static final int KEEP_ALIVE = 1;
    private static final BlockingQueue<Runnable> sWorkQueue =
    new LinkedBlockingQueue<Runnable>(10);
    private static final ThreadFactory sThreadFactory = new ThreadFactory() {
    private final AtomicInteger mCount = new AtomicInteger(1);
    public Thread More ...newThread(Runnable r) {
    return new Thread(r, "AsyncTask #" + mCount.getAndIncrement());
    }
    };
    private static final ThreadPoolExecutor sExecutor = new ThreadPoolExecutor(CORE_POOL_
    SIZE,
    MAXIMUM_POOL_SIZE, KEEP_ALIVE, TimeUnit.SECONDS, sWorkQueue, sThreadFactory);
    private static final int MESSAGE_POST_RESULT = 0x1;
    private static final int MESSAGE_POST_PROGRESS = 0x2;
    private static final int MESSAGE_POST_CANCEL = 0x3;
    

    从代码还可以看出,默认核心线程池的大小是5,缓存任务队列是10。 意味着,如果线程池的线程数量小于5,这个时候新添加一个异步任 务则会新建一个线程;如果线程池的数量大于等于5,这个时候新建一 个异步任务这个任务会被放入缓存队列中等待执行。

    注意的地方

    • 由于Handler需要和主线程交互,而Handler又是内置于AsnycTask中的,所以, AsyncTask的创建必须在主线程。
    • AsyncTaskResult的doInBackground(mParams)方法执行异步任务运行在子线 程中,其他方法运行在主线程中,可以操作UI组件。
    • 不要手动的去调用AsyncTask的onPreExecute, doInBackground, publishPro- gress, onProgressUpdate, onPostExecute方法,这些都是由Android系统自 动调用的
    • 一个任务AsyncTask任务只能被执行一次。
    • 运行中可以随时调用cancel(boolean)方法取消任务,如果成功调用isCancelled() 会 返 回 true,并 且 不 会 执 行 onPostExecute() 方 法 了,取 而 代 之 的 是 调 用 onCancelled() 方法。而且从源码看,如果这个任务已经执行了这个时候调用 cancel是不会真正的把task结束,而是继续执行,只不过改变的是执行之后的回 调方法是onPostExecute还是onCancelled。

    --------------

    Activity OnConfiguration

    1、如果你的App没有明确指定屏幕 方向和configChanges时,当用户旋转屏幕的时候Activity就会重新 启动,而这个时候您的异步加载数据的线程可能正在请求网络。当一 个新的Activity被重新创建之后,可能由重新启动了一个新的任务去 请求网络,这样之前的一个异步任务不经意间就泄露了,假设你还在 onPostExecute写了一些其他逻辑,这个时候就会发生意想不到异常。

    2、一般简单的数据类型的,对付configChanges我们很好处理,我们直接 可 以 通 过onSaveInstanceState() 和 onRestoreInstanceState() 进 行 保 存 与 恢 复。

    3、对于AsyncTask,我们可以用到Square开源的EventBus类库http://square.github.io/ otto/。首先自定义一个AsyncTask的子类,在onPostExecute方法中, 把返回结果抛给事件总线。

    @Override
    protected String doInBackground(Void... params) {
    Random random = new Random();
    final long sleep = random.nextInt(10);
    try {
    Thread.sleep(10 * 6000);
    } catch (InterruptedException e) {
    e.printStackTrace();
    }
    return "Slept for " + sleep + " seconds";
    }
    @Override
    protected void onPostExecute(String result) {
    MyBus.getInstance().post(new AsyncTaskResultEvent(result));
    }
    

    在Activity的onCreate中注册这个事件总线,这样异步线程的消息就会 被otta分发到当前注册的activity,这个时候返回结果就在当前activity 的onAsyncTaskResult中了。

    @Override
    protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.otto_layout);
    findViewById(R.id.button).setOnClickListener(new View.OnClickListener() {
    @Override public void onClick(View v) {
    new MyAsyncTask().execute();
    }
    });
    MyBus.getInstance().register(this);
    }
    @Override
    protected void onDestroy() {
    MyBus.getInstance().unregister(this);
    super.onDestroy();
    }
    @Subscribe
    public void onAsyncTaskResult(AsyncTaskResultEvent event) {
    Toast.makeText(this, event.getResult(), Toast.LENGTH_LONG).show();
    }
  • 相关阅读:
    Vue常见问题总结
    vue学习记录
    内卷
    at least once 和 at most once 问题
    IO学习笔记(全)
    IO学习笔记7
    IO学习笔记6
    IO学习笔记5
    IO学习笔记4
    IO学习笔记3
  • 原文地址:https://www.cnblogs.com/sdksdk0/p/5585080.html
Copyright © 2011-2022 走看看