Android8.1 Launcher3 去掉抽屉(四)

Android8.1 Launcher3 去掉抽屉(四)

前段时间做了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);
        }

这个方法虽然简单,但是有取巧的成分在,不够稳妥;时间原因,先解决问题,优化的事情慢慢来!

你可能感兴趣的:(Android)