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. echarts.js--前端可视化数据图形

    ECharts,一个使用 JavaScript 实现的开源可视化库,可以流畅的运行在 PC 和移动设备上, 兼容当前绝大部分浏览器(IE8/9/10/11,Chrome,Firefox,Safari等 ...

  2. python2.7-巡风源码阅读

    推荐个脚本示例网站:https://www.programcreek.com/python/example/404/thread.start_new_thread,里面可以搜索函数在代码中的写法,只有 ...

  3. codevs 1006 等差数列

    提交地址:http://codevs.cn/problem/1006/ 1006 等差数列  时间限制: 1 s  空间限制: 128000 KB  题目等级 : 黄金 Gold   题目描述 Des ...

  4. .Net Core小技巧 - 使用Swagger上传文件

    前言 随着前后端分离开发模式的普及,后端人员更多是编写服务端API接口.调用接口实现文件上传是一个常见的功能,同时也需要一个选择文件上传的界面,可以编写前端界面上传,可以使用Postman.curl来 ...

  5. codefroces 55D Beautiful numbers

    [Description] 美丽数是指能被它的每一位非0的数字整除的正整数. [Input] 包含若干组数据,每组数据一行两个数n,m,表示求[n,m]之间的美丽数的个数. [output] 对于每组 ...

  6. 洛谷P3244 [HNOI2015]落忆枫音

    #include<cstdio> #include<cstdlib> #include<algorithm> #include<cstring> #in ...

  7. 利用maven打jar包(项目来自GitHub)

    1.首先去GitHub上clone一个项目.(前提,maven项目) 2.切换到项目根目录. 3.执行mvn package. 第一次操作失败: 分析错误原因(javac):maven无法找到jdk, ...

  8. Linux学习之CentOS(十六)-----内存置换空间(swap)之建置(转)

    内存置换空间(swap)之建置 安装时一定需要的两个 partition 啰! 一个是根目录,另外一个就是 swap(内存置换空间), swap 的功能就是在应付物理内存不足的情况下所造成的内存延伸记 ...

  9. Object 类

  10. 我的博客地址和github地址

    博客地址 http://www.cnblogs.com/sjzsjzsjz/ github地址  https://github.com/sjzsjzsjz