Android TextView.setText() invoked & returned before Thread.sleep() blocks until sleep() returns. Why?

前端 未结 2 1753
走了就别回头了
走了就别回头了 2020-12-11 10:32

In the Android framework, if a TextView\'s setText() method is called, and after it returns Thead.sleep() is called, then the screen of the device does not display the given

相关标签:
2条回答
  • 2020-12-11 11:31

    1)Never sleep that long on the UI thread. In fact, never sleep on it at all. That causes it to block and makes the phone unresponsive

    2)setText calls invalidate on the view. That will cause the framework to draw the view again as soon as its able- but that means needs to finish the current things its doing and get back to the main Looper (basically, it needs to return from whatever method in your code it first calls). Until then, the change won't be visible on screen.

    Edit: to put it another way, inside the framework we have

    do{
        Message msg = nextMessage();
        if(msg.what == ON_CREATE){
           currentActivity.onCreate();
        }
        else if(msg.what == DRAW){
            rootView.onDraw();
            //draw entire screen
        }
        else 
          ...  //Thousands of more events like touches, handlers, etc
    

    It can't get to the draw message until its done with the current message. Its single threaded.

    0 讨论(0)
  • 2020-12-11 11:38

    The reason for the observed behavior is that Views are only redrawn after the completion of each cycle through the event loop. The android onCreate() method, as well as touch events such as clicking a button, are invoked by the framework from within the event loop. Thus, methods such as onCreate() or onClick() will execute to completion before any Views are redrawn, and there will be no visible effect on the display until after those methods have returned. Changes to Views made from within those methods will only become visible after completion of the event loop cycle from within which the framework invoked said method (onCreate(), onClick(), etc.).

    To achieve the behavior requested in the question, invocation of the sleep() method must occur after completion of the event loop cycle in which you invoked setText() with the text you want to be displayed during time the thread is blocking. One way to do this is simply to replace the call to sleep() with a call to View.post(). View.post() takes a Runnable whose run() method will be called after the current cycle of the event loop has completed and the framework has displayed the text you want to see during the time the thread is blocking. Change the doDelay() method in the question by placing the call to Thread.sleep() inside a Runnable's run() method like this:

        public void doDelay(View view) {
            final TextView textView = (TextView) view;
            textView.setText("Sleeping");
            textView.post(new Runnable() {
                public void run() {
                    try {
                        Log.d("Sleeper", "Thread " + Thread.currentThread() + " going to sleep...");
                        Thread.sleep(5000L);
                        Log.d("Sleeper", "Thread " + Thread.currentThread() + " now awake");
                        textView.setText("Ready");
                    } catch (InterruptedException e) { finish(); }
                }
            });
        }
    

    My thanks goes to to Gabe Sechan, whose guidance got me unstuck enough to answer my own question.

    0 讨论(0)
提交回复
热议问题