2017-01-31 3 views
1

Ich habe eine for-Schleife, in der ich die setText Methode anrufen möchte. Dies funktioniert ohne Fehler außer der Tatsache, dass sich der Text erst ändert, wenn das Skript ausgeführt wird. Ich möchte, dass ich den Code jedes Mal ändere, wenn ich die Methode setText anrufe. Ich habe meinen Code unten angehängt, es sollte ziemlich direkt sein. Code:Periodisch aktualisierter Text wird nicht angezeigt

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

Verwenden Sie 'Handler' anstelle von' Thread.sleep (250); 'auf Haupt Thread –

+0

Ich bin mir nicht sicher, ob ich folge. – pudility

Antwort

1

Das ist, was "Auslassen von Frames" genannt wird.

Es ist Zeit zu lernen!

Bevor wir zur Antwort gehen, wollen wir erklären, was hier vor sich geht.

Wahrscheinlich wissen Sie bereits, dass Android eine Bildrate von 60 Bildern pro Sekunde hat, was bedeutet, dass alle 1/60 Sekunden der Bildschirm gerendert und dem Benutzer angezeigt wird (um die beste Definition zu liefern) . Es macht das, indem Sie einen Rendering-Code in Ihrer App (und überall dort, wo etwas wiedergegeben wird) alle 1/60 Sekunden berechnen, wie der angezeigte Bildschirm in diesem bestimmten ms aussehen soll (es wird ein Frame genannt).

Der Code, der das ausführt, wird jedoch auf dem UI-Thread ausgeführt. Wenn Sie irgendetwas tun, wenn der Rendering-Tick einsetzt, wird das Frame einfach vom Androiden-Framework gelöscht (es wird nicht berechnet). In Ihrem Fall verursacht Thread.sleep(250);, dass Ihre Frames gelöscht werden, weil es den UI-Thread für 250 ms in jeder Iteration Ihrer for-Schleife hält (also 250 ms * (10-1), das sind viele Frames).

Das Löschen eines Rahmens bedeutet, dass auf der Benutzeroberfläche keine Aktualisierung angezeigt wird.

Lösung

Statt Thread.sleep(250); und Auslassen von Frames zu verwenden, sollten Sie Ihre Update-Aufgaben planen alle 250 ms ausgeführt wird. Das ist es.

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

Weitere

Android UI : Fixing skipped frames

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

+0

Ich benutze Ihren Code, aber es gibt mir eine Fehlermeldung, die 'Variable 'Handler' Initialisierer 'neue Handler(). PostDelayed (neue Runnable() {@Override öffentlichen void run() {...' ist redundant 'I Ich weiß nicht, wie ich das beheben kann :( – pudility

+0

Das passiert, wenn ich den Mauszeiger darüber bewege. Der Fehler, der beim Versuch angezeigt wird, ist 'Fehler: (28, 21) error: kann der Variablen keinen Wert zuweisen Ich danke dir! – pudility

+0

cool, danke nochmal für dich help.he beschwert sich, dass ich 'i' nicht in die Funktion irgendwelche Ideen auf diesem? – 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

Das Problem ist, zu lesen, sind Sie Thread.sleep auf dem UI-Thread aufrufen. Wenn der Thread schläft, kann er die Benutzeroberfläche nicht aktualisieren (was auf dem Bildschirm angezeigt wird).