Memory jitter of Android Handler and how to create Handler in sub-thread

1. Introduction

        Handler, as a message distribution tool that survives on the main thread, is frequently used in the App development process and is also frequently asked in interviews.

        Common interview questions such as: How to create sub-threads? What is the mechanism of Handler? Memory jitter, etc. Next, we will summarize and guide the use of Handler

Two, use

1. Use in the main thread

        The use of the main thread is a common way of writing Handler, as follows:

var handler=Handler() is created in this way

        However, one could argue that we are paired with weak references during usage.

public abstract class WeakHanlder<T> extends Handler {

    private WeakReference<T> weakReference;

    public WeakHanlder(T activity) {
        weakReference = new WeakReference<T>(activity);
    }

    @Override
    public final void handleMessage(Message msg) {
        if (weakReference.get() == null) {
            handleMessageWhenNotServive(msg);
        } else {
            if (weakReference.get() instanceof Fragment) {
                Fragment fragment = (Fragment) weakReference.get();
                if (fragment.getActivity() == null) {
                    handleMessageWhenNotServive(msg);
                } else {
                    handleMessageWhenServive(msg, weakReference.get());
                }
            } else {
                handleMessageWhenServive(msg, weakReference.get());
            }

        }


    }

    //当引用对象存在(未被GC回收)时,调用此方法
    public abstract void handleMessageWhenServive(Message msg, T host);

    //当引用对象不存在(已被GC回收)时,调用此方法,非必须重写
    public void handleMessageWhenNotServive(Message msg) {
    }


    public WeakReference<T> getWeakReference() {
        return weakReference;
    }

}

If referenced, it can avoid the current target object being recycled, and the message of the handler has not been consumed, which will cause OOM.

1.2, memory jitter

The direct cause of memory jitter is that objects cannot be created and consumed. This phenomenon can be directly seen through the profiler tool of AndroidStudio.

If you keep releasing and creating, the pop chart is like the electrocardiogram we see, with wavy lines up and down, forming a state of jitter.

What is the reason for this?

When Handler sends a message, we should not always create it through new Message,

It should pass handler.obtain(), which is reused in memory. In Message, there is an object called mPool, which is the current Message thread pool. Take one when it is used, and release it when it is not used.

        var handler=Handler()

        var msg= handler.obtainMessage()
        msg.what=0;
        handler.sendMessage(msg)
        
        

If we only send one notification, we can send an empty message directly by

 handler.sendEmptyMessage(1)

1.3、OOM

        The handler is asked more frequently than oom, and everyone should be very clear about the reason for oom. This is related to GC recycling. GC recycling is divided into two situations, one is GC and the other is GCRoot. GCRoot is the static variable we often define.

If we do not manually recycle the static object, GCRoot will not be released, so there is another way to define it as a static variable for use

companion object{
    var handler=Handler()

}

2. The child thread creates a Handler

        It may be the first time for some friends to hear that sub-threads create Handlers, because Handlers are the main thread, and they are commonly used to handle UI update operations of sub-threads. This is the first time that many sub-threads have been created. This will involve multi-threading issues

Child thread creates Handler:

child thread creation

public class TestThread extends Thread implements Runnable {

    private Looper looper;


    @Override
    public void run() {


        Looper.prepare();

        looper = Looper.myLooper();


        Looper.loop();

    }


    public Looper getLooper() {

        return looper;
    }


}

transfer:

        var thread=TestThread()
        thread.start()



        var handler = Handler(thread.looper,object :Handler.Callback{
            override fun handleMessage(p0: Message): Boolean {
                showToast("TestThread")
                return false
            }
        })
        handler.sendEmptyMessage(1)

        At this point, the creation of the child thread has been completed, but there is a problem here. When we call the child thread start(), the thread starts to execute the run() function. At the same time, we also call getLooper() to get it. When the cpu time is not allocated to this thread, the looper we get is empty. Here, there is clearly a minefield.

This involves multithreading issues:

        Processing can be done through wait and notify, some people may ask, why not sleep? Sleep will cause the thread to block, and wait is to transfer the cpu time. For this, we can design a multi-thread for waiting and notification.

        Some people will mention using locks to complete, you can try it, and here you can also remind the fair lock, ReentrantLock.

This problem has been solved in the Android system thread HandlerThread

With wait and notify and synchronized:

public class TestThread extends Thread implements Runnable {

    private Looper looper;


    @Override
    public void run() {

        Looper.prepare();
        synchronized (this) {

            looper = Looper.myLooper();
            notifyAll();

        }
        Looper.loop();

    }


    public Looper getLooper() {

        synchronized (this) {
            try {
                while (looper == null) {
                    wait();
                }
            } catch (Exception e) {

            }

        }
        return looper;
    }


}

With HandlerThread:

When run() is executed, the current object is locked by synchronized

run()
getLooper()
​​​​​​

        This completes a multi-threaded mechanism. When polled looper is empty, enter the waiting state, when receive notify(), release.

At the same time, it also supports exiting the message queue

In this way we have completed the child thread creation Handler.

Attach the HandlerThread source address: HandlerThread.java - OpenGrok cross reference for /frameworks/base/core/java/android/os/HandlerThread.java

Guess you like

Origin blog.csdn.net/qq36246172/article/details/129119270