Handler原理及基本概念

  • Message 意为消息,发送到Handler进行处理的对象,携带描述信息和任意数据。
  • MessageQueue 意为消息队列,Message的集合。
  • Looper 有着一个很难听的中文名字,消息泵,用来从MessageQueue中抽取Message,发送给Handler进行处理。
  • Handler 处理Looper抽取出来的Message。

在如下操作中都是基于UI主线程,在异步任务中使用Handler机制更新UI必须用new Handler();来初始化。

// 默认使用UI主线程的Looper
Handler mHandler = new Handler();
mHandler.post(new Runnable(){});

Thread创建与销毁

在Android开发中经常会使用到线程,一想到线程,很多同学就立即使用

new Thread(){...}.start();这样的方式。这样如果在一个Activity中多次调用上面的代码,那么将创建多个匿名线程,程序运行的越久可能会越来越慢。因此,需要一个Handler来启动一个线程,以及删除一个线程。

保证线程不会重复的创建。

使用HandlerThread和Handler配合实现异步后台任务

特点

  • 由2个Handler和1个HandlerThread来实现
  • 后台线程串行执行

代码示例:

// UI线程的Handler
Handler mHandler = new Handler(){
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
// 处理UI更新
}; HandlerThread mBackThread = new HandlerThread("mybackthread");
mBackThread.start();
// 后台线程的Handler
Handler mBackHandler = new Handler(mBackThread.getLooper());
mBackHandler.post(new Runnable() {
@Override
public void run() {
// 后台线程执行耗时操作,异步
...
// mHandler发消息,回到主线程更新UI
mHandler.sendMessage(msg);
}
});

注意mBackHandler的初始化必须在mBackThread.start();之后,否则拿不到这个线程的looper。

这种模式通过mBackHandler.post(new Runnable() {})来实现后台异步任务执行,所有后台任务都是通过HandlerThread这个线程执行的,但是HandlerThread是串行执行任务的,也就是每次post后进入队列排队执行。

HandlerThread的退出:

