Подтвердить что ты не робот

Как дождаться завершения runOnUiThread для Android?

У меня есть рабочий поток, который создает runnable-объект и вызывает runOnUiThread на нем, потому что он имеет дело с представлениями и элементами управления. Я хотел бы сразу использовать результат работы объекта runnable. Как дождаться окончания? Меня это не беспокоит, если он блокирует.

4b9b3361

Ответ 1

Просто поцарапайте основные моменты

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

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

Между тем... в myRunnable...

void run()
{
   // do stuff

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

Ответ 2

Возможно, немного упрощенное, но мьютекс выполнит эту работу:

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();
}

Ответ 3

Эндрю ответ хороший, я создаю класс для более легкого использования.

Выполнение интерфейса:

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

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

Реализация класса:

/**
 * 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();
            }
        }
    }

}

Использование:

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

actionRunnable.startOnUiAndWait();

Ответ 4

Решение может заключаться в использовании Java FutureTask<T>, который имеет то преимущество, что кто-то еще затронул все потенциальные проблемы concurrency для вас:

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
}

Вы даже можете вернуть результат из основного потока, заменив Void на что-то еще.

Ответ 5

Я думаю, что самый простой способ добиться этого - использовать "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

(Я считаю, что этот вопрос является дубликатом Как сделать задачу таймера ждать до завершения runOnUiThread)

Ответ 6

На случай, если кто-то столкнется с этим во время разработки в приложении Xamarin, я оставлю здесь свой С# -код, который сделал свое дело.

Мой адаптер RecyclerView был установлен слишком поздно, поэтому он возвращал значение null в моем конструкторе ScrollListener. Таким образом, мой код ожидает, пока поток пользовательского интерфейса завершит работу и снимет "блокировку".

Все это выполняется внутри фрагмента (Activity возвращает родительский объект Activity).

Semaphore semaphore = new Semaphore(1, 1);
semaphore.WaitOne();
Activity?.RunOnUiThread(() =>
{
    leaderboard.SetAdapter(adapter);
    semaphore.Release();
});
semaphore.WaitOne();
scrollListener = new LazyLoadScrollListener(this, (LinearLayoutManager)layoutManager);
leaderboard.SetOnScrollListener(scrollListener);
semaphore.Release();

Надеюсь, это кому-нибудь поможет.

Ответ 7

Используйте класс AsyncTask, его методы onPostExecure и onProgressUpdate выполняются потоком MAIN (поток пользовательского интерфейса).

http://developer.android.com/reference/android/os/AsyncTask.html

Это лучший способ для вашего дела!

Надеюсь, это поможет вам.