Android Handler

Handler是什么?
Handler是Android提供的一套用来更新UI的机制,也是一套消息处理机制,可以通过它发送消息,也可以通过它处理消息。
所有Activity生命周期回调的方法,都是通过handler机制去发送消息的,然后根据不同的消息(message)做相应的分支处理。例如发送一个消息给 Framework,告知需要调用onCreate()或onDestory()方法。实际上在 Framework 当中,Activity的交互大部分都是用AMS(Activity Manager Service)做处理的。整个应用程序的核心的一个类就是 Activity Thread,Activity Thread就是通过handler机制接收到 Activity Manager Service发送的有关Activity生命周期的管理的消息(比如启动)。
为什么要使用Handler?
Android在设计的时候,就封装了一套消息的创建、传递、处理机制,如果不遵循这样的机制,就没有办法更新UI信息,并且会抛出异常信息。这样的机制便包含Handler机制。
我们需要把这些耗时的操作,放在一个子线程中,因为子线程涉及到UI更新,Android主线程是线程不安全的,也就是说,更新UI只能在主线程中更新,子线程中操作是危险的。这个时候,Handler就出现了。来解决这个复杂的问题 ,由于Handler运行在主线程中(UI线程中),它与子线程可以通过Message对象来传递数据, 这个时候,Handler就承担着接受子线程传过来的(子线程用sedMessage()方法传递)Message对象(里面包含数据),把这些消息放入主线程队列中,配合主线程进行更新UI。
Handler主要接受子线程发送的数据,并用此数据配合主线程更新UI。
当应用程序启动时,Android首先会开启一个主线程 (也就是UI线程) ,主线程为管理界面中的UI控件,进行事件分发,比如说, 你要是点击一个 Button ,Android会分发事件到Button上,来响应你的操作。如果此时需要一个耗时的操作,例如: 联网读取数据,或者读取本地较大的一个文件的时候,你不能把这些操作放在主线程中,如果你放在主线程中的话,界面会出现假死现象,如果5秒钟还没有完成的话,会收到Android系统的一个错误提示 "强制关闭"。


  1. 我们要创建一个handler的时候,它会和默认的一个线程进行绑定,而这个默认的线程当中就有一个MessageQueue(消息队列)。
  2. handler的两个用途:(1)定时发送一个Messages或者Runnables对象;(2)可以在一个线程当中去处理并执行一个Action的动作。
  3. 主线程运行一个消息队列,并管理着一些顶级的应用对象(top-level application objects),包括Activity、Broadcast Receiver等等,这些对象默认都是创建在Activity Thread(也就是我们常说的UI线程或者主线程)当中。
    下面图是通过postDelayed来更新图片
    Handler的示例,实现图片轮播。
    代码实现
  4. 在主布局中定义一个ImageView控件。
  5. 在 MainActivity 中创建并初始化ImageView,定义一个图片数组 images 和数组下标索引 index,创建一个Handler对象。
  6. 创建一个内部类 MyRunnable 实现 Runnable 接口,重写 run() 方法:
    public void run() {
    index++;
    index = index%3; // 图片轮播(一般是通过ViewPager实现图片轮播)
    imageView.setImageResource(images[index]);
    handler.postDelayed(myRunnable,1000); // 每隔一秒换一次图片
    }
  7. 在onCreate()方法中调用handler,也就是在主线程中调用handler:
    handler.postDelayed(myRunnable,1000);

使用“Message”方式“发送消息”,使“Handler处理消息,并更新UI”
1.定义Handler,并且实例化,使用默认构造函数即可。
2.重写handlerMessage方法。
private Handler msgHandler=new Handler(){
//定义handler,重写处理message方法。当该handler发送消息的时候,这个方法会被执行。
public void handleMessage(android.os.Message msg) {
//msg为当有sendMessage方法调用时,传过来的Message对象。
mTextView.setText("msg:"+msg.arg1);
};
};
3.定义Message对象。其中,Message提供了三个公共变量。arg1,arg2,obj,可以将消息放入其中,作为消息信息。然后发送消息即可
new Thread()
{
public void run() {
Message message=msgHandler.obtainMessage();//从Handler对象中获取Message对象,而不是自己new,这样效率高。
message.arg1=1;
message.sendToTarget(); //对于从handler对象中获取的message,可以直接使用该方法发送消息。
//msgHandler.sendMessage(message); //发送消息
};
}.start();

