Android Handler使用详解

2023-05-16

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

        它最根本的目的就是解决多线程并发问题,假设如果在一个Activity当中,有多个线程去更新UI,并且都没有加锁机制,就会产生更新界面错乱。如果对更新UI的操作都进行枷锁处理又会使应用性能下降,所以Android给我们提供了一套更新UI的机制,我们只需要遵循这样的机制就可以了,根本不用去关心多线程问题,多有的更新UI操作,都是在主线程的消息队列当中去轮询处理的。

handler的使用:

1、使用handler更新UI

详细参考:Android Handler使用详解之UI更新

定义handler

private Handler handler = new Handler();

定义Runnable

Runnable runnable = new Runnable() {
	public void run() {
		tetxView.setText("cx");
	}
};

启动Runnable

handler.post(runnable);

2、使用handler延时更新UI

前面相同,只有启动时有差别

handler.postDelayed(runnable, 2000);//延时2s更新UI

延时发送通知

handler.sendEmptyMessageDelayed(what, 2000);

3、使用handler消息传递

创建消息,可以创建不同类型的消息(这里arg1、arg2和obj)

Message message = new Message(); //或Message message = handler.obtainMessage();这是也可以用message.sendToTarget();发送消息
message.arg1=66;
message.arg2=33;
message.obj="cx";
handler.sendMessage(message);

接收并处理消息

private Handler handler = new Handler(){
	public void handleMessage(Message msg) {
		tetxView.setText((String) msg.obj + msg.arg1 + msg.arg2);
	};
};

4、消息延时传递sendMessageDelayed,与上面相同。

5、handler移除功能

例如:在2中的延时更新UI过程中,在延时过程中移除,则UI不再更新。

handler.removeCallbacks(runnable);

6、handler消息拦截

消息接收

private Handler handler = new Handler(new Callback() {
		
	@Override
	public boolean handleMessage(Message msg) {
		// TODO Auto-generated method stub
		Toast.makeText(getApplicationContext(), "1", 1).show();
		return true;//返回false,执行完上面的代码在执行下面的;返回true,则不再执行下面的代码
	}
}){
	@Override
	public void handleMessage(Message msg) {
		// TODO Auto-generated method stub
		Toast.makeText(getApplicationContext(), "2", 1).show();
	}
};

发送一个空消息

handler.sendEmptyMessage(1);

7、handler原理总结:

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

8、创建与子线程相关的Handler

主线程的Handler中不要执行耗时操作,否则界面会出现卡死现象。

创建主线程Handler

private Handler handler = new Handler(){
	public void handleMessage(android.os.Message msg) {
		System.out.println("UI-----------"+Thread.currentThread());
	};
};

创建子线程和子线程Handler

class MyThread extends Thread{
	public Handler handler;
	@Override
	public void run() {
		// TODO Auto-generated method stub
		Looper.prepare();//要创建handler必须先创建接收handler消息的Looper
		handler=new Handler(){
			public void handleMessage(android.os.Message msg) {
				System.out.println("-----------"+Thread.currentThread());
			};
		};
		Looper.loop();//开始循环Looper
	}
};

发送消息

MyThread thread=new MyThread();//定义子线程
thread.start();//启动子线程
thread.handler.sendEmptyMessage(1);//向子线程Handler发送消息
handler.sendEmptyMessage(1);<span style="font-family: Arial, Helvetica, sans-serif;">//向主线程Handler发送消息</span>

9、HandlerThread

在主线程的Handler中传入子线程中定义的Looper时,会出现空指针问题。

定义子线程及子线程中的Handler和Looper

class MyThread extends Thread{
	public Handler handler;
	public Looper looper;
	@Override
	public void run() {
		// TODO Auto-generated method stub
		Looper.prepare();
		looper=Looper.myLooper();
		handler=new Handler(){
			public void handleMessage(android.os.Message msg) {
				System.out.println("-----------"+Thread.currentThread());
			};
		};
		Looper.loop();
	}
};

