【问题标题】:Can't create handler inside thread that has not called Looper.prepare() on some devices无法在某些设备上未调用 Looper.prepare() 的线程内创建处理程序
【发布时间】:2014-09-22 16:10:33
【问题描述】:

我知道已经有很多这样的问题,但我不明白我做错了什么。该应用程序崩溃而没有显示任何内容。此外,我的设备或模拟器上也不会出现该错误。仅在某些设备上(比如 30-40%?)。

无法在未调用 Looper.prepare() 的线程内创建处理程序

MainActivity.java

public class MainActivity extends Activity implements Runnable {

Gebruiker gebruiker = new Gebruiker();
private DatabaseHelper db;
Context context;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    context = this;
    if(isOnline()){
        downloadData();
    } else {
        AlertDialog.Builder builder = new AlertDialog.Builder(context);
        builder.setMessage("Deze app vereist een actieve verbinding met het internet!")
               .setCancelable(false)
               .setPositiveButton("OK", new DialogInterface.OnClickListener() {
                   public void onClick(DialogInterface dialog, int id) {
                       android.os.Process.killProcess(android.os.Process.myPid());
                   }
               });
        AlertDialog alert = builder.create();
        alert.show();
    }       
    db = new DatabaseHelper(this);
}

@Override
public boolean onCreateOptionsMenu(Menu menu) {
    // Inflate the menu; this adds items to the action bar if it is present.
    getMenuInflater().inflate(R.menu.main, menu);
    return true;
}

private ProgressDialog pDialog;

public void downloadData() {
    pDialog = ProgressDialog.show(this,
            "Controleren op bestaande gebruiker..", "Even geduld", true,
            false);
    Thread thread = new Thread(this);
    thread.start();
}

public void run() {
    // add downloading code here
    HttpReader httpReader = new HttpReader();
    String url = "*****";
    url += Secure.getString(getApplicationContext().getContentResolver(),
            Secure.ANDROID_ID);
    JsonHelper jsonHelper = new JsonHelper();

    gebruiker = jsonHelper.getGebruiker((httpReader.getTextFromUrl(url)
            .trim()));

    handler.sendEmptyMessage(0);
}

private Handler handler = new Handler() {
    @Override
    public void handleMessage(Message msg) {
        pDialog.dismiss();

        if (gebruiker == null) {
            // ga naar aanmaken gebruiker
            Intent intent = new Intent(MainActivity.this,
                    AanmakenUser.class);
            startActivity(intent);
        } else {
            // ga naar hoofdmenu
            db.droppen();
            db.insertGebruiker(gebruiker);
            Intent intent = new Intent(MainActivity.this, Hoofdmenu.class);
            startActivity(intent);
            // ga naar menu
        }
    }
};

public boolean isOnline() {
    ConnectivityManager cm = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
    NetworkInfo netInfo = cm.getActiveNetworkInfo();
    if (netInfo != null && netInfo.isConnectedOrConnecting()) {
        return true;
    }
    return false;
}

LogCat

