zoukankan      html  css  js  c++  java
  • 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

  • 相关阅读:
    HDU 5642 King's Order 动态规划
    HDU 5640 King's Cake GCD
    HDU 5641 King's Phone 模拟
    HDU 5299 Circles Game 博弈论 暴力
    HDU 5294 Tricks Device 网络流 最短路
    HDU 5289 Assignment rmq
    HDU 5288 OO’s Sequence 水题
    星际争霸 虚空之遗 人族5BB 操作流程
    Codeforces Beta Round #3 D. Least Cost Bracket Sequence 优先队列
    Codeforces Beta Round #3 C. Tic-tac-toe 模拟题
  • 原文地址:https://www.cnblogs.com/liuning8023/p/3800829.html
Copyright © 2011-2022 走看看