zoukankan      html  css  js  c++  java
  • Android Handler

    最近经常用到Handler,今天复习了一下,知识还是要经常复习的哈,温故知新!

    Handler主要接受子线程数据,并用此数据配合主线程更新UI。

    Handler的作用:

    (1)发送和处理消息(Message)。

    (2)发送和处理Runnable对象。

      对于Android里的消息处理,涉及到Handler,Looper,Message,MessageQueue等概念,先理顺这些概念。

    Message:消息,其中包含了消息ID,消息处理对象以及处理的数据等,由MessageQueue统一列队,终由Handler处理。

    Handler:处理者,负责Message的发送及处理。使用Handler时,需要实现handleMessage(Message msg)方法来对特定的Message进行处理,例如更新UI等。

    MessageQueue:消息队列,用来存放Handler发送过来的消息,并按照FIFO(队列先进先出)规则执行。当然,存放Message并非实际意义的保存,而是将Message以链表的方式串联起来的,等待Looper的抽取。

    Looper:一个线程可以产生一个Looper对象,用来管理MessageQueue,它就像一个消息泵,不断地从MessageQueue中抽取Message执行。因此,一个MessageQueue需要一个Looper。

    一、发送和处理消息(Message)

    Handler myHandler = new Handler() {
    
                @Override
                public void handleMessage(Message msg) {
                    super.handleMessage(msg);
                    if (msg.what == 1) {
                        
                    }
                }
    
            };
            // 第一种 调用myHandler.obtainMessage() 获得的Message已经跟myHandler绑定
            Message msg1 = myHandler.obtainMessage();
            // 直接调用 sendToTarget() 就可以把消息送入队列,等待Handler执行
            msg1.sendToTarget();
            // 第二种 直接用Message的构造函数
            Message msg2 = new Message();
            // 调用Handler 实例的 sendMessage()方法把消息送入队列,等待Handler执行
            myHandler.sendMessage(msg2);// 即时send
            myHandler.sendEmptyMessageAtTime(1, uptimeMillis);// 在uptimeMillis时间点,send属性what值为1的Message
            myHandler.sendEmptyMessage(1);// send属性what值为1的Message
            //其他以此类推

    DEMO1

    在Activity中,定义一个Button,TextView,我们点击Button来实时的更新这个TextView的内容。

    package com.dimos.handler;
    
    import android.app.Activity;
    import android.os.Bundle;
    import android.os.Handler;
    import android.os.Looper;
    import android.os.Message;
    import android.view.View;
    import android.widget.Button;
    import android.widget.TextView;
    
    public class MainActivity extends Activity {
        private TextView textView;
        private MyHandler myHandler;// 定义一个自己的Handle类
        private Button button;
        private MyThread m = new MyThread(); // 定义一个自己的线程类
    
        @Override
        public void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            textView = (TextView) findViewById(R.id.txtShow);
            button = (Button) findViewById(R.id.btnOnlick);
            button.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View arg0) {
                    myHandler = new MyHandler();
                    new Thread(m).start();
                    System.out.println("主线程运行ID:" + Thread.currentThread().getId());
                }
            });
        }// 在对UI进行更新时,执行时所在的线程为主UI线程
    
        class MyHandler extends Handler {// 继承Handler类时,必须重写handleMessage方法
            public MyHandler() {
            }
    
            public MyHandler(Looper looper) {
                super(looper);
            }
    
    
    
            @Override
            public void handleMessage(Message msg) {// 执行接收到的通知,此时执行的顺序是按照队列进行,即先进先出
                super.handleMessage(msg);
                Bundle b = msg.getData();
                String textStr1 = b.getString("textStr");
                textView.setText(textStr1);// 更改TextView中的值
            }
        }// 该线程将会在单独的线程中运行
    
        class MyThread implements Runnable {
            int i = 1;
    
            @Override
            public void run() {
                while (i < 11) {
                    System.out.println("当前运行线程ID:" + Thread.currentThread().getId());
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    Message msg = new Message();
                    Bundle b = new Bundle();
                    b.putString("textStr", "线程运行" + i + "次");
                    i++;
                    msg.setData(b);
                    myHandler.sendMessage(msg);// 通过sendMessage向Handler发送更新UI的消息
                }
                i = 1;// 下次启动线程时重新计数。
            }
        }
    }

    XML文件 activity_main.xml如下:

    <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools"
        android:layout_width="match_parent"
        android:layout_height="match_parent" >
        
        <Button 
            android:id="@+id/btnOnlick"
            android:layout_height="wrap_content"
            android:layout_width="fill_parent"
            android:text="点击"/>
    
        <TextView
            android:id="@+id/txtShow"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="被点前"
            android:layout_centerHorizontal="true"
            android:layout_centerVertical="true"/>
    
    </RelativeLayout>

    可以看到,屏幕上的TextView在实时变化,考察线程ID可以得知是由哪一个线程来完成这项工作的。再次点击按钮后,则会触发新的线程去执行实时更新的操作。

    二、发送和处理消息 Runnable

    Runnable runnable = new Runnable() {
    
                @Override
                public void run() {
                    
                }
            };
            long time = System.currentTimeMillis();
            myHandler.post(runnable);// 即使post
            myHandler.postAtFrontOfQueue(runnable);// 插入队头
            myHandler.postAtTime(runnable, time);// 在time时间点 post
            myHandler.postDelayed(runnable, 3000);// 延迟3秒 post
            // 其他以此类推

    DEMO2

    package com.dimos.handler;
    
    import android.app.Activity;
    import android.os.Bundle;
    import android.os.Handler;
    
    public class HandlerMsg extends Activity {
    
        private Handler handler = new Handler();
    
        @Override
        public void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            handler.post(new MyRunnable());
            System.out.println("Oncreate---The Thread id is :"
                    + Thread.currentThread().getId());
            setContentView(R.layout.activity_main);
        }
    
        private class MyRunnable implements Runnable {
            public void run() {
                System.out.println("Runnable---The Thread is running");
                System.out.println("Runnable---The Thread id is :"
                        + Thread.currentThread().getId());
                try {
                    Thread.sleep(6000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
    
            }
    
        }
    }

    控制台的输出结果:

    : Oncreate---The Thread id is :1
    : Runnable---The Thread is running
    : Runnable---The Thread id is :1

    程序启动后6秒,我们才看到activity_main.xml中的内容(只是显示一个TextView)。

    这表明handler和主线程是同一个线程。如果这时候你做的是一个耗时的操作(比如下载),那么这样是不可行的。

    android给我们提供了Looper这样一个类。其实Android中每一个Thread都跟着一个Looper,Looper可以帮助Thread维护一个消息队列。

    DEMO3

    package com.dimos.handler;
    
    import android.app.Activity;
    import android.os.Bundle;
    import android.os.Handler;
    import android.os.HandlerThread;
    
    public class HandlerMsg2 extends Activity {
    
        private Handler handler = null;
    
        @Override
        public void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
    
            HandlerThread handlerThread = new HandlerThread("myHandlerThread");
            handlerThread.start();
    
            handler = new Handler(handlerThread.getLooper());
    
            handler.post(new MyRunnable());
    
            System.out.println("Oncreate---The Thread id is :"
                    + Thread.currentThread().getId());
    
            setContentView(R.layout.activity_main);
    
        }
    
        private class MyRunnable implements Runnable {
    
            public void run() {
                System.out.println("Runnable---The Thread is running");
                System.out.println("Runnable---The Thread id is :"
                        + Thread.currentThread().getId());
                try {
                    Thread.sleep(6000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
    
            }
    
        }
    }

    输出结果:

    : Oncreate---The Thread id is :1
    : Runnable---The Thread is running
    : Runnable---The Thread id is :2833

    程序启动后,我们立刻看到activity_main.xml中的内容,这样就达到了多线程的结果。

    其实handler.post(Runnable)很强大,在很多地方都有用到,如

    Gallery的onItemClick 跟onTouchEvent 不能同时用在3.0之后,但是可以用handler.post(Runnable)解决:

    Create Handler作为一个全局变量

    private Handler handler;

    onCreate中new Handler,所以handler在主线程

    handler = new Handler();

    然后在Gallery的onItemClick里面用handler.post(Runnable),like this

    handler.post(new Runnable() {
                
                @Override
                public void run() {
                    // Do what ever...
                }
            });
  • 相关阅读:
    过滤textarea
    vue引用jquery
    vue_ajax插件Axios
    VeeValidate
    mongodb
    WEBGL实现--three.js笔记整理
    My SQLworkbench问题总结
    vue遇到的问题
    MYSQL使用笔记
    vue笔记
  • 原文地址:https://www.cnblogs.com/ycclmy/p/3175155.html
Copyright © 2011-2022 走看看