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
分享到:
相关推荐
在Android开发中,`Handler`、`AsyncTask`和`Looper`是三个关键组件,用于在后台线程和主线(UI)线程之间进行通信,处理异步任务和更新用户界面。下面将详细阐述这三个组件的工作原理以及如何使用它们。 **Handler...
开发者可以通过阅读和分析这些代码来学习如何在Service中正确地使用Toast,同时理解多线程和UI更新的规则。 此外,了解如何调试和跟踪Service中的问题也是很重要的。Android Studio提供了强大的工具,如Logcat,...
### ToastUtil工具类详解 ...通过上述对`ToastUtil`工具类的详细介绍,可以看出该工具类为开发者提供了简洁高效的Toast管理方案,极大地提高了开发效率并确保了应用内Toast样式的统一性和美观度。
`Handler`是Android消息处理机制的一部分,它与`Looper`和`Message`协同工作,用于在不同的线程之间传递消息。在主线程中创建`Handler`实例,然后在子线程中通过该`Handler`发送`Message`,这样就可以在子线程完成...
在线程中正确使用Toast显示提示信息 在 Android 应用程序开发中,使用 Toast 来显示提示信息是一种非常常见...通过正确使用 Toast,可以提高应用程序的响应速度和用户体验,并避免应用程序崩溃和其他不可预期的结果。
默认情况下,`Toast`的显示时间分为两种:`LENGTH_SHORT`(约2秒)和`LENGTH_LONG`(约3.5秒)。然而,在某些情况下,开发者可能需要自定义`Toast`的显示时间以适应特定的用户体验需求。本文将深入探讨如何自定义`...
这个毕业设计的源码示例探讨了五种不同的`Toast`效果,帮助学习者深入理解如何定制和扩展`Toast`的显示方式。下面我们将详细讲解这些知识点。 1. **基本的Toast使用**: 在Android中,`Toast`通常用于显示简短的...
因此,需要确保Toast的创建和显示都在主线程中进行,可以使用`runOnUiThread`或`Looper.getMainLooper().post`来保证这一点。 了解并实现这些不同的Toast效果,开发者不仅可以提高应用的用户体验,还能更好地掌握...
总结来说,解决`Toast`内容堆积的问题,关键在于合理管理和控制`Toast`的生命周期,以及确保其更新和显示都在主线程进行。`Toast.cancel()` 在某些情况下可能不足以解决所有问题,因此需要结合其他技术手段,如使用`...
为了解决这个问题,我们可以利用Handler和Looper来在主线程上执行显示Toast的操作。 以下是使用Handler解决Service中Toast无法显示问题的步骤: 1. 在Service的适当位置(如onCreate())创建一个新的Handler实例,...
因为`Toast`必须在主线程中显示,所以我们使用`Looper.prepare()`和`Looper.loop()`来切换到主线程执行`Toast`的显示操作。 ```java public void showToastInThread(Context context, String msg){ Looper.prepare...
在Android开发中,`Toast`是一种轻量级的通知机制,用于在短时间内向用户显示简短的信息,而不会中断用户的操作。这些信息会在指定的时间后...在实际开发中,根据需求选择合适的`Toast`显示方式和时机是非常重要的。
在Android开发中,理解核心组件如Looper、Handler和HandlerThread对于构建高效且响应式的用户界面至关重要。这些组件共同协作,确保UI线程不被阻塞,从而提供流畅的用户体验。 首先,主线程(也称为UI线程)是...
Handler handler = new Handler(Looper.getMainLooper()); handler.post(new Runnable() { @Override public void run() { //放在UI线程弹Toast Toast.makeText(Setting.this, 正在更新请稍后, Toast.LENGTH_...
private static Handler mHandler = new Handler(Looper.getMainLooper()); private static Toast mToast = null; private static Object synObject = new Object(); public static void showToastByThread(Context...
- **线程管理**:使用Handler和Looper进行消息传递,确保Crouton在合适的时间和线程上显示。 4. **使用方法** - **添加依赖**:首先需要将Crouton库添加到项目的依赖项中,通常是通过Gradle导入。 - **创建...
默认情况下,`Toast`显示的是系统预设的布局和文本,但有时候开发者可能需要根据需求自定义`Toast`的样式、内容或者显示时长。本节将深入探讨如何自定义`Toast`的布局以及设置显示时间。 首先,让我们理解`Toast`的...
`ToastDemo.rar` 文件中的示例可能包含了如何灵活运用`Toast`的各种方法和技巧。让我们深入探讨一下`Toast`的使用及其在自定义和多线程场景下的应用。 ### 1. `Toast`的基本用法 `Toast`类提供了创建和显示简短...