更新1
さらにデバッグを行ったところ、コンストラクターはメインUIスレッドから実行されていますが、handleMessage(Message)メソッドは作成したスレッドで実行されているため、ハンドラーの理解とは完全に矛盾しています。
問題
私はしばらくの間Androidに取り組んできましたが、文書化されていないように見える問題に遭遇しました。私は自分のコードで特別なことは何もしていません。ハンドラーのhandleMessageメソッドからアラートダイアログやトーストメッセージなどのUI要素をアプリケーションで作成できないようです。
さらに、「スレッドがLooper.prepare()を呼び出さなかった」という例外が発生します。ただし、Threadオブジェクト内にハンドラーを作成していないため、Looper.prepare()を呼び出す必要はないと思います。メインUIスレッドでコンストラクターを呼び出し、それを新しいスレッドのコンストラクターに渡します。
私が期待すること
トーストメッセージとアラートダイアログが表示されます。
実際に何が起こるか
何もない。アプリケーションでデバッガーを実行しましたが、JVMがスレッドを起動することがわかりました。runメソッドが呼び出され、メッセージがディスパッチされます。ハンドラーがメソッドを処理し、AlertDialogとToastメッセージを作成するすべてのメソッドを実行しましたが、何も表示されません。
このアプリケーションは、4.2を実行しているエミュレーター、4.0.4を実行している友人のSamsung Galaxy S3、および2.3.5を実行している自分のDroidX2で実行しました。
プログラムの流れ
- UIスレッドでハンドラーを作成します。
- メッセージをハンドラーにディスパッチするスレッドを作成して開始します。
- ハンドラーがメッセージを処理します
ソースコード
package com.nguyenmp.ErrorTest;
import android.app.Activity;
import android.app.AlertDialog;
import android.app.Dialog;
import android.content.Context;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.view.View;
import android.widget.Button;
import android.widget.Toast;
public class MyActivity extends Activity {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//Init the UI
setContentView(R.layout.main);
//Create a new handler, passing it the current activity context
final Handler handler = new MyHandler(MyActivity.this);
//Bind a listener to the button on the UI
View view = findViewById(R.id.button);
view.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//Start a new thread that will send a message to that handler
new MyThread(handler).start();
}
});
}
private class MyThread extends Thread {
private final Handler mHandler;
MyThread(Handler handler) {
mHandler = handler;
}
@Override
public void run() {
//Dispatch message to UI thread asynchronously
Looper.prepare();
mHandler.dispatchMessage(mHandler.obtainMessage());
}
}
private class MyHandler extends Handler {
private final Context mContext;
MyHandler(Context context) {
mContext = context;
}
@Override
public void handleMessage(Message msg) {
//Show that we got the message
AlertDialog.Builder builder = new AlertDialog.Builder(mContext);
builder.setTitle("HelloWorld");
builder.setMessage("It worked!");
builder.show();
//Another variant of showing that we got the message
Toast.makeText(mContext, "Message Received", Toast.LENGTH_SHORT).show();
System.out.println("Yeah");
}
}
}