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

AsnycTask的内部的实现机制的更多相关文章

  1. Qt 的内部进程通信机制

    Qt 的内部进程通信机制 续欣 (xxin76@hotmail.com), 博士.大学讲师 2004 年 4 月 01 日 Qt 作为一种跨平台的基于 C++ 的 GUI 系统,能够提供给用户构造图形 ...

  2. Storm内部的消息传递机制

    作者:Jack47 转载请保留作者和原文出处 欢迎关注我的微信公众账号程序员杰克,两边的文章会同步,也可以添加我的RSS订阅源. 一个Storm拓扑,就是一个复杂的多阶段的流式计算.Storm中的组件 ...

  3. 05-Servlet与内部加载机制(part1)

     一.什么是Servlet Servlet 运行在服务端的Java小程序, 是sun公司提供一套规范(接口)     主要功能: 用来处理客户端请求 响应给浏览器的动态资源 servlet的实质就是j ...

  4. 通过WordCount解析Spark RDD内部源码机制

    一.Spark WordCount动手实践 我们通过Spark WordCount动手实践,编写单词计数代码:在wordcount.scala的基础上,从数据流动的视角深入分析Spark RDD的数据 ...

  5. 实现PHP内部的通知机制,如当一个类的属性发生变化时,另外一个类就可以收到通知

    设计模式:观察者模式 当一个对象的状态发生改变时,依赖他的对象会全部收到通知,并自动更新. 使用场景 一个事件发生后,要执行一连串更新操作.传统的编程方式,就是在事件的代码之后直接加入处理逻辑,当更新 ...

  6. Hadoop_18_MapRduce 内部的shuffle机制

    1.Mapreduce的shuffle机制: Mapreduce中,map阶段处理的数据如何传递给Reduce阶段,是mapreduce框架中最关键的一个流程,这个流程就叫shuffle 将mapta ...

  7. javasrcipt的作用域和闭包(二)续篇之:函数内部提升机制与Variable Object

    一个先有鸡还是先有蛋的问题,先看一段代码: a = 2; var a; console.log(a); 通常我们都说JavaScript代码是由上到下一行一行执行,但实际这段代码输出的结果是2.但这段 ...

  8. 并发—JVM内部机制和外部机制处理方法

    并发常见的编程场景,一句话概括就是,需要协调多个线程之间的协作,已保证程序按照自己原本的意愿执行.那么究竟应该如何协调多个线程? 这个问题比较宽泛,一般情况下,我们按照方式的纬度去简单区分,有以下两种 ...

  9. 第二章·Elasticsearch内部分片及分片处理机制介绍

    一.副本分片介绍 什么是副本分片? 副本分片的主要目的就是为了故障转移,如果持有主分片的节点挂掉了,一个副本分片就会晋升为主分片的角色. 在索引写入时,副本分片做着与主分片相同的工作.新文档首先被索引 ...

随机推荐

  1. [LeetCode] Split Array into Consecutive Subsequences 将数组分割成连续子序列

    You are given an integer array sorted in ascending order (may contain duplicates), you need to split ...

  2. [LeetCode] Brick Wall 砖头墙壁

    There is a brick wall in front of you. The wall is rectangular and has several rows of bricks. The b ...

  3. 网易云安全两篇论文入选计算机视觉顶级会议ICCV

    本文由  网易云发布. 10月22日至29日,全球计算机视觉顶尖专家们共聚威尼斯,参加ICCV2017国际计算机视觉大会,就领域内最新成果展开集中研讨,大会论文集也代表了计算机视觉领域最新的发展方向和 ...

  4. Python super使用

    一 基础使用 在类的继承中,如果重定义某个方法,该方法会覆盖父类的同名方法,但有时,我们希望能同时实现父类的功能,这时,我们就需要调用父类的方法了,可通过使用 super 来实现,比如: #!/usr ...

  5. [SHOI2008]小约翰的游戏John

    Description 小约翰经常和他的哥哥玩一个非常有趣的游戏:桌子上有n堆石子,小约翰和他的哥哥轮流取石子,每个人取 的时候,可以随意选择一堆石子,在这堆石子中取走任意多的石子,但不能一粒石子也不 ...

  6. ●POJ 3378 Crazy Thairs

    题链: http://poj.org/problem?id=3378 题解: 树状数组维护,高精度. 依次考虑以每个位置结尾可以造成的贡献. 假设当前位置为i,为了达到5个元素的要求,我们需要求出,在 ...

  7. 2015 多校联赛 ——HDU5301(技巧)

    Your current task is to make a ground plan for a residential building located in HZXJHS. So you must ...

  8. poj 1269 线段与线段相交

    Intersecting Lines Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 13605   Accepted: 60 ...

  9. bzoj 1925: [Sdoi2010]地精部落

    Description 传说很久以前,大地上居住着一种神秘的生物:地精. 地精喜欢住在连绵不绝的山脉中.具体地说,一座长度为 N 的山脉 H可分 为从左到右的 N 段,每段有一个独一无二的高度 Hi, ...

  10. bzoj4558[JLoi2016]方 容斥+count

    4558: [JLoi2016]方 Time Limit: 20 Sec  Memory Limit: 256 MBSubmit: 452  Solved: 205[Submit][Status][D ...