2017-01-31 3 views
1

У меня есть цикл for, в котором я бы назвал метод setText. Это работает без каких-либо ошибок, за исключением того факта, что текст не изменяется до тех пор, пока скрипт не будет запущен. То, что я хочу, это изменить код каждый раз, когда я вызываю метод setText. Я прикрепил свой код ниже, он должен быть довольно прочным. код:Периодически обновляемый текст не отображается

package com.example.zoe.andone; 

import android.support.v7.app.AppCompatActivity; 
import android.os.Bundle; 
import android.view.MenuItem; 
import android.view.View; 
import android.widget.TextView; 

import java.util.concurrent.TimeUnit; 

public class MainActivity extends AppCompatActivity { 

    @Override 
    protected void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 
     setContentView(R.layout.activity_main); 
    } 
    public void startLoop(View view) { 
     String string = getString(R.string.hello); 
     ((TextView)findViewById(R.id.hello)).setText("starting..."); 
     for (int i = 0; i < 10; i++) { 
      String updated = Integer.toString(i); 
      ((TextView)findViewById(R.id.hello)).setText(updated); 
      try { 
       Thread.sleep(250); 
      } catch(InterruptedException ex) { 
       Thread.currentThread().interrupt(); 
      } 
     } 
     ((TextView)findViewById(R.id.hello)).setText("done!"); 
    } 
} 
+0

Использовать 'Handler' вместо вызова' Thread.sleep (250); 'on main Thread –

+0

Не уверен, что я следую. – pudility

ответ

1

Это то, что называется "сбрасывают кадры".

Пришло время учиться!

Прежде чем перейти к ответу, давайте объясним, что здесь происходит.

Возможно, вы уже знаете, что у андроида частота кадров 60 кадров в секунду (60 кадров в секунду), что означает, что каждые 1/60 секунды экран отображается и отображается пользователю (для обеспечения наилучшего определения) , Он делает это, запустив некоторый код рендеринга в вашем приложении (и везде, где есть что-то, что нужно сделать) каждые 1/60 секунды, чтобы вычислить, как отображаемый экран должен выглядеть в этом конкретном мс (он называется фреймом).

Однако код, выполняющий это, работает в потоке пользовательского интерфейса, и если вы делаете что-либо, когда галочка рендеринга запускается, инфраструктура андроида просто отбрасывает этот фрейм (он не будет его вычислять). В вашем случае Thread.sleep(250); - это то, что заставляет ваши кадры удаляться, потому что он удерживает поток пользовательского интерфейса в течение 250 мс на каждой итерации цикла for (так что это 250 мс * (10 - 1), это много кадров).

Удаление кадры означает отсутствие обновления в пользовательском интерфейсе.

Решение

Вместо использования Thread.sleep(250); и потери кадров, вы должны планировать свои задачи обновления для запуска каждые 250 мс. Вот и все.

private int i = 0; // Does the trick! 
public void startLoop(View view) { 
    String string = getString(R.string.hello); 
    ((TextView)findViewById(R.id.hello)).setText("starting..."); 
     final Handler handler = new Handler(); 
     handler.postDelayed(new Runnable() { 
      @Override 
      public void run() { 
       if (i < 10) { 
        String updated = Integer.toString(i); 
        i++; 
        updateHelloOnUiThread(updated); 
       } else { 
        updateHelloOnUiThread("done!"); 
        handler.removeCallbacksAndMessages(null); 
        i = 0; // For future usages 
       } 
      } 
     },250); 
} 

private void updateHelloOnUiThread(final String text) { 
    MainActivity.this.runOnUiThread(new Runnable() { 
      @Override 
      public void run() { 
       ((TextView)findViewById(R.id.hello)).setText(text); 
      } 
    }); 
} 

Дальнейшее чтение

Android UI : Fixing skipped frames

High Performance Android Apps, Chapter 4. Screen and UI Performance

+0

Я использую ваш код, однако он дает мне ошибку, говоря «Переменная» обработчик «initializer» new Handler(). PostDelayed (new Runnable() {@Override public void run() {... 'является избыточным' I не знаю, как это исправить :( – pudility

+0

Это то, что происходит, когда я нахожу на нем. Ошибка, возникающая при попытке ее создания, - ошибка «Ошибка: (28, 21): не может назначить значение конечной переменной i' спасибо! – pudility

+0

круто, еще раз спасибо за помощь, жалобы на то, что я не передал функции «i' в функции какие-либо идеи по этому поводу? – pudility

1
this.runOnUiThread(new Runnable() { 
      @Override 
      public void run() { 
       int globalTimer = 0; 

       int limitTimer = 10; 
       int i = 0; 

       // create Timer 
       Timer timer = new Timer(); 
       timer.schedule(new TimerTask() { 
        @Override 
        public void run() { 
         globalTimer++; 
         //run your code 
         ((TextView)findViewById(R.id.hello)).setText(i+""); 
         i++; 
         //check if globalTimer is equal to limitTimer 
         if (globalTimer == limitTimer) { 
          timer.cancel(); // cancel the Timer 
         } 
        } 

       }, 0, 250); 
      } 
     }); 
0

Проблема заключается в том, что вы звоните Thread.sleep в потоке пользовательского интерфейса. Если поток спал, он не может обновить пользовательский интерфейс (что отображается на экране).

Смежные вопросы