前段时间做了Launcher3模块,然后又紧接着SystemUI,Settings,备份;时间赶得比较紧,有些重要的东西都写了博客记录一下。
没想到有些人看了我的博客还指出了问题,在这里很感谢这些能指出我错误的朋友们。其实我前几天就看见了,但是真的没时间解决这个问题,也不好意思回复。
这里就解决一下前几篇Launcher3去掉应用抽屉博客中遗留的一个java.lang.StackOverflowError问题;
先看一下日志
06-21 07:26:46.037: E/AndroidRuntime(14384): FATAL EXCEPTION: main
06-21 07:26:46.037: E/AndroidRuntime(14384): Process: com.android.launcher3, PID: 14384
06-21 07:26:46.037: E/AndroidRuntime(14384): java.lang.StackOverflowError: stack size 8MB
06-21 07:26:46.037: E/AndroidRuntime(14384): at android.os.Bundle.writeToParcel(Bundle.java:1232)
06-21 07:26:46.037: E/AndroidRuntime(14384): at android.os.Parcel.writeBundle(Parcel.java:878)
06-21 07:26:46.037: E/AndroidRuntime(14384): at android.content.Intent.writeToParcel(Intent.java:9595)
06-21 07:26:46.037: E/AndroidRuntime(14384): at android.os.Parcel.writeParcelable(Parcel.java:1791)
06-21 07:26:46.037: E/AndroidRuntime(14384): at android.os.Parcel.writeValue(Parcel.java:1697)
06-21 07:26:46.037: E/AndroidRuntime(14384): at android.os.Parcel.writeArrayMapInternal(Parcel.java:838)
06-21 07:26:46.037: E/AndroidRuntime(14384): at android.os.BaseBundle.writeToParcelInner(BaseBundle.java:1542)
06-21 07:26:46.037: E/AndroidRuntime(14384): at android.os.Bundle.writeToParcel(Bundle.java:1232)
06-21 07:26:46.037: E/AndroidRuntime(14384): at android.os.Parcel.writeBundle(Parcel.java:878)
06-21 07:26:46.037: E/AndroidRuntime(14384): at android.content.Intent.writeToParcel(Intent.java:9595)
......
06-21 07:26:47.326: E/AndroidRuntime(14384): at android.os.Parcel.writeParcelable(Parcel.java:1791)
06-21 07:26:47.326: E/AndroidRuntime(14384): at android.os.Parcel.writeValue(Parcel.java:1697)
06-21 07:26:47.326: E/AndroidRuntime(14384): at android.os.Parcel.writeArrayMapInternal(Parcel.java:838)
06-21 07:26:47.326: E/AndroidRuntime(14384): at android.os.BaseBundle.writeToParcelInner(BaseBundle.java:1542)
06-21 07:26:47.326: E/AndroidRuntime(14384): at android.os.Bundle.writeToParcel(Bundle.java:1232)
06-21 07:26:47.326: E/AndroidRuntime(14384): at android.os.Parcel.writeBundle(Parcel.java:878)
06-21 07:26:47.326: E/AndroidRuntime(14384): at android.content.Intent.writeToParcel(Intent.java:9595)
06-21 07:26:47.326: E/AndroidRuntime(14384): at android.app.IActivityManager$Stub$Proxy.startActivity(IActivityManager.java:4362)
06-21 07:26:47.326: E/AndroidRuntime(14384): at android.app.Instrumentation.execStartActivity(Instrumentation.java:1611)
06-21 07:26:47.326: E/AndroidRuntime(14384): at android.app.Activity.startActivityForResult(Activity.java:4501)
06-21 07:26:47.326: E/AndroidRuntime(14384): at com.android.launcher3.Launcher.startActivityForResult(Launcher.java:1867)
06-21 07:26:47.326: E/AndroidRuntime(14384): at android.app.Activity.startActivity(Activity.java:4816)
06-21 07:26:47.326: E/AndroidRuntime(14384): at com.android.launcher3.Launcher.startActivitySafely(Launcher.java:2685)
06-21 07:26:47.326: E/AndroidRuntime(14384): at com.android.launcher3.Launcher.startAppShortcutOrInfoActivity(Launcher.java:2443)
06-21 07:26:47.326: E/AndroidRuntime(14384): at com.android.launcher3.Launcher.onClickAppShortcut(Launcher.java:2427)
06-21 07:26:47.326: E/AndroidRuntime(14384): at com.android.launcher3.Launcher.onClick(Launcher.java:2266)
06-21 07:26:47.326: E/AndroidRuntime(14384): at android.view.View.performClick(View.java:6300)
06-21 07:26:47.326: E/AndroidRuntime(14384): at android.view.View$PerformClick.run(View.java:24941)
06-21 07:26:47.326: E/AndroidRuntime(14384): at android.os.Handler.handleCallback(Handler.java:790)
06-21 07:26:47.326: E/AndroidRuntime(14384): at android.os.Handler.dispatchMessage(Handler.java:99)
06-21 07:26:47.326: E/AndroidRuntime(14384): at android.os.Looper.loop(Looper.java:164)
06-21 07:26:47.326: E/AndroidRuntime(14384): at android.app.ActivityThread.main(ActivityThread.java:6523)
06-21 07:26:47.326: E/AndroidRuntime(14384): at java.lang.reflect.Method.invoke(Native Method)
06-21 07:26:47.326: E/AndroidRuntime(14384): at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:438)
06-21 07:26:47.326: E/AndroidRuntime(14384): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:857)
日志比较长,这里省略了中间一部分,但是碰到这个问题的同学,肯定是有全部日志的,中间都是重复的内容,没什么意义。
java.lang.StackOverflowError: stack size 8MB是由于当前线程的栈满了
这个错误主要就是因为递归的次数过多,在这里应该就是无限递归下去,但是程序肯定不能这么跑,于是就报了这个错误。但是报错一次,重新启动Launcher之后又不会报错了,没有搞清楚是什么原因,而且清除launcher数据之后也会报错,所以应该是跟数据库有些关系。
因为时间关系,我就没有去查看数据库原因,直接从代码中解决,这个解决方式比较简单
src/com/android/launcher3/Launcher.java -> startActivitySafely():
public boolean startActivitySafely(View v, Intent intent, ItemInfo item) {
if (mIsSafeModeEnabled && !Utilities.isSystemApp(this, intent)) {
Toast.makeText(this, R.string.safemode_shortcut_error, Toast.LENGTH_SHORT).show();
return false;
}
// Only launch using the new animation if the shortcut has not opted out (this is a
// private contract between launcher and may be ignored in the future).
boolean useLaunchAnimation = (v != null) &&
!intent.hasExtra(INTENT_EXTRA_IGNORE_LAUNCH_ANIMATION);
Bundle optsBundle = useLaunchAnimation ? getActivityLaunchOptions(v) : null;
UserHandle user = item == null ? null : item.user;
// Prepare intent
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
if (v != null) {
intent.setSourceBounds(getViewBounds(v));
}
try {
if (Utilities.ATLEAST_MARSHMALLOW
&& (item instanceof ShortcutInfo)
&& (item.itemType == Favorites.ITEM_TYPE_SHORTCUT
|| item.itemType == Favorites.ITEM_TYPE_DEEP_SHORTCUT)
&& !((ShortcutInfo) item).isPromise()) {
// Shortcuts need some special checks due to legacy reasons.
startShortcutIntentSafely(intent, optsBundle, item);
} else if (user == null || user.equals(Process.myUserHandle())) {
// Could be launching some bookkeeping activity
startActivity(intent, optsBundle);
} else {
LauncherAppsCompat.getInstance(this).startActivityForProfile(
intent.getComponent(), user, intent.getSourceBounds(), optsBundle);
}
return true;
} catch (ActivityNotFoundException|SecurityException e) {
Toast.makeText(this, R.string.activity_not_found, Toast.LENGTH_SHORT).show();
Log.e(TAG, "Unable to launch. tag=" + item + " intent=" + intent, e);
}
return false;
}
因为点击图库不会报错,所以我们可以看到图库走的逻辑是
user == null || user.equals(Process.myUserHandle())
而我们从allapp中取出的app走的逻辑是
Utilities.ATLEAST_MARSHMALLOW
&& (item instanceof ShortcutInfo)
&& (item.itemType == Favorites.ITEM_TYPE_SHORTCUT
|| item.itemType == Favorites.ITEM_TYPE_DEEP_SHORTCUT)
&& !((ShortcutInfo) item).isPromise()
于是尝试这把 startShortcutIntentSafely
方法替换为 startActivity
,运行发现仍然不行,但是还有一个else,我这里把 startShortcutIntentSafely 替换为
LauncherAppsCompat.getInstance(this).startActivityForProfile(
intent.getComponent(), user, intent.getSourceBounds(), optsBundle);
运行一下,不报错了!
最终代码:
try {
if (Utilities.ATLEAST_MARSHMALLOW
&& (item instanceof ShortcutInfo)
&& (item.itemType == Favorites.ITEM_TYPE_SHORTCUT
|| item.itemType == Favorites.ITEM_TYPE_DEEP_SHORTCUT)
&& !((ShortcutInfo) item).isPromise()) {
// Shortcuts need some special checks due to legacy reasons.
// modify fix bug begin
// startShortcutIntentSafely(intent, optsBundle, item);
LauncherAppsCompat.getInstance(this).startActivityForProfile(
intent.getComponent(), user, intent.getSourceBounds(), optsBundle);
// modify fix bug end
} else if (user == null || user.equals(Process.myUserHandle())) {
// Could be launching some bookkeeping activity
startActivity(intent, optsBundle);
} else {
LauncherAppsCompat.getInstance(this).startActivityForProfile(
intent.getComponent(), user, intent.getSourceBounds(), optsBundle);
}
return true;
} catch (ActivityNotFoundException|SecurityException e) {
Toast.makeText(this, R.string.activity_not_found, Toast.LENGTH_SHORT).show();
Log.e(TAG, "Unable to launch. tag=" + item + " intent=" + intent, e);
}
这个方法虽然简单,但是有取巧的成分在,不够稳妥;时间原因,先解决问题,优化的事情慢慢来!