Androidサービスでは、バックグラウンドタスクを実行するためのスレッドを作成しました。
私は、スレッドがメインスレッドのメッセージキューに特定のタスクをポストする必要がある状況、例えばRunnable
を持っています。
メインスレッドのHandler
を取得し、他のスレッドからそれにMessage
/Runnable
をポストする方法はありますか?
ありがとう、
注:この回答は注目を集めているので、更新する必要があります。元の回答が投稿されて以来、@ 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);
以下のコメンターが正しく指摘しているように、これはサービスの一般的な解決策ではなく、あなたの活動から起動されたスレッドだけのためのものです(サービスはそのようなスレッドでありえますが、全部ではありません)。サービス活動のコミュニケーションの複雑なトピックについては、公式文書のサービスセクション全体を読んでください - それは複雑なので、基本を理解するためにお金を払うでしょう: 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() {
});
これがあなたが探しているものであることを願っています。
コンテキストにアクセスできない場合は、別の簡単な方法があります。
1)。メインルーパーからハンドラを作成します。
Handler uiHandler = new Handler(Looper.getMainLooper());
2)。 Runnableインターフェースを実装します。
Runnable runnable = new Runnable() { // your code here }
3)。 RunnableをuiHandlerに投稿してください。
uiHandler.post(runnable);
これですべてです;-)スレッドを楽しんでください。ただし、同期することを忘れないでください。
あなたがコードをスレッドで実行するなら、例えば何らかのアクションを遅らせるには、コンテキストからrunOnUiThread
を呼び出す必要があります。例えば、あなたのコードがMainActivity
クラスの中にあるならば、これを使います:
MainActivity.this.runOnUiThread(new Runnable() {
@Override
public void run() {
myAction();
}
});
あなたのメソッドがメイン(UIスレッド)または他のスレッドのどちらからでも呼び出せる場合は、次のようなチェックが必要です。
public void myMethod() {
if( Looper.myLooper() == Looper.getMainLooper() ) {
myAction();
}
else {
}
要約コードブロックは次のとおりです。
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
})
アクティビティ中の場合、使用
runOnUiThread {
//code that runs in main
}
アクティビティコンテキストがあるの場合、mContextは
mContext.runOnUiThread {
//code that runs in main
}
コンテキストが利用できないのどこかにいる場合は、
Handler(Looper.getMainLooper()).post {
//code that runs in main
}
私が考えることができる一つの方法はこれです:
1)UIをサービスにバインドします。
2)Binder
を登録するHandler
で以下のようなメソッドを公開します。
public void registerHandler(Handler handler) {
mHandler = handler;
}
3)UIスレッドで、サービスにバインドした後に上記のメソッドを呼び出します。
mBinder.registerHandler(new Handler());
4)あなたのタスクを投稿するためにサービスのスレッドでハンドラを使用します。
mHandler.post(runnable);
RxAndroidを使用している場合は特に、あなたがコンテキストを持っていない場合は特に簡単な方法:
AndroidSchedulers.mainThread().scheduleDirect {
runCodeHere()
}
これは古い質問ですが、KotlinとJavaの両方で使用しているメインスレッドのワンライナーに出会いました。これはサービスにとって最善の解決策ではないかもしれませんが、フラグメント内でUIを変更するものを呼び出すためにこれは非常に単純で明白です。
Java(8):
getActivity().runOnUiThread(()->{
//your main thread code
});
コトリン:
this.runOnUiThread {
//your main thread code
}
HandlerThread
は、Androidの通常のJava Threadsにとってより良いオプションです。
requestHandler
post
Runnable
に対するrequestHandler
タスクHandlerThread
からのUIスレッドとの通信
Handler
を使用してLooper
を作成します。responseHandler
およびhandleMessage
メソッドのオーバーライドRunnable
)のHandlerThread
タスク内で、sendMessage
に対してresponseHandler
を呼び出します。sendMessage
は、handleMessage
内でresponseHandler
が呼び出された結果です。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);
役に立つ記事:
ハンドラを使用したより正確なKotlinコード:
Handler(Looper.getMainLooper()).post {
// your codes here run on main Thread
}
この方法に従ってください。この方法を使用すると、バックグラウンドスレッドから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);
}
public void mainWork() {
new Handler(Looper.getMainLooper()).post(new Runnable() {
@Override
public void run() {
//Add Your Code Here
}
});
}
これはサービスクラスでも問題なく動作します。
kotlinでは、 Anko corountines を使用できます。
更新
doAsync {
...
}
廃止予定
async(UI) {
// Code run on UI thread
// Use ref() instead of this@MyActivity
}