启动子线程,创建一个Handler并传入子线程中的Looper

MyThread thread=new MyThread();
thread.start();
Handler handler=new Handler(thread.looper){
	public void handleMessage(android.os.Message msg) {
		System.out.println(msg);
	};
};

        运行程序会出现错误,thread.looper为空,因为在主线程中创建Handler时,子线程中的Looper还没有创建,这就是多线程并发的问题。修改上面代码:

HandlerThread thread=new HandlerThread("chenxu");//主要功能就是创建Looper,参数为线程名。
thread.start();
Handler handler=new Handler(thread.getLooper()){
	public void handleMessage(android.os.Message msg) {
		//可执行耗时操作
		System.out.println(">>>>>>>>>>>>" + Thread.currentThread());//与上面线程名一致
	};
};
handler.sendEmptyMessage(1);

        这时的handler就相当于是子线程中的handler,即使执行耗时操作也不会出现界面卡顿的现象。

10、主线程与子线程信息交互

import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.Message;

public class MainActivity extends Activity {
	private Handler threadHandler;
	
	//主线程handler
	Handler handler = new Handler(){
		public void handleMessage(android.os.Message msg) {
			Message message = new Message();
			//向子线程发送消息
			threadHandler.sendMessageDelayed(message, 1000);
			System.out.println("main handler");
		};
	};
	
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		
		
		HandlerThread thread = new HandlerThread("threadHandler");//主要功能就是创建Looper,参数为线程名。
		thread.start();
		//子线程handler
		threadHandler = new Handler(thread.getLooper()){
			public void handleMessage(android.os.Message msg) {
				Message message = new Message();
				//向主线程发送消息
				handler.sendMessageDelayed(message, 1000);
				System.out.println("threadHandler handler");
			};
		};
		handler.sendEmptyMessage(1);
	}
}

11、其他消息传递方法

发送消息

handler.obtainMessage(1,true).sendToTarget();
handler.obtainMessage(2,"str").sendToTarget();

接收消息

Handler handler = new Handler() {

	@Override
	public void handleMessage(Message msg) {
		super.handleMessage(msg);
			switch (msg.what) {
				case 1:
					boolean b = (Boolean)msg.obj;
				break;
				
				case 2:
					String  s = (String)msg.obj;
			break;
		}
	}
};

12、Handler黄色警告

        出现黄色警告是因为 Handler 在 Android 中用于消息的发送与异步处理,常常在 Activity 中作为一个匿名内部类来定义,此时 Handler 会隐式地持有一个外部类对象(通常是一个 Activity)的引用。当 Activity 已经被用户关闭时,由于 Handler 持有 Activity 的引用造成 Activity 无法被 GC 回收,这样容易造成内存泄露。

        解决办法:将其定义成一个静态内部类(此时不会持有外部类对象的引用),在构造方法中传入 Activity 并对 Activity 对象增加一个弱引用,这样 Activity 被用户关闭之后,即便异步消息还未处理完毕,Activity 也能够被 GC 回收,从而避免了内存泄露。

private MyHandler mHandler = new MyHandler((Activity) context);

// 发送消息
Message message = new Message();
message.what = 1;
mHandler.sendMessage(message);

// 静态内部类
static class MyHandler extends Handler {
    // 弱引用
    WeakReference weakReference;
    public MyHandler(Activity activity) {
        weakReference = new WeakReference(activity);
    }

    @Override
    public void handleMessage(Message msg) {
        switch (msg.what) {
            case 1:
                Toast.makeText((Context) weakReference.get(), "收到消息", Toast.LENGTH_SHORT).show();
                break;
            default:
                // do something...
                break;
        }
    }
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Android Handler使用详解 的相关文章

  • 如何快速自动发送FCM或APNS消息?

