Fragmentation icon indicating copy to clipboard operation
Fragmentation copied to clipboard

fragment已经弹栈,但是视图依然残留在页面上

Open cocowobo opened this issue 5 years ago • 11 comments

Issues Guideline

Following information can help us to resolve the issue faster.

  • Library version 1.3.7
  • Support-v4 version 28.0.0
  • Logs
  • Screenshots image

image

In addition, we do not accept issues unrelated to Fragmentation.

1.应用场景,在主页fragment启动后,经过网络请求,发现token过期,于是弹出登录页面, 2.我的使用方式:因为为了让用户不论在任何界面都会受到token过期的提示,于是在主页fragment也就是第一个fragment中写了个eventbus的接受事件。使用 startWithPopTo(WalletLoginFragment.newInstance(), ZhuYeFragment.class, false); 来启动登录页面,不论用户打开了多少个页面都会将打开的fragment弹栈,回到主页fragment,然后启动登录fragment 3.出现问题为:当多个网络请求同时收到token过期了,就会多次向主页fragment发送eventbus事件,在及其短的时间里面,多次启动登录页面,会达到第一张图的效果,只启动了一个fragment,实际上是在极短的时间里面启动又销毁登录页面,只留下最后一次启动的登录页面, 这个时候,会发现最上面的登录页面之上有前几次被销毁的登录页面的view残留,但是点击事件可以穿透到被覆盖的最后一个登录页面上,怎么可以验证是我说的最上面残留了之前被销毁的登录页面的残留尼?我是这样做的,我每次打开登录页面都给数字加一,点击标题自动弹出当前页面的数字,确实点击标题,弹出了最后的页面的数字,且点击事件相应了, 第二张图是我在此时点击返回键,销毁登录页面,看栈内确实没有登录页面了,但是视图上残留的老的登录页面视图依然没有被销毁,同时点击事件响应的已经是主页fragment了,

PS:作者的库我用了2年多。 源码看了有50%。但是因为太复杂我也就大概了解了,用的也很顺手,但是这个问题出现后,我就懵逼了,一步步跟踪源码,都没法找到为什么,fragment已经销毁了,但是view视图有残留,现在我是限制了快速多次调用startWithPopTo。

提这个issues的目的有两个,1.在库里面去限制这个方法多次调用,或者解决多次调用执行完成后view销毁不彻底的情况,2.学点为什么会出现这个问题? 辛苦@YoKeyword 了!拜谢

cocowobo avatar Jun 17 '19 05:06 cocowobo

页面穿透的问题我也遇到了,出现的情景是同一个页面快速连续进入退出,现在只能是强制性限制连点,请问一下有没有什么好的方法来解决呢

zhangjianwei1 avatar Jul 16 '19 01:07 zhangjianwei1

我也遇到页面穿透问题,点的快的时候进入下个页面后还可以操作上个页面

yaoshiming avatar Jul 16 '19 06:07 yaoshiming

也遇到页面穿透问题 +1。startwithpop的原理应该也是FragmentTransactionreplace方法。我试过直接使用replace就不会出现页面穿透的问题。需要通过研究源码要来看看问题到底处在哪。

RexHuang1 avatar Jul 26 '19 10:07 RexHuang1

我也遇到这个问题,我单独出来用replace,测试了很多次,没有遇到这个问题。难道是项目的bug

JantHsueh avatar Aug 01 '19 11:08 JantHsueh

view.setOntouchListener(this) 然后返回true,解决fragment页面穿透问题

zhangjianwei1 avatar Aug 06 '19 09:08 zhangjianwei1

image

关于你的这种场景我也有 也是通过发送eventbus来启动登录界面 但我的不会有残影 我的启动方式这样的 加了启动模式SINGLETASK, 同时判断栈顶是否已经存在 如果存在就不启动 你可以参考下 看下能否解决你的问题

