Android Handler的使用

Android Handler算是一个很神奇的东西吧,为什么这么说呢,因为刚开始学习Android的时候讲师就一值在说Handler的重要性,下面就来看看对Handler的浅度理解吧:

一.什么是Handler

 Handler是Android给我们提供用来更新UI的一套机制,是一套消息处理机制,可以通过它来发送消息和处理消息。那作为开发者的我们,不禁会疑问?Google为什么要设计这套机制呢?这是为了解决在非UI线程中更新UI组件比较麻烦的问题。那么Android为什么不能在非UI线程中更新呢?首先Android的UI控件不是线程安全的,这是因为避免多线程并发所带来不安全问题。例如作一个假设,现在在子线程中刷新界面,同时也在UI线程中刷新界面,就会出现刷新不同步,简单来讲通过Handler就可以更新UI操作切换到主线程中执行。


二.Handler机制

 Handler机制主要角色

Message:消息,就是一个载体,包含消息ID,消息处理对象和处理的数据等,统一放到MessageQueue,最终由Handler处理。

Handler:用于同一个进程的线程间通信,消息处理者,专门负责Message的发送和处理。我们使用Handler时,一般通过handleMessage(Message msg)来处理Message,也就是统一处理消息的回调,确保自己发出的消息也是自己来处理。

MessageQueue:由名字可推出这是队列,就是存放Handler发送过来的消息,按照先进先出的顺序规则来执行。将链表的数据结构以Message来串联起来,等待Looper的抽取,为什么需要队列呢?因为同一线程在一个时间只能处理一个消息。因此需要队列来保存这些消息,然后挨个挨个拿出来处理,创建一个线程时并不会自动创建MessageQueue,但是主线程创建时会默认创建Looper对象,而Looper创建时就会创建MessageQueue,其他非主线程需要looper的时候就会通过调用prepare函数来实现。

Looper:首先要理解一个线程是一段可执行的代码,作为App的主线程,不能让代码执行完,因为代码执行完的话app就会自动退出,因此不能让主线程不能让代码段执行,只能在代码中插入一个死循环,这时候Looper的作用就体现出来了,将主线程变成Looper线程。并且这时主线程就会在等其他线程发消息(更新UI和Activity状态等等)那,另外,Looper不断从消息队列拿出消息给主线程,也就是无限循环去查找是否有消息,有就去处理,没有的话就一直等待,一个MessageQueue需要一个Looper。

Thread:负责调度整个消息的循环。

通过上面可以得知:Handler的作用是发送和处理消息,Handler发送的消息必须被送到指定MessageQueue中,也就是说,要让Handler正常工作就必须有一个MessageQueue,但是MessageQueue是由Looper来抽取自身的Message,也因此当前线程中必须有一个Looper对象。

图解:


Handler深度理解

根据上面可得:每一个线程都必须有Looper,但是我们不禁会有疑问?主线程我们并没有创建Looper?其实主线程是ActivityThread,ActivityThread被创建的时候就会初始化Looper。


上面红色箭头就是主线程创建Looper对象代码语句。那么我们继续进入Looper去看看究竟是什么操作。


果然上面所分析的几个主要角色都在:Looper,MessageQueue,Thread,但是还多了一个ThreadLocal,这个是什么呢?其实这个是一个线程内部的数据存储类,通过它可以在指定线程中存储数据,数据存储以后,只有在指定的线程获取到存储数据,对于其他线程来说则无法获取到数据,后面例子再详细叙述。

这时候又有疑问,为什么主线程中有一个死循环,但是没有造成阻塞呢?那我们从ActivityThread类开始分析:这个并不是一个真正的线程,就只是一个类,从main方法看到有Looper,那找找其对应的Handler,ActivityThread有一个内部类,继承Handler,并找到handleMessage


仔细观察:Activity的生命周期都有对应的case条件,并且service的生命周期等等都有条件。也就是通过loop来分发消息内部类的Handler,就会进入handleMessage。就会根据对应的条件来执行对应的代码,不断执行传递过来的消息。那么可以总结来说:ActivityThread的main方法主要是来做消息循环的,如果消息循环退出了,那么程序就退出了。但是从队列里取出消息可能会造成阻塞,如果某个消息处理的时间过于长,那么会影响UI线程的刷新,就造成卡顿现象。不会造成卡在的真正原因主要有二:

1.当没有消息来的时候就会wait,有句柄写的时候就会唤醒,进行等待。

2.所有的UI更新操作都通过handler来发消息。如各种的点击事件都会造成句柄写的操作来唤醒等待。

主线程是UI线程,优先级很高,主线程的死循环会不会特别消耗CPU资源呢?

其实如果主线程的队列里没有消息时,就会阻塞在loop的queue.next()里,这时候主线程就会释放CPU资源进入休眠状态,直到下个消息进来时就会唤醒主线程,现在是通过pipe管道来写入数据,类似I/0,不占用资源。


三.例子实践

下面简单写一个小例子加深理解:

倒计时例子:

public

classMainActivityextendsActivity{

privateTextView text_one;

privatemHandler mhandler =newmHandler(this);

@Override

protectedvoidonCreate(Bundle savedInstanceState){

super.onCreate(savedInstanceState);

        setContentView(R.layout.activity_main);

        text_one = findViewById(R.id.text_one);

        start();

    }

//Handler静态内部类 防止内存泄漏

privatestaticclassmHandlerextendsHandler{

      WeakReference<MainActivity> weakReference;

publicmHandler(MainActivity mainActivity){

weakReference =newWeakReference(mainActivity);

      }

@Override

publicvoidhandleMessage(Message msg){

          MainActivity mainActivity = weakReference.get();

if(mainActivity !=null){

                mainActivity.text_one.setText(String.valueOf(msg.arg1));

          }

      }

    }

privatevoidstart(){

newThread(newRunnable() {

@Override

publicvoidrun(){

for(inti =10;i>0;i--){

Message msg =newMessage();

msg.what =01;

                    msg.arg1 = i;

                    mhandler.sendMessage(msg);

try{

Thread.sleep(1000);

}catch(InterruptedException e) {

                        e.printStackTrace();

                    }

                }

//计时结束后先不管

            }

        }).start();

  }

@Override

protectedvoidonDestroy(){

super.onDestroy();

if(mhandler !=null){

mhandler.removeCallbacksAndMessages(null);

      }

  }

以上就是对Handler的理解,谢谢观看!

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