Handler 作用:主要接受子线程发送的数据, 并用此数据配合主线程更新UI.

解释: 

当应用程序启动时,Android首先会开启一个主线程 (也就是UI线程) , 主线程为管理界面中的UI控件,进行事件分发, 比如说, 你要是点击一个 Button ,Android会分发事件到Button上,来响应你的操作。 如果此时需要一个耗时的操作,例如: 联网读取数据, 或者读取本地较大的一个文件的时候,你不能把这些操作放在主线程中,,如果你放在主线程中的话,界面会出现假死现象, 如果5秒钟还没有完成的话,会收到Android系统的一个错误提示 "强制关闭". 

这个时候我们需要把这些耗时的操作,放在一个子线程中,因为子线程涉及到UI更新,Android主线程是线程不安全的,也就是说,更新UI只能在主线程中更新,子线程中操作是危险的. 会出现如下异常:


即:只有创建该控件的线程才可以操作该控件


这个时候,Handler就出现了 。由于Handler运行在主线程中(UI线程中), 它与子线程可以通过Message对象来传递数据, 这个时候,Handler就承担着接受子线程传过来的Message对象,(里面包含数据) , 把这些消息放入主线程队列中,配合主线程进行更新UI。

例子如下:

1》布局文件:activity_main.xml

                        

效果如下:


2》MainActivity.java代码

代码中有很详细的备注

