首页 理论教育 使用Handler实现异步消息处理

使用Handler实现异步消息处理

时间:2023-06-30 理论教育 版权反馈
【摘要】:子线程通过Handler给UI线程发送消息主要分为以下4个步骤。在Handler中捕获所需消息,并根据获取的消息更新界面。Handler的用法有很多,表4.4对Handler常用方法进行了总结。表4.4Handler常用方法3.View注入框架Butter KnifeButter Knife是一个专注于Android系统的View注入框架。本实验使用的另一个Material Design控件是Snackbar,其作用和Toast的作用相似。

使用Handler实现异步消息处理

1.实验目的

(1)熟悉Handler异步通信机制。

(2)了解Butter Knife的用法。

(3)了解Android Material Design风格控件的使用方法。

(4)掌握Web View控件的使用。(5)熟悉相对布局的标签。

2.Handler异步通信机制

Handler实现了Android中的异步通信机制。Android中界面事件由一个线程负责,这个线程被称为UI线程(界面线程)或主线程。Android中只允许UI线程修改Activity组件,所以在实际Android开发中,需要启动子线程通过Handler更改界面属性,如图4.11所示。

图4.11 Handler工作原理

图4.11描述了在创建Handler之前Android先创建了一个Looper对象和一个消息队列MessageQueue。当子线程通过Handler的send Message(Message msg)方法发送消息时,Android会调用入队列方法向MessageQueue中插入这条消息,Looper不断轮询调用MessageQueue的next()方法,如果发现有消息,则调用Message出队列方法读取消息,接着将消息分配给Handler的handle Message(Message msg)方法,UI线程在空闲时将消息更新至界面。

子线程通过Handler给UI线程发送消息主要分为以下4个步骤。

(1)创建一个Handler对象。

(2)从子线程中获取Message对象,通过boolean send Message(Message msg)方法发送消息。

Message对象有多种属性可以选择,其中常用的有以下几种。

•what属性:int类型,主线程用于识别子线程发来的信号量

•arg1、arg2属性:int类型,如果传递的消息类型为int型,可以赋值给arg1、arg2。

•obj属性:Object类型,如果传递的消息是String或者其他,可以赋值给obj。

(3)在Handler中捕获所需消息,并根据获取的消息更新界面。

(4)通过Handler的post()方法启动子线程。

Handler的用法有很多,表4.4对Handler常用方法进行了总结。

表4.4 Handler常用方法

3.View注入框架Butter Knife

Butter Knife是一个专注于Android系统的View注入框架。Butter Knife具有强大的View绑定和OnClick事件处理功能,可以简化代码和提升开发效率。以前的实验中总有很多find View ById()方法的调用以获取View对象和OnClick点击事件,使用Butter Knife可以略去这些步骤。Butter Knife项目的github地址为https:github.com/JakeWharton/butterknife,其中有最新版本的Butter Knife以及使用说明。Butter Knife的使用步骤如下。

(1)在Project的build.gradle文件的dependencies闭包中添加引用的插件。

(2)在App的build.gradle中添加应用程序模块和依赖。

(3)在Android Studio的settings中安装Android Butter Knife Zelezny插件,安装后重启开发环境生效。

(4)在Activity中生成获取控件和OnClick事件的代码。

4.Material Design

Material Design是由Google公司于2014年推出的全新的设计语言,Google公司表示这种设计语言旨在为手机平板电脑台式机和其他平台提供更一致、更广泛的外观和感觉,增强用户的视觉感受,使用户有更好的体验。本实验使用的是Floating ActionButton和Snackbar控件,除此之外常用的还有Drawer Layout、Navigation View、Card View等控件或布局。

使用这些控件时的共同点是必须引入com.android.support.design依赖。当然也有很多开源项目已经将相关的界面封装好,可直接引入相关依赖,按照项目说明使用。

本实验采用了Floating ActionButton控件,该控件的使用与普通控件相似,但是它具有一些特殊的XML属性,主要有以下几种。

(1)android:src:Floating Action Button中显示的图标。

(2)app:background Tint:正常的背景颜色。

(3)app:rippleColor:按下时的背景颜色。

(4)app:elevation:正常的阴影大小。

(5)app:pressed TranslationZ:按下时的阴影大小。

(6)app:layout_anchor:设置Floating ActionButton的锚点,即以哪个控件为参照设置位置。

(7)app:layout_anchor Gravity:Floating ActionButton相对于锚点的位置。

(8)app:fabSize:Floating ActionButton的大小,包括normal和mini(分别对应56 dp和40 dp)。

(9)app:border Width:边框大小,不需要边框则将该值设置为0 dp。

(10)android:clickable:一般设置为true,否则不能触发点击事件。

