1、Asynctask简介

1.1 使用方法简介

Asynctask作为Android的基础之一,怎么使用就不多讲解了,网上到处都是教程,建议查看Android官方API文档:https://developer.android.google.cn/reference/android/os/AsyncTask.html

这里只实现一个小Demo程序,供大家赏玩:

界面:

Android AsyncTask的优缺点详解_第1张图片

这个程序其实特别简单,就是两个按钮,点击分别用来测试AysncTask和Handler两种模式的实现,点击后会有相应的Log提示。

功能简介:

Asynctask的实现:

private class IAsyncTask extends AsyncTask { protected String doInBackground(String... args1) { Log.i(TAG, "doInBackground in:" + args1[0]); int times = 10; for (int i = 0; i < times; i++) { publishProgress(i);//提交之后,会执行onProcessUpdate方法 } Log.i(TAG, "doInBackground out"); return "over"; } /** * 在调用cancel方法后会执行到这里 */ protected void onCancelled() { Log.i(TAG, "onCancelled"); } /** * 在doInbackground之后执行 */ protected void onPostExecute(String args3) { Log.i(TAG, "onPostExecute:" + args3); } /** * 在doInBackground之前执行 */ @Override protected void onPreExecute() { Log.i(TAG, "onPreExecute"); } /** * 特别赞一下这个多次参数的方法,特别方便 * @param args2 */ @Override protected void onProgressUpdate(Integer... args2) { Log.i(TAG, "onProgressUpdate:" + args2[0]); } }

点击第一个按钮后会执行这里,点击按钮的写法如下:

mBtnSyncTask.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { new IAsyncTask().execute("yanlog test"); } });

执行结果的Log如下:

02-19 21:55:12.179 10824-11010/com.plbear.asynctasktest I/AsyncTaskTest: doInBackground in:yanlog test//doInbackground是在10824进程,11010线程中执行02-19 21:55:12.179 10824-11010/com.plbear.asynctasktest I/AsyncTaskTest: doInBackground out 02-19 21:55:12.184 10824-10824/com.plbear.asynctasktest I/AsyncTaskTest: onProgressUpdate:0//剩下的都是在10824线程中执行,Android特别好的是,主线程的线程号跟进程号是一致的02-19 21:55:12.184 10824-10824/com.plbear.asynctasktest I/AsyncTaskTest: onProgressUpdate:102-19 21:55:12.184 10824-10824/com.plbear.asynctasktest I/AsyncTaskTest: onProgressUpdate:202-19 21:55:12.184 10824-10824/com.plbear.asynctasktest I/AsyncTaskTest: onProgressUpdate:302-19 21:55:12.184 10824-10824/com.plbear.asynctasktest I/AsyncTaskTest: onProgressUpdate:402-19 21:55:12.184 10824-10824/com.plbear.asynctasktest I/AsyncTaskTest: onProgressUpdate:502-19 21:55:12.184 10824-10824/com.plbear.asynctasktest I/AsyncTaskTest: onProgressUpdate:602-19 21:55:12.184 10824-10824/com.plbear.asynctasktest I/AsyncTaskTest: onProgressUpdate:702-19 21:55:12.184 10824-10824/com.plbear.asynctasktest I/AsyncTaskTest: onProgressUpdate:802-19 21:55:12.184 10824-10824/com.plbear.asynctasktest I/AsyncTaskTest: onProgressUpdate:902-19 21:55:12.184 10824-10824/com.plbear.asynctasktest I/AsyncTaskTest: onPostExecute:over

Handler+Message实现:

 主要代码如下:

 private class IHandler extends Handler{ @Override public void handleMessage(Message msg){ switch(msg.what){ case 1:  Log.e(TAG,"handler:"+msg.obj);  break; default:  break; } } }

其中,调用地方如下:

mBtnHandlerTest.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { final Handler handler = new IHandler(); new Thread(new Runnable() {  @Override  public void run() {  for (int i = 0; i < 10; i++) {  Message msg = new Message();  msg.what = 1;  msg.obj = new Integer(i);  Log.e(TAG, "post message:" + i);  handler.sendMessage(msg);  }  } }).start(); } });

可以看到Log打印结果如下:

