Blankj / AndroidUtilCode

:fire: Android developers should collect the following utils(updating).
https://blankj.com/2016/07/31/android-utils-code/
Apache License 2.0
33.24k stars 10.67k forks source link

ToastUtils 连续调用两次崩溃问题 #508

Closed spd-heshuip closed 6 years ago

spd-heshuip commented 6 years ago

Android版本:Android 7.1.1
环境:Genymotion 模拟器 使用该库版本:1.16.1

image

连续两次或者多次调用ToastUtils.showShort(),偶尔出现崩溃问题,日志如下: image

连续调用ToastUtils.showShort这种场景还是会用得到的,比如说多个网络请求同时报错提示,希望能尽快解决,谢谢了!

Blankj commented 6 years ago

1.16.2 版本你试试

Blankj commented 6 years ago

你的问题是因为我之前是监听 topAcitivy,出现你的这个问题是 showToast 的时候, topActivity 还没能绑定到 window,所以 toast 也就没有 window 可以依附,现在 toast 还是改回了很早之前的 application 来显示,应该没你说的问题了。

spd-heshuip commented 6 years ago

刚刚试了下,还是会出现崩溃问题;但是我把targetSdkVersion从27改成25,就不会出现崩溃问题了,具体原因好像是Android7.1.1版本导致的,我用其他的版本就不会出现这个问题;

Blankj commented 6 years ago

我知道你说的那个问题,我在试下

spd-heshuip commented 6 years ago

在GitHub上搜索到有个解决方案,不知道有没有效果; https://github.com/cat9/ToastCompat

Blankj commented 6 years ago

原因是因为你应用此时有个 window 是 Toast 类型的,然后显示我 toast 的时候才会报错,我现在在修复

Blankj commented 6 years ago

你那边怎么复现的?我连续崩溃不了,25,26,27都试了

Blankj commented 6 years ago

你说的有问题啊,出问题的应该是 25 的版本啊,25以后的都有 catch 异常的

spd-heshuip commented 6 years ago

我的环境是: compileSdkVersion 27 targetSdkVersion 25 然后在Activity中连续调用ToastUtils.showShort,如果没有崩溃的话,可以杀掉应用,重新再打开,再试一次;

Blankj commented 6 years ago

image image 崩溃不了哦

spd-heshuip commented 6 years ago

你把targetSdkVersion改成27试试,改成25我这边是不会崩溃的,

Blankj commented 6 years ago

你试试 1.16.3 版本,我修复了

spd-heshuip commented 6 years ago

刚刚试了下,已经可以了,谢谢大牛; 另外想了解下是什么原因导致的呢?如何修复的?

Blankj commented 6 years ago

hook 了 toast view 的 addview,包裹了一层异常,相关代码如下

    private static final class ApplicationContextWrapperForApi25 extends ContextWrapper {

        ApplicationContextWrapperForApi25() {
            super(Utils.getApp());
        }

        @Override
        public Context getApplicationContext() {
            return this;
        }

        @Override
        public Object getSystemService(@NonNull String name) {
            if (Context.WINDOW_SERVICE.equals(name)) {
                // noinspection ConstantConditions
                return new WindowManagerWrapper(
                        (WindowManager) getBaseContext().getSystemService(name)
                );
            }
            return super.getSystemService(name);
        }

        private static final class WindowManagerWrapper implements WindowManager {

            private final WindowManager base;

            private WindowManagerWrapper(@NonNull WindowManager base) {
                this.base = base;
            }

            @Override
            public Display getDefaultDisplay() {
                return base.getDefaultDisplay();
            }

            @Override
            public void removeViewImmediate(View view) {
                base.removeViewImmediate(view);
            }

            @Override
            public void addView(View view, ViewGroup.LayoutParams params) {
                try {
                    base.addView(view, params);
                } catch (BadTokenException e) {
                    Log.e("WindowManagerWrapper", e.getMessage());
                } catch (Throwable throwable) {
                    Log.e("WindowManagerWrapper", "[addView]", throwable);
                }
            }

            @Override
            public void updateViewLayout(View view, ViewGroup.LayoutParams params) {
                base.updateViewLayout(view, params);
            }

            @Override
            public void removeView(View view) {
                base.removeView(view);
            }
        }
    }