background

Handler Handler

Handler and memory leaks

The Handler itself does not leak memory. Memory leaks are caused by circular references, but by the nature of the Handler, it often holds an external Context, making it a common circular reference scenario. A common way to solve this problem is to use weak references

   static  class MyHandler : Handler {
        var context: WeakReference<Context>

        constructor(context: Context) {
            this.context = WeakReference(context)
        }

        override fun handleMessage(msg: Message) {
            when (msg.what) {
                SKIP_MAIN -> {
                    context.get()? .apply { startActivity(Intent(this, MainActivity::class.java))
                    }
                }
                else -> throw IllegalArgumentException()
            }
            super.handleMessage(msg)
        }
    }
Copy the code

It is also possible to actively remove the message and nullify the Handler in the external object corresponding to the lifecycle

    override fun onCreate(savedInstanceState: Bundle?). {
        super.onCreate(savedInstanceState)
        mHandler = MyHandler(this);
    }

    override fun onDestroy(a) {
        super.onDestroy()
        mHandler.removeCallbacksAndMessages(null);
        mHandler = null;
    }
Copy the code

Can child threads update the UI?

Use Looper

new Thread(new Runnable() {
  @Override
  public void run(a) {
    Looper.prepare();
    Toast.makeText(HandlerActivity.this."It won't crash!", Toast.LENGTH_SHORT).show();
    Looper.loop();
  }
}).start();
Copy the code

Why is Looper not stuck when there are dead loops

  1. Processes and threads

Typically an App runs in a process that has multiple threads in it. If one thread becomes overloaded, will the entire application freeze?

Of course not, the CPU ensures that each task has as fair a slice of time as possible, meaning that a full thread does not affect the execution of tasks on other threads, thus preventing the entire application from being stuck. Unless this thread is the main thread, because it takes over a lot of important work including the UI.

  1. The essence of Caton

From a UI drawing point of view, drawing in 16ms is done without feeling the drop frames, which are stuck on the UI. We execute an infinite loop of code, but as long as we make sure that the event of the response is responded and the UI of the drawing is drawn within the 16ms period, we don’t feel stuck either.

  1. Pipe/epoll mechanism

Although it does not cause a lag, does it cost performance to do this? The Loop queue.next() method uses Linux’s pipe/epoll mechanism, which is similar to the way we normally listen for callbacks. That is, wake up when there is an event and block when there is no event. Therefore, the main thread is dormant most of the time and does not consume a lot of CPU resources.

  1. Why design for an infinite loop

For example, the life cycle method of the system component Activity relies on the message mechanism of the Handler. If the Loop exits, the system message cannot respond. So if you try to exit the main Loop an exception will occur

Caused by: java.lang.IllegalStateException: Main thread not allowed to quit.
at android.os.MessageQueue.quit(MessageQueue.java:415) 
at android.os.Looper.quit(Looper.java:240)
Copy the code

What is LocalThread

Look at a case, if I want the data to be thread scoped and different threads have different copies of the data.

int num = 1; Log.d("ThreadLocalActivity", "Thread:" + Thread.currentThread().getName() + " name:" + name.get()); new Thread("thread1") { @Override public void run() { num = 2; } }.start(); new Thread("thread2") { @Override public void run() { num = 3; } }.start(); Logd (" now num is :"+num);Copy the code

That’s the chestnut on top. I’m looking forward

Num = 1 on the main thread

In thread1 num = 2

In thread2 num = 3

Typically, you can use a Map with the thread name as the key to store the data in. LocalThread encapsulates this approach

/ / that
    private ThreadLocal<Integer> num = new ThreadLocal<>();

/ / use
    num.set(1);
    Log.d("ThreadLocalActivity"."Thread:" + Thread.currentThread().getName() + " name:" + name.get());
    new Thread("thread1") {
        @Override
        public void run() {
            num.set(2);
          }
    }.start();
    new Thread("thread2") {
        @Override
        public void run() {
            num.set(3)
        }
    }.start();
    logd("Now num is :"+num);
Copy the code