He construido un reproductor de música simple en Android. La vista para cada canción contiene un SeekBar, implementado así:
public class Song extends Activity implements OnClickListener,Runnable {
private SeekBar progress;
private MediaPlayer mp;
// ...
private ServiceConnection onService = new ServiceConnection() {
public void onServiceConnected(ComponentName className,
IBinder rawBinder) {
appService = ((MPService.LocalBinder)rawBinder).getService(); // service that handles the MediaPlayer
progress.setVisibility(SeekBar.VISIBLE);
progress.setProgress(0);
mp = appService.getMP();
appService.playSong(title);
progress.setMax(mp.getDuration());
new Thread(Song.this).start();
}
public void onServiceDisconnected(ComponentName classname) {
appService = null;
}
};
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.song);
// ...
progress = (SeekBar) findViewById(R.id.progress);
// ...
}
public void run() {
int pos = 0;
int total = mp.getDuration();
while (mp != null && pos<total) {
try {
Thread.sleep(1000);
pos = appService.getSongPosition();
} catch (InterruptedException e) {
return;
} catch (Exception e) {
return;
}
progress.setProgress(pos);
}
}
Esto funciona bien Ahora quiero un temporizador que cuente los segundos / minutos del progreso de la canción. Así que puse una TextView
en el diseño, lo consigue con findViewById()
en onCreate()
y poner esto en run()
después progress.setProgress(pos)
:
String time = String.format("%d:%d",
TimeUnit.MILLISECONDS.toMinutes(pos),
TimeUnit.MILLISECONDS.toSeconds(pos),
TimeUnit.MINUTES.toSeconds(TimeUnit.MILLISECONDS.toMinutes(
pos))
);
currentTime.setText(time); // currentTime = (TextView) findViewById(R.id.current_time);
Pero esa última línea me da la excepción:
android.view.ViewRoot $ CalledFromWrongThreadException: solo el hilo original que creó una jerarquía de vistas puede tocar sus vistas.
Sin embargo, estoy haciendo básicamente lo mismo que estoy haciendo con SeekBar
: crear la vista onCreate
y luego tocarla run()
, y no me da esta queja.
fuente
error.setText(res.toString());
dentro del método run (), pero que no podía usar la res porque no era definitiva .. demasiado malomyActivityObject.runOnUiThread(etc)
runOnUiThread()
es un método de Actividad. Estaba ejecutando mi código en un fragmento. Terminé haciendogetActivity().runOnUiThread(etc)
y funcionó. ¡Fantástico!;Resolví esto poniendo
runOnUiThread( new Runnable(){ ..
dentrorun()
:fuente
wait(5000);
no está dentro del Runnable, de lo contrario su IU se congelará durante el período de espera. Debería considerar usar enAsyncTask
lugar de Thread para operaciones como estas.Mi solución a esto:
Llame a este método en un hilo de fondo.
fuente
runOnUiThread
conrunTestOnUiThread
. GraciasPor lo general, cualquier acción relacionada con la interfaz de usuario debe realizarse en el subproceso principal o en la interfaz de usuario, que es aquella en la que
onCreate()
se ejecuta el manejo de eventos. Una forma de estar seguro de eso es usar runOnUiThread () , otra está usando Handlers.ProgressBar.setProgress()
tiene un mecanismo para el que siempre se ejecutará en el hilo principal, por eso funcionó.Ver Roscado sin dolor .
fuente
He estado en esta situación, pero encontré una solución con el Handler Object.
En mi caso, quiero actualizar un ProgressDialog con el patrón de observador . Mi vista implementa observador y anula el método de actualización.
Entonces, mi hilo principal crea la vista y otro hilo llama al método de actualización que actualiza el ProgressDialop y ...:
Es posible resolver el problema con el objeto controlador.
A continuación, diferentes partes de mi código:
Esta explicación se puede encontrar en esta página y debe leer el "Ejemplo de Diálogo de progreso con un segundo hilo".
fuente
Puede usar el controlador para eliminar la vista sin alterar el hilo principal de la interfaz de usuario. Aquí hay un código de ejemplo
fuente
Veo que has aceptado la respuesta de @ providence. Por si acaso, ¡también puedes usar el controlador! Primero, haz los campos int.
A continuación, cree una instancia de controlador como campo.
Haz un método.
Finalmente, pon esto en el
onCreate()
método.fuente
Tuve un problema similar y mi solución es fea, pero funciona:
fuente
Yo uso
Handler
conLooper.getMainLooper()
. Funcionó bien para mí.fuente
Use este código y no es necesario que
runOnUiThread
funcione:fuente
Esto arroja explícitamente un error. Dice cualquier hilo que haya creado una vista, solo eso puede tocar sus vistas. Es porque la vista creada está dentro del espacio de ese hilo. La creación de la vista (GUI) ocurre en el hilo de la interfaz de usuario (principal). Por lo tanto, siempre usa el hilo de la interfaz de usuario para acceder a esos métodos.
En la imagen de arriba, la variable de progreso está dentro del espacio del hilo de la interfaz de usuario. Entonces, solo el hilo de la interfaz de usuario puede acceder a esta variable. Aquí, está accediendo al progreso a través del nuevo Thread (), y es por eso que recibió un error.
fuente
Esto le sucedió a mi cuando solicité un cambio de UI de a
doInBackground
desde enAsynctask
lugar de usaronPostExecute
.Tratar con la IU
onPostExecute
resolvió mi problema.fuente
onPostExecute
también es un métodoAsyncTask
pero se ejecuta en el hilo de la interfaz de usuario. Ver aquí: blog.teamtreehouse.com/all-about-android-asynctasksLas rutinas de Kotlin pueden hacer que su código sea más conciso y legible de esta manera:
O viceversa:
fuente
Estaba trabajando con una clase que no contenía una referencia al contexto. Así que no me fue posible usar lo
runOnUIThread();
que uséview.post();
y se resolvió.fuente
audioMessage
ytvPlayDuration
para el código de preguntas?audioMessage
es un objeto titular de la vista de texto.tvPlayDuration
es la vista de texto que queremos actualizar desde un subproceso sin interfaz de usuario. En la pregunta anterior,currentTime
es la vista de texto pero no tiene un objeto titular.Cuando utilice AsyncTask, actualice la IU en el método onPostExecute
fuente
Estaba enfrentando un problema similar y ninguno de los métodos mencionados anteriormente funcionó para mí. Al final, esto hizo el truco para mí:
Encontré esta joya aquí .
fuente
Este es el seguimiento de la pila de la excepción mencionada
Entonces, si vas y cavas, entonces sabrás
Donde mThread se inicializa en el constructor como a continuación
Todo lo que quiero decir es que cuando creamos una vista particular, la creamos en UI Thread y luego intentamos modificarla en un Worker Thread.
Podemos verificarlo a través del fragmento de código a continuación
cuando inflamos el diseño y más tarde donde obtiene una excepción.
fuente
Si no desea utilizar la
runOnUiThread
API, puede implementarAsynTask
para las operaciones que tardan unos segundos en completarse. Pero en ese caso, también después de procesar su trabajodoinBackground()
, debe devolver la vista finalizadaonPostExecute()
. La implementación de Android solo permite que el hilo principal de la interfaz de usuario interactúe con las vistas.fuente
Si simplemente desea invalidar (llamar a la función repintar / volver a dibujar) desde su subproceso no UI, use postInvalidate ()
Esto publicará una solicitud de invalidación en el subproceso de interfaz de usuario.
Para más información: what-does-postinvalidate-do
fuente
Para mí, el problema era que estaba llamando
onProgressUpdate()
explícitamente desde mi código. Esto no debe hacerse. Llamé en supublishProgress()
lugar y eso resolvió el error.fuente
En mi caso, tengo
EditText
en Adaptador, y ya está en el hilo de la interfaz de usuario. Sin embargo, cuando se carga esta Actividad, se bloquea con este error.Mi solución es que necesito eliminarlo
<requestFocus />
de EditText en XML.fuente
Para las personas que luchan en Kotlin, funciona así:
fuente
Resuelto: simplemente coloque este método en doInBackround Class ... y pase el mensaje
fuente
En mi caso, la persona que llama demasiadas veces en poco tiempo recibirá este error, simplemente pongo la verificación del tiempo transcurrido para no hacer nada si es demasiado corto, por ejemplo, ignorar si la función se llama menos de 0,5 segundos:
fuente
Si no puede encontrar un UIThread, puede usarlo de esta manera.
su contexto actual significa que necesita analizar el contexto actual
fuente
Tenemos que usar UI Thread para el trabajo de manera verdadera. Podemos usar UI Thread en Kotlin:
@canerkaseler
fuente
En Kotlin simplemente ponga su código en el método de actividad runOnUiThread
fuente