02-19 22:25:17.689 9234-9319/com.plbear.asynctasktest E/AsyncTaskTest: post message:0 //可以看到提交是在9319号子进程中提交02-19 22:25:17.689 9234-9319/com.plbear.asynctasktest E/AsyncTaskTest: post message:102-19 22:25:17.689 9234-9319/com.plbear.asynctasktest E/AsyncTaskTest: post message:202-19 22:25:17.689 9234-9319/com.plbear.asynctasktest E/AsyncTaskTest: post message:302-19 22:25:17.689 9234-9319/com.plbear.asynctasktest E/AsyncTaskTest: post message:402-19 22:25:17.689 9234-9319/com.plbear.asynctasktest E/AsyncTaskTest: post message:502-19 22:25:17.689 9234-9319/com.plbear.asynctasktest E/AsyncTaskTest: post message:602-19 22:25:17.689 9234-9319/com.plbear.asynctasktest E/AsyncTaskTest: post message:702-19 22:25:17.689 9234-9319/com.plbear.asynctasktest E/AsyncTaskTest: post message:802-19 22:25:17.689 9234-9319/com.plbear.asynctasktest E/AsyncTaskTest: post message:902-19 22:25:17.692 9234-9234/com.plbear.asynctasktest E/AsyncTaskTest: handler:0 //可以看到提交完是在9234主线程中执行。02-19 22:25:17.692 9234-9234/com.plbear.asynctasktest E/AsyncTaskTest: handler:102-19 22:25:17.692 9234-9234/com.plbear.asynctasktest E/AsyncTaskTest: handler:202-19 22:25:17.692 9234-9234/com.plbear.asynctasktest E/AsyncTaskTest: handler:302-19 22:25:17.692 9234-9234/com.plbear.asynctasktest E/AsyncTaskTest: handler:402-19 22:25:17.692 9234-9234/com.plbear.asynctasktest E/AsyncTaskTest: handler:502-19 22:25:17.692 9234-9234/com.plbear.asynctasktest E/AsyncTaskTest: handler:602-19 22:25:17.692 9234-9234/com.plbear.asynctasktest E/AsyncTaskTest: handler:702-19 22:25:17.692 9234-9234/com.plbear.asynctasktest E/AsyncTaskTest: handler:802-19 22:25:17.692 9234-9234/com.plbear.asynctasktest E/AsyncTaskTest: handler:9

以上,简单梳理了下怎么实现,不赘言。

1.2 Android 内部源码实现

关于Handler+Message+Message Queue+Looper的实现就不介绍了,老生常谈了。所以下面主要看一下AsyncTask的源码实现:

AsyncTask的核心方法应该是

public final AsyncTask execute(Params... params)

那我们就看下当调用了execute方法后,都发生了什么,下面是执行的序列图。

Android AsyncTask的优缺点详解_第2张图片

我知道我画的不够标准了,凑合着看吧。下面关于这个图的一些说明。

  • 在第4步,execute的时候,这个时候可以看到,doInBackground已经转到子线程中执行了,这个是很关键的一个点,我特意用了一个异步处理的箭头标注了。
  • 在第9步,当doInbackground执行完,执行到finish方法的时候,由通过sendMessage的方法回到了主线程中了,所以后面的onPostExecute和onCanceled都是在主线程中执行的。

嗯,就这么多吧。关于AsyncTask的源码我上传到github中了,大家对照着源码看会更清楚一点。

https://github.com/YanYoJun/AndroidSource/blob/master/AsyncTask.java

关于AsyncTask的源码分析,还有一篇博客写的很好,请参看:

//www.jb51.net/article/81939.htm

备注:

源码里面还有三个地方值得深究下,分别是:

  • FutureTask值得看下,回头写了博客我把链接贴在这里
  • AsyncTask中的SerialExecutor类写的太漂亮了,回头单独写一个博客欣赏下。
  • 关于上面的ThreadPollExecutor我其实没有研究。。。回头写个博客研究下。

2、优点

简单,快捷

这个说法就是近乎于扯淡吧,主要还是看使用习惯,我就挺喜欢用Handler的。

但是Android定义了这个东西,可以看到各种消息封装的还是很不错的,很规范。大家可以按照这个“优美的框架”来写,代码不会太出格。

3、缺点

3.1  AsyncTask实际上后台线程之后一个!!!

今天仔细研究了下源码,发现网上写的大部分是错的,AsyncTask的真正的后台线程只有一个!!不信,看下面的代码:

我们首先定义一个IAsyncTAsk,其中的doInBackground方法这么写:

private class IAsyncTask extends AsyncTask { protected String doInBackground(String... args1) {/* Log.i(TAG, "doInBackground in:" + args1[0]); int times = 10; for (int i = 0; i < times; i++) { publishProgress(i);//提交之后,会执行onProcessUpdate方法 } Log.i(TAG, "doInBackground out");*/ Log.i(TAG, "doInBackground in thread:" + args1[0]); try { int times = 4; for (int i = 0; i < times; i++) {  Log.i(TAG, "thread alive:" + i + " for times"+args1[0]); //这个doInBackground就打印一个Log,然后sleep 20 毫秒  Thread.sleep(20); } } catch (Exception e) { } return "over"; }

调用的地方这么写:

