本文内容

  • 环境
  • 演示 Handler 消息处理
  • 参考资料

Handler 有两个主要作用或者说是步骤:发送消息和处理消息。在新启动的线程中发送消息,在主线程中获取、并处理消息。Android 平台只允许UI线程修改 Activity 里的UI组件。

本文只给出核心代码,如果你是初学者,可以下载本文后面的源代码。

环境


  • Windows 2008 R2 64 位
  • Eclipse ADT V22.6.2,Android 4.4.3
  • 三星 SM-G3508,Android OS 4.1

演示 Handler 消息处理


演示主程序如下图 1 所示,有 4 个演示。

图 1 主程序

主程序 XML 页面,只是四个按钮,并为它们添加相应事件,显示 4 个演示的 Activity 而已,略,核心代码如下所示:

public class MainActivity extends Activity {
    Handler handler = new Handler();
    Intent intent = null;
 
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
 
        findViewById(R.id.btn1).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                intent = new Intent(MainActivity.this, Handler1Demo.class);
                startActivity(intent);
            }
        });
 
        findViewById(R.id.btn2).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                intent = new Intent(MainActivity.this, Handler2Demo.class);
                startActivity(intent);
            }
        });
 
        findViewById(R.id.btn3).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                intent = new Intent(MainActivity.this, Handler3Demo.class);
                startActivity(intent);
            }
        });
 
        findViewById(R.id.btn4).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                intent = new Intent(MainActivity.this, Handler4Demo.class);
                startActivity(intent);
            }
        });
    }
}

.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, "Courier New", courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }

加入和移除 Handler 到主线程

“加入”和“移除” Handler 到主线程,点击“开始”时,每隔1秒,将 Handler 加入到主线程队列中,执行 Runnable 中 run 方法内的代码,显示当前时间;点击“结束”时,从主线程队列移除  Handler。

图 2 加入和移除 Handler 到主线程

XML 页面包含三个组件:两个 Button,一个 TextView(TextView 在 ScrollView 内),略,核心代码如下所示:

public class Handler1Demo extends Activity {
    private TextView tv = null;
    private Button start = null;
    private Button end = null;
 
    Handler handler = new Handler();
    // 线程每次执行时,输出时间,延时1秒加入主线程队列
    Runnable r = new Runnable() {
        public void run() {
            tv.append(new Date().toLocaleString() + "\r\n");
            handler.postDelayed(r, 1000);
        }
    };
 
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.handler_1_demo);
 
        tv = (TextView) findViewById(R.id.text_view);
 
        start = (Button) findViewById(R.id.start);
        end = (Button) findViewById(R.id.end);
        // 开始 将handler加入到主线程队列中
        start.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                handler.post(r);
            }
        });
        // 结束 从主线程队列中移除handler
        end.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                handler.removeCallbacks(r);
            }
        });
    }
}

.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, "Courier New", courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }

定时 Handler

利用 Timer、TimerTask 和 Handler 定时刷新时间。

图 3 定时 Handler

XML 页面文件略,核心代码如下所示:

public class Handler2Demo extends Activity {
    private TextView tv = null;
    Timer timer = new Timer();
    Handler handler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            switch (msg.what) {
            case 1:
                // 处理消息
                tv = (TextView) findViewById(R.id.text_view);
                tv.append(new Date().toLocaleString() + "\r\n");
                break;
            }
            super.handleMessage(msg);
        }
 
    };
 
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.handler_2_demo);
 
        timer.schedule(new TimerTask() {
            public void run() {
                Message message = new Message();
                message.what = 1;
                handler.sendMessage(message);
            }
        }, 0, 1000);
    }
}

.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, "Courier New", courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }

播放动画

跟前一个示例类似。

图 4 播放动画

XML 页面文件略,核心代码如下所示:

public class Handler3Demo extends Activity {
    // 定义周期性显示的图片的ID
    int[] imageIds = new int[] { R.drawable.java, R.drawable.ee,
            R.drawable.ajax, R.drawable.xml, R.drawable.classic };
    int currentImageId = 0;
 
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.handler_3_demo);
        final ImageView show = (ImageView) findViewById(R.id.show);
        final Handler myHandler = new Handler() {
            @Override
            public void handleMessage(Message msg) {
                // 如果该消息是本程序所发送的
                if (msg.what == 0x1233) {
                    // 动态地修改所显示的图片
                    show.setImageResource(imageIds[currentImageId++
                            % imageIds.length]);
                }
            }
        };
        // 定义一个计时器,让该计时器周期性地执行指定任务
        new Timer().schedule(new TimerTask() {
            @Override
            public void run() {
                // 发送空消息
                myHandler.sendEmptyMessage(0x1233);
            }
        }, 0, 1200);
    }
}

