Android: Actualización de la Interfaz de Usuario desde Hilos Secundarios con runOnUiThread()

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():

  1. Se verifica si el hilo que realiza la llamada es el hilo principal.
  2. Si es así, la Runnable se ejecuta inmediatamente.
  3. Si no es el hilo principal, la Runnable se pone en cola utilizando uiThreadHandler.post() para ser ejecutada por el Looper del 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.

Etiquetas: Android runOnUiThread UI Thread Multithreading Handler

Publicado el 6-21 19:10