`
liujianguangaaa
  • 浏览: 235249 次
  • 性别: Icon_minigender_1
  • 来自: 湖南
社区版块
存档分类
最新评论

Toast 和 Looper

阅读更多

Toast 和 Looper,一个属于 android.widget,一个属于 android.os,两个貌似联系不怎么紧密的类,却通过下面这个异常联系到了一起:

E/AndroidRuntime( 1819): java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare()
E/AndroidRuntime( 1819):        at android.os.Handler.<init>(Handler.java:121)
E/AndroidRuntime( 1819):        at android.widget.Toast.<init>(Toast.java:397)
E/AndroidRuntime( 1819):        at android.widget.Toast.makeText(Toast.java:230)
E/AndroidRuntime( 1819):        at android.widget.Toast.makeText(Toast.java:256)

由以上的错误信息可以看出:程序要创建 handler,但是发现 Looper.prepare 还没有被调用。通过 Android SDK 中的 Reference 可以看到,Looper、Handler 的调用是非常有讲究的,如下面示例代码:

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();
    }
}

言归正题,继续寻找 Toast、Looper 和 Handler 三者之间的联系,也许谜底就能解开了。欲揭谜底,从源码入手是一条捷径。

Toast.java 的第230行的代码是创建一个新的 Toast 实例,而实例化的过程中,就需要执行第397行,也就是声明并创建 Handler 的实例。那么来看 Handler.java 的第121行到底做了什么,如下所示:

mLooper = Looper.myLooper();
if (mLooper == null) {
    throw new RuntimeException(
        "Can't create handler inside thread that has not called Looper.prepare()");
}

到此,距离真相的解开近了一大步,既然抛出了 RuntimeException,那么 mLooper 肯定是 null,但是为什么 Looper.myLooper() 会返回 null?继续进入到 Looper.java 中寻根究底。

/**
 * Return the Looper object associated with the current thread.  Returns
 * null if the calling thread is not associated with a Looper.
 */
public static final Looper myLooper() {
    return (Looper)sThreadLocal.get();
}

以上就是 myLooper() 方法的真实面貌,通过注释可以看出问题的真正原因在于当前线程并没有绑定 Looper,返回为 null 是正确但非正常的结果。

问题的根本原因已经解开,但是另外一个疑团也就产生了:为何当前线程没有 Looper 呢?经过对代码进行 review,原因找到了:当事者在 non-UI 线程进行 Toast.makeText

分享到:
评论

相关推荐

    Handler与AsyncTask,Looper使用示例

    在Android开发中,`Handler`、`AsyncTask`和`Looper`是三个关键组件,用于在后台线程和主线(UI)线程之间进行通信,处理异步任务和更新用户界面。下面将详细阐述这三个组件的工作原理以及如何使用它们。 **Handler...

    自己整理的Toast(吐司)工具类.txt

    ### ToastUtil工具类详解 ...通过上述对`ToastUtil`工具类的详细介绍,可以看出该工具类为开发者提供了简洁高效的Toast管理方案,极大地提高了开发效率并确保了应用内Toast样式的统一性和美观度。

    android service toast 01

    开发者可以通过阅读和分析这些代码来学习如何在Service中正确地使用Toast,同时理解多线程和UI更新的规则。 此外,了解如何调试和跟踪Service中的问题也是很重要的。Android Studio提供了强大的工具,如Logcat,...

    android service thread toast handler

    `Handler`是Android消息处理机制的一部分,它与`Looper`和`Message`协同工作,用于在不同的线程之间传递消息。在主线程中创建`Handler`实例,然后在子线程中通过该`Handler`发送`Message`,这样就可以在子线程完成...

    如何在线程中正确使用Toast显示提示信息

    在线程中正确使用Toast显示提示信息 在 Android 应用程序开发中,使用 Toast 来显示提示信息是一种非常常见...通过正确使用 Toast,可以提高应用程序的响应速度和用户体验,并避免应用程序崩溃和其他不可预期的结果。

    android Toast设置显示时间效果

    默认情况下,`Toast`的显示时间分为两种:`LENGTH_SHORT`(约2秒)和`LENGTH_LONG`(约3.5秒)。然而,在某些情况下,开发者可能需要自定义`Toast`的显示时间以适应特定的用户体验需求。本文将深入探讨如何自定义`...

    Android 五种不同的Toast效果-IT计算机-毕业设计.zip

    这个毕业设计的源码示例探讨了五种不同的`Toast`效果,帮助学习者深入理解如何定制和扩展`Toast`的显示方式。下面我们将详细讲解这些知识点。 1. **基本的Toast使用**: 在Android中,`Toast`通常用于显示简短的...

    安卓Andriod源码——五种效果的Toast.zip

    因此,需要确保Toast的创建和显示都在主线程中进行,可以使用`runOnUiThread`或`Looper.getMainLooper().post`来保证这一点。 了解并实现这些不同的Toast效果,开发者不仅可以提高应用的用户体验,还能更好地掌握...

    Toast类避免显示时间叠加的方法

    因为`Toast`必须在主线程中显示,所以我们使用`Looper.prepare()`和`Looper.loop()`来切换到主线程执行`Toast`的显示操作。 ```java public void showToastInThread(Context context, String msg){ Looper.prepare...

    Android Service中使用Toast无法正常显示问题的解决方法

    为了解决这个问题,我们可以利用Handler和Looper来在主线程上执行显示Toast的操作。 以下是使用Handler解决Service中Toast无法显示问题的步骤: 1. 在Service的适当位置(如onCreate())创建一个新的Handler实例,...

    Android中使用Toast.cancel()方法优化toast内容显示的解决方法

    在Android开发中,`Toast` 是一种常用的轻量级提示方式,用于显示简短的...这种方法的关键在于利用单例的`Toast`实例和主线程`Handler`来控制`Toast`的显示与更新,避免了因频繁创建`Toast`对象而引发的视觉延迟问题。

    Android Toast通知用法实例详解

    在Android开发中,`Toast`是一种轻量级的通知机制,用于在短时间内向用户显示简短的信息,而不会中断用户的操作。这些信息会在指定的时间后...在实际开发中,根据需求选择合适的`Toast`显示方式和时机是非常重要的。

    了解Android核心:Looper,Handler和HandlerThread

    在Android开发中,理解核心组件如Looper、Handler和HandlerThread对于构建高效且响应式的用户界面至关重要。这些组件共同协作,确保UI线程不被阻塞,从而提供流畅的用户体验。 首先,主线程(也称为UI线程)是...

    Android编程实现Toast只显示最后一条的方法

    private static Handler mHandler = new Handler(Looper.getMainLooper()); private static Toast mToast = null; private static Object synObject = new Object(); public static void showToastByThread(Context...

    Android studio 提示框Toast 弹出框AlertDialog 多种提示方法

    Handler handler = new Handler(Looper.getMainLooper()); handler.post(new Runnable() { @Override public void run() { //放在UI线程弹Toast Toast.makeText(Setting.this, 正在更新请稍后, Toast.LENGTH_...

    Android高级应用源码-Crouton 丰富样式的Toast.zip

    - **线程管理**:使用Handler和Looper进行消息传递,确保Crouton在合适的时间和线程上显示。 4. **使用方法** - **添加依赖**:首先需要将Crouton库添加到项目的依赖项中,通常是通过Gradle导入。 - **创建...

    自定义布局和显示时间的Toast

    默认情况下,`Toast`显示的是系统预设的布局和文本,但有时候开发者可能需要根据需求自定义`Toast`的样式、内容或者显示时长。本节将深入探讨如何自定义`Toast`的布局以及设置显示时间。 首先,让我们理解`Toast`的...

    ToastDemo.rar

    `ToastDemo.rar` 文件中的示例可能包含了如何灵活运用`Toast`的各种方法和技巧。让我们深入探讨一下`Toast`的使用及其在自定义和多线程场景下的应用。 ### 1. `Toast`的基本用法 `Toast`类提供了创建和显示简短...

Global site tag (gtag.js) - Google Analytics