0

1.I have a problem about creating a handler in a child thread

like

public class Main4Activity extends Activity {

private TextView mTextView;

@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    mTextView = (TextView) findViewById(R.id.text_view);
    new Thread() {
        @Override
        public void run() {
            Looper.prepare();
            @SuppressLint("HandlerLeak") Handler handler = new Handler() {
                @Override
                public void handleMessage(Message msg) {
                    Toast.makeText(Main4Activity.this, "handler msg", Toast.LENGTH_SHORT).show();
                    try {
                        Thread.sleep(200);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    mTextView.setText("100");
                }
            };
            handler.sendEmptyMessage(1);
            Looper.loop();
        }
    }.start();
}

} The above code will crash.

Process: com.example.hellokai.kotlindemo, PID: 27485
                                               android.view.ViewRootImpl$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.
                                                   at android.view.ViewRootImpl.checkThread(ViewRootImpl.java:6986)
                                                   at android.view.ViewRootImpl.requestLayout(ViewRootImpl.java:1074)
                                                   at android.view.View.requestLayout(View.java:19889)
                                                   at android.view.View.requestLayout(View.java:19889)
                                                   at android.view.View.requestLayout(View.java:19889)
                                                   at android.view.View.requestLayout(View.java:19889)
                                                   at android.support.constraint.ConstraintLayout.requestLayout(ConstraintLayout.java:1959)
                                                   at android.view.View.requestLayout(View.java:19889)
                                                   at android.widget.TextView.checkForRelayout(TextView.java:7369)
                                                   at android.widget.TextView.setText(TextView.java:4480)
                                                   at android.widget.TextView.setText(TextView.java:4337)
                                                   at android.widget.TextView.setText(TextView.java:4312)
                                                   at com.example.hellokai.kotlindemo.Main4Activity$1$1.handleMessage(Main4Activity.java:40)
                                                   at android.os.Handler.dispatchMessage(Handler.java:102)
                                                   at android.os.Looper.loop(Looper.java:154)
                                                   at com.example.hellokai.kotlindemo.Main4Activity$1.run(Main4Activity.java:45)

2.I know to update ui in the main thread,handler creation in the main thread to create, and then send a message in the child thread to the handler can update Ui.

3.My question is what is the role of the handler created in the child thread? When do we need to do that? What is the use of the scene?

Hope someone can solve my confusion!

kai hello
  • 135
  • 1
  • 2
  • 13

2 Answers2

1
  1. I have a problem about creating a handler in a child thread.

Your are updating ui from the background thread.

For Example you could send a message from a thread and update ui like

private Handler handler = new Handler(Looper.getMainLooper()) {
    @Override
    public void handleMessage(Message msg) {
        Toast.makeText(Main4Activity.this.getApplicationContext(), "handler msg", Toast.LENGTH_SHORT).show();

        mTextView.setText((String)msg.obj);
    }
};

and then

  new Thread() {
        @Override
        public void run() {

            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            Message msg = Message.obtain(); // Creates an new Message instance
            msg.obj = "Hello";
            handler.sendMessage(msg);

        }
    }.start();

Or If you just want a delay there is not need for a thread, looper and sleep as already noted in comments by pskink https://developer.android.com/reference/android/os/Handler.html

  1. I know to update ui in the main thread,handler creation in the main thread to create, and then send a message in the child thread to the handler can update Ui.

Yes your are right you can create the handler on the ui thread you can send message from the thread and update your ui

  1. My question is what is the role of the handler created in the child thread?

Handler is associated with a thread's looper. If you have a handler in ui thread its associated with it. In your case you have it inside a thread and hence handler is associated with that threads looper.

When do we need to do that? What is the use of the scene?

When you want to communicate from a backgroud thread to ui thread or from ui thread to background thread.

Raghunandan
  • 132,755
  • 26
  • 225
  • 256
  • Thanks for your answer! From the sub-thread to create a handler is to deal with time-consuming threads, this time handlr should be in a work thread, rather than the main thread in the implementation. I saw Google wrapped a HandlerThread class. I do not understand the HandlerThread and ordinary Thread difference.Why do not use a thread class to deal with, but with a HandlerThread class to deal with, and packaging HandlerThread class to deal with, what is its advantage? – kai hello Sep 12 '17 at 07:34
  • HandlerThread has a looper. looper has a message queue which keeps the thread alive for a longer time looping over the message queue. Thread in java is done after the its run method finishes. You can communicate between threads using a Handler. If you have a java thread and you want it to be alive for a longer time you would have looper.loop and looper.prepare. Also call quit when done – Raghunandan Sep 12 '17 at 07:38
  • https://blog.mindorks.com/android-core-looper-handler-and-handlerthread-bd54d69fe91a do have a read. You could also look at home these classes work looking at the source code Apart from that you can look at Extending a service topic in docs which also helps you understand HandlerThread and handler – Raghunandan Sep 12 '17 at 07:40
  • Have i answered your questions or do you have confusions yet? – Raghunandan Sep 12 '17 at 08:50
  • I am sorry that I have other things to deal with so before I reply to you, I understand the difference between HandlerThread and Thread. You share the article very well. – kai hello Sep 12 '17 at 10:23
  • no problems. you can edit your question or ask a new question if you have further questions and i will try best to answer. – Raghunandan Sep 12 '17 at 10:28
0

Your code

new Thread() {
    @Override
    public void run() {
        Looper.prepare();
        @SuppressLint("HandlerLeak") Handler handler = new Handler() {
            @Override
            public void handleMessage(Message msg) {
                Toast.makeText(Main4Activity.this, "handler msg", Toast.LENGTH_SHORT).show();
                try {
                    Thread.sleep(200);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                mTextView.setText("100");
            }
        };
        handler.sendEmptyMessage(1);
        Looper.loop();
    }
}.start();

Can be rewrote to use Android apis:

new Handler(getMainLooper()).postDelayed(
new Runnable() {
    @Override
    public void run() {
                Toast.makeText(Main4Activity.this, "handler msg", Toast.LENGTH_SHORT).show();
                mTextView.setText("100");
        }
    }
}, 200);

Note also that your main problem is that you create the Handler inside the Runnable that already is in a worker-thread, you can also create it early in the onCreate.

Marcos Vasconcelos
  • 18,136
  • 30
  • 106
  • 167