Cómo cambiar un TextView cada segundo en Android
He hecho un reproductor de música Android simple. Quiero tener un TextView que muestre la hora actual de la canción en formato de minutos: segundos. Así que lo primero que intenté fue hacer la actividad Runnable y poner esto en run ():
int position = 0; while (MPService.getMP() != null && position<MPService.duration) { try { Thread.sleep(1000); position = MPService.getSongPosition(); } catch (InterruptedException e) { return; } // ... convert position to formatted minutes:seconds string ... currentTime.setText(time); // currentTime = (TextView) findViewById(R.id.current_time);
Pero eso falla porque sólo puedo tocar un TextView en el hilo donde se creó. Así que intenté usar runOnUiThread (), pero eso no funciona porque entonces Thread.sleep (1000) se llama repetidamente en el hilo principal, por lo que la actividad se bloquea en una pantalla en blanco. Así que cualquier idea de cómo puedo resolver esto?
nuevo código:
private int startTime = 0; private Handler timeHandler = new Handler(); private Runnable updateTime = new Runnable() { public void run() { final int start = startTime; int millis = appService.getSongPosition() - start; int seconds = (int) ((millis / 1000) % 60); int minutes = (int) ((millis / 1000) / 60); Log.d("seconds",Integer.toString(seconds)); // no problem here if (seconds < 10) { // this is hit, yet the text never changes from the original value of 0:00 currentTime.setText(String.format("%d:0%d",minutes,seconds)); } else { currentTime.setText(String.format("%d:%d",minutes,seconds)); } timeHandler.postAtTime(this,(((minutes*60)+seconds+1)*1000)); } }; private ServiceConnection onService = new ServiceConnection() { public void onServiceConnected(ComponentName className, IBinder rawBinder) { appService = ((MPService.LocalBinder)rawBinder).getService(); // start playing the song, etc. if (startTime == 0) { startTime = appService.getSongPosition(); timeHandler.removeCallbacks(updateTime); timeHandler.postDelayed(updateTime,1000); } }
Utilice un Timer
para esto (en lugar de un bucle de while
con un Thread.Sleep
en ella). Consulte este artículo para ver un ejemplo de cómo utilizar un temporizador para actualizar periódicamente un elemento de interfaz de usuario:
Actualización de la interfaz de usuario desde un temporizador
Editar : enlace de way-back actualizado, gracias a Arialdo
: http://web.archive.org/web/20100126090836/http://developer.android.com/intl/zh-TW/resources/articles/timed-ui- updates.html
Editar 2 : enlace no retroceder, gracias a gatoatigrado
: http://android-developers.blogspot.com/2007/11/stitch-in-time.html
que hay de esto
int delay = 5000; // delay for 5 sec. int period = 1000; // repeat every sec. Timer timer = new Timer(); timer.scheduleAtFixedRate(new TimerTask() { public void run() { //your code } }, delay, period);
Tienes que usar un controlador para manejar la interacción con la GUI. Específicamente un hilo no puede tocar NADA en el hilo principal. Haces algo en un hilo y si necesitas algo que se cambie en tu hilo principal, entonces llamas a un manejador y lo haces allí.
Específicamente se vería algo como esto:
Thread t = new Thread(new Runnable(){ ... do stuff here
Handler.postMessage (); }
Entonces en algún otro lugar en su código, usted hace
Handler h = new Handler(){
algo algo … modificar elemento ui aquí}
Idea es como esto, hilo hace algo, notifica al manejador, el manejador toma este mensaje y hace algo como actualizar un textview en el subproceso de la interfaz de usuario.
Este es un ejemplo más Timer y estoy usando este código en mi proyecto. https://stackoverflow.com/a/18028882/1265456
Creo que el siguiente artículo del blog claramente da una muy buena solución. Especialmente, si es un servicio de fondo y desea actualizar regularmente su interfaz de usuario desde este servicio utilizando una funcionalidad parecida a un temporizador. Realmente me ayudó, mucho más que el blog de 2007 publicado por MusiGenesis anterior.