Android中的线程机制
Android中的好多应用,如UI更新,游戏开发,和耗时的操作都需要用到多线程的知识。而对Android中的线程机制好多人多觉得学习有困难。下面我们就一起来学习一下。
谈及Android中的线程我们会涉及到如下几个概念:
1. Handler 2. Looper 3. HandlerThread 4.Message 5. MessageQueue
下面我们由浅入深来探讨一下。我们用java多线程中很经典的例子计时器为例。我们要编写实现一个计时器,该如何编写呢?按照java中多线程的思路,我们很自然的会这样实现
代码如下:
[java] view plain copy- packagexuan.blog.hander;
- importandroid.app.Activity;
- importandroid.os.Bundle;
- importandroid.util.Log;
- importandroid.view.View;
- importandroid.widget.Button;
- importandroid.widget.TextView;
- publicclassclockActivityextendsActivity{
- /**Calledwhentheactivityisfirstcreated.*/
- privateStringTAG="clockActivity";
- privateButtonendButton;
- privateTextViewtextView;
- privateThreadclockThread;
- privateinttimer=0;
- privatebooleanisRunning=true;
- @Override
- publicvoidonCreate(BundlesavedInstanceState){
- super.onCreate(savedInstanceState);
- setContentView(R.layout.main);
- endButton=(Button)findViewById(R.id.endBtn);
- textView=(TextView)findViewById(R.id.textview);
- endButton.setOnClickListener(newView.OnClickListener(){
- @Override
- publicvoidonClick(Viewv){
- //TODOAuto-generatedmethodstub
- isRunning=false;
- }
- });
- clockThread=newThread(newRunnable(){
- @Override
- publicvoidrun(){
- //TODOAuto-generatedmethodstub
- while(isRunning){
- try{
- Thread.currentThread().sleep(1000);
- timer++;
- textView.setText("走了"+timer+"秒");
- Log.d(TAG,"time:"+timer);
- }catch(InterruptedExceptione){
- e.printStackTrace();
- }
- }
- }});
- clockThread.start();
- }
- }
我们用Thread的构造方法创建了一个线程对象,并启动了该线程,在该线程中来计算并更新textView。
然而,在Android中运行我们会发现这样会抛出异常!!
这是因为Android系统中的视图组件并不是线程安全的,在Android中UI的更新必须由主线程来完成。而上面我们违反了这一规则。
我们应该如何解决这个问题呢?我们应该让主线程负责创建,显示和更新UI控件,启动子线程,停止子线程。让子线程完成计算并向主线程发出更新UI的消息让主线程来更新UI。
如何实现子线程和主线程之间的消息传递呢?Android中为我们提供了Handler机制。
Handler是android中多线程间传递消息和计划任务的“工具”类。Handler会在多个线程中发送Message和Runnable。
andler在多线程中有两方面的应用:
1.发送消息,在不同的线程间发送消息,使用方法sendXXX();
2.计算任务,在未来执行某任务,使用方法postXXX();
一个线程发出消息后,接受消息是通过重写Handler类中的handleMessage(Message)方法实现。
Handler也可以通过postXXX()方法提交计划任务,当取出一个任务Runnable是便会执行其中的run()方法。
经过分析,我们用handler发送消息的应用修改上述代码:
[java] view plain copy- publicclassclockActivityextendsActivity{
- /**Calledwhentheactivityisfirstcreated.*/
- privateStringTAG="clockActivity";
- privateButtonendButton;
- privateTextViewtextView;
- privateThreadclockThread;
- privateinttimer=0;
- privatebooleanisRunning=true;
- privateHandlerhandler;
- @Override
- publicvoidonCreate(BundlesavedInstanceState){
- super.onCreate(savedInstanceState);
- setContentView(R.layout.main);
- endButton=(Button)findViewById(R.id.endBtn);
- textView=(TextView)findViewById(R.id.textview);
- endButton.setOnClickListener(newView.OnClickListener(){
- @Override
- publicvoidonClick(Viewv){
- //TODOAuto-generatedmethodstub
- isRunning=false;
- }
- });
- handler=newHandler(){
- @Override
- publicvoidhandleMessage(Messagemsg){
- //TODOAuto-generatedmethodstub
- super.handleMessage(msg);
- switch(msg.what){
- case0:textView.setText("走了"+timer+"秒");
- }
- }
- };
- clockThread=newThread(newRunnable(){
- @Override
- publicvoidrun(){
- //TODOAuto-generatedmethodstub
- while(isRunning){
- try{
- Thread.currentThread().sleep(1000);
- timer++;
- //textView.setText("走了"+timer+"秒");
- Messagemsg=newMessage();
- msg.obj=timer;
- msg.what=0;
- handler.sendMessage(msg);
- Log.d(TAG,"time:"+timer);
- }catch(InterruptedExceptione){
- e.printStackTrace();
- }
- }
- }});
- clockThread.start();
- }
- }
通过这种方式便实现了子线程和主线程之间的通信。当然我们也可以通过Handler的执行计划任务来完成这计时器的功能,代码如下:
- publicclassclockActivityextendsActivity{
- /**Calledwhentheactivityisfirstcreated.*/
- privateStringTAG="clockActivity";
- privateButtonendButton;
- privateTextViewtextView;
- privateinttimer=0;
- privatebooleanisRunning=true;
- privateHandlerhandler;
- @Override
- publicvoidonCreate(BundlesavedInstanceState){
- super.onCreate(savedInstanceState);
- setContentView(R.layout.main);
- endButton=(Button)findViewById(R.id.endBtn);
- textView=(TextView)findViewById(R.id.textview);
- endButton.setOnClickListener(newView.OnClickListener(){
- @Override
- publicvoidonClick(Viewv){
- //TODOAuto-generatedmethodstub
- isRunning=false;
- }
- });
- handler=newHandler();
- Runnabler=newRunnable(){
- @Override
- publicvoidrun(){
- //TODOAuto-generatedmethodstub
- if(isRunning){
- textView.setText("走了"+timer+"秒");
- timer++;
- handler.postDelayed(this,1000);//提交任务r,延时1秒执行
- }
- }
- };
- handler.postDelayed(r,1000);
- }
- }
注意运行完handler.postDelayed(r,1000);只是提交了一次任务,因此为了反复执行要在run()方法中再次提交。注意上述方法中发送任务和执行任务都是在主线程中实现的,我们并没有令启动线程。
在下一篇文章中,我们在具体分析一下Android中的消息机制。
更多相关文章
- Android(安卓)知识体系
- Android的线程使用来更新UI----Thread、Handler、Looper、TimerT
- 无废话Android之smartimageview使用、android多线程下载、显式意
- Android的消息机制
- android,handler实现两个线程通信
- Android常见问题总结(一)
- Android(安卓)Binder入门指南之Binder服务的消息循环
- Android(安卓)老生常谈之消息机制
- Android异步处理三:Handler+Looper+MessageQueue深入详解