web-dev-qa-db-ja.com

メインスレッドで他のスレッドからコードを実行する

Androidサービスでは、バックグラウンドタスクを実行するためのスレッドを作成しました。

私は、スレッドがメインスレッドのメッセージキューに特定のタスクをポストする必要がある状況、例えばRunnableを持っています。

メインスレッドのHandlerを取得し、他のスレッドからそれにMessage/Runnableをポストする方法はありますか?

ありがとう、

276
Ahmed

注:この回答は注目を集めているので、更新する必要があります。元の回答が投稿されて以来、@ dzeikeiからのコメントは元の回答とほぼ同じくらい注目を集めています。 2つの解決策があります。

1.あなたのバックグラウンドスレッドがContextオブジェクトへの参照を持っているなら:

バックグラウンドワーカースレッドがContextオブジェクトにアクセスできることを確認します(アプリケーションコンテキストまたはサービスコンテキストのいずれか)。その後、バックグラウンドワーカースレッドでこれを行います。

// Get a handler that can be used to post to the main thread
Handler mainHandler = new Handler(context.getMainLooper());

Runnable myRunnable = new Runnable() {
    @Override 
    public void run() {....} // This is your code
};
mainHandler.post(myRunnable);

2.バックグラウンドスレッドがContextオブジェクトを持っていない(または必要としている)場合

(@dzeikeiが提案):

// Get a handler that can be used to post to the main thread
Handler mainHandler = new Handler(Looper.getMainLooper());

Runnable myRunnable = new Runnable() {
    @Override 
    public void run() {....} // This is your code
};
mainHandler.post(myRunnable);
558
David Wasser

以下のコメンターが正しく指摘しているように、これはサービスの一般的な解決策ではなく、あなたの活動から起動されたスレッドだけのためのものです(サービスはそのようなスレッドでありえますが、全部ではありません)。サービス活動のコミュニケーションの複雑なトピックについては、公式文書のサービスセクション全体を読んでください - それは複雑なので、基本を理解するためにお金を払うでしょう: http://developer.Android.com/guide/components/services .html#通知

以下の方法は、最も単純な場合に機能する可能性があります。

私があなたを正しく理解しているならば、あなたはアプリケーションのGUIスレッドで実行されるために若干のコードを必要とします(「メイン」スレッドと呼ばれる何かについて考えることができません)。これにはActivityのメソッドがあります。

someActivity.runOnUiThread(new Runnable() {
        @Override
        public void run() {
           //Your code to run in GUI thread here
        }//public void run() {
});

Doc: http://developer.Android.com/reference/Android/app/Activity.html#runOnUiThread%28Java.lang.Runnable%29

これがあなたが探しているものであることを願っています。

127

コンテキストにアクセスできない場合は、別の簡単な方法があります。

1)。メインルーパーからハンドラを作成します。

Handler uiHandler = new Handler(Looper.getMainLooper());

2)。 Runnableインターフェースを実装します。

Runnable runnable = new Runnable() { // your code here }

3)。 RunnableをuiHandlerに投稿してください。

uiHandler.post(runnable);

これですべてです;-)スレッドを楽しんでください。ただし、同期することを忘れないでください。

28
tema_man

あなたがコードをスレッドで実行するなら、例えば何らかのアクションを遅らせるには、コンテキストからrunOnUiThreadを呼び出す必要があります。例えば、あなたのコードがMainActivityクラスの中にあるならば、これを使います:

MainActivity.this.runOnUiThread(new Runnable() {
    @Override
    public void run() {
        myAction();
    }
});

あなたのメソッドがメイン(UIスレッド)または他のスレッドのどちらからでも呼び出せる場合は、次のようなチェックが必要です。

public void myMethod() {
   if( Looper.myLooper() == Looper.getMainLooper() ) {
       myAction();
   }
   else {

}
27

要約コードブロックは次のとおりです。

   new Handler(Looper.getMainLooper()).post(new Runnable() {
       @Override
       public void run() {
           // things to do on the main thread
       }
   });

これには、Activity参照またはApplication参照を渡すことは含まれません。

コトリン換算量:

    Handler(Looper.getMainLooper()).post(Runnable {
        // things to do on the main thread
    })
15
david m lee

Kotlinバージョン

アクティビティ中の場合、使用

runOnUiThread {
    //code that runs in main
}

アクティビティコンテキストがあるの場合、mContextは

mContext.runOnUiThread {
    //code that runs in main
}

コンテキストが利用できないのどこかにいる場合は、

Handler(Looper.getMainLooper()).post {  
    //code that runs in main
}
4

私が考えることができる一つの方法はこれです:

1)UIをサービスにバインドします。
2)Binderを登録するHandlerで以下のようなメソッドを公開します。

public void registerHandler(Handler handler) {
    mHandler = handler;
}

3)UIスレッドで、サービスにバインドした後に上記のメソッドを呼び出します。

