Can't create handler inside thread that has not called Looper.prepare()类型的错误及修改方法
2015-05-14 13:56
423 查看
首先将错误帖出来,(大概很多朋友都碰到过吧):
E/AndroidRuntime( 9874): FATAL EXCEPTION: Thread-1034
E/AndroidRuntime( 9874): java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare()
E/AndroidRuntime( 9874): at android.os.Handler.<init>(Handler.java:205)
E/AndroidRuntime( 9874): at android.os.Handler.<init>(Handler.java:119)
E/AndroidRuntime( 9874): at android.app.Dialog.<init>(Dialog.java:107)
E/AndroidRuntime( 9874): at android.app.AlertDialog.<init>(AlertDialog.java:119)
E/AndroidRuntime( 9874): at android.app.AlertDialog$Builder.create(AlertDialog.java:994)
E/AndroidRuntime( 9874): at com.android.camera.ActivityBase.updateStorageHint(ActivityBase.java:871)
E/AndroidRuntime( 9874): at com.android.camera.PhotoModule.updateCameraParametersPreference(PhotoModule.java:6274)
E/AndroidRuntime( 9874): at com.android.camera.PhotoModule.setCameraParameters(PhotoModule.java:7059)
E/AndroidRuntime( 9874): at com.android.camera.PhotoModule.startPreview(PhotoModule.java:5605)
E/AndroidRuntime( 9874): at com.android.camera.PhotoModule.access$1400(PhotoModule.java:190)
E/AndroidRuntime( 9874): at com.android.camera.PhotoModule$CameraStartUpThread.run(PhotoModule.java:627)
从上述调用栈上来看,就知道是一个 CameraStartUpThread 线程中跑了关于UI显示方面的东东导致的。Android app层规定的比较死板,
一般在非 UI 的线程中不允许调弹出框,对话框之类的东东。而在上述错误中正是由于 ActivityBase.java 类的 updateStorageHint() 函数中创建了一个对话框导致的,而这个函数又被非 UI 线程 CameraStartUpThread 间接调用 。
要解决此问题也非常简单:
方法一,将对话框创建的地方放在 UiThread 中跑。
[java] view
plaincopy
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setCancelable(false)
.setTitle(getString(R.string.not_enough_dialog_title))
.setMessage(message)
.setNeutralButton(R.string.not_enough_dialog_clear,
new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
startActivity(clearIntent);
}
})
.setNegativeButton(android.R.string.cancel,
new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
finish();
}
});
源代码:
[java] view
plaincopy
if (mNeedClearRotateDialog == null || !mNeedClearRotateDialog.isShowing()) {
mNeedClearRotateDialog = builder.create();
}
改为:
[java] view
plaincopy
if (mNeedClearRotateDialog == null || !mNeedClearRotateDialog.isShowing()) {
mActivity.runOnUiThread(new Runnable() {
public void run() {
mNeedClearRotateDialog = builder.create();
}
});
}
注:如果当前类不是 Activity 类的话,还需要在 runOnUiThread 前加上 mActivity 类对象来调用,如上所示。另外该 Runnable() 是一个匿名线程,该线程中变量需要是 final 类型的。这里还需要将 builder 变量改为 final 类型的。
方法二:在 CameraStartupThread() 一开始调用的地方就加上runOnUiThread
源码:
[java] view
plaincopy
checkStoragePathPreference(mPreferences);
if (mActivity != null) {
Long leftSpace = Storage.getAvailableSpace();
vity.updateStorageHint(leftSpace);
}
改为:
[java] view
plaincopy
checkStoragePathPreference(mPreferences);
if (mActivity != null) {
final Long leftSpace = Storage.getAvailableSpace();
mActivity.runOnUiThread(new Runnable() {
public void run() {
mActivity.updateStorageHint(leftSpace);
}
});
}
再次重申匿名线程中的变量需要改为 final 类型的,不然会报错。
相对而言,推荐方法一,这样影响的地方比较小,如果在 mAcitivity.updateStorageHint(leftSpace) 函数调用中没有什么复杂的逻辑的话方法二也是可行的。
UiThread 一般都是用于界面显示的一些东西,不要把一些复杂的计算或者耗电的逻辑放到其中。如果有比较耗时的操作的话就建议新开线程来在后台做了。
很多 ANR 都是来源于主线程中跑了一些比较耗时耗资源的操作,导致按键响应不及时,或者等待过久 发生的。
E/AndroidRuntime( 9874): FATAL EXCEPTION: Thread-1034
E/AndroidRuntime( 9874): java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare()
E/AndroidRuntime( 9874): at android.os.Handler.<init>(Handler.java:205)
E/AndroidRuntime( 9874): at android.os.Handler.<init>(Handler.java:119)
E/AndroidRuntime( 9874): at android.app.Dialog.<init>(Dialog.java:107)
E/AndroidRuntime( 9874): at android.app.AlertDialog.<init>(AlertDialog.java:119)
E/AndroidRuntime( 9874): at android.app.AlertDialog$Builder.create(AlertDialog.java:994)
E/AndroidRuntime( 9874): at com.android.camera.ActivityBase.updateStorageHint(ActivityBase.java:871)
E/AndroidRuntime( 9874): at com.android.camera.PhotoModule.updateCameraParametersPreference(PhotoModule.java:6274)
E/AndroidRuntime( 9874): at com.android.camera.PhotoModule.setCameraParameters(PhotoModule.java:7059)
E/AndroidRuntime( 9874): at com.android.camera.PhotoModule.startPreview(PhotoModule.java:5605)
E/AndroidRuntime( 9874): at com.android.camera.PhotoModule.access$1400(PhotoModule.java:190)
E/AndroidRuntime( 9874): at com.android.camera.PhotoModule$CameraStartUpThread.run(PhotoModule.java:627)
从上述调用栈上来看,就知道是一个 CameraStartUpThread 线程中跑了关于UI显示方面的东东导致的。Android app层规定的比较死板,
一般在非 UI 的线程中不允许调弹出框,对话框之类的东东。而在上述错误中正是由于 ActivityBase.java 类的 updateStorageHint() 函数中创建了一个对话框导致的,而这个函数又被非 UI 线程 CameraStartUpThread 间接调用 。
要解决此问题也非常简单:
方法一,将对话框创建的地方放在 UiThread 中跑。
[java] view
plaincopy
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setCancelable(false)
.setTitle(getString(R.string.not_enough_dialog_title))
.setMessage(message)
.setNeutralButton(R.string.not_enough_dialog_clear,
new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
startActivity(clearIntent);
}
})
.setNegativeButton(android.R.string.cancel,
new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
finish();
}
});
源代码:
[java] view
plaincopy
if (mNeedClearRotateDialog == null || !mNeedClearRotateDialog.isShowing()) {
mNeedClearRotateDialog = builder.create();
}
改为:
[java] view
plaincopy
if (mNeedClearRotateDialog == null || !mNeedClearRotateDialog.isShowing()) {
mActivity.runOnUiThread(new Runnable() {
public void run() {
mNeedClearRotateDialog = builder.create();
}
});
}
注:如果当前类不是 Activity 类的话,还需要在 runOnUiThread 前加上 mActivity 类对象来调用,如上所示。另外该 Runnable() 是一个匿名线程,该线程中变量需要是 final 类型的。这里还需要将 builder 变量改为 final 类型的。
方法二:在 CameraStartupThread() 一开始调用的地方就加上runOnUiThread
源码:
[java] view
plaincopy
checkStoragePathPreference(mPreferences);
if (mActivity != null) {
Long leftSpace = Storage.getAvailableSpace();
vity.updateStorageHint(leftSpace);
}
改为:
[java] view
plaincopy
checkStoragePathPreference(mPreferences);
if (mActivity != null) {
final Long leftSpace = Storage.getAvailableSpace();
mActivity.runOnUiThread(new Runnable() {
public void run() {
mActivity.updateStorageHint(leftSpace);
}
});
}
再次重申匿名线程中的变量需要改为 final 类型的,不然会报错。
相对而言,推荐方法一,这样影响的地方比较小,如果在 mAcitivity.updateStorageHint(leftSpace) 函数调用中没有什么复杂的逻辑的话方法二也是可行的。
UiThread 一般都是用于界面显示的一些东西,不要把一些复杂的计算或者耗电的逻辑放到其中。如果有比较耗时的操作的话就建议新开线程来在后台做了。
很多 ANR 都是来源于主线程中跑了一些比较耗时耗资源的操作,导致按键响应不及时,或者等待过久 发生的。
相关文章推荐
- Can't create handler inside thread that has not called Looper.prepare()类型的错误及修改方法
- 报错“Can't create handler inside thread that has not called Looper.prepare()” 的处理方法
- 错误解决 Can't create handler inside thread that has not called Looper.prepare()
- Can't create handler inside thread that has not called Looper.prepare() 错误
- Can't create handler inside thread that has not called Looper.prepare()解决方法
- Can't create handler inside thread that has not called Looper.prepare() 终极解决方法
- Can't create handler inside thread that has not called Looper.prepare() 错误有关问题
- Can't create handler inside thread that has not called Looper.prepare()的终极解决方法
- 错误: Can't create handler inside thread that has not called Looper.prepare()
- Can't create handler inside thread that has not called Looper.prepare() 错误有关问题
- Can't create handler inside thread that has not called Looper.prepare()
- Android开发报错 Can't create handler inside thread that has not called Looper.prepare()
- Can't create handler inside thread that has not called Looper.prepare()
- CountDownTimer 导致的一个崩溃 (Can't create handler inside thread that has not called Looper.prepare())
- java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare()
- Android开发报错 Can't create handler inside thread that has not called Looper.prepare()
- Android蓝牙开发,报BluetoothAdapter﹕ Can't create handler inside thread that has not called Looper.prepare
- Can't create handler inside thread that has not called Looper.prepare()
- Can't create handler inside thread that has not called Looper.prepare()
- Android : Can't create handler inside thread that has not called Looper.prepare()