• Android Handler 消息处理使用


    本文内容

    • 环境
    • 演示 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

    图 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);
                }
            });
        }
    }

    加入和移除 Handler 到主线程

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

    2

    图 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() + "
    ");
                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);
                }
            });
        }
    }

    定时 Handler

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

    3

    图 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() + "
    ");
                    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);
        }
    }

    播放动画

    跟前一个示例类似。

    4

    图 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);
        }
    }

    计算质数

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

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

    • Looper:每个线程只有一个 Looper,它负责管理 MessageQueue,不断从 MessageQueue 中取出消息,并将消息分给对应的 Handler 处理。
    • MessageQueue:由 Looper 负责管理。采用先进先出的方式管理 Message。
    • Handler:它能把消息发给 Looper 管理的 MessageQueue,并负责处理 Looper 分给它的消息。

    5

    图 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);
        }
    }

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

    参考资料


    下载 Demo

  • 相关阅读:
    ajax简单案例
    jquery中的数据传输
    java-Reflect
    Factory Method 和AbstractFactory
    Singleton
    英语六级口语备考指南
    ACM信息汇总
    jquery练习
    char可不可以存汉字
    信息安全
  • 原文地址:https://www.cnblogs.com/liuning8023/p/3800829.html
Copyright © 2020-2023  润新知