版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
1、,本章要求:,第16章线程与消息处理,Runnable接口创建、开启、休眠和中断线程 建一个Handler对象发送并处理消息 开启新线程实现电子广告牌 多彩的霓虹灯 简易打地鼠游戏 开启一个新线程播放背景音乐,16.1 多线程的实现 16.2 Handler消息传递机制 16.3 综合实例多彩的霓虹灯,第16章线程与消息处理,在程序开发时,对于一些比较耗时的操作,我们通常会为其开僻一个单独的线程来执行,这样可以尽可能减少用户的等待时间。在Android中,默认情况下,所有的操作都是在主线程中进行,这个主线程负责管理与UI相关的事件,而在我们自己创建的子线程中,又不能对UI组件进行操作,因此,A
2、ndroid提供了消息处理传递机制来解决这一问题。本章将对Android中如何实现多线程以及如何通过线程和消息处理机制操作UI界面进行详细介绍。,第16章线程与消息处理,16.1.1 创建线程 16.1.2 开启线程 16.1.3 线程的休眠 16.1.4 中断线程,16.1 多线程的实现,在Android中,提供了两种创建线程的方法,一种是通过Thread类的构造方法创建线程对象,并重写run()方法实现,另一种是通过实现Runnable接口实现,下面分别进行介绍。 1通过Thread类的构造方法创建线程 在Android中,可以使用Thread类提供的以下构造方法来创建线程。 Thread
3、(Runnable runnable) 该构造方法的参数runnable,可以通过创建一个Runnable类的对象并重写其run()方法来实现,例如,要创建一个名称为thread的线程,可以使用下面的代码。 Thread thread=new Thread(new Runnable() /重写run()方法 Override public void run() /要执行的操作 ); 说明: 在run()方法中,可以编写要执行的操作的代码,当线程被开启时,run()方法将会被执行。,16.1.1 创建线程,2通过实现Runnable接口创建线程 在Android中,可以通过实现Runnable接
4、口来创建线程。实现Runnable接口的语法格式如下: public class ClassName extends Object implements Runnable 当一个类实现Runnable接口后,还需要实现其run()方法,在run()方法中,可以编写要执行的操作的代码。 例如,要创建一个实现了Runnable接口的Activity,可以使用下面的代码。 public class MainActivity extends Activity implements Runnable Override public void onCreate(Bundle savedInstanceSt
5、ate) super.onCreate(savedInstanceState); setContentView(R.layout.main); Override public void run() /要执行的操作 ,创建线程对象后,还需要开启线程,线程才能执行。Thread类提供了start()方法,可以开启线程,其语法格式如下: start() 例如,存在一个名称为thread的线程,如果想开启该线程,可以使用下面的代码。 thread.start();/开启线程,16.1.2 开启线程,线程的休眠就是让线程暂停多长时间后再次执行。同Java一样,在Android中,也可以使用Thread类
6、的sleep()方法,让线程休眠指定的时间。sleep()方法的语法格式如下: sleep(long time) 其中的参数time用于指定休眠的时间,单位为毫秒。 例如,想要线程休眠1秒钟,可以使用下面的代码。 Thread.sleep(1000);,16.1.3 线程的休眠,当需要中断指定线程时,可以使用Thread类提供的interrupt()方法来实现。使用interrupt()方法可以向指定的线程发送一个中断请求,并将该线程标记为中断状态。interrupt()方法的语法格式如下: interrupt() 例如,存在一个名称为thread的线程,如果想中断该线程,可以使用下面的代码。
7、 /省略部分代码 errupt(); /省略部分代码 public void run() while(!Thread.currentThread().isInterrupted() /省略部分代码 另外,由于当线程执行wait()、join()或者sleep()方法时,线程的中断状态将被清除,并且抛出InterruptedException,所以,如果在线程中执行了wait()、join()或者sleep()方法,那么,想要中断线程时,就需要使用,16.1.4 中断线程,一个boolean型的标记变量来记录线程的中断状态,并通过该标记变量来控制循环的执行与停止。例如,通过名
8、称为isInterrupt的boolean型变量来标记线程的中断,关键代码如下: private boolean isInterrupt=false;/定义一下标记变量 /省略部分代码 /在需要中断线程时,将isInterrupt的值设置为true public void run() while(!isInterrupt) /省略部分代码 【例16-1】 在Eclipse中创建Android项目,通过实现Runnable接口来创建线程、开启线程、让线程休眠指定时间和中断线程。(实例位置:光盘MR源码第16章16-1) (1)修改新建项目的res/layout目录下的布局文件main.xml,将
9、默认添加,的TextView组件删除,然后在默认添加的线性布局管理器中添加两个按钮,一个用于开启线程,另一个用于中断线程。 (2)打开默认添加的MainActivity,让该类实现Runnable接口,修改后的创建类的代码如下: public class MainActivity extends Activity implements Runnable (3)实现Runnable接口中的run()方法,在该方法中,判断当前线程是否被中断,如果没有被中断,则将循环变量+1,并在日志中输出循环变量的值,具体代码如下: Override public void run() while (!Threa
10、d.currentThread().isInterrupted() i+; Log.i(循环变量:, String.valueOf(i); (4)在该MainActivity中,创建两个成员变量,具体代码如下: private Thread thread;/声明线程对象 int i; /循环变量,(5)在onCreate()方法中,首先获取布局管理器中添加的“开始”按钮,然后为该按钮添加单击事件监听器,在重写的onCreate()方法中,根据当前Activity创建一个线程,并开启该线程,具体代码如下: Button startButton = (Button) findViewById(R.
11、id.button1); / 获取“开始”按钮 startButton.setOnClickListener(new OnClickListener() Override public void onClick(View v) i = 0; thread = new Thread(MainActivity.this); / 创建一个线程 thread.start(); / 开启线程 ); (6)获取布局管理器中添加的“停止”按钮,并为其添加单击事件监听器,在重写的onCreate()方法中,如果thread对象不为空,则中断线程,并向日志中输出提示信息,具体代码如下: Button stopB
12、utton = (Button) findViewById(R.id.button2); / 获取“停止”按钮 stopButton.setOnClickListener(new OnClickListener() Override,public void onClick(View v) if (thread != null) errupt(); / 中断线程 thread = null; Log.i(提示:, 中断线程); ); (7)重写MainActivity的onDestroy()方法,在该方法中,中断线程,具体代码如下: Override protected vo
13、id onDestroy() if (thread != null) errupt(); / 中断线程 thread = null; super.onDestroy(); ,运行本实例,在屏幕上将显示一个“开始”按钮和一个“停止”按钮,单击“开始”按钮后,将在日志面板中输出循环变量的值,单击“停止”按钮,将中断线程。日志面板的显示结果如图16-1所示。 图16-1 在日志面板中输出的内容,16.2.1 循环者Looper简介 16.2.2 消息处理类Handler简介 16.2.3 消息类Message简介,16.2 Handler消息传递机制,Android中引入Hand
14、ler消息传递机制,用来实现在新创建的线程中操作UI界面,本节将对Handler消息传递机制进行介绍。,16.2 Handler消息传递机制,在介绍Lopper之前,需要先来了解另一个概念,那就是MessageQueue。在Android中,一个线程对应一个Looper对象,而一个Looper对象又对应一个MessageQueue(消息队列)。MessageQueue用于存放Message(消息),在MessageQueue中,存放的消息按照FIFO(先进先出)原则执行,由于MessageQueue被封装到Looper里面了,所以这里不对MessageQueue进行过多介绍。 Looper对象
15、用来为一个线程开启一个消息循环,用来操作MessageQueue。默认情况下Android中新创建的线程是没有开启消息循环的。但是主线程除外,系统为自动为主线程创建Looper对象,开启消息循环。所以,当我们在主线程中,应用下面的代码创建Handler对象时,就不会出错,而如果在新创建的非主线程中,应用下面的代码创建Handler对象时,将产生如图16-2所示的异常信息。 Handler handler2 = new Handler();,16.2.1 循环者Looper简介,图16-2 在非主线程中创建Handler对象产生的异常信息 如果想要在非主线程中,创建Handler对象,首先需要使
16、用Looper类的prepare()方法来初始化一个Looper对象,然后创建这个Handler对象,再使用Looper类的loop()方法,启动Looper,从消息队列里获取和处理消息。 【例16-2】 在Eclipse中创建Android项目,创建一个继承了Thread类的LooperThread,并在重写的run()方法中,创建一个Handler对象发送并处理消息。(实例位置:光盘MR源码第16章16-2) (1)创建一个继承了Thread类的LooperThread,并在重写的run()方法中,创建一个Handler对象发送并处理消息,关键代码如下: public class Loop
17、erThread extends Thread public Handler handler1;/ 声明一个Handler对象,Override public void run() super.run(); Looper.prepare();/ 初始化Looper对象 / 实例化一个Handler对象 handler1 = new Handler() public void handleMessage(Message msg) Log.i(Looper,String.valueOf(msg.what); ; Message m=handler1.obtainMessage();/ 获取一个消息
18、 m.what=0 x11;/ 设置Message的what属性的值 handler1.sendMessage(m);/ 发送消息 Looper.loop();/ 启动Looper ,(2)在MainActivity的onCreate()方法中,创建一个LooperThread线程,并开启该线程,关键代码如下: LooperThread thread=new LooperThread();/创建一个线程 thread.start();/开启线程 运行本实例,在日志面板(LogCat)中输出如图16-3所示的内容。 图16-3 在日志面板(LogCat)中输出的内容 Looper类提供的常用方法
19、如表16-1所示。 表16-1 Looper类提供的常用方法,注意: 写在Looper.loop()之后的代码不会被执行,这个函数内部是一个循环,当调用Handler.getLooper().quit()方法后,loop()方法才会中止,其后面的代码才能得以运行。,16.2.2 消息处理类Handler简介,消息处理类(Handler)允许发送和处理Message或Rannable对象到其所在线程的MessageQueue中。Handler有以下两个主要作用: (1)将Message或Runnable应用post()方法或sendMessage()方法发送到Message Queue中,在发送
20、时可以指定延迟时间、发送时间或者要携带的Bundle数据。当MessageQueue循环到该Message时,调用相应的Handler对象的handlerMessage()方法对其进行处理。 (2)在子线程中与主线程进行通信,也就是在工作线程中与UI线程进行通信。 说明: 在一个线程中,只能一个Looper和MessageQueue,但是,可以有多个Handler,而且这些Handler可以共享同一个Looper和MessageQueue。 Handler类提供的常用的发送和处理消息的方法如表16-2所示。 表16-2 Handler类提供的常用方法,16.2.3 消息类Message简介,消
21、息类(Message)被存放在MessageQueue中,一个MessageQueue中可以包含多个Message对象。每个Message对象可以通过Message.obtain()方法或者Handler.obtainMessage()方法获得。一个Message对象具有如表16-3所示的5个属性。 表16-3 Message类的属性 说明: 使用Message类的属性可以携带int型和数据,如果要携带其他类型的数据,可以先将要携带的数据保存到Bundle对象中,然后通过Message类的setDate()方法将其添加到Message中。,综上所述,Message类的使用方法比较简单,只要在使
22、用它时,注意以下3点即可: 尽管Message有public的默认构造方法,但是通常情况下,需要使用Message.obtain()方法或Handler.obtainMessage()方法来从消息池中获得空消息对象,以节省资源。 如果一个Message只需要携带简单的int型信息,应优先使用Message.arg1和Message.arg2属性来传递信息,这比用Bundle更省内存。 尽可能使用Message.what来标识信息,以便用不同方式处理Message。,本实例要求在Android程序中实现多彩霓虹灯的效果,运行程序,将在Android窗口中显示一个多彩的霓虹灯,它可以不断的变换颜色
23、,如图16-4所示。 图16-4 多彩的霓虹灯 程序开发步骤如下: (1)修改新建项目的res/layout目录下的布局文件main.xml,将默认添加的TextView组件删除,并为默认添加的线性布局管理器设置ID属性。,16.3 综合实例多彩的霓虹灯,(2)在res/values/目录下,创建一个保存颜色资源的colors.xml文件,在该文件中,定义7个颜色资源,名称依次为color1、color2、color7;颜色值分别为代表赤、橙、黄、绿、青、蓝、紫所对应的颜色值。colors.xml文件的关键代码如下: #ffff0000 #ffff6600 #ffffff00 #ff00ff0
24、0 #ff00ffff #ff0000ff #ff6600ff (3)在该MainActivity中,声明程序中所需的成员变量,具体代码如下: private Handler handler;/创建Handler对象 private static LinearLayout linearLayout; / 整体布局 public static TextView tv = new TextView14; /,TextView数组 /使用颜色资源 int bgColor=new intR.color.color1,R.color.color2,R.color.color3, R.color.colo
25、r4,R.color.color5,R.color.color6,R.color.color7; private int index=0;/当前颜色值 (4)在MainActivity的onCreate()方法中,首先获取线程布局管理器,然后获取屏幕的高度,接下来再通过一个for循环创建14个文本框组件,并添加到线性布局管理器中,具体代码如下: linearLayout=(LinearLayout)findViewById(R.id.ll); /获取线性布局管理器 int height=this.getResources().getDisplayMetrics().heightPixels;/
26、获取屏幕的高度 for(int i=0;itv.length;i+) tvi=new TextView(this);/创建一个文本框对象 tvi.setWidth(this.getResources().getDisplayMetrics().widthPixels); /设置文本框宽度 tvi.setHeight(height/tv.length);,/为设置文本框高度 linearLayout.addView(tvi);/将TextView组件添加到线性布局管理器中 (5)创建并开启一个新线程,在重写的run()方法中,实现一个循环,在该循环中,首先获取一个Message对象,并为其设置一
27、个消息标识,然后发送消息,最后让线程休眠1秒钟,具体代码如下: Thread t = new Thread(new Runnable() Override public void run() while (!Thread.currentThread().isInterrupted() Message m = handler.obtainMessage();/获取一个Message m.what=0 x101;/设置消息标识 handler.sendMessage(m);/发送消息 try Thread.sleep(new Random().nextInt(1000);/休眠1秒钟, catch
28、 (InterruptedException e) e.printStackTrace();/输出异常信息 ); t.start(); / 开启线程 (6)创建一个Handler对象,在重写的handleMessage()方法中,为每个文本框设置背景颜色,该背景颜色从颜色数组中随机获取,具体代码如下: handler = new Handler() Override public void handleMessage(Message msg) int temp=0;/临时变量 if (msg.what = 0 x101) for(int i=0;itv.length;i+) temp=new Random().nextInt(bgColor.lengt
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 足癣患者的心理支持与教育
- 2026年医疗数字孪生与人工智能融合
- 2026年企业绿色供应链管理培训教材
- 2026年公司薪酬等级体系设计与宽带调整
- 麦粒肿的用药安全指导
- 2026年慢性阻塞性肺疾病呼吸康复操
- 2026年既有建筑绿色改造与认证经验
- 2026年农村灾后重建房屋节能技术应用
- 2026年药品采购价格谈判与议价管理流程
- 2026年健身房年度教练专业与私教销售培训
- (高清版)DZT 0064.2-2021 地下水质分析方法 第2部分:水样的采集和保存
- 职业技能标准&挖掘铲运和桩工机械司机
- 车辆防火和防化学伤害安全技术要求
- 《序数效用理论课程》课件
- 童年二声部合唱简谱说唱版-
- 害虫管理的策略及技术和方法
- 广东省普通高中学生档案
- 社工考试综合能力笔记(中级)
- GB/T 22892-2008足球
- 养老保险欠费补缴注销申报表
- CNAS质量体系文件(质量手册程序文件)
评论
0/150
提交评论