AndroidでrunOnUiThreadをどのように使用しますか?


157

私はAndroidを初めて使用し、UIスレッドを使用しようとしているため、簡単なテストアクティビティを作成しました。しかし、ボタンをクリックしたときにアプリが応答しなくなったため、何かを誤解したと思います

public class TestActivity extends Activity {

    Button btn;
    int i = 0;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        btn = (Button)findViewById(R.id.btn);
        btn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                runThread();
            }
        });
    }

    private void runThread(){
        runOnUiThread (new Thread(new Runnable() {  
            public void run() {
                while(i++ < 1000){
                    btn.setText("#"+i);
                    try {
                        Thread.sleep(300);
                    } 
                    catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
             }
        }));
    }
}

回答:


204

以下は、修正されたrunThread関数のスニペットです。

private void runThread() {

    new Thread() {
        public void run() {
            while (i++ < 1000) {
                try {
                    runOnUiThread(new Runnable() {

                        @Override
                        public void run() {
                            btn.setText("#" + i);
                        }
                    });
                    Thread.sleep(300);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }.start();
}

これはほとんどすぐに収集されたごみではなかったのですか?おそらく、Thread()への参照を維持する必要があります
Nick

14
@Nick:ガベージコレクターはスタックも監視します。つまり、スレッドの実行中は、GCされません。
Miro Kropacek

@Vipul、電話の回転について質問がありました。電話を回転させたら、このスレッドが実行され、新しいスレッドは作成されません。電話が回転したときに新しいスレッドが作成されないようにするためのヒントを教えてください。
user1836957 2018

89

関数としてラップし、バックグラウンドスレッドからこの関数を呼び出すだけです。

public void debugMsg(String msg) {
    final String str = msg;
    runOnUiThread(new Runnable() {
        @Override
        public void run() {
            mInfo.setText(str);
        }
    });
}

3
外部スコープのデータにアクセスする方法を示すことにfinal
賛成

27

あなたはそれを背中合わせに持っています。ボタンをクリックするとrunOnUiThread()、が呼び出されますが、クリックハンドラーがUIスレッドで既に実行されているため、これは必要ありません。次に、コードrunOnUiThread()は新しいバックグラウンドスレッドを起動し、そこでUI操作を実行しようとすると失敗します。

代わりに、クリックハンドラーから直接バックグラウンドスレッドを起動します。次に、の呼び出しをの呼び出しのbtn.setText()中にラップしますrunOnUiThread()


クリックハンドラーが既にUIスレッドにあることは事実ですが、への呼び出しrunOnUiThread()は不要ですが、害はありません。そのメソッドのJavadocは、「指定されたアクションをUIスレッドで実行します。現在のスレッドがUIスレッドの場合、アクションはすぐに実行されます。現在のスレッドがUIスレッドでない場合、アクションはイベントキューにポストされます。 UIスレッドの。」
k2col 2017年


10

runOnUiThread()を使用するいくつかの手法があります。

これはAndroidBasicThreadActivityと呼ばれる私のメインスレッド(UIスレッド)であり、ワーカースレッドからさまざまな方法で更新します-

public class AndroidBasicThreadActivity extends AppCompatActivity
{
    public static TextView textView;
    @Override
    protected void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_android_basic_thread);

        textView = (TextView) findViewById(R.id.textview);

        MyAndroidThread myTask = new MyAndroidThread(AndroidBasicThreadActivity.this);
        Thread t1 = new Thread(myTask, "Bajrang");
        t1.start();
    }
}

1.)ワーカースレッドの引数としてアクティビティのインスタンスを渡す

class MyAndroidThread implements Runnable
{
    Activity activity;
    public MyAndroidThread(Activity activity)
    {
        this.activity = activity;
    }
    @Override
    public void run()
    {

        //perform heavy task here and finally update the UI with result this way - 
        activity.runOnUiThread(new Runnable()
        {
            @Override
            public void run()
            {
                AndroidBasicThreadActivity.textView.setText("Hello!! Android Team :-) From child thread.");
            }
        });
    }
}

2.)ワーカースレッドでビューのpost(Runnable runnable)メソッドを使用する

class MyAndroidThread implements Runnable
{
    Activity activity;
    public MyAndroidThread(Activity activity)
    {
        this.activity = activity;
    }
    @Override
    public void run()
    {
     //perform heavy task here and finally update the UI with result this way - 
       AndroidBasicThreadActivity.textView.post(new Runnable()
      { 
        @Override
        public void run()
        {
            AndroidBasicThreadActivity.textView.setText("Hello!! Android Team :-) From child thread.");
        }
    });

    }
}

3.)android.osパッケージのHandlerクラスを使用 するコンテキスト(this / getApplicationContext())またはアクティビティのインスタンス(AndroidBasicThreadActivity.this)がない場合は、以下のようにHandlerクラスを使用する必要があります-

class MyAndroidThread implements Runnable
{
    Activity activity;
    public MyAndroidThread(Activity activity)
    {
        this.activity = activity;
    }
    @Override
   public void run()
  {
  //perform heavy task here and finally update the UI with result this way - 
  new Handler(Looper.getMainLooper()).post(new Runnable() {
        public void run() {
            AndroidBasicThreadActivity.textView.setText("Hello!! Android Team :-) From child thread.");
        }
    });
  }
}