01-10 16:12:16.444: E/AndroidRuntime(6090): FATAL EXCEPTION: Thread-10
01-10 16:12:16.444: E/AndroidRuntime(6090): java.lang.ExceptionInInitializerError
01-10 16:12:16.444: E/AndroidRuntime(6090):     at db.jochen.quizapp.MainActivity.run(MainActivity.java:68)
01-10 16:12:16.444: E/AndroidRuntime(6090):     at java.lang.Thread.run(Thread.java:1019)
01-10 16:12:16.444: E/AndroidRuntime(6090): Caused by: java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare()
01-10 16:12:16.444: E/AndroidRuntime(6090):     at android.os.Handler.<init>(Handler.java:121)
01-10 16:12:16.444: E/AndroidRuntime(6090):     at android.os.AsyncTask$InternalHandler.<init>(AsyncTask.java:421)
01-10 16:12:16.444: E/AndroidRuntime(6090):     at android.os.AsyncTask$InternalHandler.<init>(AsyncTask.java:421)
01-10 16:12:16.444: E/AndroidRuntime(6090):     at android.os.AsyncTask.<clinit>(AsyncTask.java:152)
01-10 16:12:16.444: E/AndroidRuntime(6090):     ... 2 more
01-10 16:12:16.454: D/dalvikvm(6090): GC_CONCURRENT freed 79K, 48% free 2843K/5379K, external 3695K/4614K, paused 2ms+5ms
01-10 16:12:16.454: W/ActivityManager(278):   Force finishing activity db.jochen.quizapp/.MainActivity
01-10 16:12:16.544: E/SkLayout_wtle(6090): ellipsis failed line number does not match 1 0
01-10 16:12:16.624: D/fast-dormancy(165): [FDM]: finish the match exclude list procedure, but can not match any one
01-10 16:12:16.624: D/fast-dormancy(165): [FDM]: GoDormant? 0
01-10 16:12:16.624: D/fast-dormancy(165): [FDM]: Threads Status Mutex Locked in fdm_main_loop
01-10 16:12:16.624: D/fast-dormancy(165): [FDM]: Threads Status Mutex Unlocked in fdm_main_loop
01-10 16:12:16.624: D/fast-dormancy(165): [FDM]: finish the match exclude list procedure, but can not match any one
01-10 16:12:16.624: D/fast-dormancy(165): [FDM]: GoDormant? 0
01-10 16:12:16.624: D/fast-dormancy(165): [FDM]: Threads Status Mutex Locked in fdm_main_loop
01-10 16:12:16.624: D/fast-dormancy(165): [FDM]: Threads Status Mutex Unlocked in fdm_main_loop
01-10 16:12:16.624: I/ActivityManager(278): No longer want com.sonyericsson.tvlauncher (pid 4961): hidden #16
01-10 16:12:16.664: E/WindowManager(6090): Activity db.jochen.quizapp.MainActivity has leaked window com.android.internal.policy.impl.PhoneWindow$DecorView@2afd4aa0 that was originally added here
01-10 16:12:16.664: E/WindowManager(6090): android.view.WindowLeaked: Activity db.jochen.quizapp.MainActivity has leaked window com.android.internal.policy.impl.PhoneWindow$DecorView@2afd4aa0 that was originally added here
01-10 16:12:16.664: E/WindowManager(6090):      at android.view.ViewRoot.<init>(ViewRoot.java:269)
01-10 16:12:16.664: E/WindowManager(6090):      at android.view.WindowManagerImpl.addView(WindowManagerImpl.java:148)
01-10 16:12:16.664: E/WindowManager(6090):      at android.view.WindowManagerImpl.addView(WindowManagerImpl.java:91)
01-10 16:12:16.664: E/WindowManager(6090):      at android.view.Window$LocalWindowManager.addView(Window.java:424)
01-10 16:12:16.664: E/WindowManager(6090):      at android.app.Dialog.show(Dialog.java:241)
01-10 16:12:16.664: E/WindowManager(6090):      at android.app.ProgressDialog.show(ProgressDialog.java:109)
01-10 16:12:16.664: E/WindowManager(6090):      at android.app.ProgressDialog.show(ProgressDialog.java:97)
01-10 16:12:16.664: E/WindowManager(6090):      at db.jochen.quizapp.MainActivity.downloadData(MainActivity.java:59)
01-10 16:12:16.664: E/WindowManager(6090):      at db.jochen.quizapp.MainActivity.onCreate(MainActivity.java:33)
01-10 16:12:16.664: E/WindowManager(6090):      at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1047)
01-10 16:12:16.664: E/WindowManager(6090):      at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:1623)
01-10 16:12:16.664: E/WindowManager(6090):      at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:1675)
01-10 16:12:16.664: E/WindowManager(6090):      at android.app.ActivityThread.access$1500(ActivityThread.java:121)
01-10 16:12:16.664: E/WindowManager(6090):      at android.app.ActivityThread$H.handleMessage(ActivityThread.java:943)
01-10 16:12:16.664: E/WindowManager(6090):      at android.os.Handler.dispatchMessage(Handler.java:99)
01-10 16:12:16.664: E/WindowManager(6090):      at android.os.Looper.loop(Looper.java:138)
01-10 16:12:16.664: E/WindowManager(6090):      at android.app.ActivityThread.main(ActivityThread.java:3701)
01-10 16:12:16.664: E/WindowManager(6090):      at java.lang.reflect.Method.invokeNative(Native Method)
01-10 16:12:16.664: E/WindowManager(6090):      at java.lang.reflect.Method.invoke(Method.java:507)
01-10 16:12:16.664: E/WindowManager(6090):      at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:878)
01-10 16:12:16.664: E/WindowManager(6090):      at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:636)
01-10 16:12:16.664: E/WindowManager(6090):      at dalvik.system.NativeStart.main(Native Method)