    我正在开发一项后端服务 通过 FCM 或 APNS 向移动应用程序发送推送通知 我想创建一个可以在一分钟内运行的自动化测试 并验证服务器是否可以成功发送通知 请注意 我不一定需要检查通知是否已送达 只需检查 FCM 或 APNS 是否已成功
  • 在包“android”中找不到属性“backgroundTint”的资源标识符

    我发现了一些视图 xml 属性 例如backgroundTint backgroundTintMode 但是当我使用它作为视图属性定义时 Eclipse 显示错误 No resource identifier found for attri
  • android中向sqlite中插入大量数据

    目前 我必须一次向我的 Android 中插入超过 100 亿条数据 然而 内存不足的问题会使程序崩溃 sqlite 插入测试非常简单 只需使用 for 循环生成 sql 插入命令并通过 开始 和 提交 进行包装 private Array
  • 在 Android Studio 中,为什么我必须在模拟器中单击“运行应用程序”两次才能启动应用程序?

    在 Android Studio 中 当我按播放按钮在 Android 模拟器上安装并运行应用程序时 大约 5 10 秒后 我在屏幕底部收到一条消息 显示 安装成功 但应用程序实际上并未运行在模拟器上 我必须再次按下播放按钮 这是非常令人沮
  • Android - 从资产中解析巨大(超大)JSON 文件的最佳方法

    我正在尝试从资产文件夹中解析一些巨大的 JSON 文件 我如何加载并添加到 RecyclerView 我想知道解析这种大文件 大约 6MB 的最佳方法是什么 以及您是否知道可以帮助我处理此文件的良好 API 我建议您使用GSON lib h
  • android xamarin 中的 reCaptcha

    我想在 Xamarin android 应用程序中实现验证码 我抓住了这个在 Android 中集成 googles reCaptcha 验证 https www c sharpcorner com article how to integ
  • Adobe 是否为其 PDF 阅读器提供 Android SDK 或 API? [关闭]

    Closed 这个问题不符合堆栈溢出指南 help closed questions 目前不接受答案 我希望能够在我们的应用程序内的视图中显示本地 PDF 文件 在 Android 4 03 下的平板电脑上运行 目前 我们将 Adob eR
  • 找不到处理意图 com.instagram.share.ADD_TO_STORY 的活动

    在我们的 React Native 应用程序中 我们试图让用户根据视图 组件中的选择直接将特定图像共享到提要或故事 当我们尝试直接使用 com instagram share ADD TO FEED 进行共享时 它以一致的方式完美运行 但是
  • 使用 Android 发送 HTTP Post 请求

    我一直在尝试从 SO 和其他网站上的大量示例中学习 但我无法弄清楚为什么我编写的示例不起作用 我正在构建一个小型概念验证应用程序 它可以识别语音并将其 文本 作为 POST 请求发送到 node js 服务器 我已确认语音识别有效 并且服务
  • 无法访问 com.google.android.gms.internal.zzbfm 的 zzbfm 类文件未找到

    我正在将我的 Android 应用程序项目从GCM to FCM 为此 我使用 Android Studio 中的 Firebase 助手工具 并遵循 Google 开发人员指南中的说明 一切都很顺利 并将我的应用程序代码更改为FCM根据助
  • 尝试将相机切换回前面但出现异常

    尝试将相机切换回前面 但出现异常 找不到 问题请检查并帮助 error 01 27 11 49 00 376 E AndroidRuntime 30767 java lang RuntimeException Unable to start
  • 是否有 ADB 命令来检查媒体是否正在播放

    我想使用 ADB 命令检查根植于终端的外部设备中是否正在播放音频 视频 我无法找到任何 ADB 命令 如果有 我尝试过 adb shell dumpsys media player 我想要一个命令来指定视频是否正在运行 您可以使用以下命令查
  • JavaMail 只获取新邮件