...代わりにちょうど活動のrunOnUIThreadについて繰り返しのありがとう、あなたはそれを呼び出すすべての可能な方法を記載している。..
アルン

...代わりにちょうど活動のrunOnUIThreadについて繰り返しのありがとう、あなたはそれを呼び出すすべての可能な方法を記載している。..
アルン

6

フラグメントで使用する場合は、単に

getActivity().runOnUiThread(new Runnable() {
    @Override
    public void run() {
        // Do something on UiThread
    }
});

1

あなたのこれ:

@UiThread
    public void logMsg(final String msg) {
        new Handler(Looper.getMainLooper()).post(new Runnable() {
            @Override
            public void run() {
                Log.d("UI thread", "I am the UI thread");


            }
        });
    }

1

ワーカースレッドを使用して、アプリをよりスムーズにし、ANRを回避します。Worker Treadの重いプロセスの後でUIを更新する必要があるかもしれません。UIは、UIスレッドからのみ更新できます。このような場合、ハンドラーまたはrunOnUiThreadの両方に、UIスレッドで実行されるRunnable runメソッドがあります。onClickメソッドはUIスレッドで実行されるため、ここでrunOnUiThreadを使用する必要はありません。

Kotlinの使用

活動中、

this.runOnUiThread {
      // Do stuff
}

フラグメントから、

activity?.runOnUiThread {
      // Do stuff
}

Javaを使用して

this.runOnUiThread(new Runnable() {
     void run() {
         // Do stuff
     }
});

0

このサンプルから使用できます:

次の例では、この機能を使用して、バックグラウンドスレッドによって処理された同義語検索の結果を公開します。

OnCreateアクティビティのコールバック中に目標を達成するために、作成されたスレッドでsearchTaskを実行するようにonClickListenerを設定します。

ユーザーが[検索]ボタンをクリックすると、R.id.wordEt EditTextに入力された単語を検索し、スレッドを開始してRunnableを実行するRunnable匿名クラスを作成します。

検索が完了したら、Runnable SetSynonymResultのインスタンスを作成して、UIスレッドを介してシノニムTextViewに結果を公開します。

このテクニックは、特にActivityインスタンスにアクセスできない場合は、最も便利なものではない場合があります。したがって、次の章では、バックグラウンドコンピューティングタスクからUIを更新するためのよりシンプルでクリーンな手法について説明します。

public class MainActivity extends AppCompatActivity {

    class SetSynonymResult implements Runnable {
        String synonym;

        SetSynonymResult(String synonym) {
            this.synonym = synonym;
        }

        public void run() {
            Log.d("AsyncAndroid", String.format("Sending synonym result %s on %d",
                    synonym, Thread.currentThread().getId()) + " !");
            TextView tv = (TextView) findViewById(R.id.synonymTv);
            tv.setText(this.synonym);
        }
    }

    ;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        Button search = (Button) findViewById(R.id.searchBut);
        final EditText word = (EditText) findViewById(R.id.wordEt);
        search.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Runnable searchTask = new Runnable() {
                    @Override
                    public void run() {
                        String result = searchSynomim(word.getText().toString());
                        Log.d("AsyncAndroid", String.format("Searching for synonym for %s on %s",
                                word.getText(), Thread.currentThread().getName()));
                        runOnUiThread(new SetSynonymResult(result));
                    }
                };
                Thread thread = new Thread(searchTask);
                thread.start();
            }
        });

    }

    static int i = 0;

    String searchSynomim(String word) {
        return ++i % 2 == 0 ? "fake" : "mock";
    }
}

出典

非同期AndroidプログラミングHelder Vasconcelos


0

これは私がそれを使う方法です:

runOnUiThread(new Runnable() {
                @Override
                public void run() {
                //Do something on UiThread
            }
        });

0
  @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        gifImageView = (GifImageView) findViewById(R.id.GifImageView);
        gifImageView.setGifImageResource(R.drawable.success1);

        new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    //dummy delay for 2 second
                    Thread.sleep(8000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }

                //update ui on UI thread
                runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        gifImageView.setGifImageResource(R.drawable.success);
                    }
                });

            }
        }).start();

    }

0

これを試して: getActivity().runOnUiThread(new Runnable...

その理由は:

1)へお電話でこの暗黙のrunOnUiThreadはを参照しているAsyncTaskではなく、あなたのフラグメント。

2)フラグメントにrunOnUiThreadがありません。

ただし、アクティビティにはあります。

既にメインスレッドにいる場合、ActivityはRunnableを実行するだけであることに注意してください。そうでない場合は、Handlerを使用します。これのコンテキストを心配したくない場合は、フラグメントにハンドラーを実装できます。これは実際には非常に簡単です。

//クラスインスタンス

private Handler mHandler = new Handler(Looper.getMainLooper());

//コードの他の場所

mHandler.post(<your runnable>);

// ^これは常にメインスレッドの次の実行ループで実行されます。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.