NiceNicks avatar Aug 09 '19 06:08 NiceNicks

image

关于你的这种场景我也有 也是通过发送eventbus来启动登录界面 但我的不会有残影 我的启动方式这样的 加了启动模式SINGLETASK, 同时判断栈顶是否已经存在 如果存在就不启动 你可以参考下 看下能否解决你的问题

@JunFreeman 我遇到了楼主同样的问题,使用了和你相同的处理方式,先判断在不在栈顶,同时使用singleTalk的方式启动,但是还是会出现,只是概率没这么高了

kilinwei avatar Sep 29 '19 08:09 kilinwei

微信截图_20190929170028

上面的图为我写的一个demo,用于复现问题的,很简单,进入activity之后默认加载FirstFragment,然后点击button3,开启一个线程,模拟快速点击botton2,一般点击第二次button3之后,就会复现问题, 如下图,背景图小机器人是activity的背景,两个Fragment的背景全部为透明; 同时在布局分析器中,也看不到盖在上面的SecondFragment(第二个Fragment)的内容,只看到FirstFragment(第一个Fragment)的内容,按照预期,应该只能看到第一个Fragment的内容,但是现在看到了两个

微信截图_20190929165748

另外,在分析内存的时候,发现存在多个SecondFragment的实例,发生了内存泄漏

微信截图_20190929171332

kilinwei avatar Sep 29 '19 09:09 kilinwei

https://github.com/YoKeyword/Fragmentation/issues/897#issue-330106725 这个issue里给出了两个解决办法,第二个对我没有效果,我把第二个的代码修改了一下,就ok了

    //        当前方法执行在MainThread,所以立即执行移除视图
            if (animation.getDuration() == 0) {
                try {
                    mock.removeViewInLayout(fromView);
                    container.removeView(mock);
                } catch (Exception ignored) {
                }
                return;
            }
            if (from.isDetached()) {
                try {
                    Log.w(TAG, "mockPopToAnim: from.isDetached() = true,删除视图" );
                    mock.removeViewInLayout(fromView);
                    container.removeView(mock);
                } catch (Exception ignored) {
                }
                return;
            }
            animation.setAnimationListener(new Animation.AnimationListener() {
                @Override
                public void onAnimationStart(Animation animation) {
                    mHandler.postDelayed(new Runnable() {
                        @Override
                        public void run() {
                            try {
                                mock.removeViewInLayout(fromView);
                                //会出现视图没有更新的问题
                                //container.removeViewInLayout(mock);
                                container.removeView(mock);
                            } catch (Exception ignored) {
                            }
                        }
                    }, animation.getDuration());
                }
    
                @Override
                public void onAnimationEnd(Animation animation) {
                }
    
                @Override
                public void onAnimationRepeat(Animation animation) {
    
                }
            });
            fromView.startAnimation(animation);
    //        mHandler.postDelayed(new Runnable() {
    //            @Override
    //            public void run() {
    //                try {
    //                    mock.removeViewInLayout(fromView);
    //                    container.removeViewInLayout(mock);
    //                } catch (Exception ignored) {
    //                }
    //            }
    //        }, animation.getDuration());

kilinwei avatar Oct 09 '19 03:10 kilinwei

我的解决方式是在MainActivity上添加 android:launchMode="singleTask",解决的

waterpotter avatar Oct 22 '19 06:10 waterpotter

我也遇到这样的问题,我写了篇文章,从源码角度,详细分析了该问题。

调用removeViewInternal、removeView 屏幕还是显示被删除界面 的解决方法和源码分析

作者确实很牛逼,但作者不再维护了,应该有很多小伙伴还在使用这个库,而且这么好的库,应该一直传承下去,也是广大Android同胞的福报,哈哈哈,所以我打算继续维护,我会在下一个版本1.0.4 修复该问题

最新版本已发布 详情 #1237

JantHsueh avatar Jan 17 '20 08:01 JantHsueh