Handler 原理分析和使用之HandlerThread
前面已经提到过Handler的原理以及Handler的三种用法。这里做一个非常简单的一个总结:
- Handler 是跨线程的Message处理。负责把Message推送到MessageQueue和处理。
- Looper 用来轮询MessageQueue,获取Message 发送给指定的Handler进行处理。
- Looper 需要和线程绑定,绑定那个线程,Handler就会在那个线程处理Message
前两篇文章使用Handler处理的场景是:主线程(UI线程)被子线程更新。即使用主线程的Handler和Looper,在子线程中发Message。然后主线程处理 handlerMessage。
-----------------------------------------------------------------------------------------
下面反过来说,如何从UI线程发消息,让子线程处理。
最为通常的做法是:new Thread().start。起一个线程去完成一个任务,任务完成线程就可以自毙了。当然了如果不需要子线程返回结果,而且只有一个线程,那么这是最简单的了。
另一种方法是SyncTask。实例如下:
import android.os.AsyncTask;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.TextView; public class MainActivity extends AppCompatActivity implements View.OnClickListener{ private TextView myTextView;
private Button myButton;
private MyAsyncTask myTask;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
myTextView = (TextView)this.findViewById(R.id.text_view);
myButton = (Button)this.findViewById(R.id.post);
myButton.setOnClickListener(this);
//主线程初始化异步任务
myTask = new MyAsyncTask();
//主线程启动异步任务,
myTask.execute(10);
} @Override
public void onClick(View v) {
//主线程取消异步任务
myTask.cancel(true);
} /**
* AsyncTask<T, Q, K> 是异步任务基类 包含三个泛型参数。
* T 类型参数为执行异步任务时的参数类型doInBackground(T)
* Q 类型参数为执行过程中的参数类型onProgressUpdate(Q)
* K 类型参数为执行结束onPostExecute(K)或中取消执行时的类型参数onCancelled(K)
*/
class MyAsyncTask extends AsyncTask<Integer, Integer, Long>{ @Override
//执行异步任务核心方法,主语T参数类型
protected Long doInBackground(Integer... params) {
int size = params[0];
long totalSize = 0l;
for(int i = 0; i < size; i++){
totalSize += 10000;
publishProgress((int) ((i / (float) size) * 100));
if(isCancelled()){
break;
}
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
return totalSize;
} @Override
//开始执行异步任务前,更新UI线程。
protected void onPreExecute() {
myTextView.setText("downLoad start !!");
} @Override
//执行异步任务中,更新UI线程
protected void onProgressUpdate(Integer... values) {
int progress = values[0];
myTextView.setText(progress + "%");
} @Override
//执行异步任务后,更新UI线程
protected void onPostExecute(Long aLong) {
myTextView.setText("Task finished");
} @Override
//执行异步任务被取消后,跟新UI线程
protected void onCancelled(Long aLong) {
myTextView.setText("Task camcelled");
}
}
}
通过实例可以看出,SyncTask不但可以给主线程提供启动和停止接口,还可以给主线程上报过程。当然了开销也是有的。
实际上这种方式也可以用 Handler 原理分析和使用(一)中的例子实现。
以上都是主线程启动一个子线程完成任务。但是如果要做多个异步任务,该如何实现?
首先,从多个异步任务来考虑,如果还是各自不同的话,先考虑到的是线程池。这个在后面的多线程部分在说明。
还有一种方式就是使用HandlerThread。这个就是通过主线程获取其他线程给HandlerThread发消息,使其完成相关的任务。在例举说明HandlerThread使用之前,先看看以下例子。也是主线程给子线程发消息,让子线程处理任务。
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue; public class MainActivity extends AppCompatActivity implements View.OnClickListener{ private TextView myTextView;
private Button myButton;
private MyThread myThread;
private Handler myThreadHandler;
private int count = 0;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
myTextView = (TextView)this.findViewById(R.id.text_view);
myButton = (Button)this.findViewById(R.id.post);
myButton.setOnClickListener(this);
//定义子线程
myThread = new MyThread();
//获取子线程的Handler
myThreadHandler = myThread.getHandler();
//启动子线程
myThread.start(); } @Override
public void onClick(View v) {
count++;
//通过子线程的Handler,主线程给子线程发送消息(添加任务)
myThreadHandler.sendEmptyMessage(count);
} /**
* 子线程
*/
public class MyThread extends Thread{
public Handler mThreadHandler = null;
//任务队列
public BlockingQueue<Integer> queue = null;
public MyThread(){
super();
queue = new ArrayBlockingQueue<Integer>(20);
//获取子线程的Looper
Looper mThreadLopper = Looper.myLooper();
//初始化子线程的Handler
mThreadHandler = new Handler(mThreadLopper, new Handler.Callback() {
@Override
//接收到主线程发的任务
public boolean handleMessage(Message msg) {
//任务添加到队列
queue.add(msg.what);
return false;
}
});
}
public Handler getHandler(){
return mThreadHandler;
}
public void run(){
while(true){
try{
//任务的处理
int what = queue.take();
Log.e("Test", "Click Button = " + what);
}catch(InterruptedException e){ } }
} }
}
上面的例子说明了两件事情。第一,非主线程有自己的Looper(很多文章说没有),第二Handler可以处理非主线程的任务。实际上上面的例子,使用了sendMessage()方法,其实际上用处并不是很广泛,甚至有些憋屈,本身已经有了一个MessageQueue,为什么还要使用一个ArrayBlockingQueue?
实际上上述的例子,完全可以通过HandlerThread来替代。例子如下
import android.os.Handler;
import android.os.HandlerThread;
import android.os.Message;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.TextView; public class MainActivity extends AppCompatActivity implements View.OnClickListener{ public TextView myTextView;
private Button myButton;
private HandlerThread myThread;
private Handler myThreadHandler;
private int count = 0;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
myTextView = (TextView)this.findViewById(R.id.text_view);
myButton = (Button)this.findViewById(R.id.post);
myButton.setOnClickListener(this);
//初始化HandlerThread
myThread = new HandlerThread("handlerThread_test");
//启动HandlerThread
myThread.start();
//初始化HandlerThrand的Handler对象
myThreadHandler = new Handler(myThread.getLooper(), new Handler.Callback() {
@Override
//实现消息处理。
public boolean handleMessage(Message msg) {
int what =msg.what;
Log.e("Test", "Click Button = " + what);
return false;
}
});
} @Override
public void onClick(View v) {
count++;
//通过Handler给HandlerThread线程发送消息
myThreadHandler.sendEmptyMessage(count);
//通过Handler给HandlerThreand发送要执行的任务。
myThreadHandler.post(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
Log.e("Test", "Hello world1");
}
});
myThreadHandler.post(new Runnable() {
@Override
public void run() {
Log.e("Test", "Hello world2");
}
});
}
}
从这个例子不难看出HandlerThread实际上是一个Thread,而这个Thread是负责处理Handler派发的消息和任务。此外值得注意有三点:
第一,只有一个线程来处理各种任务。
第一,执行的任务时有序的。也就是说顺序可以被控制。
第二,可以执行各种自定义的任务。
最后关于HandlerThread的退出:myThread.quit();
HandlerThread与SyncTask相比较,缺少执行过程的反馈。但是执行任务的多样性超过SyncTask。当然了都只启动了一个线程。
HandlerThread与Handler-Thread模式比较,也是缺少执行反馈。但是执行多任务时,HandlerThread却只需要一个线程。
所有的Handler就到这里了。也不经意间把SyncTask拿出来溜了一下。其他两篇
Handler完了。
Handler 原理分析和使用之HandlerThread的更多相关文章
- Handler 原理分析和使用(二)
在上篇 Handler 原理分析和使用(一)中,介绍了一个使用Handler的一个简单而又常见的例子,这里还有一个例子,当然和上一篇的例子截然不同,也是比较常见的,实例如下. import andro ...
- Handler 原理分析和使用(一)
我为什么写Handler,原因主要还在于它在整个 Android 应用层面非常之关键,他是线程间相互通信的主要手段.最为常用的是其他线程通过Handler向主线程发送消息,更新主线程UI. 下面是一个 ...
- Handler系列之原理分析
上一节我们讲解了Handler的基本使用方法,也是平时大家用到的最多的使用方式.那么本节让我们来学习一下Handler的工作原理吧!!! 我们知道Android中我们只能在ui线程(主线程)更新ui信 ...
- [转]Handler MessageQueue Looper消息循环原理分析
Handler MessageQueue Looper消息循环原理分析 Handler概述 Handler在Android开发中非常重要,最常见的使用场景就是在子线程需要更新UI,用Handler ...
- Android中Input型输入设备驱动原理分析(一)
转自:http://blog.csdn.net/eilianlau/article/details/6969361 话说Android中Event输入设备驱动原理分析还不如说Linux输入子系统呢,反 ...
- 使用AsyncTask异步更新UI界面及原理分析
概述: AsyncTask是在Android SDK 1.5之后推出的一个方便编写后台线程与UI线程交互的辅助类.AsyncTask的内部实现是一个线程池,所有提交的异步任务都会在这个线程池中的工作线 ...
- 转载:solr MoreLikeThis的原理分析
转载地址:http://blog.sina.com.cn/s/blog_5ddc071f0101muos.html 在solr中有两种方式实现MoreLikeThis:MoreLikeThisHand ...
- WebViewJavascriptBridge 原理分析
WebViewJavascriptBridge 原理分析 网上好多都是在介绍 WebViewJavascriptBridge如何使用,这篇文章就来说说 WebViewJavascriptBridge ...
- Android中Input型输入设备驱动原理分析<一>
话说Android中Event输入设备驱动原理分析还不如说Linux输入子系统呢,反正这个是没变的,在android的底层开发中对于Linux的基本驱动程序设计还是没变的,当然Android底层机制也 ...
随机推荐
- load dll
Assembly myassembly = Assembly.LoadFrom("testdll.dll"); Type type = myassembly.GetType(&qu ...
- Centos环境下删除Oracle11g客户端文档
将安装目录删除 [root@Oracle /root]# rm -rf /opt/oracle/ 将/usr/bin下的文件删除[root@Oracle /root]# rm /usr/local/b ...
- python 零散记录(四) 强调字典中的键值唯一性 字典的一些常用方法
dict中键只有在值和类型完全相同的时候才视为一个键: mydict = {1:1,':1} #此时mydict[1] 与 mydict['1']是两个不同的键值 dict的一些常用方法: clear ...
- bat坐拥大数据。数据挖掘/大数据给他们带来什么。
阿里巴巴CTO即阿里云负责人王坚博士说过一句话:云计算和大数据,你们都理解错了. 实际上,对于大数据究竟是什么业界并无共识.大数据并不是什么新鲜事物.信息革命带来的除了信息的更高效地生产.流通和消 ...
- EJB (not bound)
问题: 在代码实在找不到错误的情况下,仍然报:XXXX not bound 问题产生过程: 通过下图方式创建的项目:EJBTest2_1 勾选下面两项,即可生成:EJBTest2_1EJB 和 EJB ...
- C#如何将线程中的代码抛到主线程去执行
private SynchronizationContext mainThreadSynContext; //主线程 mainThreadSynContext = new WindowsFormsSy ...
- YII 权限管理
CREATE TABLE IF NOT EXISTS `admin_role` ( `id` ) unsigned NOT NULL auto_increment, `name` ) NOT NULL ...
- 中文乱码问题(使用Servlet3.0新特性实现文件上传——上传文件名中文乱码问题)
问题描述:就是文件传送过来的文件名等是乱码 解决方法:将传送的JSP页面(即含有表单的页面)的页面编码方式改为: <%@ page contentType="text/html; ch ...
- textarea在光标位置插入文字
最近开发类似计算器界面,需要在textarea中编辑公式,涉及到 在光标位置插入 字符. 效果如下: + - * / 添加文字 // html代码如下: <!doctype html> & ...
- GitHub简历
My GitHub Résumé可以帮你生成一份github简历,你只需要输入你的github用户名.