package com.cxc.handlerdemo;import android.app.Activity;import android.os.Bundle;import android.view.Menu;import android.view.MenuItem;public class MainActivity extends Activity {@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);}@Overridepublic boolean onCreateOptionsMenu(Menu menu) {// Inflate the menu; this adds items to the action bar if it is present.getMenuInflater().inflate(R.menu.main, menu);return true;}@Overridepublic boolean onOptionsItemSelected(MenuItem item) {// Handle action bar item clicks here. The action bar will// automatically handle clicks on the Home/Up button, so long// as you specify a parent activity in AndroidManifest.xml.int id = item.getItemId();if (id == R.id.action_settings) {return true;}return super.onOptionsItemSelected(item);}}

运行的结果为:

package com.cxc.threadandhandler;import android.app.Activity;import android.os.Bundle;import android.os.Handler;import android.os.HandlerThread;import android.os.Looper;import android.os.Message;import android.util.Log;import android.view.Menu;import android.view.MenuItem;import android.view.View;import android.view.View.OnClickListener;import android.widget.Button;import android.widget.TextView;public class MainActivity extends Activity {private static final String TAG = "com.cxc.threadandhandler.mainactivity";private static final int MESSAGE_KEY = 1001;private TextView show_info_tv;private Button start_task_bt;private Handler myHandler = new Handler() {@Overridepublic void handleMessage(Message msg) {// TODO Auto-generated method stubsuper.handleMessage(msg);if (msg.what == MESSAGE_KEY) {// 接收消息并更新UILog.d(TAG, "--thread:" + Thread.currentThread().getId()+"--reciver:"+msg.obj.toString());show_info_tv.setText(msg.obj.toString());}}};@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);Log.d(TAG, "---main---" + Thread.currentThread().getId());Log.d(TAG, "---onCreate---");initViews();}private void initViews() {Log.d(TAG, "---initViews---");show_info_tv = (TextView) findViewById(R.id.show_info_tv);start_task_bt = (Button) findViewById(R.id.start_task_bt);start_task_bt.setOnClickListener(myButtonClickListener);}OnClickListener myButtonClickListener = new OnClickListener() {@Overridepublic void onClick(View v) {// TODO Auto-generated method stubswitch (v.getId()) {case R.id.start_task_bt:// to-do// 将耗时的操作移到子线程中Log.d(TAG, "---Start Task Button Click---");BackgroundThread backgroundThread = new BackgroundThread();new Thread(backgroundThread).start();// 启动后台线程,以处理耗时任务break;default:break;}}};class BackgroundThread implements Runnable {public BackgroundThread() {// TODO Auto-generated constructor stub}@Overridepublic void run() {// TODO Auto-generated method stubLog.d(TAG, "-----work thread ---" + Thread.currentThread().getId());backgroundThreadProcessing();}// 在后台执行一些处理的方法---耗时操作private void backgroundThreadProcessing() {// to-do 耗时操作Log.d(TAG, "-----work thread -backgroundThreadProcessing ---"+ Thread.currentThread().getId());for (int i = 0; i < 10; i++) {String text = show_info_tv.getText().toString();text += ("#" + i);Message msg = new Message();msg.what = MESSAGE_KEY;//用于区分不同的消息msg.obj = text;//消息内容Log.d(TAG, "--thread:" + Thread.currentThread().getId()+"--send:"+text);myHandler.sendMessage(msg);//发送消息// 当前线程(后台子线程)休眠1000mstry {Thread.sleep(1000);} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}}}}}

运行结果:


可以看到主线程(UI线程)已经接收到了子线程发送过来的数据。

这一点也可以从程序的Log看出来

06-02 16:25:19.299: D/com.cxc.threadandhandler.mainactivity(10304): ---main---106-02 16:25:19.299: D/com.cxc.threadandhandler.mainactivity(10304): ---onCreate---06-02 16:25:19.299: D/com.cxc.threadandhandler.mainactivity(10304): ---initViews---06-02 16:25:30.259: D/com.cxc.threadandhandler.mainactivity(10304): ---Start Task Button Click---06-02 16:25:30.259: D/com.cxc.threadandhandler.mainactivity(10304): -----work thread ---634606-02 16:25:30.259: D/com.cxc.threadandhandler.mainactivity(10304): -----work thread -backgroundThreadProcessing ---634606-02 16:25:30.259: D/com.cxc.threadandhandler.mainactivity(10304): --thread:6346--send:显示后台任务情况#006-02 16:25:30.259: D/com.cxc.threadandhandler.mainactivity(10304): --thread:1--reciver:显示后台任务情况#006-02 16:25:31.259: D/com.cxc.threadandhandler.mainactivity(10304): --thread:6346--send:显示后台任务情况#0#106-02 16:25:31.259: D/com.cxc.threadandhandler.mainactivity(10304): --thread:1--reciver:显示后台任务情况#0#106-02 16:25:32.264: D/com.cxc.threadandhandler.mainactivity(10304): --thread:6346--send:显示后台任务情况#0#1#206-02 16:25:32.264: D/com.cxc.threadandhandler.mainactivity(10304): --thread:1--reciver:显示后台任务情况#0#1#206-02 16:25:33.264: D/com.cxc.threadandhandler.mainactivity(10304): --thread:6346--send:显示后台任务情况#0#1#2#306-02 16:25:33.264: D/com.cxc.threadandhandler.mainactivity(10304): --thread:1--reciver:显示后台任务情况#0#1#2#306-02 16:25:34.264: D/com.cxc.threadandhandler.mainactivity(10304): --thread:6346--send:显示后台任务情况#0#1#2#3#406-02 16:25:34.264: D/com.cxc.threadandhandler.mainactivity(10304): --thread:1--reciver:显示后台任务情况#0#1#2#3#406-02 16:25:35.264: D/com.cxc.threadandhandler.mainactivity(10304): --thread:6346--send:显示后台任务情况#0#1#2#3#4#506-02 16:25:35.264: D/com.cxc.threadandhandler.mainactivity(10304): --thread:1--reciver:显示后台任务情况#0#1#2#3#4#506-02 16:25:36.264: D/com.cxc.threadandhandler.mainactivity(10304): --thread:6346--send:显示后台任务情况#0#1#2#3#4#5#606-02 16:25:36.264: D/com.cxc.threadandhandler.mainactivity(10304): --thread:1--reciver:显示后台任务情况#0#1#2#3#4#5#606-02 16:25:37.269: D/com.cxc.threadandhandler.mainactivity(10304): --thread:6346--send:显示后台任务情况#0#1#2#3#4#5#6#706-02 16:25:37.269: D/com.cxc.threadandhandler.mainactivity(10304): --thread:1--reciver:显示后台任务情况#0#1#2#3#4#5#6#706-02 16:25:38.269: D/com.cxc.threadandhandler.mainactivity(10304): --thread:6346--send:显示后台任务情况#0#1#2#3#4#5#6#7#806-02 16:25:38.269: D/com.cxc.threadandhandler.mainactivity(10304): --thread:1--reciver:显示后台任务情况#0#1#2#3#4#5#6#7#806-02 16:25:39.269: D/com.cxc.threadandhandler.mainactivity(10304): --thread:6346--send:显示后台任务情况#0#1#2#3#4#5#6#7#8#906-02 16:25:39.269: D/com.cxc.threadandhandler.mainactivity(10304): --thread:1--reciver:显示后台任务情况#0#1#2#3#4#5#6#7#8#9



可以看出,主线程(UI线程)的线程ID为1,而我们自己启动的线程ID为6346,可以说明它们确实不在一个线程中。

关于线程的相关知识可以参考:Java线程之两种方法Runnable和Thread的区别

更多相关文章

  1. 如何在后台运行Linux命令?
  2. Android录屏单帧获取方案
  3. Android线程安全
  4. Android面试题之二(中)
  5. Android艺术探索读书笔记 -IPC机制
  6. 理解UI线程——swt, Android, 和Swing的UI机理
  7. android离开一个页面时关闭子线程
  8. iOS到Android到底有多远
  9. Android(安卓)重要基本开发规范

随机推荐

  1. Linux下Android(安卓)ADB驱动安装详解
  2. JNI 入门
  3. 8. android Tab 选项卡控件
  4. Android Service AIDL 远程调用服务 【简
  5. Android Debug certificate expired
  6. android实现服务器图片本地缓存
  7. Android EditText 光标控制,颜色修改,显示
  8. 利用 Android Keystore 系统 加密存储和
  9. Android笔记1
  10. Android TextView全属性