首页 > 其他分享 >Android的Handler机制原理详解

Android的Handler机制原理详解

时间:2023-10-30 22:32:52浏览次数:37  
标签:Handler 线程 Looper activity msg Android Message 详解

Android的Handler机制是一种用于处理和调度线程之间消息传递的机制,通常用于在后台线程中执行任务,并将结果返回到主线程中更新UI。Handler机制的核心是Message和MessageQueue,以及Looper。

以下是Android Handler机制的主要组成部分和工作原理:

1.Message(消息):Message是一个包含要传递的数据和指令的对象。它可以携带整数、字符串、Bundle等不同类型的数据。当需要在不同线程之间传递数据或执行任务时,通常会创建一个Message并将其发送给Handler。

2.Handler(处理程序):Handler是用于处理Message的对象。它通常与一个特定的线程(通常是主线程)关联。通过Handler,您可以将Message发送到与其关联的线程的消息队列中,以便在那个线程中执行处理。

3.Looper(消息循环器):Looper是一个用于管理线程的消息队列的对象。每个线程都可以有一个Looper,它会在线程上创建一个消息队列,允许该线程接收并处理Message。主线程通常已经具有一个默认的Looper,而后台线程需要显式创建一个Looper。

4.MessageQueue(消息队列):MessageQueue是一个FIFO(先进先出)队列,用于存储待处理的Message。每个Looper都有一个关联的MessageQueue,Handler将Message发送到这个队列中,然后由Looper依次处理队列中的Message。

Handler机制的工作流程:

1.在主线程(或其他线程)上创建一个Handler对象,这个Handler会关联到当前线程的Looper。

2.在后台线程中,创建一个Message对象,可以将一些数据和处理指令放入这个Message。

3.使用Handler的sendMessage方法将Message发送到与Handler关联的Looper的MessageQueue中。

4.Looper在后台线程中不断轮询MessageQueue,当有新的Message到达时,将Message取出并交给Handler处理。

5.Handler收到Message后,可以根据Message中的指令执行相应的操作,通常是在主线程中更新UI。

6.如果需要定时任务或循环执行,可以使用Handler的postDelayed方法。

Handler 的三种使用方法,分别是:

Handler.sendMessage(Message) Handler.post(Runnable) Handler.obtainMessage(what).sendToTarget();

2. Handler.sendMessage()方法

Handler.sendMessage(Msg) 方法是最为常见的一种方法。

2.1 使用步骤说明

其使用步骤分四步,如下所示: 1、步骤一:新建 Handler 对象,覆写 handleMessage(Message) 方法。 2、步骤二:新建 Message 对象,设置其携带的数据。 3、步骤三:在子线程中通过 Handler.sendMessage(Message) 方法发送信息。 4、步骤四:在 Handler 的 handleMessage(Message msg) 方法中处理消息,通知主线程作出相对应的 UI 工作。