.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, "Courier New", courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }

计算质数

这个一个更复杂的 Handler。计算从 2 开始,到你指定数之间的所有质数,并用 Toast 显示出来。

Handler 涉及如下几个组件:Message、Looper 和 MessageQueue。

  • Looper:每个线程只有一个 Looper,它负责管理 MessageQueue,不断从 MessageQueue 中取出消息,并将消息分给对应的 Handler 处理。

  • MessageQueue:由 Looper 负责管理。采用先进先出的方式管理 Message。
  • Handler:它能把消息发给 Looper 管理的 MessageQueue,并负责处理 Looper 分给它的消息。

图 5 计算质数

XML 页面文件略,核心代码如下所示:

public class Handler4Demo extends Activity {
    static final String UPPER_NUM = "upper";
    EditText etNum;
    CalThread calThread;
 
    // 定义一个线程类
    class CalThread extends Thread {
        public Handler mHandler;
 
        public void run() {
            Looper.prepare();
            mHandler = new Handler() {
                // 定义处理消息的方法
                @Override
                public void handleMessage(Message msg) {
                    if (msg.what == 0x123) {
                        int upper = msg.getData().getInt(UPPER_NUM);
                        List<Integer> nums = new ArrayList<Integer>();
                        // 计算从2开始、到upper的所有质数
                        outer: for (int i = 2; i <= upper; i++) {
                            // 用i处于从2开始、到i的平方根的所有数
                            for (int j = 2; j <= Math.sqrt(i); j++) {
                                // 如果可以整除,表明这个数不是质数
                                if (i != 2 && i % j == 0) {
                                    continue outer;
                                }
                            }
                            nums.add(i);
                        }
                        // 使用Toast显示统计出来的所有质数
                        Toast.makeText(Handler4Demo.this, nums.toString(),
                                Toast.LENGTH_LONG).show();
                    }
                }
            };
            Looper.loop();
        }
    }
 
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.handler_4_demo);
        etNum = (EditText) findViewById(R.id.etNum);
        calThread = new CalThread();
        // 启动新线程
        calThread.start();
    }
 
    // 为按钮的点击事件提供事件处理函数
    public void cal(View source) {
        // 创建消息
        Message msg = new Message();
        msg.what = 0x123;
        Bundle bundle = new Bundle();
        bundle.putInt(UPPER_NUM, Integer.parseInt(etNum.getText().toString()));
        msg.setData(bundle);
        // 向新线程中的Handler发送消息
        calThread.mHandler.sendMessage(msg);
    }
}

.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, "Courier New", courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }

在新线程内创建了一个 Handler,由于在新线程中创建 Handler 时必须先创建 Looper,因此程序先调用 Looper.prepare() 方法为当前线程创建了一个 Looper实例,并创建配套的MessageQueue,新线程有了 Looper 对象后,接下来创建了一个Handler对象,该 Handler 可以处理其他线程发送过来的消息。程序最后调用了 Looper.loop() 的启动方法。

参考资料


下载 Demo

