How to create and use Handler in the child thread

Previous article we analyzed from the perspective of the source code Handler realization of this article we said Handler at how to create a sub-thread, Handler created just two steps in the child thread:

  1. Create a looper: Looper.prepare ()
  2. Start looper: Looper.loop ()

To create the external current Thread Handler provides a method to get the current Looper,

Java code is as follows:

public class HandlerThread extends Thread {

    private Looper mLooper;

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

    public Looper getLooper() throws Exception {
        if (!isAlive()) {
            throw new Exception("current thread is not alive");
        }
        if (mLooper == null) {
            throw new Exception("current thread is not start");
        }
        return mLooper;
    }
}

Let us take a look at using the following:

class MainActivity : AppCompatActivity() {
    
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        val handlerThread = com.example.handlerdemo.HandlerThread()
        handlerThread.start()
        val handler1 = object : Handler(handlerThread.getLooper()) {
            override fun handleMessage(msg: Message?) {
                super.handleMessage(msg)
                Log.d("aaa", "thread:${Thread.currentThread().name},handle message")
            }
        }

        handler1.sendMessage(Message.obtain())
    }
    
}

The code above is to create a very simple and HandlerThread start, and then create a Handler by HandlerThread looper, sending a message for authentication.
However, we will find that we run a direct crash, abnormal follows:
Here Insert Picture Description
to find the corresponding code that we found to be caused by an uninitialized mLooper, can we first start looper code is then obtained, why not initialize it? In fact, here is a typical thread synchronization problem, because we start HandlerThread and create Handler are running in the main thread, and HandlerThread run method is to run sub-threads, all leading to getting looper HandlerThread not yet initialized looper, then how to solve this problem?

The most simple solution: by notifyAll and wait

public class HandlerThread extends Thread {

    private Looper mLooper;

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

    public Looper getLooper() throws Exception {
        if (!isAlive()) {
            throw new Exception("current thread is not alive");
        }
        synchronized (this){
            if (null == mLooper){
                wait();
            }
        }
        return mLooper;
    }
}

In operation, the output log is as follows:
Here Insert Picture Description
We found handler process is a process rather than the main thread in the child thread.
In fact, there are many ways to resolve thread synchronization, such as infinite loop waiting, Semaphore (Semaphore), etc., but is recommended to use the above method.

In fact, SDK has provided us with HandlerThread, we do not need to achieve their own, some people might say this is not your egg hurt?
I want to say that we not only have to use the api SDK provided, we have to learn thinking of them, I can say clearly that all classes and api SDK it? In the beginning I really do not know HandlerThread this class, then there are the needs of the project was able to achieve this class, I remember very clearly, is beginning to pay attention to thread synchronization issues, use of the time only to find, this class although very simple but it involves a lot of knowledge, such as the operating principle Handler, thread synchronization.
Here we look at HandlerThread system:
Here Insert Picture Description
through these two constructors we can find the name of this thread and set priorities.
Here Insert Picture Description
Compare more onLooperPrepared methods and our run method, which is to subclass rewritten.
We look getLooper method:
Here Insert Picture Description
and I wrote the main difference in the synchronized code block, except as follows:

  1. If we are to judge, and the judge while loop system.
  2. We do not have the time to determine isAlive, and the system judgment.
  3. Without throwing an exception, but directly returned null.

Let's think the first question whether the while loop, think about if you call

handlerThread.notifyAll();

Then we will return null, obviously this is not what we want, so the while loop is necessary, as long as the looper is null waits.

The second problem: As already judged isAlive (), while circulating the need for interpretation again, note that wait is pending operation, if pending when the user ends the thread, the thread is over at this time, so the need to judge.

The third question: is throwing an exception or returns null, and now want to come personally feel that these two methods are not very good, first of all return null, which requires the user to handle the null case, throwing an exception will be less convenient in use, the user need to handle their own exceptions, as follows:
Here Insert Picture Description
require the user to try ... catch
but the 2-to-1 return null, then think better, but when we need to pay attention to some use.
Continue to look HandlerThread Source:

Here Insert Picture Description
Here are a Handler object, if this Handler, how to override that handleMessage way to do that? Temporarily did not think this method of sense in what?

Continue to look:
Here Insert Picture Description
Here are two ways to exit, these two methods is a method looper's no longer here to explain.

Conclusion: is such a simple function, which involves many aspects, when looking at the source code is more important is to learn their thoughts, looking at the source code when you can think about is if I write this function, how can I to write? Do not just think about it, not hands-on writing, after writing and comparing the system will learn more things.

Published 113 original articles · won praise 66 · Views 300,000 +

Guess you like

Origin blog.csdn.net/mengks1987/article/details/87797941
Recommended