资源预览内容
第1页 / 共33页
第2页 / 共33页
第3页 / 共33页
第4页 / 共33页
第5页 / 共33页
第6页 / 共33页
第7页 / 共33页
第8页 / 共33页
第9页 / 共33页
第10页 / 共33页
亲,该文档总共33页,到这儿已超出免费预览范围,如果喜欢就下载吧!
资源描述
本章要求:本章要求:第第1616章章线程与消息处理线程与消息处理通过实现Runnable接口创建、开启、休眠和中断线程建一个Handler对象发送并处理消息开启新线程实现电子广告牌多彩的霓虹灯简易打地鼠游戏开启一个新线程播放背景音乐整理课件整理课件16.1 多线程的实现16.2 Handler消息传递机制16.3 综合实例多彩的霓虹灯第第1616章章线程与消息处理线程与消息处理整理课件整理课件 在程序开发时,对于一些比较耗时的操作,我们通常会为其开僻一个单独的线程来执行,这样可以尽可能减少用户的等待时间。在Android中,默认情况下,所有的操作都是在主线程中进行,这个主线程负责管理与UI相关的事件,而在我们自己创建的子线程中,又不能对UI组件进行操作,因此,Android提供了消息处理传递机制来解决这一问题。本章将对Android中如何实现多线程以及如何通过线程和消息处理机制操作UI界面进行详细介绍。第第1616章章线程与消息处理线程与消息处理整理课件整理课件16.1.1 创建线程16.1.2 开启线程16.1.3 线程的休眠16.1.4 中断线程16.1 16.1 多线程的实现多线程的实现整理课件整理课件在Android中,提供了两种创建线程的方法,一种是通过Thread类的构造方法创建线程对象,并重写run()方法实现,另一种是通过实现Runnable接口实现,下面分别进行介绍。1通过Thread类的构造方法创建线程在Android中,可以使用Thread类提供的以下构造方法来创建线程。Thread(Runnable runnable)该构造方法的参数runnable,可以通过创建一个Runnable类的对象并重写其run()方法来实现,例如,要创建一个名称为thread的线程,可以使用下面的代码。Thread thread=new Thread(new Runnable()/重写run()方法Overridepublic void run() /要执行的操作);说明:在run()方法中,可以编写要执行的操作的代码,当线程被开启时,run()方法将会被执行。16.1.1 16.1.1 创建线程创建线程整理课件整理课件2通过实现Runnable接口创建线程在Android中,可以通过实现Runnable接口来创建线程。实现Runnable接口的语法格式如下:public class ClassName extends Object implements Runnable当一个类实现Runnable接口后,还需要实现其run()方法,在run()方法中,可以编写要执行的操作的代码。例如,要创建一个实现了Runnable接口的Activity,可以使用下面的代码。public class MainActivity extends Activity implements Runnable Overridepublic void onCreate(Bundle savedInstanceState) super.onCreate(savedInstanceState);setContentView(R.layout.main);Overridepublic void run() /要执行的操作整理课件整理课件创建线程对象后,还需要开启线程,线程才能执行。Thread类提供了start()方法,可以开启线程,其语法格式如下:start()例如,存在一个名称为thread的线程,如果想开启该线程,可以使用下面的代码。thread.start();/开启线程16.1.2 16.1.2 开启线程开启线程整理课件整理课件线程的休眠就是让线程暂停多长时间后再次执行。同Java一样,在Android中,也可以使用Thread类的sleep()方法,让线程休眠指定的时间。sleep()方法的语法格式如下:sleep(long time)其中的参数time用于指定休眠的时间,单位为毫秒。例如,想要线程休眠1秒钟,可以使用下面的代码。Thread.sleep(1000);16.1.3 16.1.3 线程的休眠线程的休眠整理课件整理课件当需要中断指定线程时,可以使用Thread类提供的interrupt()方法来实现。使用interrupt()方法可以向指定的线程发送一个中断请求,并将该线程标记为中断状态。interrupt()方法的语法格式如下:interrupt()例如,存在一个名称为thread的线程,如果想中断该线程,可以使用下面的代码。/省略部分代码thread.interrupt();/省略部分代码public void run() while(!Thread.currentThread().isInterrupted()/省略部分代码另外,由于当线程执行wait()、join()或者sleep()方法时,线程的中断状态将被清除,并且抛出InterruptedException,所以,如果在线程中执行了wait()、join()或者sleep()方法,那么,想要中断线程时,就需要使用16.1.4 16.1.4 中断线程中断线程整理课件整理课件一个boolean型的标记变量来记录线程的中断状态,并通过该标记变量来控制循环的执行与停止。例如,通过名称为isInterrupt的boolean型变量来标记线程的中断,关键代码如下:private boolean isInterrupt=false;/定义一下标记变量 /省略部分代码/在需要中断线程时,将isInterrupt的值设置为truepublic void run() while(!isInterrupt)/省略部分代码【例16-1】 在Eclipse中创建Android项目,通过实现Runnable接口来创建线程、开启线程、让线程休眠指定时间和中断线程。(实例位置:光盘MR源码第16章16-1)(1)修改新建项目的res/layout目录下的布局文件,将默认添加整理课件整理课件的TextView组件删除,然后在默认添加的线性布局管理器中添加两个按钮,一个用于开启线程,另一个用于中断线程。(2)打开默认添加的MainActivity,让该类实现Runnable接口,修改后的创建类的代码如下:public class MainActivity extends Activity implements Runnable (3)实现Runnable接口中的run()方法,在该方法中,判断当前线程是否被中断,如果没有被中断,则将循环变量+1,并在日志中输出循环变量的值,具体代码如下:Overridepublic void run() while (!Thread.currentThread().isInterrupted() i+;Log.i(循环变量:, String.valueOf(i);(4)在该MainActivity中,创建两个成员变量,具体代码如下:private Thread thread;/声明线程对象int i; /循环变量整理课件整理课件(5)在onCreate()方法中,首先获取布局管理器中添加的“开始”按钮,然后为该按钮添加单击事件监听器,在重写的onCreate()方法中,根据当前Activity创建一个线程,并开启该线程,具体代码如下:Button startButton = (Button) findViewById(R.id.button1); / 获取“开始”按钮startButton.setOnClickListener(new OnClickListener() Overridepublic void onClick(View v) i = 0;thread = new Thread(MainActivity.this); / 创建一个线程thread.start(); / 开启线程);(6)获取布局管理器中添加的“停止”按钮,并为其添加单击事件监听器,在重写的onCreate()方法中,如果thread对象不为空,则中断线程,并向日志中输出提示信息,具体代码如下:Button stopButton = (Button) findViewById(R.id.button2); / 获取“停止”按钮stopButton.setOnClickListener(new OnClickListener() Override整理课件整理课件public void onClick(View v) if (thread != null) thread.interrupt(); / 中断线程thread = null;Log.i(提示:, 中断线程););(7)重写MainActivity的onDestroy()方法,在该方法中,中断线程,具体代码如下:Overrideprotected void onDestroy() if (thread != null) thread.interrupt(); / 中断线程thread = null;super.onDestroy();整理课件整理课件运行本实例,在屏幕上将显示一个“开始”按钮和一个“停止”按钮,单击“开始”按钮后,将在日志面板中输出循环变量的值,单击“停止”按钮,将中断线程。日志面板的显示结果如图16-1所示。图16-1 在日志面板中输出的内容整理课件整理课件16.2.1 循环者Looper简介16.2.2 消息处理类Handler简介16.2.3 消息类Message简介16.2 Handler16.2 Handler消息传递机制消息传递机制整理课件整理课件 Android中引入Handler消息传递机制,用来实现在新创建的线程中操作UI界面,本节将对Handler消息传递机制进行介绍。16.2 Handler16.2 Handler消息传递机制消息传递机制整理课件整理课件 在介绍Lopper之前,需要先来了解另一个概念,那就是MessageQueue。在Android中,一个线程对应一个Looper对象,而一个Looper对象又对应一个MessageQueue(消息队列)。MessageQueue用于存放Message(消息),在MessageQueue中,存放的消息按照FIFO(先进先出)原则执行,由于MessageQueue被封装到Looper里面了,所以这里不对MessageQueue进行过多介绍。Looper对象用来为一个线程开启一个消息循环,用来操作MessageQueue。默认情况下Android中新创建的线程是没有开启消息循环的。但是主线程除外,系统为自动为主线程创建Looper对象,开启消息循环。所以,当我们在主线程中,应用下面的代码创建Handler对象时,就不会出错,而如果在新创建的非主线程中,应用下面的代码创建Handler对象时,将产生如图16-2所示的异常信息。Handler handler2 = new Handler();16.2.1 16.2.1 循环者循环者LooperLooper简介简介整理课件整理课件图16-2 在非主线程中创建Handler对象产生的异常信息如果想要在非主线程中,创建Handler对象,首先需要使用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 LooperThread extends Thread public Handler handler1;/ 声明一个Handler对象整理课件整理课件Overridepublic 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();/ 获取一个消息m.what=0x11;/ 设置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类提供的常用方法如表16-1所示。表16-1 Looper类提供的常用方法方 法描 述prepare()用于初始化Looperloop()调用loop()方法后,Looper线程就开始真正工作了,它会从消息队列里获取消息和处理消息myLooper()可以获取当前线程的Looper对象getThread()用于获取Looper对象所属的线程quit()用于结束Looper循环整理课件整理课件注意:写在Looper.loop()之后的代码不会被执行,这个函数内部是一个循环,当调用Handler.getLooper().quit()方法后,loop()方法才会中止,其后面的代码才能得以运行。整理课件整理课件16.2.2 16.2.2 消息处理类消息处理类HandlerHandler简介简介消息处理类(Handler)允许发送和处理Message或Rannable对象到其所在线程的MessageQueue中。Handler有以下两个主要作用:(1)将Message或Runnable应用post()方法或sendMessage()方法发送到Message Queue中,在发送时可以指定延迟时间、发送时间或者要携带的Bundle数据。当MessageQueue循环到该Message时,调用相应的Handler对象的handlerMessage()方法对其进行处理。(2)在子线程中与主线程进行通信,也就是在工作线程中与UI线程进行通信。说明:在一个线程中,只能一个Looper和MessageQueue,但是,可以有多个Handler,而且这些Handler可以共享同一个Looper和MessageQueue。Handler类提供的常用的发送和处理消息的方法如表16-2所示。表16-2 Handler类提供的常用方法整理课件整理课件方 法描 述handleMessage(Messagemsg)处理消息的方法。通常重写该方法来处理消息,在发送消息时,该方法会自动回调post(Runnabler)立即发送Runnable对象,该Runnable对象最后将被封装成Message对象postAtTime(Runnabler,longuptimeMillis)定时发送Runnable对象,该Runnable对象最后将被封装成Message对象postDelayed(Runnabler,longdelayMillis)延迟多少毫秒发送Runnable对象,该Runnable对象最后将被封装成Message对象sendEmptyMessage(intwhat)发送空消息sendMessage(Messagemsg)立即发送消息sendMessageAtTime(Messagemsg,longuptimeMillis)定时发送消息sendMessageDelayed(Messagemsg,longdelayMillis)延迟多少毫秒发送消息整理课件整理课件16.2.3 16.2.3 消息类消息类MessageMessage简介简介消息类(Message)被存放在MessageQueue中,一个MessageQueue中可以包含多个Message对象。每个Message对象可以通过Message.obtain()方法或者Handler.obtainMessage()方法获得。一个Message对象具有如表16-3所示的5个属性。表16-3 Message类的属性说明:使用Message类的属性可以携带int型和数据,如果要携带其他类型的数据,可以先将要携带的数据保存到Bundle对象中,然后通过Message类的setDate()方法将其添加到Message中。属 性类 型描 述arg1int用来存放整型数据arg2int用来存放整型数据objObject用来存放发送给接收器的Object类型的任意对象replyToMessenger用来指定此Message发送到何处的可选Messager对象whatint用于指定用户自定义的消息代码,这样接收者可以了解这个消息的信息整理课件整理课件综上所述,Message类的使用方法比较简单,只要在使用它时,注意以下3点即可:尽管Message有public的默认构造方法,但是通常情况下,需要使用Message.obtain()方法或Handler.obtainMessage()方法来从消息池中获得空消息对象,以节省资源。如果一个Message只需要携带简单的int型信息,应优先使用和属性来传递信息,这比用Bundle更省内存。尽可能使用来标识信息,以便用不同方式处理Message。整理课件整理课件 本实例要求在Android程序中实现多彩霓虹灯的效果,运行程序,将在Android窗口中显示一个多彩的霓虹灯,它可以不断的变换颜色,如图16-4所示。图16-4 多彩的霓虹灯程序开发步骤如下:(1)修改新建项目的res/layout目录下的布局文件,将默认添加的TextView组件删除,并为默认添加的线性布局管理器设置ID属性。16.3 16.3 综合实例综合实例多彩的霓虹灯多彩的霓虹灯整理课件整理课件(2)在res/values/目录下,创建一个保存颜色资源的文件,在该文件中,定义7个颜色资源,名称依次为color1、color2、color7;颜色值分别为代表赤、橙、黄、绿、青、蓝、紫所对应的颜色值。文件的关键代码如下: #ffff0000 #ffff6600 #ffffff00 #ff00ff00 #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.color4,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;/获取屏幕的高度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对象,并为其设置一个消息标识,然后发送消息,最后让线程休眠1秒钟,具体代码如下:Thread t = new Thread(new Runnable()Overridepublic void run() while (!Thread.currentThread().isInterrupted() Message m = handler.obtainMessage();/获取一个Messagem.what=0x101;/设置消息标识handler.sendMessage(m);/发送消息try Thread.sleep(new Random().nextInt(1000);/休眠1秒钟整理课件整理课件 catch (InterruptedException e) e.printStackTrace();/输出异常信息);t.start(); / 开启线程(6)创建一个Handler对象,在重写的handleMessage()方法中,为每个文本框设置背景颜色,该背景颜色从颜色数组中随机获取,具体代码如下:handler = new Handler() Overridepublic void handleMessage(Message msg) int temp=0;/临时变量if (msg.what = 0x101) for(int i=0;itv.length;i+)temp=new Random().nextInt(bgColor.length);/产生一个随机数整理课件整理课件/去掉重复的并且相邻的颜色if(index=temp)temp+;if(temp=bgColor.length)temp=0;index=temp;/为文本框设置背景tvi.setBackgroundColor(getResources().getColor(bgColorindex);super.handleMessage(msg);(7)在文件的标记中,设置android:theme属性,实现全屏显示,关键代码如下:android:theme=android:style/Theme.Black.NoTitleBar整理课件整理课件(1)在现实生活中,很多事情都是同时进行的,例如,我们可以一边看书,一边喝咖啡。而计算机则可以一边播放音乐,一边打印文档。对于这种可以同时进行的任务,我们可以用线程来表示,每个线程完成一个任务,并与其他线程同时执行,这种机制被称为多线程。(2)线程的休眠就是让线程暂停多长时间后再次执行。(3)MessageQueue用于存放Message(消息),在MessageQueue中,存放的消息按照FIFO(先进先出)原则执行,MessageQueue被封装到Looper里面了。(4)Looper对象用来为一个线程开启一个消息循环,用来操作MessageQueue。默认情况下Android中新创建的线程是没有开启消息循环的。(5)消息处理类(Handler)允许发送和处理Message或Rannable对象到其所在线程的MessageQueue中。(6)消息类(Message)被存放在MessageQueue中,一个MessageQueue中可以包含多个Message对象。每个Message对象可以通过Message.obtain()方法或者Handler.obtainMessage()方法获得。知识点提炼整理课件整理课件16-1 在Android程序中创建线程有几种方法,分别是什么?16-2 休眠线程需要用到Thread类的哪个方法?16-3 如何中断一个线程?16-4 怎样中断线程?16-5 简单描述消息传递机制用到的几个主要类。习题整理课件整理课件
网站客服QQ:2055934822
金锄头文库版权所有
经营许可证:蜀ICP备13022795号 | 川公网安备 51140202000112号