Android Handler

本文详细介绍了Android中的Handler机制,包括其工作原理、涉及的主要组件如Looper、MessageQueue等,以及如何利用Handler在主线程和子线程间发送消息和Runnable对象以实现UI更新。

最近经常用到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...
            }
        });

 

转载于:https://www.cnblogs.com/ycclmy/p/3175155.html

### AndroidHandler 的使用教程及常见问题解决 #### 1. Handler 的定义和作用 HandlerAndroid 开发中用于线程间通信的关键组件,主要用于在不同线程之间传递消息并执行特定的任务。它特别适用于更新 UI 和处理异步任务[^1]。 #### 2. 创建和初始化 Handler 为了使用 Handler 进行消息传递,首先需要创建一个 Looper 线程,并在此基础上实例化 Handler 对象: ```java // 创建一个新的 HandlerThread 并启动它 HandlerThread handlerThread = new HandlerThread("handler_thread"); handlerThread.start(); // 获取该线程的 Looper 实例,并基于此创建 Handler Handler handler = new Handler(handlerThread.getLooper()); ``` #### 3. 发送和处理消息 可以通过 `sendMessage` 或者 `post` 方法向 Handler 发送消息或运行指定的操作: ```java // 使用 sendMessage 方式发送 Message 对象 Message msg = handler.obtainMessage(); msg.what = 0; handler.sendMessage(msg); // 使用 post 延迟执行某个 Runnable handler.postDelayed(new Runnable() { @Override public void run() { // 更新 UI 操作或其他逻辑 } }, 1000); // 延迟一秒后执行 ``` #### 4. 结合 Runnable 使用 可以将要执行的具体任务封装成 Runnable 类型的对象并通过 Handler 来调度它们: ```java Runnable myTask = new Runnable() { @Override public void run() { // 执行具体任务 } }; handler.post(myTask); ``` #### 5. 避免内存泄漏 当在一个 Activity 内部创建 Handler 时需要注意潜在的内存泄漏风险。因为内部类形式的 Handler 默认持有外部类(通常是 Activity)的一个强引用,这可能导致即使 Activity 已经销毁也无法被垃圾回收器释放。为了避免这种情况发生,建议采用静态内部类的方式声明 Handler,并通过弱引用来访问所需的上下文资源[^4]。 ```java static class MyHandler extends Handler { private final WeakReference<Context> weakContext; public MyHandler(Context context) { this.weakContext = new WeakReference<>(context); } @Override public void handleMessage(Message msg) { Context context = weakContext.get(); if (context != null && !((Activity) context).isFinishing()) { // 处理消息... } } } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值