    我想知道是否有一种方法可以在javamail中只获取新消息 例如 在初始加载时 获取收件箱中的所有消息并存储它们 然后 每当应用程序再次加载时 仅获取新消息 而不是再次重新加载它们 javamail 可以做到这一点吗 它是如何工作的 一些背
  • 获取当前 android.intent.category.LAUNCHER 活动的实例

    我创建了一个库项目 并在多个应用程序之间共享 我实现了一个简单的会话过期功能 该功能将在一段时间后将用户踢回到登录屏幕 登录屏幕活动是我的主要活动 因此在清单中它看起来像这样
  • 如何根据 gradle 风格设置变量

    我想传递一个变量test我为每种风格设置了不同的值作为 NDK 的定义 但出于某种原因 他总是忽略了最后味道的价值 这是 build gradle apply plugin com android library def test andr
  • Android 套接字和 asynctask

    我即将开始制作一个应该充当 tcp 聊天客户端的应用程序 我一直在阅读和阅读 我得出的结论是最好 如果不需要 将我的套接字和异步任务中的阅读器 问题是我不确定从哪里开始 因为我是 Android 新手 这至少对我来说是一项艰巨的任务 但据我
  • 在activity_main.xml中注释

    我是安卓新手 据我所知 XML 中的注释与 HTML 中的注释相同 使用 形式 我想在 Android 项目的 Activity main xml 配置文件中写一些注释 但它给了我错误 值得注意的是 我使用的是 Eclipse 但目前 我直
  • 如何确定对手机号码的呼叫是本地呼叫还是 STD 或 ISD

    我正在为 Android 开发某种应用程序 但不知道如何获取被叫号码是本地或 STD 的号码的数据 即手机号码检查器等应用程序从哪里获取数据 注意 我说的是手机号码 而不是固定电话 固定电话号码 你得到的数字是字符串类型 因此 您可以获取号
  • 一次显示两条Toast消息?

    我希望在一个位置显示一条 Toast 消息 并在另一位置同时显示另一条 Toast 消息 多个 Toast 消息似乎总是按顺序排队和显示 是否可以同时显示两条消息 是否有一种解决方法至少可以提供这种外观并且不涉及扰乱活动布局 Edit 看来
  • android sdk 的位置尚未在 Windows 操作系统的首选项中设置

    在 Eclipse 上 我转到 windows gt Android SDK 和 AVD Manager 然后弹出此消息 Android sdk 的位置尚未在首选项中设置 进入首选项 在侧边栏找到 Android 然后会出现一个 SDK 位

随机推荐

  • 2022牛客多校第一场A、C、D、G、I、J

    A Villages Landlines 题意 xff1a 在一条横轴上给定 n n n 个点横坐标 x s x s
  • MATLAB矩阵操作1——删除全0列和nan列

    MATLAB矩阵操作1 删除全0列和nan列 1 对全0列或行的删除2 对全为NAN列的删除3 对存在NAN列的删除 1 对全0列或行的删除 clear a 61 0 0 0 NaN 0 NaN NaN NaN 0 0 0 5 0 0 Na
  • Spring框架的知识点

    spring框架是 一个开源的容器性质的轻量级框架 主要有三大特点 xff1a 容器 IOC 控制反转 AOP 面向切面编程 DI 依赖注入 spring框架有哪些优点 xff08 三大优点 xff09 xff08 1 xff09 容器 x
  • 6.存储系统与辅存(cache的映射方式的各种问题解析)

    存储系统体系结构 6 1 存储系统6 2 程序访问的局部性原理6 3 主存地址到cache地址的映射6 4 cache的映像方式全相联映像方式直接映像方式组相联映像方式 6 1 存储系统 衡量存储器有三个指标 xff1a 容量 速度 价格
  • 127.0.0.1是什么地址

    背景情况 xff1a 将maven项目用eclipse中的tomcat启动 xff0c 登录web网页 xff0c 使用的IP为127 0 0 1 xff0c 思考为何用的这个网址 环境配置 xff1a eclipse2020 06 xff
  • SpringMVC工作流程(超级详细版)

