更新 1
我又做了一些调试,发现构造函数是从主 UI 线程运行的,但是 handleMessage(Message) 方法是在我创建的线程上运行的,这与我对 Handlers 的理解完全矛盾。
问题
我已经在 Android 上工作了一段时间,但遇到了一个似乎没有记录的问题。我没有对我的代码做任何特别的事情。我似乎无法让我的应用程序从处理程序的 handleMessage 方法创建任何 UI 元素,例如警报对话框和 Toast 消息。
此外,我得到一个“线程没有调用 Looper.prepare()”异常。但是,我相信我什至不需要调用 Looper.prepare() ,因为我没有在 Thread 对象内创建 Handler 。我在主 UI 线程中调用构造函数,然后将其传递给新线程的构造函数。
我的期望
我应该会看到 Toast 消息和警报对话框。
实际发生了什么
没有。我在应用程序上运行了调试器,发现 JVM 确实启动了线程。调用 run 方法并分派消息。处理程序处理该方法,我运行了创建 AlertDialog 以及 Toast 消息的所有方法,但没有显示任何内容。
我在运行 4.2 的模拟器、运行 4.0.4 的朋友的三星 Galaxy S3 和运行 2.3.5 的我自己的 Droid X2 上运行了这个应用程序。
程序流程
- 我在 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");
}
}
}