Because of my knowledge of Handler, I added 5K directly? !

1 What is Handler?

The thread switching tool class provided by android. The main function is to switch from the child thread back to the main thread to perform the UI refresh operation through the handler.

1.1 Why can Handler realize thread switching?

When creating the Handler, you need to pass in the Looper of the target thread . (If the Looper is not passed in, the Looper of the current thread is taken by default. If the current thread is not ready, the Looper will throw an exception.)
When sendMessage, the current Handler object will be assigned to the target variable in the Message. And save the Message to the MessageQueue passed into the target thread Looper .
When Looper consumes the Message, it will get the taeget in the Message to execute the dispatchMessage(msg) method, thereby achieving thread switching.

Friends who read my article for the first time can follow me, share Android-related information from time to time, share Android hotspots in real time, and know what's new on Android for the first time.

1.2 Why can the main thread refresh the UI, but not the child threads?

'Android UI refresh is not thread-safe'  so there must be a thread dedicated to this thing, that is the main thread.
When refreshing the ui, it will check whether the current thread is the main thread, if not, it will throw an exception.

When the view is updated, due to changes in size, position, etc., requestLayout will be executed to tell the parent View to update the layout.
Then the parent View will also call requestLayout layer by layer, and finally go to ViewRootImpl#requestLayout,
and thread checking will be performed in its requestLayout .

//ViewRootImpl#requestLayout
@Override
public void requestLayout() {
        if (!mHandlingLayoutInLayoutRequest) {
            checkThread();
            mLayoutRequested = true;
            scheduleTraversals();
        }
    }

//ViewRootImpl#checkThread
void checkThread() {
    if (mThread != Thread.currentThread()) {
        throw new CalledFromWrongThreadException(
                "Only the original thread that created a view hierarchy can touch its views.");
    }
}

Strictly speaking, it is not impossible for a child thread to refresh the ui. Should ndroid be designed to refresh the ui only on the main thread?

Designed as a single-threaded refresh, the purpose is to improve stability and improve performance. ①Improve stability: If the problem of resource sharing in multithreading is not handled properly, it will cause data loss, duplication and confusion. Single thread can effectively reduce the risk of errors and improve stability.
②Extended from ①, if you want to deal with the problem of multi-threaded resource sharing, you need to increase synchronization locks, atomic classes, thread-safe collections, etc. There will inevitably be waiting, and because UI refresh is very
frequent, if there is a large number of and frequent waiting, it will increase the burden on the cpu, resulting in performance degradation.

I am here to organize and share interview questions related to Android intermediate and high-level with the big guys, View, Handler, Binder, Android learning PDF + architecture video + interview document + source code notes, advanced architecture technology advanced brain map, Android development interview special materials, Advanced advanced framework information, if you need it, you can also privately message me [Advanced] to get

2 How many Handlers does a thread have?

You can create an infinite number, but there will only be one Looper inside.

2.1 How many Loopers are there in a thread? How to guarantee?

A thread has only one Looper;
Looper is the only thread guaranteed by ThreadLocal, which is created and set into ThreadLocal in the Looper.prepare method.

2.2 Why can ThreadLocal guarantee the uniqueness of Looper thread?

Because the thread maintains a container of ThreadLocalMap, the container is specifically provided to ThreadLocal to obtain data.
The key is ThreadLocal, and the value is the data that needs to be obtained.

ThreadLocal design idea ① Thread holds a global variable ThreadLocalMap<ThreadLocal (weak reference), T (strong reference)> threadLocals
② ThreadLocal internal
get() -> get the current thread object -> get threadLocals (and judge empty, just empty it Create threadLocals for this thread) -> map.get(this) get the value
set(T value) -> get the current thread object -> get threadLocals (and if it is empty, create threadLocals for this thread) -> map. set(this, value)
remove() -> get the current thread object -> get threadLocals -> map.remove(this)

3 Why can the main thread be a new Handler?

Main thread: ActivityThread main method has prepared Looper for us. Looper.prepareMainLooper() Looper.loop()  This is an endless loop, which is the key to the main thread's survival.
So you can directly new Handler in the main thread, and you don't need to wear Looper parameters. (If Looper is not passed in, the Looper of the current thread is taken by default. If the current thread is not ready, Looper will throw an exception)

3.1 How to use Handler in child threads?

**Looper.prepare()**Prepare the Looper **Looper.loop()** Let the Looper run Looper.myLooper()  provided to the Handler to obtain the Looper of the thread.
Because the Looper of the child thread is created in prepare(), There is no guarantee that the external Hander can get a valid Looper immediately, so it needs to do the synchronization lock operation.

HandlerThread  encapsulates all synchronization operations, you can also use it.

3.2 What should I do if there is no message in the Looper maintained by the child thread?

Because Looper.loop() will always block the thread, the thread will not exit, which may cause memory leaks.
Need to manually exit Looper.quit() -> MessageQueue quit()
MessageQueue quit() work: clear all Messages, nativeWake wakes up waiting, next() continues execution, dispose()

3.3 Why doesn't the Looper of the main thread need to exit?