【问题讨论】:

  • 离题-您可以过滤您的 logcat 错误,以便只获得必要的日志。
  • 是的,我知道,但我没有自己制作日志。我的设备没有抛出异常并且工作正常,但无论如何谢谢!
  • MainActivity 的第 68 行是什么?
  • 第 68 行是 HttpReader httpReader = new HttpReader();

标签: java android multithreading progressdialog runnable


【解决方案1】:

您的处理程序可能是在另一个线程中创建的,而不是没有循环器的主线程。为避免这种情况,您应该在带有 looper 的线程中创建处理程序(例如:在主线程中,在 onCreate 中),或者为处理程序提供 looper:

private Handler handler = new Handler(Looper.getMainLooper()) {
    ...

【讨论】:

  • 感谢您的帮助!
【解决方案2】:

如果您的线程没有监听 Looper,您如何管理发送到处理程序的请求?

文档说: 公共处理程序()

在 API 级别 1 中添加 默认构造函数将此处理程序与当前线程的 Looper 相关联。如果该线程没有 Looper,则该处理程序将无法接收消息,因此会引发异常。

如果您希望辅助线程能够管理 Handler,您必须调用 Looper.prepare()

例子:

public class MyThread extends Thread {
    private Handler mHandler;

    public void run() {
        Looper.prepare();
        mHandler = new Handler() {
            @Override
            public void handleMessage(Message msg) {
                switch (msg.what) {
                    // manage the message
                }
            }
        };
        Looper.loop();
    }

    public void stopLooper() {
        if (Looper.myLooper()!=null)
            Looper.myLooper().quitSafely();
    }
}

【讨论】:

  • 我应该在哪里称呼这个活套?在公共 void run() 中?
  • 在答案中添加示例
  • 谢谢,现在可以使用了!你知道为什么它可以在某些设备上运行吗?
  • 可能是因为在处理程序上接收消息时您的线程仍然处于活动状态。 looper 确保您的线程处于活动状态,直到您自己停止(在 looper 上调用 quit() )。然后应该修改示例以便能够从外部访问looper。
【解决方案3】:

您在后台执行操作的方法非常奇怪(即Activity implements Runnable)。我想,问题在于您调用downloadData() 方法的方式,也许是从其他后台线程。 (顺便问一下,你怎么称呼它,即MainActivity的引用存储在哪里?)

Loaders 可以轻松解决您的任务,完美匹配 Activity 的生命周期,并且需要更少的代码。

【讨论】:

  • 感谢您的提示,我只是 Android 开发的初学者 :) MainActivity 是通过启动应用程序来启动的,如果您的意思是这样的话。
  • 不,我的意思是,如果downloadData() 方法是公开的,那么您必须以某种方式持有对 MainActivity 实例的引用才能调用它。这是非常糟糕的做法,因为它可能会导致内存泄漏。
猜你喜欢
  • 1970-01-01
  • 2012-08-15
  • 2011-09-06
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多