android中Handler的初步认识(一)

说实话,之前在java开发的时候,很少涉及多线程的东西。由于开发的项目体量比较小,技术也比较差,所以更多的考虑的是功能,很少对并发做优化

 

如今借着学习Android的机会,希望可以对多线程的知识有一个更好更全面地认识。哎,感觉自己技术基础还是太差,好好加油吧

 

首先,安卓使用的时单线程模型:

    当一个程序第一次启动时,Android会同时启动一个对应的主线程(Main Thread),主线程主要负责处理与UI相关的事件,如:用户的按键事件,用户接触屏幕的事件以及屏幕绘图事件,并把相关的事件分发到对应的组件进行处理。所以主线程通常又被叫做UI线程。

    在开发Android应用时必须遵守单线程模型的原则: Android UI操作并不是线程安全的并且这些操作必须在UI线程中执行。

           如果在非UI线程中直接操作UI线程,会抛出android.view.ViewRoot$CalledFromWrongThreadException:Only  the original thread that created a view hierarchy can touch itsviews,这与普通的java程序不同。

    由于UI线程负责事件的监听和绘图,因此,必须保证UI线程能够随时响应用户的需求,UI线程里的操作应该向中断事件那样短小,费时的操作(如网络连接)需要另开线程,否则,如果UI线程超过5s没有响应用户请求,会弹出对话框提醒用户终止应用程序。

    如果在新开的线程中需要对UI进行设定,就可能违反单线程模型,因此android采用一种复杂的Message Queue机制保证线程间通信。

    以上内容摘自 http://www.cnblogs.com/nio-nio/archive/2012/07/23/2604900.html,是我在网上看到的相 对比较容易理解的说明。读完以上这几段话之后,我对安卓单线程模式的理解:如果你要对UI进行操作那这些操作应该都放到主线程中;如果你要处理一些业务逻 辑或者其它的比较费时的操作,那就把这些操作放到子线程中。那因为大多数的UI更新都是基于业务逻辑的判断,如何让处理逻辑的子线程和处理UI的主线程通 信呢,这就需要用到Handler


Handler是干什么的: 


        Handler可以分发Message对象和Runnable对象到主线程中,每个Handler实例,都会绑定到创建他的线程中(一般是位于主线程),它有两个作用:  (1): 安排消息或Runnable 在某个主线程中某个地方执行, (2)安排一个动作在不同的线程中执行。

关于Handler的使用,我们首先来看一个简单例子:

        我们假设有这么一个需求:我们需要在程序中点击一个开始按钮,然后我们的程序会在后台启动一个定时任务(每隔一秒打印一个语句)。另外,我们还需要一个取消按钮,点击它终止后台的定时任务.

       我们先在界面中加入两个按钮,一个开始,一个取消。接下来是activity

 

[java] view plaincopyprint?在CODE上查看代码片派生到我的代码片

  1. package com.example.hander1;  

  2.   

  3. import java.util.Date;  

  4. import android.app.Activity;  

  5. import android.os.Bundle;  

  6. import android.os.Handler;  

  7. import android.util.Log;  

  8. import android.view.View;  

  9. import android.view.View.OnClickListener;  

  10. import android.widget.Button;  

  11.   

  12. public class MainActivity extends Activity {  

  13.   

  14.     Button startButton = null;  

  15.     Button stopButton = null;  

  16.     Handler handler = new Handler();  

  17.       

  18.     protected void onCreate(Bundle savedInstanceState) {  

  19.         super.onCreate(savedInstanceState);  

  20.         setContentView(R.layout.activity_main);  

  21.           

  22.         startButton = (Button) findViewById(R.id.startButton);  

  23.         stopButton = (Button) findViewById(R.id.stopButton);  

  24.           

  25.         //为button绑定onclicklistener  

  26.         startButton.setOnClickListener(new ButtonOnclikListener());  

  27.         stopButton.setOnClickListener(new ButtonOnclikListener());  

  28.     }  

  29.       

  30.     Runnable going = new Runnable() {     

  31.         @Override  

  32.         public void run() {  

  33.             //线程每次执行,打印日志  

  34.             Log.i("run", "going  "+new Date().getSeconds());  

  35.             //延时一秒钟后,再次将线程加入队列中  

  36.             handler.postDelayed(going, 1000);  

  37.         }  

  38.     };  

  39.   

  40.     class ButtonOnclikListener implements OnClickListener{  

  41.   

  42.         @Override  

  43.         public void onClick(View v) {     

  44.             switch(v.getId()){  

  45.             case R.id.startButton:  

  46.                 begin();  

  47.                 break;  

  48.             case R.id.stopButton:  

  49.                 stop();  

  50.                 break;  

  51.             default:  

  52.                 break;  

  53.             }  

  54.         }  

  55.           

  56.     }  

  57.       

  58.     //该方法将going添加到message queue中   

  59.     void begin(){  

  60.         handler.post(going);  

  61.     }  

  62.       

  63.     //从message queue中移除going  

  64.     void stop(){  

  65.         handler.removeCallbacks(going);  

  66.     }  

  67.   

  68. }  

 

下面是运行结果,程序启动后是这样

      当我点击启动按钮后,后台每秒中打印一条语句

     当我点击取消按钮后,后台不再打印语句

对于这个程序的运行过程我是这样理解的:

      1、当我点击启动按钮时:调用handler.post(going); 

handler的post方法说明是这样的:Causes the Runnable  r to be added to the message queue. The runnable will be run on the  thread to which this handler is attached.

         也就是说,当我调用了handler.post(going);这个方法之后,handler会将我实现的Runnable对象加入到message  queue中,系统会根据message  queue来执行。后面一句很重要,runnable会在当前handler所属的那个线程中执行,也就是说我的going会在程序的主线程中执行,而不 是新开启的其它线程。

·      2、在going的run方法中,我调用了handler.postDelayed(going, 1000);

     postDelayed这个方法和前面的post方法类似,只不过第二个参数的作用是让我的going延迟一秒钟执行。

     这样其实就形成了一个死循环(我没有规定跳出的条件),程序在我点击启动之后,每隔一秒钟会在message queue中加入执行going的内容。

3、当我点击取消按钮时:调用handler.removeCallbacks(going);

       虽在我在上面的写法中形成了一个死循环,但是我可以通过handler.removeCallbacks(going)这个方法,将message  queue这个队列中的going去掉,这样就不再执行going了。而且根据这个方法源码中的注释:Remove any pending posts  of Runnable r that are in the message queue. 应该是会把message  queue中所有未执行going全部去掉。

这个程序虽然很简单,但是我在一次看到的时候,仍然陷入了误区。由于没有仔细阅读 API,我刚开始以为handler.post()这个方法会新开启一个线程。后来看到API的时候才明白原来这个程序,只有一个主线程,只不过是通过 handler将实现的Runnable 对象加入到message queue中执行的。



转载于:https://my.oschina.net/tslin/blog/370201

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值