スレッドを実行しているAndroidアプリがあります。 Toastメッセージをメッセージと共に表示したい。
これを行うと、次の例外が発生します。
Logcatトレース:
FATAL EXCEPTION: Timer-0
Java.lang.RuntimeException: Can't create handler inside thread that has not
called Looper.prepare()
at Android.os.Handler.<init>(Handler.Java:121)
at Android.widget.Toast$TN.<init>(Toast.Java:322)
at Android.widget.Toast.<init>(Toast.Java:91)
at Android.widget.Toast.makeText(Toast.Java:238)
Toastメッセージをスレッドからユーザーインターフェイスにプッシュするための回避策はありますか?
バックグラウンドスレッドからToastポップアップを作成しようとしたため、この例外が発生しました。
Toastにはユーザーインターフェイスにプッシュするアクティビティが必要ですが、スレッドにはそれがありません。
したがって、1つの回避策は、スレッドに親ActivityとToastへのリンクを与えることです。
Toastメッセージを送信するスレッドに次のコードを配置します。
parent.runOnUiThread(new Runnable() {
public void run() {
Toast.makeText(parent.getBaseContext(), "Hello", Toast.LENGTH_LONG).show();
}
});
このスレッドを作成したバックグラウンドスレッドで、親アクティビティへのリンクを保持します。スレッドクラスで親変数を使用します。
private static YourActivity parent;
スレッドを作成するとき、次のように、コンストラクターを介してパラメーターとして親Activityを渡します。
public YourBackgroundThread(YourActivity parent) {
this.parent = parent;
}
これで、バックグラウンドスレッドがToastメッセージを画面にプッシュできます。
Androidは基本的に2つのスレッドタイプ、つまりUIスレッドとバックグラウンドスレッドで動作します。 Androidドキュメントによると-
この問題を解決するためにUIスレッドの外部からAndroid UIツールキットにアクセスしないでください。Androidは、他のスレッドからUIスレッドにアクセスするいくつかの方法を提供します。以下に役立つメソッドのリストを示します。
Activity.runOnUiThread(Runnable)
View.post(Runnable)
View.postDelayed(Runnable, long)
現在、この問題を解決するためのさまざまな方法があります。コードサンプルで説明します
runOnUiThread
new Thread()
{
public void run()
{
myactivity.this.runOnUiThread(new runnable()
{
public void run()
{
//Do your UI operations like dialog opening or Toast here
}
});
}
}.start();
ルーパー
スレッドのメッセージループを実行するために使用されるクラス。デフォルトでは、スレッドにはメッセージループが関連付けられていません。ループを作成するには、ループを実行するスレッドでprepare()を呼び出し、次にloop()を呼び出して、ループが停止するまでメッセージを処理します。
class LooperThread extends Thread {
public Handler mHandler;
public void run() {
Looper.prepare();
mHandler = new Handler() {
public void handleMessage(Message msg) {
// process incoming messages here
}
};
Looper.loop();
}
AsyncTask
AsyncTaskを使用すると、ユーザーインターフェイスで非同期作業を実行できます。ワーカースレッドでブロッキング操作を実行してから、スレッドやハンドラーを自分で処理する必要なく、結果をUIスレッドに公開します。
public void onClick(View v) {
new CustomTask().execute((Void[])null);
}
private class CustomTask extends AsyncTask<Void, Void, Void> {
protected Void doInBackground(Void... param) {
//Do some work
return null;
}
protected void onPostExecute(Void param) {
//Print Toast or open dialog
}
}
ハンドラ
ハンドラーを使用すると、スレッドのMessageQueueに関連付けられたMessageおよびRunnableオブジェクトを送信および処理できます。
Message msg = new Message();
new Thread()
{
public void run()
{
msg.arg1=1;
handler.sendMessage(msg);
}
}.start();
Handler handler = new Handler(new Handler.Callback() {
@Override
public boolean handleMessage(Message msg) {
if(msg.arg1==1)
{
//Print Toast or open dialog
}
return false;
}
});
ここに私がやってきたことがあります:
public void displayError(final String errorText) {
Runnable doDisplayError = new Runnable() {
public void run() {
Toast.makeText(getApplicationContext(), errorText, Toast.LENGTH_LONG).show();
}
};
messageHandler.post(doDisplayError);
}
これにより、メソッドをいずれかのスレッドから呼び出すことができます。
MessageHandlerは、アクティビティ内で..として宣言されています.
Handler messageHandler = new Handler();
http://developer.Android.com/guide/components/processes-and-threads.html から:
さらに、Android UIツールキットはスレッドセーフではありません。 そのため、ワーカースレッドからUIを操作しないでください— UIスレッドからユーザーインターフェイスを操作する必要があります。したがって、Androidのシングルスレッドモデルには2つのルールがあります。
- UIスレッドをブロックしないでください
- UIスレッドの外部からAndroid UIツールキットにアクセスしないでください
ワーカースレッドでアイドル状態を検出し、メインスレッドでトーストを表示する必要があります。
より詳細な回答が必要な場合は、コードを投稿してください。
コード発行後:
strings.xml
<string name="idleness_toast">"You are getting late do it fast"</string>
YourWorkerThread.Java
Toast.makeText(getApplicationContext(), getString(R.string.idleness_toast),
Toast.LENGTH_LONG).show();
AlertDialogを使用しないで、選択してください。 AlertDialogとToastは2つの異なるものです。
単にBeginInvokeOnMainThread()を使用できます。デバイスのメイン(UI)スレッドでアクションを呼び出します。
Device.BeginInvokeOnMainThread(() => { displayToast("text to display"); });
それはシンプルで、私にとって完璧に機能します!
編集:C#Xamarinを使用している場合に機能します
runOnUiThread(new Runnable(){
public void run() {
Toast.makeText(getApplicationContext(), "Status = " + message.getBody() , Toast.LENGTH_LONG).show();
}
});
これは私のために働く