Handler和Application

原创 2016年08月30日 21:48:22

Handler

handler是什么 ?

是android给我们提供用来更新UI的一套机制, 也是一套消息处理的机制, 我们可以发送消息, 也可以通过它处理消息

为什么要用handler

Android在设计的时候, 就封装了一套消息创建, 传递, 处理机制, 如果不遵循这样的机制就没有办法更新UI信息, 就会抛出一异常信息

handler怎么用 ?

文档表述:
A Handler allows you to send and process Message and Runnable objects associated with a thread’s MessageQueue. Each Handler instance is associated with a single thread and that thread’s message queue. When you create a new Handler, it is bound to the thread / message queue of the thread that is creating it – from that point on, it will deliver messages and runnables to that message queue and execute them as they come out of the message queue.

android为什么要设计只能通过Handler机制更新UI ?

最根本的原因是解决多线程并发问题.
假设如果在一个Activity当中, 有多个线程去更新UI, 并且都没有加锁机制, , 那么会产生什么样的现象呢 ?

更新界面错乱 !

如果对更新UI的操作都进行加锁处理的话又会产生什么样的问题呢

性能下降!!!!!

处于对以上目的问题的考虑, android给我们一套更新Ui的机制, 我们只需要遵循这样的机制就可以了,
根本不用关心多线程的问题, 所以更新UI的操作, 都是在主线程的消息队列当中去轮询处理的

Handler原理是什么 ?

面试重要!!!!!

Handler封装了消息的发送 (主要包括把消息发送给谁)

Android中对应 “生产者和消费者” 模型

Message : 产品
MessageQueue : 仓库 (永远用不到, Android已封装好)
Looper : 循环
Handler : 对仓库和循环的一个持有 (通过Handler放置产品) [类似物流]
Handler.Callback 回调接口, 必须自己去实现

Looper

1, 内部包含一个消息队列也就是MessageQueue, 所有的Handler发送的消息都走向这个消息队列

2, Looper.looper方法, 就是一个死循环, 不断的从MessageQueue去取消息, 如果有消息就处理消息, 没有消息就阻塞

3, 一个线程可以产生一个Looper对象,由它来管理此线程里的MessageQueue(消息队列)。

MessageQueue

就是一个消息队列, 可以添加消息, 并处理消息

Handler

内部会跟Looper进行关联, 也就是说Handler的内部可以找到Looper, 找到了Looper也就找到了, MessageQueue , 在Handler中发送消息, 其实就是向MessageQueue队列中发送消息

UIthread 通常就是main thread,而Android启动程序时会替它建立一个MessageQueue。

总结:

handler负责发送消息, Looper负责接收Handler发送的消息, 并直接把消息回传给handler自己, MessageQueue就是一个存储消息的容器

对Looper和Looper.loop的深入理解

Android中的Looper类,是用来封装消息循环和消息队列的一个类,用于在android线程中进行消息处理。handler其实可以看做是一个工具类,用来向消息队列中插入消息的。

(1) Looper类用来为一个线程开启一个消息循环。 默认情况下android中新诞生的线程是没有开启消息循环的。(主线程除外,主线程系统会自动为其创建Looper对象,开启消息循环。) Looper对象通过MessageQueue来存放消息和事件。一个线程只能有一个Looper,对应一个MessageQueue。

(2) 通常是通过Handler对象来与Looper进行交互的。Handler可看做是Looper的一个接口,用来向指定的Looper发送消息及定义处理 方法。 默认情况下Handler会与其被定义时所在线程的Looper绑定,比如,Handler在主线程中定义,那么它是与主线程的Looper绑定。 mainHandler = new Handler() 等价于new Handler(Looper.myLooper()). Looper.myLooper():获取当前进程的looper对象,类似的 Looper.getMainLooper() 用于获取主线程的Looper对象。

(3) 在非主线程中直接new Handler() 会报如下的错误: E/AndroidRuntime( 6173): Uncaught handler: thread Thread-8 exiting due to uncaught exception E/AndroidRuntime( 6173): java.lang.RuntimeException: Can’t create handler inside thread that has not called Looper.prepare() 原因是非主线程中默认没有创建Looper对象,需要先调用Looper.prepare()启用Looper。

(4) Looper.loop(); 让Looper开始工作,从消息队列里取消息,处理消息。

注意:写在Looper.loop()之后的代码不会被执行,这个函数内部应该是一个循环,当调用mHandler.getLooper().quit()后,loop才会中止,其后的代码才能得以运行。

感谢原作者

Handler机制运行过程

以上是对Handler整个运行机制内部的详细描述, 有兴趣的同学可以查看一下源码

Handler创建消息

每一个消息都需要被指定的Handler处理,通过Handler创建消息便可以完成此功能。Android消息机制中引入了消息池。Handler创建消息时首先查询消息池中是否有消息存在,如果有直接从消息池中取得,如果没有则重新初始化一个消息实例。使用消息池的好处是:消息不被使用时,并不作为垃圾回收,而是放入消息池,可供下次Handler创建消息时使用。消息池提高了消息对象的复用,减少系统垃圾回收的次数。消息的创建流程如图所示。

这里写图片描述

//推荐使用, Message中有一个消息池, 会循环使用内部的message
Message message = Message.obtain();
Message obtain = Message.obtain(handler, 0, String.valueOf(i + 1))
Message.obtain(handler);
handler.obtainMessage()

Handler发送消息

UI主线程初始化第一个Handler时会通过ThreadLocal创建一个Looper,该Looper与UI主线程一一对应。使用ThreadLocal的目的是保证每一个线程只创建唯一一个Looper。之后其他Handler初始化的时候直接获取第一个Handler创建的Looper。Looper初始化的时候会创建一个消息队列MessageQueue。至此,主线程、消息循环、消息队列之间的关系是1:1:1。