 int N = 5; for (int i = 0; i < N; i++) {  Log.d(TAG,"asyncTask post Task:"+i);  new IAsyncTask().execute("asyncTask times:"+i); //点击Button后,在onClick方法中建立5个后台子线程。 }

我们来看打印结果:

02-20 21:48:08.206 14812-14812/com.plbear.asynctasktest D/AsyncTaskTest: asyncTask post Task:0 //在主线程中进行提交操作02-20 21:48:08.211 14812-14812/com.plbear.asynctasktest D/AsyncTaskTest: asyncTask post Task:102-20 21:48:08.211 14812-14812/com.plbear.asynctasktest D/AsyncTaskTest: asyncTask post Task:202-20 21:48:08.211 14812-14812/com.plbear.asynctasktest D/AsyncTaskTest: asyncTask post Task:302-20 21:48:08.211 14812-14812/com.plbear.asynctasktest D/AsyncTaskTest: asyncTask post Task:402-20 21:48:08.212 14812-18067/com.plbear.asynctasktest I/AsyncTaskTest: doInBackground in thread:asyncTask times:0 //可以看到,虽然系统开起了18067、18068、02-20 21:48:08.212 14812-18067/com.plbear.asynctasktest I/AsyncTaskTest: thread alive:0 for timesasyncTask times:0//18069,18070这几个子线程,但是这几个子线程02-20 21:48:08.232 14812-18067/com.plbear.asynctasktest I/AsyncTaskTest: thread alive:1 for timesasyncTask times:0 //是串行执行的!!!震惊了有没有!!!02-20 21:48:08.253 14812-18067/com.plbear.asynctasktest I/AsyncTaskTest: thread alive:2 for timesasyncTask times:0 //这不是巧合,试了好几次都是这样!!02-20 21:48:08.273 14812-18067/com.plbear.asynctasktest I/AsyncTaskTest: thread alive:3 for timesasyncTask times:002-20 21:48:08.294 14812-18068/com.plbear.asynctasktest I/AsyncTaskTest: doInBackground in thread:asyncTask times:102-20 21:48:08.294 14812-18068/com.plbear.asynctasktest I/AsyncTaskTest: thread alive:0 for timesasyncTask times:102-20 21:48:08.315 14812-18068/com.plbear.asynctasktest I/AsyncTaskTest: thread alive:1 for timesasyncTask times:102-20 21:48:08.335 14812-18068/com.plbear.asynctasktest I/AsyncTaskTest: thread alive:2 for timesasyncTask times:102-20 21:48:08.356 14812-18068/com.plbear.asynctasktest I/AsyncTaskTest: thread alive:3 for timesasyncTask times:102-20 21:48:08.377 14812-18069/com.plbear.asynctasktest I/AsyncTaskTest: doInBackground in thread:asyncTask times:202-20 21:48:08.377 14812-18069/com.plbear.asynctasktest I/AsyncTaskTest: thread alive:0 for timesasyncTask times:202-20 21:48:08.397 14812-18069/com.plbear.asynctasktest I/AsyncTaskTest: thread alive:1 for timesasyncTask times:202-20 21:48:08.417 14812-18069/com.plbear.asynctasktest I/AsyncTaskTest: thread alive:2 for timesasyncTask times:202-20 21:48:08.438 14812-18069/com.plbear.asynctasktest I/AsyncTaskTest: thread alive:3 for timesasyncTask times:202-20 21:48:08.462 14812-18070/com.plbear.asynctasktest I/AsyncTaskTest: doInBackground in thread:asyncTask times:302-20 21:48:08.462 14812-18070/com.plbear.asynctasktest I/AsyncTaskTest: thread alive:0 for timesasyncTask times:302-20 21:48:08.483 14812-18070/com.plbear.asynctasktest I/AsyncTaskTest: thread alive:1 for timesasyncTask times:302-20 21:48:08.504 14812-18070/com.plbear.asynctasktest I/AsyncTaskTest: thread alive:2 for timesasyncTask times:302-20 21:48:08.524 14812-18070/com.plbear.asynctasktest I/AsyncTaskTest: thread alive:3 for timesasyncTask times:302-20 21:48:08.545 14812-18070/com.plbear.asynctasktest I/AsyncTaskTest: doInBackground in thread:asyncTask times:402-20 21:48:08.545 14812-18070/com.plbear.asynctasktest I/AsyncTaskTest: thread alive:0 for timesasyncTask times:402-20 21:48:08.565 14812-18070/com.plbear.asynctasktest I/AsyncTaskTest: thread alive:1 for timesasyncTask times:402-20 21:48:08.585 14812-18070/com.plbear.asynctasktest I/AsyncTaskTest: thread alive:2 for timesasyncTask times:402-20 21:48:08.606 14812-18070/com.plbear.asynctasktest I/AsyncTaskTest: thread alive:3 for timesasyncTask times:4

你本来希望系统应该这么执行

Android AsyncTask的优缺点详解_第3张图片

但是实际上系统是这么执行的:

Android AsyncTask的优缺点详解_第4张图片

那么从源码看下为啥会这样吧。

AsyncTask中默认的Exector是这个private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;看下SERIAL_EXECUTOR是这么定义的

public static final Executor SERIAL_EXECUTOR = new SerialExecutor(); //这是一个串行处理的Executor......................... private static class SerialExecutor implements Executor { final ArrayDeque mTasks = new ArrayDeque(); Runnable mActive; public synchronized void execute(final Runnable r) { mTasks.offer(new Runnable() { //先把要执行的子线程统一丢到mTasks队列中,这其中封装一遍Runnable public void run() {  try {  r.run();  } finally {  scheduleNext(); //当前面一个子线程处理完,开始处理下一个  } } }); if (mActive == null) { scheduleNext(); } } protected synchronized void scheduleNext() { //依次从队列中取下一个元素,串行执行 if ((mActive = mTasks.poll()) != null) { THREAD_POOL_EXECUTOR.execute(mActive);  } } }

呵呵,这下子明白了吧。

Google为什么要怎么实现我不得而知,估计有什么我没有明白的好处在里面吧。那么有没有办法规避呢?

可以看到上面有一个THREAD_POOL_EXECUTOR,这个也是一个executor是这么定义的

static { ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor( CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE_SECONDS, TimeUnit.SECONDS, sPoolWorkQueue, sThreadFactory); threadPoolExecutor.allowCoreThreadTimeOut(true); THREAD_POOL_EXECUTOR = threadPoolExecutor; }

可以看到这个是允许一定数量的子线程并行处理的。

其中参数是这么定义的

private static final int CPU_COUNT = Runtime.getRuntime().availableProcessors(); // We want at least 2 threads and at most 4 threads in the core pool, // preferring to have 1 less than the CPU count to avoid saturating // the CPU with background work private static final int CORE_POOL_SIZE = Math.max(2, Math.min(CPU_COUNT - 1, 4)); private static final int MAXIMUM_POOL_SIZE = CPU_COUNT * 2 + 1; private static final int KEEP_ALIVE_SECONDS = 30;

按照一般理解,允许同时运行的CORE进程是4个,MAXIMUM_POOL_SIZE是17个。(注:这个数字是我用荣耀8手机跑出来的,其他手机可能会有不同)

而Android中的AsyncTask提供了一个方法:

 public static void setDefaultExecutor(Executor exec) { sDefaultExecutor = exec; }

所以规避方法是:通过这个方法可以设置默认的Exector,但是这个方法是hide的,也就是Google的隐藏方法,估计需要用一下反射来处理。我偷个懒,不去实现了。

4、总结

本来嘛,我只是想简单写一下AsyncTask的一些相关知识,Copy一下网上的内容,但是没有想到写到最后,发现网上的大部分东西是错的,或者没有抓到重点。看来以后还是要自己亲自看代码,纸上得来终觉浅,便知此事要躬行。

本文中用到的工程代码可以到我的github中查看,路径:https://github.com/YanYoJun/AsyncTaskTest

以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,同时也希望多多支持脚本之家!

更多相关文章

  1. Android Input子系统-含实例源码
  2. Android 多线程----AsyncTask异步任务详解
  3. Android Studio中获取SHA1或MD5的方法
  4. Android静态图片人脸识别的完整demo(附完整源码)
  5. [转]JS调用Android里面的方法,Android调用JS里面的方法
  6. Android中常用基本控件的使用方法和步骤(.txt)
  7. 线程中的消息机制
  8. Android音频子系统源码分析之AudioTrack的使用
  9. 3.6.3新版本AndroidStudio报Could not resolve all artifacts fo

随机推荐

  1. android开发之Android(安卓)5.0 Lollipop
  2. android线程 Handler Message Queue Asyn
  3. Android(安卓)OpenGL ES2.0从放弃到入门(
  4. 一个android应用效果开发引发的惨案(andro
  5. Android中的事件处理研究
  6. Android: 记一次Android内存泄露
  7. 金三银四背后,一个 Android(安卓)程序员的
  8. Android团队成员间的代码共享!(Git+Github
  9. 仿Android联系人SideBar排序,根据拼音A-Z
  10. 基于Android(安卓)的蓝牙A2DP 功能的实现