本实验使用的另一个Material Design控件是Snackbar,其作用和Toast的作用相似。Snackbar与Toast的区别在于:Snackbar可以滑动退出,也可以处理用户交互(点击)事件,但Toast不具备这些功能。Snackbar具有的特性包括以下几种。

(1)Snackbar会在超时后或用户触摸屏幕其他地方后自动消失。

(2)Snackbar可以在屏幕上滑动关闭。

(3)Snackbar出现时不会阻碍用户在屏幕上的输入。

(4)屏幕上同时最多只能显示一个Snackbar。

(5)如果在屏幕上已有一个Snackbar的情况下,需再显示一个Snackbar,则会先将正在显示的Snackbar隐藏,再显示新的Snackbar。

(6)可在Snackbar中添加按钮等控件,处理用户点击事件。

(7)Snackbar使用Coordinator Layout作为父容器时,可以实现右滑退出。

5.WebView控件

Android 5.0系统中内置了一款高性能Web Kit内核浏览器,在SDK中封装为Web View控件。Web View的用法与普通ImageView的用法基本相似,它还提供了大量方法执行浏览器的操作。Web View控件的常用方法如下所示。

(1)void load Url(String url):加载指定URL页面。

(2)void getSettings().setJavaScript Enabled(true):如果访问的页面中有JavaScript,则Web View须设置为支持JavaScript。

(3)void set Web View Client(new Web View Client()):如果页面中存在超链接,且希望点击链接后继续在当前Browser中显示,而不是打开Android系统自带的浏览器去响应该链接,则必须覆盖Web View的Web View Client对象。

(4)int get Height():返回当前Web View容器的高度。

(5)int get Content Height():返回整个HTML页面的高度。

(6)void getSettings().setSupportZoom(true)和void getSettings().setBuiltInZoomControls(true):打开Web View的缩放功能。利用这两个方法可以使页面大小适配当前Web View控件。

最后,要使用Web View打开页面,必须在Android Manifest.xml文件中添加网络访问权限。

6.RelativeLayout

Relative Layout是相对布局,是目前使用较多的布局,RelativeLayout容器内子组件的位置总是相对于其他组件或父容器的位置。Android在设计界面时采用了坐标系设计原理,坐标原点在屏幕的左上角,如图4.12所示,x轴的取值越向右越大,y轴的取值越向下越大。在RelativeLayout中,确定了x轴和y轴的取值就能唯一确定一个控件的位置,如果未指定x轴或y轴的取值,则默认取值为0。

最新版本的Android Studio默认的布局为Constraint Layout,使用RelativeLayout需要按如下代码修改原布局文件。

图4.12 Android坐标系

相对布局中的控件或布局的位置需要通过特殊XML属性标识。例如,Text View android:layout_above="@+id/mybutton"……表示当前Text View控件的底部在ID为mybutton的控件的上方。表4.5所示为Relative Layout常用的属性。

表4.5 RelativeLayout常用的属性

(www.xing528.com)

续表

其中,Baseline是指字母排列的基准线,假设图4.13所示为一个Button控件显示的文字,那么这个按钮的基准线即为倒数第二条线。

图4.13 Baseline(基准线)

7.实验界面与功能

本实验的主要功能是使用Handler更新进度条。点击图4.14(a)所示的界面中的Floating ActionButton,会出现图4.14(b)所示的进度条,并且开始在进度条上方加载网页。页面加载完成后进度条消失,如图4.14(c)所示,并且在Floating ActionButton下方出现Snackbar,如图4.14(d)所示,点击“确定”会弹出一个Toast。

图4.14 Handler实验主要界面

本实验的重点为如何使用Handler更新界面进度条,通过Handler更新界面是Android中广泛使用的方法。

8.实验步骤

步骤1:新建模块App11。

步骤2:修改colors.xml文件,修改color Accent的取值为“#03A9F4”,设定控件的选中效果默认采用该颜色,其他保持默认。

步骤3:将加号图片“add.png”放入mipmap目录下。

步骤4:在模块下的build.gradle文件的dependencies闭包中添加Material Design基础控件所需要的依赖。

步骤5:本实验采用Butter Knife生成控件View绑定和OnClick事件,所以需要修改Project下的builder.gradle文件,添加需要引用的插件。

步骤6:按照如下配置修改模块下的build.gradle文件,增加该模块需要引用的程序包和依赖,依赖包括Butter Knife和使用Material Design控件所需要的Support Design Library。

添加完成后在该文件上方会出现“sync”按钮,单击该按钮Gradle会自动下载相关的库至C:\Users\用户名\.gradle\caches\modules-2\files-2.1目录下供代码使用。

步骤7:安装Butter Knife插件。在联网状态下,选择“File”|“Settings”|“Plugins”|“Marketplace”,在输入框中输入“Butterknife”,在随后出现的界面中单击“Install”进行安装,如图4.15所示,安装完成后需要重新启动Android Studio才能生效。