Handler、Looper、MessageQueue的初始化流程如图所示:
这里写图片描述

Hander持有对UI主线程消息队列MessageQueue和消息循环Looper的引用,子线程可以通过Handler将消息发送到UI线程的消息队列MessageQueue中

handler.sendMessage(message);
//在有Handler对象的前提下调用
message.sendToTarget();

处理消息

UI主线程通过Looper循环查询消息队列UI_MQ,当发现有消息存在时会将消息从消息队列中取出。首先分析消息,通过消息的参数判断该消息对应的Handler,然后将消息分发到指定的Handler进行处理。

子线程通过Handler、Looper与UI主线程通信的流程如图所示。

这里写图片描述

// 临时解决方案, 如果代码规范的话不会出现下面的情况
 Message obtain = Message.obtain(handler, new Runnable() {
     @Override
     public void run() {
         //可以在这个方法中执行UI操作
     }
 });
 //不会调用handler中的handleMessage, 而是调用上面的run方法
 handler.sendMessage(obtain);
 handler.post(new Runnable() {
     @Override
     public void run() {

     }
 });
 runOnUiThread(new Runnable() {
     @Override
     public void run() {

     }
 });

感谢原作者

Application

只要在一个应用中, 所有的Activity共用一个Application, 保存一些全局的变量

注意: 所有的应用被销毁的时候, Application不一定被销毁无论怎么用, Application只会创建一次

如何创建一个自己的Application

BaseApplication.java

public class BaseApplication extends Application {
    private static final String TAG = BaseApplication.class.getSimpleName();
    private String text;

    /**
     * 启动时, 只执行一次, 做应用的初始化
     */
    @Override
    public void onCreate() {
        super.onCreate();
        Log.d(TAG, "onCreate: ");
        text = "BaseApplication";

    }


    public String getText() {
        return text;
    }

    public void setText(String text) {
        this.text = text;
    }
}

在清单文件中添加

<application
     android:name=".BaseApplication"
        ...
</application>

在MainActivity中获取创建的Application

private static final String TAG = MainActivity.class.getSimpleName();

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    Log.d(TAG, "onCreate: ");
    setContentView(R.layout.activity_main);
    BaseApplication application = (BaseApplication) getApplication();
    String text = application.getText();
    Toast.makeText(MainActivity.this, text, Toast.LENGTH_SHORT).show();
    application.setText("启动一次后");
}
版权声明:本文为博主原创文章,未经博主允许不得转载。

在Android中捕获Application全局异常 阻止系统弹出强制退出的对话框

大家都知道,现在安装 Android 系统的手机和设备千差万别,在模拟器上运行良好的程序安装到某款手机上说不定就出现崩溃的现象,开发者个人不可能购买所有设备逐个调试,所以在程序发布出去之后,如果出现了...
  • wuhongqi0012
  • wuhongqi0012
  • 2013年11月01日 11:32
  • 3058

Android Studio启动异常报错修复

Internal 进来找问题的朋友有福利了,保证帮你1分钟解决问题。今天启动了AS,然后报了如下的错误,想想是因为昨天非正常关机导致的,然后搜了百度等等网站,都没有用。 最后翻墙GOOGLE后,发现...
  • Panda_Program
  • Panda_Program
  • 2017年05月06日 10:36
  • 930

Android Application的写法一

一、概述:1、在清单文件里注册 android:allowBackup="true" android:name="BaseApplication"2、在applicati...
  • lovoo
  • lovoo
  • 2016年06月22日 21:27
  • 1061

Android之handler篇

Android的消息机制主要是指Handler的运行机制,Handler的运行需要底层的MessageQueue和Looper的支撑。对于有开发过Android经验的童鞋都知道,我们一般都是用Hand...
  • zjws23786
  • zjws23786
  • 2016年07月20日 00:37
  • 3149

android-封装一个加载处理的handler类

public class LoadHandler extends Handler { private LoadListener listener; public LoadHandler(...
  • joshua_love
  • joshua_love
  • 2017年04月18日 10:19
  • 431

Handler优化以及SharedPreferences工具类的封装

eclipse里有个警告:“This Handler class should be static or leaks might occur”,为什么eclipse会提示一个handler要是静态的?...
  • ViewHandKownHealth
  • ViewHandKownHealth
  • 2016年04月02日 11:36
  • 741

Android中Application类用法

此文章转载自:http://www.cnblogs.com/renqingping/archive/2012/10/24/Application.html Application类 A...
  • huntersnail
  • huntersnail
  • 2015年05月29日 09:47
  • 2438

android中“后台”更新Activity的办法(application handler和BroadcastReceiver)

转自:http://blog.csdn.net/jason0539/article/details/18075293   第一种方法: 遇到一个问题,需要在一个activity中控制...
  • WALLEZhe
  • WALLEZhe
  • 2016年02月26日 16:09
  • 1199

Android CrashHandler编写自己的异常捕获类

平时写代码,我们可能会抛出各种异常,这些异常有些是我们测试过程中发现进行解决的,但是也有一些异常是我们未知的,不论是代码的逻辑问题还是Android本身底层的一些bug,我们都需要及时了解并进行解决。...
  • danfengw
  • danfengw
  • 2016年07月16日 16:37
  • 4270

Android中使用Handler造成内存泄露的分析和解决

Java使用有向图机制,通过GC自动检查内存中的对象(什么时候检查由虚拟机决定),如果GC发现一个或一组对象为不可到达状态,则将该对象从内存中回收。也就是说,一个对象不被任何引用所指向,则该对象会在被...
  • jdsjlzx
  • jdsjlzx
  • 2016年05月12日 18:21
  • 6369
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:Handler和Application
举报原因:
原因补充:

(最多只允许输入30个字)