runOnUiThread() es un método proporcionado por la clase Activity en Android que facilita la ejecución de código en el hilo principal (UI thread) desde un hilo secundario. Esto es crucial porque las actualizaciones de la interfaz de usuario solo pueden realizarse de forma segura en el hilo principal.
Uso Básico
Aquí tienes un ejemplo práctico de cómo utilizar runOnUiThread() para actualizar un TextView desde un hilo de trabajo:
public class MainActivity extends AppCompatActivity {
private TextView statusTextView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
statusTextView = findViewById(R.id.tv_status);
// Iniciar un nuevo hilo para operaciones largas
new Thread(new Runnable() {
@Override
public void run() {
// Simular una tarea que toma tiempo
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
// Programar la actualización de la UI para el hilo principal
runOnUiThread(new Runnable() {
@Override
public void run() {
statusTextView.setText("Tarea completada!");
}
});
}
}).start();
}
}
Con la sintaxis de expresiones lambda introducida en Java 8, el código se vuelve aún más conciso:
new Thread(() -> {
// Simular una tarea que toma tiempo
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
// Actualizar la UI usando lambda
runOnUiThread(() -> {
statusTextView.setText("Tarea completada!");
});
}).start();
Este enfoque es significativamente más directo que implementar manualmente Handler o AsyncTask para tareas de actualización de UI.
Principio de Funcionamiento
Internamente, runOnUiThread() se basa en un mecanismo similar al de Handler. Veamos el código relevante de la clase Activity:
// Dentro de la clase Activity
private final Handler uiThreadHandler = new Handler();
private Thread mainApplicationThread;
// Método llamado durante la inicialización de la Activity en el hilo principal
final void attach(...) {
// ...
mainApplicationThread = Thread.currentThread(); // Guarda la referencia al hilo principal
// ...
}
/**
* Ejecuta la acción especificada en el hilo de la UI. Si el hilo actual es
* el hilo de la UI, la acción se ejecuta inmediatamente. Si el hilo actual
* no es el hilo de la UI, la acción se envía a la cola de eventos del hilo de la UI.
*
* @param runnable La acción a ejecutar en el hilo de la UI.
*/
public final void runOnUiThread(Runnable runnable) {
if (Thread.currentThread() != mainApplicationThread) {
// Si no estamos en el hilo principal, enviamos la tarea al Handler del hilo principal
uiThreadHandler.post(runnable);
} else {
// Si ya estamos en el hilo principal, ejecutamos la tarea directamente
runnable.run();
}
}
El Handler (uiThreadHandler) se asocia con el Looper del hilo principal de la aplicación. La variable mainApplicationThread almacena una referencia al hilo principal. Cuando se llama a runOnUiThread():
- Se verifica si el hilo que realiza la llamada es el hilo principal.
- Si es así, la
Runnablese ejecuta inmediatamente. - Si no es el hilo principal, la
Runnablese pone en cola utilizandouiThreadHandler.post()para ser ejecutada por elLooperdel hilo principal cuando sea su turno.
Este mecnaismo simplifica enormemente la gestión de las actualizaciones de la interfaz de usuario desde hilos de fondo.