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. 系统引导修复 ---- Windows 和 Ubuntu

    Windows: 1.准备windows相应镜像盘,u盘启动该系统 (以下均为windows10安装界面) 2.进入安装界面<语言,时间,键盘格式>,点击"下一步" 3 ...

  2. ABP领域层知识回顾之---实体

    标题:重温ABP领域层 1. 前言  最近一段时间一直在看<ABP的开发指南>(基于DDD的经典分层架构思想).因为之前一段时间刚看完<领域驱动设计:软件核心复杂性应对之道>, ...

  3. [HAOI 2011]Problem b

    Description 对于给出的n个询问,每次求有多少个数对(x,y),满足a≤x≤b,c≤y≤d,且gcd(x,y) = k,gcd(x,y)函数为x和y的最大公约数. Input 第一行一个整数 ...

  4. [HNOI2011]数矩形

    题目描述 最近某歌手在研究自己的全球巡回演出计划,他将所有心仪的城市都用平面上的一个点来表示,并打算从中挑选出 4 个城市作为这次巡回演出的地点. 为了显示自己与众不同,他要求存在一个矩形使得挑选出的 ...

  5. 计蒜客NOIP模拟赛5 D1T1 机智的 AmyZhi

    那年一个雨季,AmyZhi 在校门外弯身买参考书. 这时 SiriusRen 走过来,一言不合甩给她一道“自认为”很难的题: --------------- 给你一个数字 NN(NN 的范围是 11  ...

  6. 2015 多校联赛 ——HDU5360(贪心+优先队列)

    Sample Input 4 8 4 1 3 2 2 1 0 3 5 3 6 4 2 1 7 6 8 3 3 2 0 5 0 3 6 4 5 2 7 7 6 7 6 8 2 2 3 3 3 0 0 2 ...

  7. [USACO08JAN]跑步Running

    题目描述 The cows are trying to become better athletes, so Bessie is running on a track for exactly N (1 ...

  8. 【docker简易笔记】docker基础信息的分享

    docker 使用的频率越来越高,所以在后续的一些博客中会分享一些docker的安装和使用. 一.docker介绍   "Docker 最初是 dotCloud 公司创始人 Solomon ...

  9. postgresql 安装使用

    www.postgresql.org去下载你需要的版本,我下载的9.6.8 安装过程中会让你输入一次密码,其余的默认就ok 默认超级用户名postgres 打开 pgadmin4,我们将语言改为中文会 ...

  10. Modern Algebra 读书笔记

    Modern Algebra 读书笔记 Introduction 本文是Introduction to Modern Algebra(David Joyce, Clark University)的读书 ...