图4.15 安装Butter Knife插件

步骤8:打开activity_main.xml文件,将该文件的布局按照本实验RelativeLayout部分所述更改为Relative Layout。参考图4.14(b)所示的界面,向界面编辑器中拖入Web View、ProgressBar(Horizontal)进度条,然后对控件做如下设置。

提示:控件属性android:visibility="invisible"和android:visibility="gone"之间的差异在于,当控件的visibility属性为invisible时,界面保留了View控件所占有的空间,而控件属性为gone时,界面不保留View控件所占有的空间。

步骤9:在Main Activity类的代码“setContent View(R.layout.activity_main);”中右击布局文件名称,依次选择“Generate…”|“Generate Butterknife Injections”,在弹出的对话框中,按图4.16所示选中4个复选框,单击“Confirm”即会生成绑定3个控件的代码和Floating ActionButton的OnClick事件,在onCreate()方法中绑定Butter Knife。

图4.16 Butter Knife绑定控件、生成OnClick事件

步骤10:定义一个Handler,用于发送异步消息至进度条,处理消息的代码后面补充。

步骤11:该类使用匿名内部类的方式定义一个线程,在线程中每1秒更新进度条进度i,并且将i赋给Message对象,放入Handler的消息队列,主线程在空闲时会从消息队列中取出该消息,更新至界面。

步骤12:当用户点击界面中的Floating ActionButton时,将进度条设置为可见,并通过Web View加载网页,网页可以和JavaScript交互,Web View可以缩放所访问的页面,如果点击页面中的超链接,仍旧在该控件中打开。最后,通过Handler.post(Runnable r)方法启动线程,并且接收和发送新线程的消息。

提示:进度条默认是不可见的,在步骤8中进度条具有属性android:visibility="invisible"。

步骤13:在updateBar Handler的handle Message(Message msg)方法中通过入参获取update Thread线程中传递来的值。如果进度小于等于100,则更新进度条的进度,并且继续运行子线程获取进度值。如果进度达到100,则设置完进度后将进度条设置为不可见,并将全局变量i置为0,最后在屏幕底部弹出Snackbar。

步骤14:使用Web View打开页面需要在Android Manifest.xml文件中添加网络访问权限。

步骤15:运行并测试App11。

知识拓展:APK签名

APK是Android设备上的安装程序,App开发完成后,一般会以APK的形式进行发布。为了保证APK的完整性、真实性等特点,一般要对APK进行签名。在调试阶段,即制作debug版本的APK时,一般以Android内置的Debug Key对APK进行签名。对外发布的版本(release版本)则需要使用Android Studio自带的APK签名工具对其进行签名。对APK进行签名的步骤如下。

步骤1:在Android Studio工具栏中选择“Generate Signed Bundle/APK…”选项,如图4.17所示,会弹出图4.18所示的“Generate Signed Bundle or APK”窗口。

图4.17 创建APK签名

图4.18 生成APK

步骤2:在“Generate Signed Bundle or APK”窗口中选择“APK”选项,单击“Next”按钮。“Android App Bundle”选项仅限于上传Google Play的应用,国内市场不支持。

步骤3:在图4.19所示的窗口中,如果之前创建过密钥则单击“Choose existing…”按钮选择已创建的密钥,如果没有创建过,则单击“Create new…”按钮创建新的密钥。

图4.19 选择/创建密钥

步骤4:在图4.20所示的窗口中选择密钥库存放路径,设置密钥库密码,输入密钥名称、密钥密码以及证书信息,单击“OK”,返回“Generate Signed Bundle or APK”窗口。

图4.20 创建新密钥

步骤5:在图4.21所示的窗口中选择步骤4中创建的密钥库,单击“Next”。

步骤6:在图4.22所示的窗口中选择“release”,签名方式同时勾选“V1(Jar Signature)”和“V2(Full APK Signature)”。如果打包签名时只勾选V1签名则不产生任何影响,但是在Android 7.0设备上不会使用更安全的验证方式;如果只勾选V2签名,则Android 7.0以下设备会显示未安装,Android 7.0以上设备使用了V2的方式验证。如果同时勾选V1和V2则所有设备都不会出现问题。

图4.21 选择密钥

图4.22 选择版本类型和签名方式

思考

(1)当进度条达到100%时线程是如何终止的?

(2)为什么调用了两次Handler的post()方法?减少一次能否达到相同的效果?

(3)尝试不使用Handler更新界面,直接设置进度条,结果和当前实验结果有什么区别。

免责声明:以上内容源自网络,版权归原作者所有,如有侵犯您的原创版权请告知,我们将尽快删除相关内容。

我要反馈