What is a Handler

The handler allows you to send and process messages associated with a thread’s Runnable object, MessageQueue. Each Handler instance is associated with a thread and the message queue for that thread. When you create a new handler, it is bound to Looper. It passes messages and runnable objects to the message queue of the Looper and executes them on the thread of the Looper.

The Handler is used to process our Message, bind a Loop, and run on the same thread as the bound Loop.

Next, kangkang code

binding.text.setOnClickListener { Handler(Looper.getMainLooper()).post { Toast.maketext (this@MainActivity," Trash-like ", toast.length_long).show()}}Copy the code

A click event will bring up a Toast with the contents of “Being in a trance”. Well, very nice. What’s the difference between you talking about it for a long time and me creating a Toast

Binding. Text. SetOnClickListener {Thread {Toast. MakeText (this @ MainActivity, "thriving drifted off," Toast. LENGTH_LONG), show () }.start() /*Handler(looper.getMainLooper ()).post {toast.maketext (this@MainActivity," Dreamy ", toast.length_long).show() * /}}Copy the code

When I run it, it crashes unexpectedly. Wuhu, I guess you all know that you can’t update the UI in the child thread, and so on

binding.text.setOnClickListener { Thread { Handler(Looper.getMainLooper()).post { Toast.makeText(this@MainActivity, Toast.length_long).show()}}.start()}Copy the code

It’s running, it’s working fine again, I lost, isn’t that amazing? In general, we all know that when a child thread is updating the UI, you can use runOnUiThread to switch to the main thread, and in fact

public final void runOnUiThread(Runnable action) {
        if (Thread.currentThread() != mUiThread) {
            mHandler.post(action);
        } else {
            action.run();
        }
    }
Copy the code

If the current thread is not the main thread, runOnUiThread will do nothing more than mHandler.post(action). Handler Handler Handler Handler Handler Handler Handler Handler Handler Handler What, no hook? Let’s move on to the Handler application below.

The use of Handler

Typically, we implement a Handler in the main thread and use it in child threads. When you are in a child thread and you have code that needs to run on the main thread, for example, to compute a complex piece of data and then update the result to the UI, you can use a Handler

class MainActivity : BaseActivity<ActivityMainBinding>() { private lateinit var myHandler: MyHandler override fun initViews() { myHandler = MyHandler(Looper.getMainLooper()) binding.text.setOnClickListener { Thread{val message = message.obtain ().apply {what = myHandler. ShowToast obj = "trance"} myHandler.sendMessage(message) }.start() } binding.btn.setOnClickListener { myHandler.sendEmptyMessage(myHandler.logOut)  } } inner class MyHandler(looper: Looper): Handler(looper){ val showToast = 1 val logOut = 2 override fun handleMessage(msg: Message) { super.handleMessage(msg) when(msg.what){ showToast ->{ val obj = msg.obj Toast. MakeText (this @ MainActivity, obj. ToString (), Toast. LENGTH_LONG). Show the logOut ()} - > {/ / logOut logic... } } } } }Copy the code

This is the easiest way to use Handler. There are usually a lot of variables like showToast that define a number of different behaviors. A text click performs pop-up toast, while a BTN click performs logout logic, can send a message anywhere, and will receive the message in the handleMessage. One thing to watch out for is memory leaks, which are not too verbose, and there are many on the web

Three Handler advanced use

In fact, we often encounter some code to delay execution, (real event in history) Boss: this button click, to delay 0.1 seconds before the reaction, give the user a special feeling, I ********. In fact, Handler can easily do all of this

binding.text.setOnClickListener { Thread{ val message = Message.obtain().apply { what = myHandler.showToast obj = "Thriving intoxication"} / / myHandler. SendMessage (message) myHandler. SendMessageDelayed (message, 100)}. The start ()}Copy the code

Okay, that’s it. The message will take 100 milliseconds to send, so try it yourself

There is a countdown display, such as verification code countdown, all kinds of strange countdown requirements, using handler can easily do

class MainActivity : BaseActivity<ActivityMainBinding>() { private lateinit var myHandler: MyHandler var countDown = 60 override fun initViews() { myHandler = MyHandler(Looper.getMainLooper()) Binding. Text. SetOnClickListener {/ /. Click on the start the countdown myHandler sendEmptyMessage (myHandler. ShowTime)} binding.btn.setOnClickListener { myHandler.sendEmptyMessage(myHandler.logOut) } } inner class MyHandler(looper: Looper) : Handler(looper) { val showToast = 1 val logOut = 2 val showTime = 3 override fun handleMessage(msg: Message) { super.handleMessage(msg) when (msg.what) { showToast -> { val obj = msg.obj Toast.makeText(this@MainActivity,  obj.toString(), Toast.length_long).show()} logOut -> {} showTime -> {log. d("MyHandler"," countDown in process :${countDown}") binding "CountDown" ${countDown} second countDown, the if (countDown > = 0) {myHandler. SendEmptyMessageDelayed (showTime, 1000)} else {countDown = 60}}}}}}Copy the code

Log. D (“MyHandler”,” countDown in progress :${countDown}”) will continue to print after exiting the page, indicating that the countDown continues

There are three ways to solve this problem, and my favorite is

 override fun onDestroy() {
        super.onDestroy()
        //countDown = -1
        myHandler.removeCallbacksAndMessages(null)
    }
Copy the code

Direct call removeCallbacksAndMessages, this parameter to null, remove all callbacks and messages is the other two methods

1. Use static inner classes: This is useful when you don’t need to update the interface, because static inner classes can’t use non-static methods and variables from external classes

2. Use static inner class + weak reference: this is suitable for updating the interface

Ok, I finished my first blog post, wish you happiness