步骤一:新建 Handler 对象,覆写 handleMessage(Message) 方法
//创建 Handler对象,并关联主线程消息队列
mHandler = new Handler(Looper.getMainLooper()) {
    @Override
    public void handleMessage(Message msg) {
        super.handleMessage(msg);
            ···略···
        }
    }
};
步骤二:新建 Message 对象,设置其携带的数据
Bundle bundle = new Bundle();
bundle.putInt(CURRENT_PROCESS_KEY, i);
Message msg = new Message();
msg.setData(bundle);
msg.what = 2;
步骤三:在子线程中通过 Handler.sendMessage(Message) 方法发送信息
mHandler.sendMessage(msg)
步骤四:在 Handler 的 handleMessage(Message msg) 方法中处理消息,通知主线程作出相对应的 UI 工作
mHandler = new Handler(Looper.getMainLooper()) {
    @Override
    public void handleMessage(Message msg) {
        super.handleMessage(msg);
        //根据信息编码及数据做出相对应的处理
        switch (msg.what) {
            case 1:
                //更新 TextView UI
                mDisplayTv.setText("CustomChildThread starting!");
                break;
            case 2:
                //获取 ProgressBar 的进度,然后显示进度值
                Bundle bundle = msg.getData();
                int process = bundle.getInt(CURRENT_PROCESS_KEY);
                mProgressBar.setProgress(process);
                break;
            default:
                break;
        }
    }
};
2.2.1Java版本的具体代码如下所示:
public class HandlerAddThreadActivity extends AppCompatActivity {
    public static final String CURRENT_PROCESS_KEY = "CURRENT_PROCESS";
    private TextView mDisplayTv;
    private Handler mHandler;
    private ProgressBar mProgressBar;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_handler_add_thread);

        TextView titleTv = findViewById(R.id.title_tv);
        titleTv.setText("Handler + Thread");
        
        mDisplayTv = findViewById(R.id.display_tv);
        mProgressBar = findViewById(R.id.test_handler_progress_bar);

        //mHandler用于处理主线程消息队列中的子线程消息
        mHandler = new Handler(Looper.getMainLooper()) {
            @Override
            public void handleMessage(Message msg) {
                super.handleMessage(msg);
                switch (msg.what) {
                    case 1:
                        //更新 TextView UI
                        mDisplayTv.setText("CustomChildThread starting!");
                        break;
                    case 2:
                        //获取 ProgressBar 的进度,然后显示进度值
                        Bundle bundle = msg.getData();
                        int process = bundle.getInt(CURRENT_PROCESS_KEY);
                        mProgressBar.setProgress(process);
                        break;
                    default:
                        break;
                }

            }
        };
        
        Button mClickBtn = findViewById(R.id.click_btn);
        mClickBtn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                //开启子线程,子线程处理UI工作
                CustomChildThread customThread = new CustomChildThread();
                customThread.start();
            }
        });
    }

    /**
     * 子线程,用于处理耗时工作
     */
    public class CustomChildThread extends Thread {

        @Override
        public void run() {
            //在子线程中创建一个消息对象
            Message childThreadMessage = new Message();
            childThreadMessage.what = 1;
            //将该消息放入主线程的消息队列中
            mHandler.sendMessage(childThreadMessage);

            //模拟耗时进度,将进度值传给主线程用于更新 ProgressBar 进度。
            for (int i = 1; i <= 5; i++) {
                try {
                    //让当前执行的线程(即 CustomChildThread)睡眠 1s
                    Thread.sleep(1000);

                    //Message 传递参数
                    Bundle bundle = new Bundle();
                    bundle.putInt(CURRENT_PROCESS_KEY, i);
                    Message progressBarProcessMsg = new Message();
                    progressBarProcessMsg.setData(bundle);
                    progressBarProcessMsg.what = 2;
                    mHandler.sendMessage(progressBarProcessMsg);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}
2.2.2Kotlin版本的代码如下所示:
class TestThreadAddHandlerActivity : AppCompatActivity() {
    companion object {
        const val PROGRESS_VALUE_KEY = "PROGRESS_VALUE"
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_thread_add_handler)

        handlerAddThreadStartBtn.setOnClickListener(View.OnClickListener {
            //工作线程开始模拟下载任务
            val workThread: WorkThread = WorkThread(this)
            workThread.start()
        })
    }

    class WorkThread(activity: TestThreadAddHandlerActivity) : Thread() {
        private var handler: MyHandler = MyHandler(activity)

        override fun run() {
            super.run()
            for (i in 0..6) {
                sleep(1000)
                //通过 Handler 将进度参数传递给 主线程,让其更新 progressBar 进度
                val message = Message()
                message.what = 1
                val bundle = Bundle()
                bundle.putInt(PROGRESS_VALUE_KEY, i)
                message.data = bundle
                handler.sendMessage(message)
            }
        }
    }

    /**
     * 静态内部类,防止内存泄漏
     */
    class MyHandler(activity: TestThreadAddHandlerActivity) : Handler() {
        private var weakReference = WeakReference(activity)

        override fun handleMessage(msg: Message) {
            super.handleMessage(msg)
            //处理消息
            when (msg.what) {
                1 -> {
                    val activity = weakReference.get()
                    if (activity != null && !activity.isFinishing) {
                        //获取消息中携带的任务处理进度参数,然后设置成 ProgressBar 的进度。
                        val progressValue: Int = msg.data.get(PROGRESS_VALUE_KEY) as Int
                        activity.handlerAddThreadProgressBar.progress = progressValue
                    }
                }
            }
        }
    }
}

3. Handler.post()方法

除了使用 Handler.sendMessage(Message) 来发送信息,Handler 还支持 post(Runnable) 方法来传递消息,通知主线程做出相对应的 UI 工作。使用方法如下:

/**
 * 将可运行的 Runnable 添加到消息队列。Runnable 将在该 Handler 相关的线程上运行处理。
 * The runnable will be run on the thread to which this handler is attached.
 */
new Handler().post(new Runnable() {
    @Override
    public void run() {
        //更新处理 UI 工作
    }
});
3.1.1Java版本的具体代码如下
public class HandlerPostFunctionActivity extends AppCompatActivity {
    private Handler mMainHandler;
    private ProgressBar mProgressBar;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_handler_add_thread);

        TextView titleTv = findViewById(R.id.title_tv);
        titleTv.setText("Handler post() function");

        mProgressBar = findViewById(R.id.test_handler_progress_bar);

        //新建静态内部类 Handler 对象
        mMainHandler = new Handler(getMainLooper());

        Button mClickBtn = findViewById(R.id.click_btn);
        mClickBtn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                //开启子线程,子线程处理UI工作
                CustomChildThread customThread = new CustomChildThread();
                customThread.start();
            }
        });
    }

    /**
     * 子线程,用于处理耗时工作
     */
    public class CustomChildThread extends Thread {

        @Override
        public void run() {
            //模拟耗时进度,将进度值传给主线程用于更新 ProgressBar 进度。
            for (int i = 1; i <= 5; i++) {
                try {
                    //让当前执行的线程(即 CustomChildThread)睡眠 1s
                    Thread.sleep(1000);

                    //新创建一个 Runnable 用户处理 UI 工作
                    MyRunnable runnable = new MyRunnable(HandlerPostFunctionActivity.this, i);
                    //调用Handler post 方法。
                    mMainHandler.post(runnable);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    /**
     * 将 Runnable 写成静态内部类,防止内存泄露
     */
    public static class MyRunnable implements Runnable {
        private int progressBarValue;
        private WeakReference<HandlerPostFunctionActivity> weakReference;

        MyRunnable(HandlerPostFunctionActivity activity, int value) {
            this.weakReference = new WeakReference<>(activity);
            this.progressBarValue = value;
        }

        @Override
        public void run() {
            HandlerPostFunctionActivity activity = weakReference.get();
            if (activity != null && !activity.isFinishing()) {
                activity.mProgressBar.setProgress(progressBarValue);
            }
        }
    }
}
3.1.2Kotlin版本的具体代码如下:
class TestHandlerPostRunnableActivity : AppCompatActivity() {
    private var mMainHandler: Handler? = null

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_thread_add_handler)

        handlerAddThreadStartBtn.setOnClickListener(View.OnClickListener {
            //工作线程开始模拟下载任务
            val workThread: WorkThread = WorkThread(this)
            workThread.start()
        })

        //创建 Handler,关联App的 主Looper 对象
        mMainHandler = Handler(Looper.getMainLooper())
    }

    class WorkThread(private var activity: TestHandlerPostRunnableActivity) : Thread() {
        private var handler: Handler? = activity.mMainHandler

        override fun run() {
            super.run()
            for (i in 0..6) {
                sleep(1000)
                //新建 Runnable 设置进度参数传,然后通过 post(Runnable) 方法,让其更新 progressBar 进度
                val runnable: MyRunnable = MyRunnable(activity, i)
                handler?.post(runnable)
            }
        }
    }

    /**
     * 处理 UI 工作。
     * 静态内部类,防止内存泄露
     */
    class MyRunnable(activity: TestHandlerPostRunnableActivity, value: Int) : Runnable {
        private var weakReference = WeakReference(activity)
        private var progressValue = value

        override fun run() {
            val activity = weakReference.get()
            if (activity != null && !activity.isFinishing) {
                //获取任务执行进度参数,更新 progressBar 进度
                activity.handlerAddThreadProgressBar.progress = progressValue
            }
        }
    }
}

4. obtainMessage()方法

obtainMessage() 方法与 sendMessage() 方法很相似,通过 mHandler.obtainMessage().sendToTarget() 发送信息。该方法与 sendMessage() 的区别就是你不用额外去创建一个 Message 对象。

obtainMessage() 方法有三种,分别是:

//指定 what 用于区分,通过 Message.what 获得
public final Message obtainMessage(int what);

//传递obj参数,通过 Message.obj 获得
public final Message obtainMessage(int what, @Nullable Object obj)

//传递arg1 arg2参数,通过 Message.arg1 Message.arg2 获得
public final Message obtainMessage(int what, int arg1, int arg2)
4.1.1ava版本的具体代码如下:
public class HandlerObtainMessageActivity extends AppCompatActivity {
    private TextView mDisplayTv;
    private Handler mHandler;
    private ProgressBar mProgressBar;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_handler_add_thread);

        TextView titleTv = findViewById(R.id.title_tv);
        titleTv.setText("Handler + Thread");

        mDisplayTv = findViewById(R.id.display_tv);
        mProgressBar = findViewById(R.id.test_handler_progress_bar);

        //mHandler用于处理主线程消息队列中的子线程消息
        mHandler = new Handler(Looper.getMainLooper()) {
            @Override
            public void handleMessage(Message msg) {
                super.handleMessage(msg);
                switch (msg.what) {
                    case 1:
                        //更新 TextView UI
                        mDisplayTv.setText("Handler obtainMessage() Test!!");
                        break;
                    case 2:
                        //通过 msg.obj 获取 ProgressBar 的进度,然后显示进度值
                        int process = (int) msg.obj;
                        mProgressBar.setProgress(process);
                        break;
                    default:
                        break;
                }

            }
        };

        Button mClickBtn = findViewById(R.id.click_btn);
        mClickBtn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                //开启子线程,子线程处理UI工作
                CustomChildThread customThread = new CustomChildThread();
                customThread.start();
            }
        });
    }

    /**
     * 子线程,用于处理耗时工作
     */
    public class CustomChildThread extends Thread {

        @Override
        public void run() {
            //发送第一条消息,代表开始执行异步任务
            mHandler.obtainMessage(1).sendToTarget();

            //模拟耗时进度,将进度值传给主线程用于更新 ProgressBar 进度。
            for (int i = 1; i <= 5; i++) {
                try {
                    //让当前执行的线程(即 CustomChildThread)睡眠 1s
                    Thread.sleep(1000);

                    //将执行进度参数 i 传递给主线程 progressBar
                    mHandler.obtainMessage(2, i).sendToTarget();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }


        }
    }

}
4.1.2Kotlin版本的具体代码如下:
class TestHandlerObtainMessageActivity : AppCompatActivity() {
    companion object {
        const val PROGRESS_VALUE_KEY = "PROGRESS_VALUE"
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_thread_add_handler)

