Handler Processing mechanism

Android subthreads cannot dynamically change the properties of UI components in the main thread. When the program starts, the Activity starts the main thread, the UI thread, which processes user input and presents the results of the calculation to the user. When dealing with some operations that may block, it is necessary to start the sub-thread to prevent the main thread from blocking. For example, when a user requests to download resources from the network, the UI cannot appear “stuck”. Examples of multi-threading abound.

eg:

finalTextView textView= findViewById(R.id.tv); Button button= (Button) findViewById(R.id.button); A button. SetOnClickListener (new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        // Create new thread
        Thread thread = new Thread(new Runnable() {
            @Override
            public void run(a) {
                // Try updating the properties of the Text View component in the main thread
                textView.setText("mask"); }}); thread.start();// Start the thread}});Copy the code

Running results:

android.view.ViewRootImpl$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.
        at android.view.ViewRootImpl.checkThread(ViewRootImpl.java:8913)
        at android.view.ViewRootImpl.requestLayout(ViewRootImpl.java:1557)
        at android.view.View.requestLayout(View.java:24694)
        at android.view.View.requestLayout(View.java:24694)
        at android.view.View.requestLayout(View.java:24694)
        at android.view.View.requestLayout(View.java:24694)
        at android.view.View.requestLayout(View.java:24694)
        at android.view.View.requestLayout(View.java:24694)
        at android.view.View.requestLayout(View.java:24694)
        at android.widget.TextView.checkForRelayout(TextView.java:9750)
        at android.widget.TextView.setText(TextView.java:6314)
        at android.widget.TextView.setText(TextView.java:6142)
        at android.widget.TextView.setText(TextView.java:6094)
        at com.xxx.a02_handler.MainActivity$1$1.run(MainActivity.java:26)
        at java.lang.Thread.run(Thread.java:929)
Copy the code

Only the thread that created the view can manipulate the view. If the TextVIew component is created in the main thread, the child thread cannot gain control of the component. So there must be a way for the child threads to notify the main thread, which then changes the component’s property values.

Handler is a Message processing mechanism provided by Android. The Handler sends and processes a Message object to the MessageQueue of its thread. When Looper polls for the Message, Use handler.handlermaeesage () to handle.

Back in the case, the main thread needs to be able to handle messages with handlers, so you can register a callback. You just need to override the methods in the Handler class that handle the message. When the newly started thread sends a message, the methods in the Handler class that handle the message are automatically called back.

The three methods are as follows:

@Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        final TextView textView = findViewById(R.id.tv); // Get the textbox component
        Button button=  findViewById(R.id.button); // Get the button component

        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                // Create new thread
                new Thread(new Runnable() {
                    @Override
                    public void run(a) {
                        // The operation to perform
                        Message message = new Message();
                        message.what = 0;
                        Bundle bundle = new Bundle();
                        bundle.putString("name"."mask");
                        message.setData(bundle);
                        mhandler.sendMessage(message);
                    }
                }).start(); // Start the thread
            }

            Handler mhandler = new Handler() {
                // Register to handle callbacks to messages
                @Override
                public void handleMessage(@NonNull Message msg) {
                    if(msg.what == 0) {
                        textView.setText(msg.getData().getString("name")); }}}; }); }Copy the code
@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    final TextView textView = findViewById(R.id.tv);
    Button button=  findViewById(R.id.button);
    button.setOnClickListener(new View.OnClickListener() {
        Message message = null;
        @Override
        public void onClick(View v) {
            // Create new thread
            new Thread(new Runnable() {
                @Override
                public void run(a) {
                    // The operation to perform
                    message = new Message();
                    message.what = 0;
                    Bundle bundle = new Bundle();
                    bundle.putString("name"."mask");
                    message.setData(bundle);
                    mhandler.post(t);
                }
            }).start(); // Start the thread
        }

        Handler mhandler = new Handler();
        Thread t = new Thread() {
            @Override
            public void run(a) {
                textView.setText(message.getData().getString("name")); }}; }); }Copy the code
@Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        final TextView textView = findViewById(R.id.tv); // Get the textbox component
        Button button=  findViewById(R.id.button); // Get the button component

        button.setOnClickListener(new View.OnClickListener() {

            Message message = null;
            @Override
            public void onClick(View v) {
                // Create new thread
                new Thread(new Runnable() {
                    @Override
                    public void run(a) {
                        // The operation to perform
                        message = new Message();
                        message.what = 0;
                        Bundle bundle = new Bundle();
                        bundle.putString("name"."mask");
                        message.setData(bundle);
                        MainActivity.this.runOnUiThread(t);
                    }
                }).start(); // Start the thread
            }

            Thread t = new Thread() {
                @Override
                public void run(a) {
                    textView.setText(message.getData().getString("name")); }}; }); }Copy the code

Handler works as follows:

Each Handler instance is associated with a single thread and that thread’s message queue. When you create a new Handler it is bound to a Looper. It will deliver messages and runnables to that Looper’s message queue and execute them on that Looper’s thread.

Each Handler instance corresponds to a thread and the message queue for that thread. When a Handler is created, it is bound to Looper. Handler sends messages and runnable objects to the message queue of the Looper and executes them on the thread of the Looper.

In the main thread, an object is automatically initialized, so you can create a Handler directly in your program, which can then be used to send and process messages. In the child thread, you must manually create a Looper object and start the Looper using the loop() method. The steps for using Handler in child threads are as follows:

  • The prepare() method of Looper is called to create a Looper object for the current thread, and the corresponding MessageQueue is created in the constructor that created the Looper object.
  • Create an instance of a Handler subclass that overrides the handlerMessage() method used to handle messages from other threads.
  • Call Looper’s loop() method to start Looper.

Eg: Create child thread 2 again in child thread 1, thus creating a looper in child thread 1, then child thread 1 also has a process of handler processing mechanism. The code is as follows:

@Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        final TextView textView = findViewById(R.id.tv); // Get the textbox component
        Button button=  findViewById(R.id.button); // Get the button component

        Looper.getMainLooper();
        button.setOnClickListener(new View.OnClickListener() {

            Message message = null;
            @Override
            public void onClick(View v) {
                Log.d("xixi"."main:"+android.os.Process.myTid());
                // Create new thread
                new Thread(subThread).start(); // Start the thread
            }
            Thread subThread = new Thread() {
                @Override
                public void run(a) {
                    Looper.prepare();
                    Log.d("xixi"."outer:"+android.os.Process.myTid());
                    new Thread() {
                        @Override
                        public void run(a) {
                            Log.d("xixi"."inner:"+android.os.Process.myTid());
                            message = new Message();
                            message.what = 0;
                            Bundle bundle = new Bundle();
                            bundle.putString("name"."mask");
                            message.setData(bundle);
                            handler.sendMessage(message);
                        }
                    }.start();
                    Looper.loop();

                }

                Handler handler = new Handler() {
                    @Override
                    public void handleMessage(@NonNull Message msg) {
                        Log.d("xixi",message.getData().getString("name")); }}; }; }); }Copy the code

Running results:

D/xixi: main:25406
D/xixi: outer:26836
D/xixi: inner:26837
D/xixiu: mask
Copy the code

Android.os. Looper main functions:

Looper.prepare(); Create a Looper object for the current thread

Looper.getMainLooper(); // Returns the Looper object for the main thread currently applied

Looper.myLooper(); // Returns the Looper object of the current thread

Looper.loop(); // Start Looper. Get the Message from the Message queue, and perform the MSG. Target. DispatchMessage (MSG), MSG. The target is bound to the Message queue Handler
Copy the code