53 votes

comment attendre qu'Android runOnUiThread soit terminé ?

J'ai un thread de travail qui crée un objet exécutable et appelle runOnUiThread dessus, car il traite des vues et des contrôles. J'aimerais utiliser le résultat du travail de l'objet exécutable tout de suite. Comment attendre qu'il se termine ? Ça ne me dérange pas si ça bloque.

64voto

Andrew Points 1629

Juste gratter les points saillants

 synchronized( myRunnable ) {
   activity.runOnUiThread(myRunnable) ;

   myRunnable.wait() ; // unlocks myRunable while waiting
}

Pendant ce temps... dans myRunnable...

 void run()
{
   // do stuff

   synchronized(this)
   {
      this.notify();
   }
}

18voto

Daniel Points 716

Peut-être un peu simpliste mais un mutex fera l'affaire :

 final Semaphore mutex = new Semaphore(0);
activity.runOnUiThread(new Runnable() {
    @Override
    public void run() {
        // YOUR CODE HERE
        mutex.release();
    }
});

try {
    mutex.acquire();
} catch (InterruptedException e) {
    e.printStackTrace();
}

10voto

olivier_sdg Points 413

La réponse d'Andrew est bonne, je crée une classe pour une utilisation plus facile.

Implémentation de l'interface :

 /**
 * Events for blocking runnable executing on UI thread
 * 
 * @author 
 *
 */
public interface BlockingOnUIRunnableListener
{

    /**
     * Code to execute on UI thread
     */
    public void onRunOnUIThread();
}

Implémentation de classe :

 /**
 * Blocking Runnable executing on UI thread
 * 
 * @author 
 *
 */
public class BlockingOnUIRunnable
{
    // Activity
    private Activity activity;

    // Event Listener
    private BlockingOnUIRunnableListener listener;

    // UI runnable
    private Runnable uiRunnable;


    /**
     * Class initialization
     * @param activity Activity
     * @param listener Event listener
     */
    public BlockingOnUIRunnable( Activity activity, BlockingOnUIRunnableListener listener )
    {
        this.activity = activity;
        this.listener = listener;

        uiRunnable = new Runnable()
        {
            public void run()
            {
                // Execute custom code
                if ( BlockingOnUIRunnable.this.listener != null ) BlockingOnUIRunnable.this.listener.onRunOnUIThread();

                synchronized ( this )
                {
                    this.notify();
                }
            }
        };
    }


    /**
     * Start runnable on UI thread and wait until finished
     */
    public void startOnUiAndWait()
    {
        synchronized ( uiRunnable )
        {
            // Execute code on UI thread
            activity.runOnUiThread( uiRunnable );

            // Wait until runnable finished
            try
            {
                uiRunnable.wait();
            }
            catch ( InterruptedException e )
            {
                e.printStackTrace();
            }
        }
    }

}

En l'utilisant :

 // Execute an action from non-gui thread
BlockingOnUIRunnable actionRunnable = new BlockingOnUIRunnable( yourActivity, new BlockingOnUIRunnableListener()
{
    public void onRunOnUIThread()
    {
        // Execute your activity code here
    }
} );

actionRunnable.startOnUiAndWait();

10voto

aha Points 2338

Une solution pourrait consister à tirer parti de Java FutureTask<T> qui présente l'avantage que quelqu'un d'autre a déjà traité tous les problèmes de simultanéité potentiels pour vous :

 public void sample(Activity activity) throws ExecutionException, InterruptedException {
    Callable<Void> callable = new Callable<Void>() {
        @Override
        public Void call() throws Exception {
            // Your task here
            return null;
        }
    };

    FutureTask<Void> task = new FutureTask<>(callable);
    activity.runOnUiThread(task);
    task.get(); // Blocks
}

Vous pouvez même renvoyer un résultat du thread principal en remplaçant Void par autre chose.

4voto

chetbox Points 216

Je pense que le moyen le plus simple d'y parvenir est d'utiliser un "CountDownLatch".

 final CountDownLatch latch = new CountDownLatch(1);
runOnUiThread(new Runnable() {
    @Override
    public void run() {

        // Do something on the UI thread

        latch.countDown();
    }
});
try {
    latch.await();
} catch (InterruptedException e) {
    e.printStackTrace();
}

// Now do something on the original thread

(Je crois que cette question est un doublon de " Comment faire en sorte que la tâche du minuteur attende la fin de runOnUiThread ")

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X