AsnyncTask——AsnyncTask内部机制
来源:互联网 发布:雨荷数据恢复视频教程 编辑:程序博客网 时间:2024/05/29 14:00
转自http://www.open-open.com/lib/view/open1434802647364.html
AsyncTask内部逻辑主要有二个部分:与主线的交互,AsyncTask内部调度
1、与主线的交互,它内部实例化了一个静态的自定义类InternalHandler,这个类是继承自 Handler的,在这个自定义类中绑定了一个叫做AsyncTaskResult的对象,每次子线程需要通知主线程,就调用sendToTarget发送消息给handler。然后在handler的handleMessage中AsyncTaskResult根据消息的类型不同(例如MESSAGEPOSTPROGRESS会更新进度条,MESSAGEPOSTCANCEL取消任务)而做不同的操作,值得一提的是,这些操作都是在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,这个时候新建一个异步任务这个任务会被放入缓存队列中等待执行。限制一个APP内AsyncTask并发的线程的数量看似是有必要的,但也带来了一个问题,假如有人就是需要同时运行10个而不是5个,或者不对线程的多少做限制,例如有些APP的瀑布流页面中的N多图片的加载。
另一方面,同时运行的任务多,线程也就多,如果这些任务是去访问网络的,会导致短时间内手机那可怜的带宽被占完了,这样总体的表现是谁都很难很快加载完全,因为他们是竞争关系。所以,把选择权交给开发者吧。
事实上,大概从Android从3.0开始,每次新建异步任务的时候AsnycTask内部默认规则是按提交的先后顺序每次只运行一个异步任务。当然了你也可以自己指定自己的线程池。
可以看出,AsyncTask使用过程中需要注意的地方不少
- 由于Handler需要和主线程交互,而Handler又是内置于AsnycTask中的,所以,AsyncTask的创建必须在主线程。
- AsyncTaskResult的doInBackground(mParams)方法执行异步任务运行在子线程中,其他方法运行在主线程中,可以操作UI组件。
- 不要手动的去调用AsyncTask的onPreExecute, doInBackground, publishProgress, onProgressUpdate, onPostExecute方法,这些都是由Android系统自动调用的
- 一个任务AsyncTask任务只能被执行一次。
- 运行中可以随时调用cancel(boolean)方法取消任务,如果成功调用isCancelled()会返回true,并且不会执行 onPostExecute() 方法了,取而代之的是调用 onCancelled() 方法。而且从源码看,如果这个任务已经执行了这个时候调用cancel是不会真正的把task结束,而是继续执行,只不过改变的是执行之后的回调方法是 onPostExecute还是onCancelled。
AsnyncTask和Activity OnConfiguration
上面提到了那么多的注意点,还有其他需要注意的吗?当然有!我们开发App过程中使用AsyncTask请求网络数据的时候,一般都是习惯在onPreExecute显示进度条,在数据请求完成之后的onPostExecute关闭进度条。这样做看似完美,但是如果您的App没有明确指定屏幕方向和configChanges时,当用户旋转屏幕的时候Activity就会重新启动,而这个时候您的异步加载数据的线程可能正在请求网络。当一个新的Activity被重新创建之后,可能由重新启动了一个新的任务去请求网络,这样之前的一个异步任务不经意间就泄露了,假设你还在onPostExecute写了一些其他逻辑,这个时候就会发生意想不到异常。
一般简单的数据类型的,对付configChanges我们很好处理,我们直接可以通过onSaveInstanceState()和onRestoreInstanceState()进行保存与恢复。 Android会在销毁你的Activity之前调用onSaveInstanceState()方法,于是,你可以在此方法中存储关于应用状态的数据。然后你可以在onCreate()或onRestoreInstanceState()方法中恢复。
但是,对于AsyncTask怎么办?问题产生的根源在于Activity销毁重新创建的过程中AsyncTask和之前的Activity失联,最终导致一些问题。那么解决问题的思路也可以朝着这个方向发展。Android官方文档 也有一些解决问题的线索。
这里介绍另外一种使用事件总线的解决方案,是国外一个安卓大牛写的。中间用到了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(); }
- AsnyncTask——AsnyncTask内部机制
- AsnyncTask与handler(二)——handler消息机制
- AsnyncTask与handler(二)——handler消息机制
- AsnyncTask与handler(二)——handler消息机制
- AsnyncTask与handler(一)——AsyncTask异步处理
- AsnyncTask与handler(一)——AsyncTask异步处理
- AsnyncTask与handler(一)——AsyncTask异步处理
- AsnyncTask的使用
- Android源码分析—深入认识AsyncTask内部机制
- 搭建高可用mongodb集群(三)—— 深入副本集内部机制
- 搭建高可用mongodb集群(三)—— 深入副本集内部机制
- 搭建高可用mongodb集群(三)—— 深入副本集内部机制
- 搭建高可用mongodb集群(三)—— 深入副本集内部机制
- 搭建高可用mongodb集群(三)—— 深入副本集内部机制
- 搭建高可用mongodb集群(三)—— 深入副本集内部机制
- 搭建高可用mongodb集群(三)—— 深入副本集内部机制
- 搭建高可用mongodb集群(三)—— 深入副本集内部机制
- 浏览器详谈及其内部工作机制 —— web开发必读
- Eclipse中根据数据库自动生成dao、mapper、model
- div边框线上添加文字
- poj3070 Fibonacci(矩阵快速幂)
- 数据结构实验图论一:基于邻接矩阵的广度优先搜索遍历
- JavaScript——表单验证
- AsnyncTask——AsnyncTask内部机制
- mybaties 一对多和多对一
- virtualbox 使用物理硬盘
- python学习笔记之基础操作
- DBUtils
- jar包对不同JDK版本的兼容性问题:Unsupported major.minor version 52.0
- hdu 1155 Bungee Jumping
- SSD MultiBoxLossLayer代码学习记录
- os x下加载bitlocker