Вопрос:

Android TextView.setText () вызывается и возвращается до блоков Thread.sleep () до тех пор, пока не вернется sleep (). Почему?

java android multithreading

1583 просмотра

2 ответа

1130 Репутация автора

В платформе Android, если вызывается метод a TextViewи setText()вызывается его возвращение Thead.sleep(), экран устройства не отображает заданный текст до тех пор, пока sleep()не вернется. Почему?

public class SleeperActivity extends Activity {
    public void onCreate(Bundle bundle) {
        super.onCreate(bundle);
        setContentView(R.layout.main);
    }

    public void doDelay(View view) {
        try {
            TextView textView = (TextView) view;
            textView.setText("Sleeping");
            Log.d("Sleeper", "This log entry is invoked before sleeping");
            Thread.sleep(5000L);
            textView.setText("Ready");
        } catch (InterruptedException e) { finish(); }
    }
}

Макет, не показанный, имеет кнопку, onClickатрибут которой установлен в doDelay().

Когда приведенный выше код скомпилирован и запущен, а кнопка нажата, текст, переданный при первом вызове, setText()не будет отображаться на экране до тех пор, пока поток не проспит пять секунд, даже если запись журнала появляется в журнале перед пять секунд начинают проходить.

Почему это происходит, и что я должен с этим делать, чтобы текст, переданный во время первого вызова, setText()появлялся на экране до того, как поток начинает спать?

Автор: Adam Mackler Источник Размещён: 16.05.2013 07:07

Ответы (2)


3 плюса

72564 Репутация автора

1) Никогда не спите так долго в потоке пользовательского интерфейса. На самом деле, никогда не спать на нем вообще. Это вызывает его блокировку и делает телефон не отвечает

2) вызовы setText становятся недействительными в представлении. Это заставит фреймворк снова нарисовать представление, как только это будет возможно, но это означает, что необходимо завершить текущие действия, которые он выполняет, и вернуться к основному Looper (в основном, он должен вернуться из любого метода в вашем коде, который он сначала вызывает ). До этого изменения не будут видны на экране.

Изменить: другими словами, в рамках мы имеем

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

Он не может добраться до сообщения отрисовки, пока не завершится с текущим сообщением. Его однопоточный.

Автор: Gabe Sechan Размещён: 16.05.2013 07:11

1 плюс

1130 Репутация автора

Решение

Причиной наблюдаемого поведения является то, что Views перерисовываются только после завершения каждого цикла в цикле событий. Метод android onCreate(), а также сенсорные события, такие как нажатие кнопки, вызываются платформой из цикла событий. Таким образом, такие методы, как onCreate()или onClick()будут выполняться до завершения перед Viewперерисовкой любых s, и на экране не будет видимого эффекта до тех пор, пока эти методы не будут возвращены. Изменения в Views, сделанные из этих методов, станут видимыми только после завершения цикла цикла событий, из которого фреймворк вызвал указанный метод ( onCreate(), onClick()и т . Д. ).

Чтобы добиться поведения, запрошенного в вопросе, вызов sleep()метода должен произойти после завершения цикла цикла событий, в котором вы вызывали setText()текст, который вы хотите отобразить во время блокировки потока. Один из способов сделать это - просто заменить вызов на sleep()вызов View.post(). View.post()принимает метод, Runnableчей run()метод будет вызван после завершения текущего цикла цикла обработки событий, и инфраструктура отобразит текст, который вы хотите видеть во время блокировки потока. Изменение doDelay()метода в вопросе путем размещения вызова Thread.sleep()внутри Runnable«s run()метод , как это:

    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(); }
            }
        });
    }

Я благодарю Гейба Сечана , чье руководство заставило меня откликнуться достаточно, чтобы ответить на мой собственный вопрос.

Автор: Adam Mackler Размещён: 17.05.2013 03:42
Вопросы из категории :
32x32