web-dev-qa-db-ja.com

Android runOnUiThreadが終了するのを待つ方法は?

実行可能オブジェクトを作成し、そのオブジェクトでrunOnUiThreadを呼び出すワーカースレッドがあります。これは、ビューとコントロールを処理するためです。実行可能なオブジェクトの作業の結果をすぐに使用したいと思います。終了するまでどのように待ちますか?ブロックされても気になりません。

43
djcouchycouch

ハイライトをスクラッチするだけ

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

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

一方... myRunnableで...

void run()
{
   // do stuff

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

おそらく少し単純ですが、ミューテックスが仕事をします:

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

アンドリューの答えは良いです、私は使いやすいようにクラスを作成します。

インターフェース実装:

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

解決策は、JavaのFutureTask<T>これは、他の誰かがすべての潜在的な並行性の問題をすでに処理しているという利点があります。

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を別のものに置き換えることで、メインスレッドから結果を返すこともできます。

7
aha

これを実現する最も簡単な方法は、「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が完了するまで待機するタイマータスクを作成する方法 」の複製であると考えています)

2
chetbox

Xamarinアプリで開発中に誰かがこれに直面した場合に備えて、トリックを作ったC#コードをここに残します。

RecyclerViewアダプターの設定が遅すぎたため、ScrollListenerコンストラクターでnullを返していました。このように、私のコードは、UIスレッドが作業を完了して「ロック」を解除するのを待ちます。

これらはすべてフラグメント内で実行されています(アクティビティは親アクティビティオブジェクトを返します)。

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

それが誰かを助けることを願っています。

0
Sergi Mascaró