Handler和Application

2024-08-30 01:32
文章标签 application handler

本文主要是介绍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的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1119417

相关文章

(南京观海微电子)——GH7006 Application Note

Features ⚫ Single chip solution for a WXGA α-Si type LCD display ⚫ Integrate 1200 channel source driver and timing controller ⚫ Display Resolution: ◼ 800 RGB x 480 ◼ 640 RGB x 480 ⚫ Display int

git中,隐藏application.properties文件,修改不用提交了

git中,隐藏application.properties文件,修改不用提交了 A、将文件名放入 .gitignore 文件中 B、执行git命令隐藏文件         执行在ide上执行命令         a、执行隐藏命令 git rm --cached src/main/resources/application.properties          b、执行提交命

webservice的安全机制2---handler实现

本节摘要:本节介绍使用handler的方式来实现webservice的IP地址的校验。   1.引言 前一节介绍了使用users.lst文件来实现webservice的用户名和密码的校验, 本节介绍使用webservice的handler来实现webservice的安全校验。 这里,不用用户名和密码来实现安全校验,换一种方式,采用IP地址校验的方式。 这里通过一个配置文件来控制是否打开

Netty源码解析4-Handler综述

Netty中的Handler简介 Handler在Netty中,占据着非常重要的地位。Handler与Servlet中的filter很像,通过Handler可以完成通讯报文的解码编码、拦截指定的报文、 统一对日志错误进行处理、统一对请求进行计数、控制Handler执行与否。一句话,没有它做不到的只有你想不到的 Netty中的所有handler都实现自ChannelHandler接口。按照输入

#error: Building MFC application with /MD[d] (CRT dll version) requires MFC shared dll version

昨天编译文件时出现了Building MFC application with /MD[d] (CRT dll version)requires MFC shared dll version~~~~的错误。   在网上很容易找到了解决的方案,公布如下:   对着你的项目点击右键,依次选择:属性、配置属性、常规,然后右边有个“项目默认值”,下面有个MFC的使用,选择“在共享 DLL 中使

How to apply streaming in azure openai dotnet web application?

题意:"如何在 Azure OpenAI 的 .NET Web 应用程序中应用流式处理?" 问题背景: I want to create a web api backend that stream openai completion responses. "我想创建一个 Web API 后端,用于流式传输 OpenAI 的完成响应。" How can I apply the f

JAX-WS - Handler详解

一、Handler说明     Handler用于处理Soap消息,如控制Header(如隐式的添加用户信息等)     Handler分成LogicalHandler和SOAPHandler,常用为SOAPHandler;客户端先处理LogicalHeader再处理SOAPHandler,服务器反之 二、开始前的准备     1、服务端         (1)接口: @W

XCode6 中如何创建empty application工程

在XCode 6中,创建IOS工程时,移除了empty application工程模板。但有时候我们又想创建empty application工程,该怎么办呢? 具体步骤如下: 1、在IOS工程中,选择创建一个Single View Application工程。 2、创建好后,把工程目录下的Main.storyboard和LaunchScreen.xib删除,扔进废纸篓。 3、打开Info

myeclipse导入项目右键runas中没有MyEclipse Server Application,而且往tomcat部署时也不能自动定位到项目

说明myeclipse没有识别导入的工程,没有web模块就没有办法使用web的server。 检查工程目录下的.project文件中有没有如下部分: <natures><nature>com.genuitec.eclipse.ast.deploy.core.deploymentnature</nature><nature>com.genuitec.eclipse.spri

常用的两种handler调用方法

一、Handler、Thread、HandlerThread三者之间的关系如下: 1、Handler:在android中负责发送和处理消息,通过它可以实现其他支线线程与主线程之间的消息通讯。 2、Thread:Java进程中执行运算的最小单位,亦即执行处理机调度的基本单位。某一进程中一路单独运行的程序。 3、HandlerThread:一个继承自Thread的类HandlerThread。