mBinder.registerHandler(new Handler());

4)あなたのタスクを投稿するためにサービスのスレッドでハンドラを使用します。

mHandler.post(runnable);
4
Dheeraj V.S.

RxAndroidを使用している場合は特に、あなたがコンテキストを持っていない場合は特に簡単な方法:

AndroidSchedulers.mainThread().scheduleDirect {
    runCodeHere()
}
3
Inn0vative1

これは古い質問ですが、KotlinとJavaの両方で使用しているメインスレッドのワンライナーに出会いました。これはサービスにとって最善の解決策ではないかもしれませんが、フラグメント内でUIを変更するものを呼び出すためにこれは非常に単純で明白です。

Java(8):

 getActivity().runOnUiThread(()->{
      //your main thread code
 });

コトリン:

this.runOnUiThread {
     //your main thread code
}
2
mevdev

HandlerThreadは、Androidの通常のJava Threadsにとってより良いオプションです。

  1. HandlerThread を作成して起動します。
  2. HandlerThreadから Handler / Looper を作成します。requestHandler
  3. postRunnableに対するrequestHandlerタスク

HandlerThreadからのUIスレッドとの通信

  1. メインスレッドにHandlerを使用してLooperを作成します。responseHandlerおよびhandleMessageメソッドのオーバーライド
  2. 他のスレッド(この場合はRunnable)のHandlerThreadタスク内で、sendMessageに対してresponseHandlerを呼び出します。
  3. このsendMessageは、handleMessage内でresponseHandlerが呼び出された結果です。
  4. Messageから属性を取得して処理し、UIを更新します

:Webサービスから受け取ったデータでTextViewを更新します。 WebサービスはUI以外のスレッドで呼び出す必要があるため、ネットワーク操作用にHandlerThreadを作成しました。 Webサービスからコンテンツを取得したら、メインスレッド(UI Thread)ハンドラにメッセージを送信すると、そのHandlerがメッセージを処理し、UIを更新します。

サンプルコード

HandlerThread handlerThread = new HandlerThread("NetworkOperation");
handlerThread.start();
Handler requestHandler = new Handler(handlerThread.getLooper());

final Handler responseHandler = new Handler(Looper.getMainLooper()) {
    @Override
    public void handleMessage(Message msg) {
        txtView.setText((String) msg.obj);
    }
};

Runnable myRunnable = new Runnable() {
    @Override
    public void run() {
        try {
            Log.d("Runnable", "Before IO call");
            URL page = new URL("http://www.your_web_site.com/fetchData.jsp");
            StringBuffer text = new StringBuffer();
            HttpURLConnection conn = (HttpURLConnection) page.openConnection();
            conn.connect();
            InputStreamReader in = new InputStreamReader((InputStream) conn.getContent());
            BufferedReader buff = new BufferedReader(in);
            String line;
            while ((line = buff.readLine()) != null) {
                text.append(line + "\n");
            }
            Log.d("Runnable", "After IO call:"+ text.toString());
            Message msg = new Message();
            msg.obj = text.toString();
            responseHandler.sendMessage(msg);


        } catch (Exception err) {
            err.printStackTrace();
        }
    }
};
requestHandler.post(myRunnable);

役に立つ記事:

ハンドルスレッド、そしてなぜあなたはあなたのAndroidアプリでそれらを使うべきなのか

Androidルーパーハンドラハンドルスレッドi

2
Ravindra babu

ハンドラを使用したより正確なKotlinコード:

Handler(Looper.getMainLooper()).post {  
 // your codes here run on main Thread
 }
2
Hamed Jaliliani

この方法に従ってください。この方法を使用すると、バックグラウンドスレッドからUIを簡単に更新できます。 runOnUiThreadはメイン(UI)スレッドで動作します。私はこのコードスニペットは、特に初心者にとって、それほど複雑ではないと思います。

AsyncTask.execute(new Runnable() {
            @Override
            public void run() {

            //code you want to run on the background
            someCode();

           //the code you want to run on main thread
 MainActivity.this.runOnUiThread(new Runnable() {

                    public void run() {

/*the code you want to run after the background operation otherwise they will executed earlier and give you an error*/
                        executeAfterOperation();

                   }
                });
            }
        });

サービスの場合

oncreateにハンドラを作成する

 handler = new Handler();

それからこのようにそれを使う

 private void runOnUiThread(Runnable runnable) {
        handler.post(runnable);
    }
1
MarGin
public void mainWork() {
    new Handler(Looper.getMainLooper()).post(new Runnable() {
        @Override
        public void run() {
            //Add Your Code Here
        }
    });
}

これはサービスクラスでも問題なく動作します。

0
Revelation A.F

kotlinでは、 Anko corountines を使用できます。

更新

doAsync {
   ...
}

廃止予定

async(UI) {
    // Code run on UI thread
    // Use ref() instead of this@MyActivity
}
0
Francis