        handlerAddThreadStartBtn.setOnClickListener(View.OnClickListener {
            //工作线程开始模拟下载任务
            val workThread: WorkThread = WorkThread(this)
            workThread.start()
        })
    }

    class WorkThread(activity: TestHandlerObtainMessageActivity) : Thread() {
        private var handler: MyHandler = MyHandler(activity)

        override fun run() {
            super.run()
            for (i in 0..6) {
                sleep(1000)
                //通过 Handler 将进度参数传递给 主线程,让其更新 progressBar 进度
                val bundle = Bundle()
                bundle.putInt(PROGRESS_VALUE_KEY, i)
                handler.obtainMessage(1, bundle).sendToTarget()
            }
        }
    }

    /**
     * 静态内部类,防止内存泄漏
     */
    class MyHandler(activity: TestHandlerObtainMessageActivity) : Handler() {
        private var weakReference = WeakReference(activity)

        override fun handleMessage(msg: Message) {
            super.handleMessage(msg)
            when (msg.what) {
                1 -> {
                    val activity = weakReference.get()
                    if (activity != null && !activity.isFinishing) {
                        //获取任务执行进度参数,然后通过 ProgressBar 显示出来
                        val bundle: Bundle = msg.obj as Bundle
                        val progressValue: Int = bundle.get(PROGRESS_VALUE_KEY) as Int
                        activity.handlerAddThreadProgressBar.progress = progressValue
                    }
                }
            }
        }
    }
}