知识拓展:
1。实例化Handler时,可以使用带一个Callback接口参数的构造函数。
其中Callback有一个未实现的方法。 这个方法有一个返回值(boolean)
2.当该Handler收到消息时,首先会调用Callback中的消息处理方法。
2.1 如果返回值为false,消息不会被截断。Handler依然可以处理该消息。
2.2 如果返回值为true,消息将会被截断。Handler中的处理消息方法不会被执行。


handler、looper、messagequeue、message四者可以这样理解:
handler:工人;
looper:传送带移动的动力;
messagequeue:传送带;
message:传送带上面的产品。
工人(handler)把自己的产品(message)放在传送带(messagequeue)尾部,在动力(looper)作用下,传送带向前移动,最终产品到达传送带头部,被取出来处理(handmessage())。


先要有个概念。
1、handler 消息处理器,负责处理消息。
2、Message 消息,包含消息id,被处理的对象。
3、MessageQueue 消息队列,存放Handler发送过来的Message
4、looper 消息泵,不间断的从MessageQueue消息队列中抽取消息。
简单的比喻looper就是水泵,MessageQueue储水的池塘,Message就是水,Handler就是操作的人。


主线程和子线程之间如何相互通信:

  1. 子线程向主线程发送消息,是通过调用主线程的Handler,发送信息给主线程的Looper,该Hnadler绑定了主线程的Looper。
  2. 主线程向子线程发送消息,是通过调用子线程的Handler,发送信息给子线程的Looper,因此必须有子线程的Looper,为了防止Looper没有初始化,所以通过HandlerThread类,来保证子线程的Looper再被主线程调用时已经初始化。
    1.创建主线程的handler,并向子线程发送消息:
    //主线程的handler
    Handler handler = new Handler(){
    public void handleMessage(android.os.Message msg) {
    Message message = new Message();
    threadHandler.sendMessageDelayed(message, 1000);//向子线程发送消息
    };
    };
    2.创建子线程的handler,向主线程发送消息,要关联一个threadHandler,threadHandler.getLooper()得到一个looper对象
    HandlerThread handlerThread = new HandlerThread("handler thread");
    handlerThread.start();//不要忘记调用start方法!
    //子线程的handler
    threadHandler = new Handler(handlerThread.getLooper()){
    @Override
    public void handleMessage(Message msg) {//处理消息
    Message message = new Message();
    handler.sendMessageDelayed(message, 1000);
    }
    };

更新UI的四种方法:
tv指一个TextView;
先在onCreate()方法中新建一个线程:
new Thread() {
public void run() {
try {
Thread.sleep(2000);
方法();
} catch (InterruptedException e) {
e.printStackTrace();
}
} }.start();
方法一:private void handle1() {
handler.post(new Runnable() {
@Override
public void run() {
tv.setText("First Way");
}
});
}
方法二:
先创建一个handler:
private Handler handler = new Handler() {
public void handleMessage(android.os.Message msg) {
tv.setText("Second Way!");
};
};
然后
private void handle2() {
handler.sendEmptyMessage(1);
}
方法三:
private void updateUI() {
runOnUiThread(new Runnable() {
@Override
public void run() {
// TODO Auto-generated method stub
tv.setText("Third Way");
}
});
}
方法四:
private void viewUI() {
tv.post(new Runnable() {

        @Override
        public void run() {
            // TODO Auto-generated method stub
            tv.setText("Fourth Way");
        }
    });
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 151,511评论 1 330
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 64,495评论 1 273
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 101,595评论 0 225
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 42,558评论 0 190
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 50,715评论 3 270
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 39,672评论 1 192
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,112评论 2 291
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 29,837评论 0 181
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 33,417评论 0 228
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 29,928评论 2 232
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 31,316评论 1 242
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 27,773评论 2 234
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 32,253评论 3 220
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 25,827评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,440评论 0 180
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 34,523评论 2 249
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 34,583评论 2 249

推荐阅读更多精彩内容