Handler interview things

1. What are the ways of communication from child thread to main thread? The principle of sub thread to main thread communication?

This is a unique concept of Android. Communication mode between threads: eventbus, rxjava, livedata. However, the underlying principles of these methods are based on handler, so I will explain the principle of handler communication for you.

handler scheduling process:

Sub thread: handler.sendMessage(msg) = "handler.enqueueMessage =" MessageQueue.enqueueMessage())
Main thread: loop. Loop = "queue.next() =" handler.handleMessage())

Core schematic diagram of handler:

Illustrations of two important categories:   ​

2. What is the cause of the handler memory leak?  

JVM garbage collection mechanism: GCroot collection mechanism

Holding chain:   static sThreadLocal ->   mLooper ->MessageQueue ->msg ->handler ->   activity

Solution: break the holding chain

3. How to create a handler in a child thread?

  • Writing method 1: directly create a handler in the sub thread. Error
new Thread(
                () -> {
                    Handler mHandler = new Handler(new Handler.Callback() {
                        @Override
                        public boolean handleMessage(@NonNull Message msg) {
                            return false;
                        }
                    });

                    mHandler.sendMessage(new Message());
                }
).start();

Error reporting display:

Process: com.wust.empty02, PID: 25002
    java.lang.RuntimeException: Can't create handler inside thread Thread[Thread-2,5,main] that has not called Looper.prepare()
        at android.os.Handler.<init>(Handler.java:207)
        at android.os.Handler.<init>(Handler.java:133)
        at com.wust.empty02.MainActivity.lambda$onCreate$0$MainActivity(MainActivity.java:20)
        at com.wust.empty02.MainActivity$$ExternalSyntheticLambda0.run(Unknown Source:2)
        at java.lang.Thread.run(Thread.java:919)

Error source location:

  • Writing 2: correct writing
new Thread(
                () -> {
                    //Create a looper for this thread
                    Looper.prepare();
                    //Create a handler for this thread
                    Handler mHandler = new Handler(new Handler.Callback() {
                        @Override
                        public boolean handleMessage(@NonNull Message msg) {
                            return false;
                        }
                    });
                    //looper open loop
                    Looper.loop();
                    
                }
).start();

  This approach has a disadvantage: in this way, the thread can only create one handler.

  • Writing 3: Pass   public Handler(@NonNull Looper looper) use this constructor to create a handler
package com.wust.empty02;


import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import androidx.appcompat.app.AppCompatActivity;

public class MainActivity extends AppCompatActivity {

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

        MyHandlerThread t = new MyHandlerThread();
        t.start();
        try {
            //If this sentence is removed, t.getmloop() will be null, because you can't guarantee that handler = new handler (t.getmloop()); Execute after t thread run
            Thread.sleep(1000*3);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        Handler handler = new Handler(t.getmLooper());
    }
}

class MyHandlerThread extends Thread {
    private Looper mLooper;

    @Override
    public void run() {
        Looper.prepare();
        this.mLooper = Looper.myLooper();
        Looper.loop();
    }

    public Looper getmLooper() {
        return mLooper;
    }
}

From the comments of the above code, we can clearly see its shortcomings. No guarantee   t. Getmloop () executes after the thread run method.

  • Method 4: use   HandlerThread create thread
HandlerThread t = new HandlerThread("wustyq");
t.start();
Handler handler = new Handler(t.getLooper());

This of the system   Why can the run method in HandlerThread ensure that   t. Before getlooper()?? Key codes + key ideas are as follows:

Why    synchronized ? To solve the problem of concurrent operations = ", i.e. run and   getLooper can only execute one at a time.

Why   notifyAll() ? Because it is possible that multiple threads have called the wait() method to wait.

Why use while? No if? Because this wait() may be awakened by another thread, notify(). So use while to detect repeatedly.

4. What is the processing scheme for the Looper maintained in the sub thread when there is no message in the message queue? What's the usage? What about the main thread?

quit: loop exit. Prevent memory leaks. Will not be stopped.

5. How does the handler handle sending delayed messages?

The underlying Linux = "epoll" will be called to complete the wait

6. How should we create Message when we use it?

obtain()

Tags: Java

Posted on Sun, 05 Dec 2021 21:29:14 -0500 by rcity