@Override
protected void onDestroy() {
super.onDestroy();
if(mBackThread != null){
mBackThread.quitSafely();
try {
mBackThread.join();
mBackThread = null;
mBackHandler = null;
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}

AsyncTask实现异步任务执行

查看源码AsyncTask只是对Thread和Handler的一个封装。

基本概念

  • 3个泛型参数

    AsyncTask <Params, Progress, Result>

    Params: 指定的是我们传递给异步任务执行时的参数的类型

    Progress: 指定的是我们的异步任务在执行的时候将执行的进度返回给UI线程的参数的类型

    Result: 指定的是异步任务执行完后返回给UI线程的结果的类型

    我们在定义一个类继承AsyncTask类的时候,必须指定好这三个泛型的类型,如果都不指定的话,则都将其写成Void
  • 4个执行步骤

    onPreExecute():UI Thread当中执行,这个方法是在执行异步任务之前的时候执行,我们可以在异步任务执行前做UI提示

    doInBackground(Params... params):这个方法就是来处理异步任务的方法,执行耗时操作。这个方法也是必须要实现的抽象方法。

    onProgressUpdate(Progess... values):UI Thread当中执行,用来更新进度条等

    onPostExecute(Result... result):UI Thread当中执行,当异步任务执行完之后,将doInBackground结果返回给这个方法来更新UI
  • 2种执行方式

    后台线程可以设置为串行或者并行执行

    串行execute(Params... params)

    并行executeOnExecutor(Executor exec, Params... params)

    注意:各SDK版本execute默认执行方式不统一,1.5中顺序执行,1.6到 2.3中并行执行,3.0以后又改回串行执行,并添加并行执行接口executeOnExecutor

注意事项

  • 必须在UI线程中加载和创建,以及调用execute
  • 不能做特别耗时的操作,建议只几秒内的异步任务
  • 一个AsyncTask对象只能被执行一次,即只能调用一次execute,否则会抛出异常报错

    Caused by: java.lang.IllegalStateException: Cannot execute task: the task has already been executed (a task can be executed only once)
  • 不能在程序中主动调用4个步骤

代码示例

// 初始化AsyncTask及执行
protected void function() {
...
// 串行执行,识别一张bitmap,每次执行前都需要重新new一个对象
mClassifierAsyncTask = new ClassifierAsyncTask();
mClassifierAsyncTask.execute(bitmap);
} // 自定义AsyncTask任务类,实现doInBackground
private ClassifierAsyncTask mClassifierAsyncTask;
private class ClassifierAsyncTask extends AsyncTask<Bitmap , Void, String >{ @Override
protected void onPreExecute() {
super.onPreExecute();
mTvResult.setText(getString(R.string.classifying));
} @Override
protected String doInBackground(Bitmap... bitmaps) {
if(mMyTfClassifier == null) {
mMyTfClassifier = new MyTfClassifier(MainActivity.this);
}
String result = mMyTfClassifier.recognizeImage(bitmaps[0]);
return result;
} @Override
protected void onPostExecute(String result) {
super.onPostExecute(result);
mTvResult.setText(result);
}
}

存在的问题

Activity屏幕旋转或销毁时,如果AsyncTask没有执行完毕就会存在内存泄露。特别是屏幕旋转时AsyncTask没有执行完毕,会导致屏幕异常。

Android常用异步任务执行方法的更多相关文章

  1. Android测试TestSuite的执行方法

    public class StartTest extends InstrumentationTestRunner {         public  TestSuite getAllTests() { ...

  2. 29个android开发常用的类、方法及接口

    在安卓开发中,我们常常都需要借助各种各样的方法.类和接口来实现相关功能.提升开发效率,但对于初学者而言,什么时候该用什么类.方法和接口呢?下面小编整理了29个,日常开发中比较常用的类.方法.接口及其应 ...

  3. 使用Task异步执行方法_多线程_应用程序池

    偶然遇到在执行登录的方法需要发送消息队列导致登录时间过长的问题,从网上查了一些方法,先将一个简单的异步处理程序的小例子展示出来,供大家参考: 备注:该方法是从应用程序程序所在的线程池中获取线程,第一次 ...

  4. ArcGIS Runtime for Android 使用异步GP服务绘制等值线

    关于基于Android上ArcGIS Server GP服务的调用,已经有前辈给出了很好的例子: http://blog.csdn.net/esrichinacd/article/details/92 ...

  5. (转)ArcGIS Runtime for Android 使用异步GP服务绘制等值线

    关于基于Android上ArcGIS Server GP服务的调用,已经有前辈给出了很好的例子: http://blog.csdn.net/esrichinacd/article/details/92 ...

  6. Android常用酷炫控件(开源项目)github地址汇总

    转载一个很牛逼的控件收集帖... 第一部分 个性化控件(View) 主要介绍那些不错个性化的 View,包括 ListView.ActionBar.Menu.ViewPager.Gallery.Gri ...

  7. Android常用库源码解析

    图片加载框架比较 共同优点 都对多级缓存.线程池.缓存算法做了处理 自适应程度高,根据系统性能初始化缓存配置.系统信息变更后动态调整策略.比如根据 CPU 核数确定最大并发数,根据可用内存确定内存缓存 ...

  8. Android 常用炫酷控件(开源项目)git地址汇总

    第一部分 个性化控件(View) 主要介绍那些不错个性化的 View,包括 ListView.ActionBar.Menu.ViewPager.Gallery.GridView.ImageView.P ...

  9. Android 常用开发工具以及Mac常用软件

    Android 常用的开发工具记录.其中包括AndroidStudio(IDEA)插件.Mac 上好用的软件以及国内知名Android开发者博客等. Android Studio 插件 codota ...

随机推荐

  1. LoggerAspect

    package nc.oss.utils; import java.util.Date; import nc.bs.framework.common.InvocationInfoProxy; impo ...

  2. Unity游戏开发之C#快速入门

    C#是微软团队在开发.NET框架时开发的,它的构想接近于C.C++,也和JAVA十分相似,有许多强大的编程功能. 个人感受是C#吸收了众多编程语言的优点,从中可以看到C.C++.Java.Javasc ...

  3. sed 插入和替换

    sed -i '/参考行/i\插入内容' *.ksh sed -i 's,原内容,替换后内容,g' *.ksh

  4. 【BZOJ 2809】2809: [Apio2012]dispatching (左偏树)

    2809: [Apio2012]dispatching Description 在一个忍者的帮派里,一些忍者们被选中派遣给顾客,然后依据自己的工作获取报偿.在这个帮派里,有一名忍者被称之为 Maste ...

  5. [BZOJ4698][SDOI2008]Sandy的卡片(后缀自动机)

    差分之后就是求多串LCS. 对其中一个串建SAM,然后把其它串放在上面跑. 对SAM上的每个状态都用f[x]记录这个状态与当前串的最长匹配长度,res[x]是对每次的f[x]取最小值.答案就是res[ ...

  6. 【高精度】POJ1001-Exponentiation

    整个题库的第二题,原本都没有屑于去做,突发奇想抱着秒杀的心态去写了代码,却硬生生地吃了4个WA.. [思路]先去除掉小数点,进行最基本的高精度乘法运算,再在运算得到的结果中添加小数点输出. [前铺]让 ...

  7. mybatis批量插入:oracle和mysql的区别

    一.oracle批量插入 <insert id="save" parameterType="java.util.List"> insert into ...

  8. Problem C: 指针:自定义函数length,调用它计算字符串的长度

    #include<stdio.h> int length(char*s) { int i,count; while(*s!='\0') { *(s++); count++; } retur ...

  9. C++ Any 任意基础类型封装

    下面是本人使用C++封装的一个针对任意基础类型以及用户自定义类型指针的通用类型.目的是为方便常用类型使用统一化及便利化.该类型的使用就与平时使用基础类型基本没什么差别.具体可参看以下代码及测试代码. ...

  10. CSS写作建议和性能优化总结(未完待续)

    这里是我从网上的一篇文章看过来的,这里先做一点小结,之后再补充. 1.CSS渲染规则 今天在微博的一篇文章上看到的,之前我都以为渲染是从左往右渲染.发现我的想法是错的.之所以采用从右往左的渲染规则,是 ...