1.Handler简介

    handler是Android系统封装的用于线程更新UI,消息处理的机制。

[说明]

查看Android Framework源码可以看到,常见的Activity的生命周期onCreate(), onStart(), onResume(), onPause(), onStop(), onDestroy()都是通过handler发送不同Message,AMS(Activity Manager Service)通过Handler向ActivityThread发送消息,在ActivityThread中执行不同的Activity的周期。


2.Handler的用法

// Google文档的地址http://developer.android.com/reference/android/os/Handler.html// Google对Handler的介绍A Handler allows you to send and process Message and Runnable objects associated with a thread's MessageQueue. Each Handler instance is associated with a single thread and that thread's message queue. When you create a new Handler, it is bound to the thread / message queue of the thread that is creating it -- from that point on, it will deliver messages and runnables to that message queue and execute them as they come out of the message queue.

[说明]

查看Google文档可以看出,Handler允许我们绑定(associate with)一个线程的MessageQueue,并通过该handler向该线程发送Message或者Runnable对象,一个Handler绑定了一个线程以及这个线程的MessageQueue,当你创建一个Handler的时候,该Handler就会和Thread以及该Thread的MessageQueue绑定。

首先,下面的程序,在子线程中更新UI:

public class MainActivity extends Activity{TextView tv;@Overrideprotected void onCreate(Bundle savedInstanceState){super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);tv = (TextView) findViewById(R.id.tv);new Thread(){public void run(){try{Thread.sleep(1000);} catch (InterruptedException e){e.printStackTrace();}tv.setText("update UI");};}.start();}}

运行之后,程序奔溃,logcat中打印信息:


[说明]

上面信息的主要内容是,不允许在子线程中更新UI线程,Android自身设定的机制则是只能在子线程中处理耗时的操作,处理完毕之后,在UIThread中更新UI,而子线程是不能更新UI的。


Handler主要提供了下面API来实现子线程与UIThread之间的通信问题:

  • sendMessage
  • sendMessageDelayed
  • post(Runnable)
  • postDelayed(Runnable, long)
(1). 使用sendMessage进行线程通信:
public class MainActivity extends Activity{@SuppressLint("HandlerLeak")Handler handler = new Handler(){public void handleMessage(android.os.Message msg){if (msg.what == 0x1){tv.setText("update UI");}};};TextView tv;@Overrideprotected void onCreate(Bundle savedInstanceState){super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);tv = (TextView) findViewById(R.id.tv);new Thread(){public void run(){try{Thread.sleep(1000);} catch (InterruptedException e){e.printStackTrace();}handler.sendEmptyMessage(0x1);};}.start();}}
sendMessageDelayed(Message, long)是延迟long毫秒之后,再发送Message。
(2).post(Runnable)
public class MainActivity extends Activity{@SuppressLint("HandlerLeak")Handler handler = new Handler(){public void handleMessage(android.os.Message msg){};};TextView tv;@Overrideprotected void onCreate(Bundle savedInstanceState){super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);tv = (TextView) findViewById(R.id.tv);new Thread(){public void run(){try{Thread.sleep(1000);} catch (InterruptedException e){e.printStackTrace();}handler.post(new Runnable(){@Overridepublic void run(){tv.setText("update UI");}});};}.start();}}

  下面利用Handler实现一个简单的图片轮换的功能,每隔1s循环替换ImageView显示的图片:
public class MainActivity extends Activity{Handler handler = new Handler();ImageView img;int[] images = // 存放循环播放的图片{ R.drawable.weather_0, R.drawable.weather_1, R.drawable.weather_2, R.drawable.weather_3, R.drawable.weather_4 };private int imgCount = images.length;private int index = 0;private long delayMillis = 1000L; // 每隔1s循环一次@Overrideprotected void onCreate(Bundle savedInstanceState){super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);img = (ImageView) findViewById(R.id.img);handler.post(imgRunnable);}private Runnable imgRunnable = new Runnable(){public void run(){img.setBackgroundResource(images[index % imgCount]);index++;handler.postDelayed(imgRunnable, delayMillis);}};}

对应的xml文件中只有一个
    




[注意] 若要终止上面的循环,可以使用下面的方法:

handler.removeCallbacks(imgRunnable);


下面使用Handler演示消息截获的用法: [说明] Handler的创建有一个接受一个Handler.Callback参数的构造方法,此方法内部的handlerMessage(Message msg)方法有boolean类型的返回值,return true可以实现类似消息截获的效果:
public class SecondActivity extends Activity{@SuppressLint("HandlerLeak")Handler handler = new Handler(new Handler.Callback(){@Overridepublic boolean handleMessage(Message msg){if (msg.what == 0x1){Log.v(LOG, "返回true,消息被截获");return true;} else if (msg.what == 0x2){Log.v(LOG, "返回false,不截获");return false;}return false;}}){@Overridepublic void handleMessage(Message msg){Log.v(LOG, "收到消息....");}};Button btn1, btn2;private final String LOG = "SecondActivity";@Overrideprotected void onCreate(Bundle savedInstanceState){super.onCreate(savedInstanceState);setContentView(R.layout.activity_second);btn1 = (Button) findViewById(R.id.btn1);btn1.setOnClickListener(new OnClickListener(){@Overridepublic void onClick(View v){handler.sendEmptyMessage(0x1);}});btn2 = (Button) findViewById(R.id.btn2);btn2.setOnClickListener(new OnClickListener(){@Overridepublic void onClick(View v){handler.sendEmptyMessage(0x2);}});}}

界面效果如下:


点击“消息截获”按键,会向handler对象传递0x1的Message,在Handler.Callback的boolean handlerMessage()方法中返回true,此时该Message不会再被void handlerMessage()方法接收到:

相反,当点击“消息不截获”按键,会发送0x2消息,Handler.Callback的boolean handlerMessage()返回false,此时消息仍然会被void handlerMessage()方法所获的:

查看Handler的源码可以看到,消息的传递是通过dispatchMessage(Message msg)来发送的,而dispatchMessage函数如下:

当使用了Handler包含Handler.Callback参数的构造函数时,mCallback != null,此时会执行mCallback.handlerMessage(msg)方法,若此方法返回true,则直接执行return返回,不再执行下面的handlerMessage(msg),若mCallback.handlerMessage(msg)返回false,mCallback.handlerMessage(msg)方法被调用之后,还会继续调用handlerMessage(msg)方法。

更多相关文章

  1. Android——GT库发布
  2. [Android]文件操作模式与SDCard读写访问
  3. Android中的SystemClock类
  4. Android周笔记(9.8-14)(持续更新)
  5. android tab之间滑动切换界面功能
  6. android通过代码控制ListView上下滚动
  7. Android(安卓)Service之串行化Service:IntentService(系列3)
  8. Android使用libgdx实现模拟方向键控制角色移动的方法
  9. Android(安卓)UI 之 ListView

随机推荐

  1. Android从右到左的布局(RTL Layout)
  2. Android(安卓)Studio 入的坑
  3. Android 图片显示与屏幕适配的问题
  4. Android 沉浸式状态栏,别搞那么麻烦
  5. Android到Flutter过度如丝般顺滑(二)
  6. Android了解四大基本组件
  7. Android TextView部分文字实现点击事件
  8. Android中退出程序的提示框及完全退出
  9. Android消息提示:AlertDialog、Toast、Not
  10. 快速使用Android BaseRecyclerViewAdapte