5. 总结:

在实际开发中,三种方法的使用都可行,具体用哪种方法,需结合你的实际情况及个人喜好。另外,在实际使用中往往将 Handler 写成静态内部类,这时需要注意防止内存泄露!(The handler class should be static or leaks might occur),具体代码见上方!

5.1 在子线程中创建Handler

思考: 在上面代码中, 我们都是在主线程中创建了 Handler 对象,那如果在子线程中创建一个 Handler 对象呢?会发生什么呢? 如下所示:我们在 CustomChildThread 线程中,新建一个 Handler 对象。

public class CustomChildThread extends Thread {
    @Override
    public void run() {
        Handler handler = new Handler(Activity.this);
        //会报错:java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare()
    }
}

结果: 抛出异常: java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare()。 原因: 因为在创建 Handler对象时要关联所处线程的 Looper对象,而我们的子线程没有 Looper,所以会抛出上述异常。 解决方法: 通过调用,Looper.prepare() 方法为子线程创建一个 Looper 对象,并且调用 Looper.loop() 方法开始消息循环。如下所示:

class CustomChildThread extends Thread {
    @Override
    public void run() {
        //为当前线程创建一个 Looper 对象
        Looper.prepare();
        
        //在子线程中创建一个 Handler 对象
        Handler handler = new Handler() {
            public void handleMessage(Message msg) {
                // 在这里处理传入的消息
            }
        };
        //开始消息循环
        Looper.loop();
    }
}