    目录 一 xff1a springMVC常用基本组件 二 xff1a SpringMVC执行的流程 一 xff1a springMVC常用基本组件 1 DispatcherServlet 是SpringMVC框架了里面的前端控制器 作用 x
  • ViewModel的基本用法

    本来想弄个游戏开始的倒计时 xff0c 结果用普通方法没弄出来 xff0c 后来发现需要用LifeCirle可以对页面进行实时更新 于是找了相关教材 package com example myapplication import andr
  • 【新手教程】如何在Win11上制作一个模仿MacOS的桌面?

    起因是早上蹲坑的时候偶然间在小红书上刷到一篇文章 xff0c 看了下效果图感觉还不错 xff0c 所以按照文章作者的流程来了一遍 过程中也遇到了一些小问题 xff0c 正好放假了有空就写一篇文章记录一下 先放一下效果 xff1a 1 创建下
  • Android 音频开发——Hal服务版本(五)

    nbsp nbsp nbsp nbsp nbsp nbsp nbsp 上一篇内容到 BroadcastRadioService 调用 openTuner 开启广播时调用不通的 Hal 服务 这一篇来看一下 两个服务的代码 nbsp Broa
  • 问题解决:nginx执行命令后临时目录权限为nobody

    1 问题 执行了nginx t xff0c nginx s reload xff0c 重启了nginx xff0c 发现部分POST接口请求出现了500错误 xff0c 然后 xff0c 查看Nginx错误日志 xff0c 类似如下 xff
  • 【C语言】解决n!和求1!+2!+3!+......+n!问题;求前n项和c语言

    文章解决问题 xff1a 本文章使用C语言解决 n 求一个数的阶乘 xff1b 求 1 xff01 43 2 xff01 43 3 xff01 43 4 xff01 43 n 本篇文章使用 xff23 语言实现解决方案 xff0c 分别运用
  • 最近邻插值法(nearest_neighbor)

    1 原理与应用 最近邻插值法nearest neighbor是最简单的灰度值插值 也称作零阶插值 xff0c 就是令变换后像素的灰度值等于距它最近的输入像素的灰度值 最近邻插值法可应用于图像的缩放 xff0c 因为简单的变换与计算 xff0
  • pytroch、tensorflow对比学习—专栏介绍

    pytorch tensorflow Comparative study 前言 人工智能 机器学习 深度学习已经成为当下最热门的前端科技之一 这三者其实是子 子集的关系 随着技术发展和应用的深入 xff0c 深度学习越来越重要 xff0c
  • 用python将摄氏温度转为华氏温度

  • 用Python画菱形

  • python函数的定义与使用

    求最大值 xff0c 最小值 xff0c 平均数 xff0c 其他还在突破 判断BMI值
  • 用python求最大公约数

    在此列举了三种方法 xff0c 用简单的代码实现 辗转相除法 辗转相减法 枚举法 一定要注意空格
  • python序列常用函数

    x in ls 如果x是ls的元素 xff0c 则返回Ture xff0c 否则返回False x not ls 如果x 不是ls的元素 xff0c 则返回Ture xff0c 否则返回False ls 43 lt 连接序列ls和lt 43
  • python中可变序列常用函数

    ls i 61 x 原位修改 修改ls中指定下标索引对应元素的值为x ls i j 61 lt 用可迭代序列lt中的元素替换ls中 i j 1 范围内的元素 lt中的元素可以多余也可以少于ls中要被替换的元素个数 xff0c 此时原列表的长
  • Android Handler使用详解

    handler是android给我们提供用来更新UI的一套机制 xff0c 也是一套消息处理的机制 xff0c 我们可以发送消息 xff0c 也可以通过它处理消息 它最根本的目的就是解决多线程并发问题 xff0c 假设如果在一个Activi