Android Handler 消息处理使用的更多相关文章

  1. Android Handler消息处理顺序分析

    看到Handler中的消息处理函数: public void dispatchMessage(Message msg){...} 这个函数是在Looper的执行消息循环loop()的时候取出Messa ...

  2. android的消息处理机制——Looper,Handler,Message

    在开始讨论android的消息处理机制前,先来谈谈一些基本相关的术语. 通信的同步(Synchronous):指向客户端发送请求后,必须要在服务端有回应后客户端才继续发送其它的请求,所以这时所有请求将 ...

  3. Android的消息处理机制Looper,Handler,Message

    android的消息处理有三个核心类:Looper,Handler和Message.其实还有一个Message Queue(消息队列),但是MQ被封装到Looper里面了,我们不会直接与MQ打交道,因 ...

  4. android的消息处理有三个核心类:Looper,Handler和Message。

    android的消息处理机制(图+源码分析)——Looper,Handler,Message   作为 一名android程序员,我学习android的一大乐趣是可以通过源码学习google大牛们的设 ...

  5. 转 Android的消息处理机制(图+源码分析)——Looper,Handler,Message

    作为一个大三的预备程序员,我学习android的一大乐趣是可以通过源码学习google大牛们的设计思想.android源码中包含了大量的设计模式,除此以外,android sdk还精心为我们设计了各种 ...

  6. 【转】Android 异步消息处理机制 让你深入理解 Looper、Handler、Message三者关系

    转载请标明出处:http://blog.csdn.net/lmj623565791/article/details/38377229 ,本文出自[张鸿洋的博客] 很多人面试肯定都被问到过,请问Andr ...

  7. 【转】android的消息处理机制(图+源码分析)——Looper,Handler,Message

    原文地址:http://www.cnblogs.com/codingmyworld/archive/2011/09/12/2174255.html#!comments 作为一个大三的预备程序员,我学习 ...

  8. android的消息处理机制(图+源码分析)——Looper,Handler,Message

    android源码中包含了大量的设计模式,除此以外,android sdk还精心为我们设计了各种helper类,对于和我一样渴望水平得到进阶的人来说,都太值得一读了.这不,前几天为了了解android ...

  9. Android应用开发学习笔记之多线程与Handler消息处理机制

    作者:刘昊昱 博客:http://blog.csdn.net/liuhaoyutz 和JAVA一样,Android下我们可以通过创建一个Thread对象实现多线程.Thread类有多个构造函数,一般通 ...

随机推荐

  1. MyEclipse使用总结——设置MyEclipse使用的Tomcat服务器

    一.设置使用的Tomcat服务器 如果不想使用MyEclipse自带的tomcat服务器版本,那么可以在MyEclipse中设置我们自己安装好的tomcat服务器 设置步骤如下: Window→Pre ...

  2. ECSHOP商城网站建设之自定义调用广告方法(二)

    原文地址:http://www.cnblogs.com/zgzy/p/3598991.html 使用ecshop进行商城网站建设时,ecshop默认的很多功能对于我们个性化设计之后不太使用.今天我们主 ...

  3. WordPress主题开发:开启导航菜单功能

    步骤一:开启导航菜单功能 <?php /* register_nav_menu( $location, $description ) 函数功能:开启导航菜单功能 @参数 string $loca ...

  4. Java并发编程的艺术(十)——线程池(1)

    线程池的作用 减少资源的开销 减少了每次创建线程.销毁线程的开销. 提高响应速度 每次请求到来时,由于线程的创建已经完成,故可以直接执行任务,因此提高了响应速度. 提高线程的可管理性 线程是一种稀缺资 ...

  5. dip和px的相互转化

    /** * 根据手机的分辨率从 dp 的单位 转成为 px(像素) */ public static int dip2px(Context context, float dpValue) { fina ...

  6. 用level-list让同一个ImageView根据条件来显示不同的内容

    感谢:http://blog.sina.com.cn/s/blog_6111ce890100psq9.html 有时候,我们为了在一个ImageView中显示不同的图片,平时往往会使用: if (条件 ...

  7. 将win7电脑无线网变身WiFi热点,让手机、笔记本共享上网

    1.以管理员身份运行命令提示符:快捷键win+R→输入cmd→回车 2.启用并设定虚拟WiFi网卡:运行命令:netsh wlan set hostednetwork mode=allow ssid= ...

  8. 《Linux就是这个范儿》

    <Linux就是这个范儿> 基本信息 作者: 赵鑫磊    (加)Jie Zhang(张洁) 丛书名: 图灵原创 出版社:人民邮电出版社 ISBN:9787115359360 上架时间:2 ...

  9. [转]PHP 真正多线程的使用

    From : http://blog.s135.com/pthreads/ PHP 5.3 以上版本,使用pthreads PHP扩展,可以使PHP真正地支持多线程.多线程在处理重复性的循环任务,能够 ...

  10. Spring Test, JUnit, Mockito, Hamcrest 集成 Web 测试

    关于Spring 3.2 1. Spring 3.2 及以上版本自动开启检测URL后缀,设置Response content-type功能, 如果不手动关闭这个功能,当url后缀与accept头不一致 ...