本文主要是介绍Handler和Application,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
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() {@Overridepublic void run() {//可以在这个方法中执行UI操作}});//不会调用handler中的handleMessage, 而是调用上面的run方法handler.sendMessage(obtain);handler.post(new Runnable() {@Overridepublic void run() {}});runOnUiThread(new Runnable() {@Overridepublic 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;/*** 启动时, 只执行一次, 做应用的初始化*/@Overridepublic void onCreate() {super.onCreate();Log.d(TAG, "onCreate: ");text = "BaseApplication";}public String getText() {return text;}public void setText(String text) {this.text = text;}
}
在清单文件中添加
<applicationandroid: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("启动一次后");
}
这篇关于Handler和Application的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!