标签:Handler,线程,Looper,activity,msg,Android,Message,详解
From: https://blog.51cto.com/u_16175630/8097380

相关文章

  • 【Redis使用】一年多来redis使用markdow笔记总结,第(1)篇:Redis命令详解
    Redis是一个高性能的key-value数据库。本文会让你知道:什么是nosql、Redis的特点、如何修改常用Redis配置、写出Redis中string类型数据的增删改查操作命令、写出Redis中hash类型数据的增删改查相关命令、说出Redis中list保存的数据类型、使用StrictRedis对象对string类型数据......
  • 重新使用android studio编写udp socket程序,备忘记录
    1,建立socket需要使用子线程而不是主线程。2,java/android使用数据报格式。3,可以利用python作为socket的客户/服务器端,非常简单。但python可以不使用数据报,而直接使用字符串。当然也可以使用数据报。当与android配合时使用数据报格式4,一般地,传输的是字符串,因此,数字要编码为字符串......
  • 揭秘:为什么80%的Android码农都做不了架构师?
    前言一般来说技术团队的金字塔顶尖往往是技术最牛的人做架构师(或TL)。所以架构师在广大码农中的占比大概平均不到20%。然而80%码农干上许多年都是重复以下内容,所以做不了架构师,正在辛苦工作的程序员们,你有没有下面几种感觉?①我的工作就是按时完成领导交给我的任务,至于代码写的怎样......
  • CSP-J 前三题详解
    没写完。先补会儿文化课作业,等会再回来继续写。T1P9748[CSP-J2023]小苹果令苹果数量为\(\texttt{n}\)。容易发现,拿苹果就是每三个一组,取第一个。需要注意的是,如果以三个一组来考虑拿苹果,最后几个苹果不满三个时也应该算一个组,第一个也要拿走。形式化的,即当\(\texttt{n}......
  • 安卓平板,学习平板、三防工业平板Android主板定制方案
    近年来,平板设备在生活和工业领域应用不断增长。学习平板和工业intelligent设备的销量都处在高速发展阶段。预计到2024年,我国平板总出货量将继续增长。安卓平板采用高度集成设计,将多媒体解码、液晶驱动、USB接口、以太网、HDMI输出、TF卡插槽、WiFi、人体感应、串口、......
  • 关于STM32芯片类型的详解
    关于STM32芯片类型的详解对于STM32芯片类型英文缩写的详解及相关型号: CL - Connect Line(互联型):包含STM32F105和STM32F107两个系列,该系列的芯片侧重于提供丰富的外设和连接选项,以满足各种连接性要求的应用场景。VL - Value Line(超值型):包含stm32f100系列,该系列的芯片是为......
  • 嵌入式Linux中内存管理详解分析
    Linux中内存管理内存管理的主要工作就是对物理内存进行组织,然后对物理内存的分配和回收。但是Linux引入了虚拟地址的概念。虚拟地址的作用如果用户进程直接操作物理地址会有以下的坏处:1、用户进程可以直接操作内核对应的内存,破坏内核运行。2、用户进程也会破坏其他进程的运行CPU......
  • 【CV】图像分割详解!
    图像分割是计算机视觉研究中的一个经典难题,已经成为图像理解领域关注的一个热点,图像分割是图像分析的第一步,是计算机视觉的基础,是图像理解的重要组成部分,同时也是图像处理中最困难的问题之一。所谓图像分割是指根据灰度、彩色、空间纹理、几何形状等特征把图像划分成若干个互不相交......
  • MySQL系列:binlog日志详解(参数、操作、GTID、优化、故障演练)
    目录简介作用系统参数--log_bin--server_id--binlog_format--sync-binlog(双一标准)--gtid-mode(gtid)--enforce-gtid-consistency(gtid)--expire-logs-day(优化参数)--binlog_cache_size(优化参数)--max_binlog_cache_size(优化参数)--max_binlog_size(优化参数)sql_log_bin日志操作开启日......
  • docker指令详解
    Docker指令详解1.生命周期管理run创建并运行容器,格式dockerrun[OPTIONS]image[COMMAND][ARG...],参数说明dockerrun[options]image[command][arg...]-d,--detach#后台运行-it,--interacticetty#交互终端形式运行-p,--publishlist#指定端口-v,--vo......