If the main thread Looper exits, the entire program will exit. Because the entire app program relies on Looper to distribute and process messages and handle life cycle callbacks.

4 What is the cause of Handler memory leak?

An anonymous inner class will hold a reference to the outer class by default. Memory leak : After the program applied to the system for allocation of memory space (new), it was not released after it was used. Memory leaks can easily cause OOM (Out of Memory). OOM : I want to use a 4M continuous space, but I can't find it. The system will throw OOM.

MessageQueue maintains all the Messages that will be processed. When enqueueMessage, the Handler object is stored in the Message target variable.
The life of all Messages may be longer than the life of the Activity where the Handler is located. The Activity is destroyed, but if the Message has not been executed, the Activity
cannot be destroyed, resulting in a memory leak.

5 How is the message blocking of Handler implemented?

The realization principle of Handler is realized by using two Linux system calls: eventfd + epoll eventfd is responsible for notifying epoll to be  responsible for monitoring.
First, a wake-up fd is created through the eventfd system call and registered in epoll.
If there is a delayed message into the queue, the blocking duration will be set for epoll according to the delay duration of the message, and epoll will automatically wake up when the timeout is known, and then return to the java layer to process the message.
If there is an immediate execution message into the queue, it will pass Write data to wake up fd to wake up epoll, and then return to the java layer to process the message.
If there is no message, epoll will block until it is awakened.

5.1 Looper.loop() will block the main thread but why doesn't ANR appear?

ANR : Application not responding abnormal ANR Cause : The current event has no chance to get treatment for example : currently dealing with a click event, but the processing inside the click event is time-consuming, the main thread will wait to deal with this time-consuming.
At the same time another click event is sent, and the new event will be blocked. When the event exceeds a certain time limit (the touch event is generally 5s) and has
not been executed, ANR will be thrown.

Therefore, the blocking of ANR and Looper.loop() is not related. And the blocking of Looper.loop() is designed to ensure that the main thread does not exit.

6 How can Handler let Message be executed as soon as possible?

Send asynchronous messages. Method : Use Message#setAsynchronous to set

This still cannot be implemented as quickly as possible. It is also necessary to add a synchronization barrier (a special message),
but the method of adding and removing synchronization barriers is not open to developers. So you need to use reflection to set it up.
Remember: the synchronization barrier must be removed after use, otherwise all synchronization messages behind the synchronization barrier cannot be executed.
The role of the synchronization barrier: intercept all synchronization messages behind the synchronization barrier, and only allow asynchronous messages to be used.

Usage scenario introduction: In ViewRoomtImpl, asynchronous messages are used a lot in order to make the message execute as soon as possible

//ViewRoomtImpl#scheduleTraversals
void scheduleTraversals() {
        if (!mTraversalScheduled) {
            mTraversalScheduled = true;
            mTraversalBarrier = mHandler.getLooper().getQueue().postSyncBarrier(); //添加消息屏障
            ...
        }
    }

//ViewRoomtImpl#unscheduleTraversals
    void unscheduleTraversals() {
        if (mTraversalScheduled) {
            mTraversalScheduled = false;
            mHandler.getLooper().getQueue().removeSyncBarrier(mTraversalBarrier); //移除消息屏障
            ...
        }
    }

7 Does the Handler have any mechanism that is helpful for program optimization?

IdleHandler : You can do some less time-consuming operations when the program is idle. How to use :
mHandler.getLooper().getQueue().addIdleHandler
mHandler.getLooper().getQueue().removeIdleHandler

IdleHandler#queueIdle(): The return value is used to tell MessageQueue true : The IdleHandler will be called every time it enters the block until the IdleHandler is removed. false : IdleHandler is automatically removed after calling IdleHandler only once.

Usage scenarios: 1. Activity startup optimization, onCreate, onStart, onResume less time-consuming but non-essential code can be executed in IdleHandler to reduce startup time.
2. If you want to add other Views that depend on this View after drawing a View, of course this View#post() can also be implemented, the difference is that the former will be executed when the message queue is idle.

8 How does MessageQueue ensure thread safety?

In order to ensure thread safety, many methods inside MessageQueue have added the object lock synchronized (this).

9 How to create Message?

Message.obtain(): Use reuse pool to reduce new Message and prevent frequent GC. (Frequent GC will cause memory jitter (STW) -> lead to
freeze ) Design mode: Flyweight mode (similar to example recycleview bindView createView)

At last

In this way, I also share a collection of ** View, Handler, Binder, Android learning PDF + architecture video + interview document + source notes, advanced architecture technology advanced brain map, Android development interview special materials, advanced advanced Architecture information **

image.png

These are all fine materials that I will read again and again in my spare time. There are detailed explanations on the high-frequency knowledge points of interviews with major factories in recent years. I believe it can effectively help everyone master knowledge and understand principles.

You can also use it to check for omissions and improve your competitiveness.

If you need it, you can also privately message me [Advanced] to get

If you like this article, you might as well give me a like, leave a message in the comment area, or forward and support it~

Guess you like

Origin blog.csdn.net/A_pyf/article/details/114092316