Fresco: 在 Android N 中执行 SharedElementReturnTransition 后共享元素消失

创建于 2016-08-31  ·  70评论  ·  资料来源: facebook/fresco

我使用最新的fresco代码做SharedElement Transition工作,在Android L、M上运行良好,但在Android N上却出错

过渡前
screenshot0

过渡后
screenshot0

bug help wanted

最有用的评论

只需在调用活动中添加此代码,如果可以帮助您+1 ! @oprisnik


setExitSharedElementCallback(new SharedElementCallback() {

            <strong i="6">@Override</strong>
            public void onSharedElementEnd(List<String> sharedElementNames,
                                           List<View> sharedElements,
                                           List<View> sharedElementSnapshots) {

                super.onSharedElementEnd(sharedElementNames, sharedElements,
                        sharedElementSnapshots);

                for (View view : sharedElements) {
                    if (view instanceof SimpleDraweeView) {
                        view.setVisibility(View.VISIBLE);
                    }
                }
            }
        });

所有70条评论

你能展示一下你是如何使用 Fresco 的演示应用程序进行过渡部分的吗?

activity_main.xml 和 activity_detail 具有相同的 SimpleDraweeView 和相同的 transitionName
在 DetailActivity 的 onCreate 方法中,如下所示:

protected void onCreate(Bundle savedInstanceState) {
getWindow().requestFeature(Window.FEATURE_CONTENT_TRANSITIONS);
getWindow().setSharedElementEnterTransition(DraweeTransition.createTransitionSet(ScalingUtils.ScaleType.CENTER_CROP, ScalingUtils.ScaleType.FIT_CENTER));
getWindow().setSharedElementReturnTransition(DraweeTransition.createTransitionSet(ScalingUtils.ScaleType.FIT_CENTER, ScalingUtils.ScaleType.CENTER_CROP));
addTransitionListener();
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_detail);
mBaselineJpegView = (SimpleDraweeView) findViewById(R.id.baseline_jpeg);
mBaselineJpegView.setImageURI(Uri.parse("https://www.gstatic.com/webp/gallery/1.sm.jpg"));
mBaselineJpegView.setOnClickListener(new View.OnClickListener() {
@覆盖
public void onClick(View v) {
Toast.makeText(DetailActivity.this, "dsasa", Toast.LENGTH_LONG).show();
}
});
}

addTransitionListener() 什么都不做,只是打印日志

那么我是否使用错误的方式进行转换?

这也发生在我身上。

我在 super.onCreate() 之前的 onCreate() 方法中有以下内容

supportRequestWindowFeature(Window.FEATURE_CONTENT_TRANSITIONS);
Transition fade = new Fade();
fade.excludeTarget(android.R.id.statusBarBackground, true);
fade.excludeTarget(android.R.id.navigationBarBackground, true);
Window window = getWindow();
window.setEnterTransition(fade);
window.setReturnTransition(fade);
window.setExitTransition(fade);
TransitionSet transitionSet = DraweeTransition
                    .createTransitionSet(ScalingUtils.ScaleType.CENTER_CROP,
ScalingUtils.ScaleType.CENTER_CROP);
window.setSharedElementEnterTransition(transitionSet);
window.setSharedElementExitTransition(transitionSet);

我遇到了同样的问题。 setSharedElementReturnTransition 不适用于 Android N。我已将日志添加到转换侦听器中,并且 onTransitionStart 和 onTransitionEnd 不会在 Android N 上触发,但在 Android M & L 上它工作得很好。
我正在使用最新版本的 Fresco 库 com.facebook。 壁画:壁画:0.14.1 与 com.facebook。 壁画:imagepipeline-okhttp3 :0.14.1
如果我使用 Picasso 库加载图像,我就没有这个问题。
场景是类似的:gridView,gridItem 导航到另一个 Activity(这部分一切正常)但是当我回去时,没有重新进入,图像闪烁并重新加载(占位符图像不可见,也不是图像已经加载)。 这只发生在 Android N (7.0) 上

关于这个问题的任何更新?

从 Fresco 切换到 Picasso,问题解决了。 太糟糕了,这个库没有按照新的 Android 操作系统版本的要求进行维护。

似乎这个问题被错误地标记为“需要-详细信息”。 此问题在 Android 7.1.1(API 级别 25)上也存在。

谢谢,我们看看

我也遇到了同样的问题,所以我 +1 修复它。

同样在这里

做吧。 做吧。 ;-)

是的,请这样做。

请...

+1

想知道为什么这不是一个高优先级..

+1

当我滚动到onActivityReenter的共享元素位置时,消失的项目又回来了,但有一点白色闪烁:

    <strong i="7">@Override</strong>
    public void onActivityReenter(int resultCode, Intent data) {
        super.onActivityReenter(resultCode, data);

        final int position = data.getIntExtra(EXTRA_GIF_POSITION, -1);
        if (resultCode == RESULT_OK && position != -1) {
            gifRecyclerView.getLayoutManager().scrollToPosition(position);
        }
    }

如果有人知道更好的修复方法,如果您能分享它,我将不胜感激。

您好,我遇到了同样的问题,但仅限于 Android 7.1.1 API 25

如果有关于该问题的任何更新,我将不胜感激。

在 7.x 的 emu 上也是如此,但我使用 onWindowFocusChanged 是身临其境的,当完成时图像会消失但会立即重新显示。

同样在这里。 在包含 SimpleDraweeView 的视图上调用 requestLayout 似乎用一些闪烁修复它。 请指教

只需在调用活动中添加此代码,如果可以帮助您+1 ! @oprisnik


setExitSharedElementCallback(new SharedElementCallback() {

            <strong i="6">@Override</strong>
            public void onSharedElementEnd(List<String> sharedElementNames,
                                           List<View> sharedElements,
                                           List<View> sharedElementSnapshots) {

                super.onSharedElementEnd(sharedElementNames, sharedElements,
                        sharedElementSnapshots);

                for (View view : sharedElements) {
                    if (view instanceof SimpleDraweeView) {
                        view.setVisibility(View.VISIBLE);
                    }
                }
            }
        });

同样的问题在这里... @antxyz我已经将您的代码放在 onCreate 方法的调用和被调用活动中,但没有成功。 返回过渡后共享元素图像仍然不可见。

我不知道它是否有助于找到解决方案,但我注意到打开软键盘时,SimpleDraweeView 变得可见。

我遇到了同样的问题,在这两次调用后它被修复了:

  1. 就在startActivity(...
    setExitSharedElementCallback(new SharedElementCallback() {
                <strong i="9">@Override</strong>
                public void onSharedElementEnd(List<String> names,
                                               List<View> elements,
                                               List<View> snapshots) {
                    super.onSharedElementEnd(names, elements, snapshots);
                    for (final View view : elements) {
                        if (view instanceof SimpleDraweeView) {
                            view.post(() -> view.setVisibility(View.VISIBLE));
                        }
                    }
                }
            });
  1. 在新活动的onCreate中:
setEnterSharedElementCallback(new SharedElementCallback() {
                <strong i="15">@Override</strong>
                public void onSharedElementEnd(List<String> names,
                                               List<View> elements,
                                               List<View> snapshots) {
                    super.onSharedElementEnd(names, elements, snapshots);
                    for (final View view : elements) {
                        if (view instanceof SimpleDraweeView) {
                            view.post(() -> view.setVisibility(View.VISIBLE));
                        }
                    }
                }
            });

@oprisnik 有任何更新吗? 很遗憾它还没有修复。
当共享元素是RecyclerView一个项目时,我仍然在使用 API 24+ 时遇到这种情况。
这张票上列出的所有解决方法都不适合我(视图从未设置为不可见/首先消失)。
我正在使用DraweeTransition.createTransitionSet()进行输入和返回转换。
有时图像会在滚动 recyclerview 之前消失,有时它会在一段时间后闪烁(可能是由于调用了 notifyDataSetChanged() )。

不确定这是否有任何帮助,但根据日志,当第二个活动关闭且共享元素返回其位置时,这是 Fresco 中发生的情况:

V/unknown:AbstractDraweeController: controller c6a03e3 9: onDetach
V/unknown:AbstractDraweeController: controller c6a03e3 9: release: image: CloseableReferenceWithFinalizer f25d513
V/unknown:AbstractDraweeController: controller f84c24e 4: onAttach: request needs submit
V/unknown:AbstractDraweeController: controller f84c24e 4: set_final_result @ onNewResult: image: CloseableReferenceWithFinalizer f25d513

当位图再次显示时会发生这种情况。
当位图显示时,不会发生最后两个事件:

V/unknown:AbstractDraweeController: controller f84c24e 4: onAttach: request needs submit
V/unknown:AbstractDraweeController: controller f84c24e 4: set_final_result @ onNewResult: image: CloseableReferenceWithFinalizer f25d513

@marcosalis返回第一个活动时(使用 recyclerView)。 这是否总是触发notifyDataSetChanged()?

@erikandre谢谢你的回答;)
经过一些测试,我可以确认没有调用 notifyDataSetChanged(),即使位图单独显示也是如此。

如果我在调用活动中的SharedElementCallback.onSharedElementEnd()中放置断点,这就是SimpleDraweeView的状态。

 DraweeHolder{controllerAttached=false, holderAttached=true, drawableVisible=false}

PipelineDraweeController{super=PipelineDraweeController{isAttached=false, isRequestSubmitted=false, hasFetchFailed=false, fetchedImage=0, events=[...]}, dataSourceSupplier={request=ImageRequest{uri=https://OMITTED, cacheChoice=DEFAULT, decodeOptions=100-false-false-false-false-ARGB_8888-null, postprocessor=null, priority=HIGH, resizeOptions=null, rotationOptions=-1 defer:true, mediaVariations=null}}}

我想可能有一些做与doDetach()doAttach()的方法SimpleDraweeView时的观点本身就是一个, RecyclerView
最后,这对我有用(添加到生成转换的 Activity 中),尽管它不是非常干净:

        setExitSharedElementCallback(new SharedElementCallback() {
            <strong i="11">@Override</strong>
            public void onSharedElementEnd(List<String> names, List<View> elements, List<View> snapshots) {
                for (View view : elements) {
                    if (view instanceof SimpleDraweeView) {
                        view.post(() -> {
                                myAdapter.notifyDataSetChanged();
                        });
                    }
                }
            }
        });

@marcosalis太好了,您找到了解决方法! 我试图在使用 Android 7 的 Genymotion 上运行的 Showcase 应用程序中重现这个特定问题,但没有成功。

recyclerview 的项目视图是什么样的? 就我而言,它只是一个包装 SimpleDraweeView 的 FrameLayout。

@marcosalis您的解决方案对我

setExitSharedElementCallback(
                    new SharedElementCallback() {
                        <strong i="7">@Override</strong>
                        public void onSharedElementEnd(List<String> names, List<View> elements, List<View> snapshots) {
                            super.onSharedElementEnd(names, elements, snapshots);
                            notifyDataSetChanged();
                        }
                    }
            );

我在玩交互活动转换时偶然发现了同样的问题。 上面提出的解决方法似乎都不起作用。 (API 25) 如下所示: https :

我想我们找到了一个解决方法,希望很快就会有一个修复程序。

解决方法可以在 dc7ec2436fc9b639fe1a39398712c360b16da468 中找到。

现在,您必须通过调用simpleDraweeView.setLegacyVisibilityHandlingEnabled(true);来设置第一个DraweeView开始转换的位置,以使用旧版可见性处理(正如您在我们的 Showcase 示例应用程序中的转换示例中所见) .

你能检查一下这是否能解决你的问题吗? 我们将很快发布一个包含此修复程序的新 Fresco 版本。

是的,谢谢! 确认这解决了问题。 期待更新的版本。

我们已发布Fresco v1.4.0 ,其中包含上述修复程序。 只需调用simpleDraweeView.setLegacyVisibilityHandlingEnabled(true);就可以了。

我们还更新了Showcase 转换示例以反映这些更改。

感谢您的修复,在我的情况下它工作得很好。 一个问题,为什么不把setGlobalLegacyVisibilityHandlingEnabled默认放到true ? 有什么性能问题吗?

可见性处理随着 Android N 发生了变化,我的变化是(有点)将行为恢复到 N 之前。 更改所有图像的此行为可能会导致其他意外问题,这就是我们决定默认情况下不启用它的原因。 一旦我们确认没有副作用,我们就会考虑默认开启它。
随意将其设置为true并报告您遇到的任何问题。

ezgif com-resize

此修复程序似乎无法随机工作。 我将 setGlobalLegacyVisibilityHandlingEnabled 设置为 true,但单击几下后,返回的图像为空白。

壁画 1.5.0,奥利奥

编辑:在开发了几天并移动了一些视图之后,我发现这个问题在我的奥利奥像素设备上不再发生了。 在我模拟的 Nexus 5x API 24 上,退出动画后图像始终为空白。

我对setLegacyVisibilityHandlingEnabled有同样的问题。 将其设置为true大部分时间都有效,但有时,只是随机地,图像在返回转换后消失。

@marcosalis只发生在奥利奥或牛轧糖上吗?

@oprisnik我已经设法在三星 S7 (Nougat) 和 API 26 的模拟器上随机重现它。让我知道我是否可以帮助调试它。

谢谢,等我有时间再试试

@oprisnik
可以确认它似乎在大多数时候都没有完成它的工作(API24 + API25)

但是,我设法使用以下 hack 让它有些工作:

        setExitSharedElementCallback(new SharedElementCallback() {
            <strong i="8">@Override</strong>
            public void onSharedElementEnd(List<String> names,
                                           List<View> elements,
                                           List<View> snapshots) {
                super.onSharedElementEnd(names, elements, snapshots);
                for (final View view : elements) {
                    if (view instanceof SimpleDraweeView) {
                        view.post(() -> {
                            view.setVisibility(View.VISIBLE);
                            view.requestLayout();
                        });
                    }
                }
            }
        });

我能够重现。 对我来说,它只是很少发生。 我会检查是否可以找到其他解决方法来解决此问题。

你好@oprisnik
您找到不同的解决方法了吗?

还没有,这很难解决,因为谷歌改变了视图可见性行为,这破坏了 Fresco 的可见性处理(我们需要用于内存管理)而且我也不会在不久的将来有很多时间来研究这个. 但是,此线程中提到了几个解决此问题的替代方法(例如来自@MartB 的手动设置可见性的解决方法)。

如果有人想研究这个,总是欢迎拉请求! :)

@oprisnikreact-native-maps模块也受到此问题的影响。
我已将这些行标记为 RootDrawable.java 文件中的注释作为解决方法。
您还记得/知道与将这些行标记为注释行相关的任何大问题吗?

遇到与@efkan相同的问题,

他们的解决方案解决了我遇到的所有问题。

@efkan我不完全清楚。 我记得我在寻找替代修复程序时也研究过这个问题,但没有考虑。 我认为删除这些检查的一个问题是底层位图已被释放(因为视图不再可见)并且尝试绘制它会抛出java.lang.RuntimeException: Canvas: trying to use a recycled bitmap ...因为BitmapDrawable没有执行任何健全性检查。

ImageView本身也有同样的错误,它不能正确恢复任何可绘制对象的可绘制可见性,但它仍然有效,因为大多数可绘制对象不进行可见性检查并且没有手动内存管理 - 以及底层位图仍然有效。

@oprisnik感谢所有这些解释。

为了测试这是否有效,将其作为设置添加到GenericDraweeHierarchyBuilder并根据它忽略RootDrawable (在GenericDraweeHierarchy创建)中的可见性检查相当容易,见 https://github.com/facebook/fresco/blob/master/drawee/src/main/java/com/facebook/drawee/generic/GenericDraweeHierarchy.java#L155)。

随意提交添加此设置的 PR,以便您可以为您的应用程序启用它并查看是否有副作用。

相同的问题仅出现在搭载 Android 7.1(或更高版本)的设备上。
以上解决方案均无效。
当网络限制为 10kb/s 时,问题总是出现。

@babyblue1314 - 上面提到的RootDrawable更改也不能为您解决问题?

@oprisnik感谢您的快速回复!
Em...我想是的,上面提到的 RootDrawable 更改也没有为我修复它。
不知道是不是我用错了。 这是它的样子:

在使用 RootDrawable 之前更改:

使用 RootDrawable 更改后:

_我应该提到网络限制为 10kb/s。 _
更重要的是,这不仅会出现在 ListView 中,还会出现在 RecyclerView 和 GridView 中,如下所示:

我的代码是:

  1. ListViewAdapter(或 RecyclerViewAdapter 或 GridViewAdapter):
SimpleDraweeView thumbnail = cholder.getView(R.id.thumbnail);

GenericDraweeHierarchyBuilder hierarchyBuilder = new GenericDraweeHierarchyBuilder(thumbnail.getContext().getResources());
GenericDraweeHierarchy hierarchy = hierarchyBuilder.build();
hierarchy.getTopLevelDrawable().setVisible(true, false);
thumbnail.setHierarchy(hierarchy);

ImageLoaderUtil.loadImage(thumbnail, item.getLogourl(), 696, 288);
  1. ImageLoaderUtil:
Uri uri = Uri.parse(url);
ImageRequestBuilder imageRequestBuilder = ImageRequestBuilder.newBuilderWithSource(uri);
imageRequestBuilder.setRotationOptions(RotationOptions.autoRotate()); 
imageRequestBuilder.setImageDecodeOptions(new ImageDecodeOptions(ImageDecodeOptions.newBuilder()
.setBitmapConfig(Bitmap.Config.RGB_565)));
imageRequestBuilder.setResizeOptions(new ResizeOptions(reqWidth, reqHeight));
ImageRequest imageRequest = imageRequestBuilder.build();

PipelineDraweeControllerBuilder draweeControllerBuilder = Fresco.newDraweeControllerBuilder();
draweeControllerBuilder.setOldController(simpleDraweeView.getController());
draweeControllerBuilder.setImageRequest(imageRequest);
draweeControllerBuilder.setTapToRetryEnabled(false); 

DraweeController draweeController = draweeControllerBuilder.build();
simpleDraweeView.setController(draweeController);

壁画 1.5.0

设备:联想,安卓 7.1.1

_如果您需要更多信息,请告诉我。

@babyblue1314我在您的视频或与过渡相关的代码中没有看到任何过渡。 你确定你在谈论同样的问题吗?

@oprisnik抱歉,我刚刚意识到这个过渡问题与我的问题不同。
我看到这个现象和我的很相似,所以……
我应该开始一个新的问题吗?

@babyblue1314是的,拜托,这似乎无关紧要。

@oprisnik我终于找到了问题的原因。
万一误会了别人,我在这里做一些解释。
我的问题与图片格式有关。
如果我使用带有 PNG 格式的imageRequestBuilder.setProgressiveRenderingEnabled(true)方法,我的问题总是可以重现。
如果我使用 PNG 格式将方法更改为imageRequestBuilder.setProgressiveRenderingEnabled(false) ,则一切正常。
@oprisnik再次感谢您的耐心等待!

请修复这个问题...

Fresco 1.9.0 没有正确解决这个问题。
该线程中的命题混合修复它取决于设备:

所以我在我的代码中使用了这两种解决方法,以确保我的代码安全,并希望涵盖所有内容。 @oprisnik我会花一些时间来尝试更好地理解问题,如果我找到解决方法,我会提交 PR。

是的,不幸的是,我们仍然没有很好地解决此问题,因为此线程中提到的所有解决方案都以一种或另一种方式失败。 如果有人对如何正确解决此问题有想法,请告诉我们,或者更好的是,提交 PR :)

尽管如此,关于 react-native-maps 组件的这个问题。 我想这是一个并发问题?
你知道问题出在哪里吗?

在查明问题方面有任何进展吗? 自四月以来,我们似乎没有听到任何消息。

我们仍然没有时间进一步调查这里发生的事情。 随时查看问题并提交拉取请求!

如前所述,底层问题似乎是一个 Android 框架错误,其中 ImageView 在从转换返回时无法正确恢复底层 Drawable 的可见性。

我在这里提交了一个 Android 错误报告: https :

我还创建了一个(非 Fresco)示例应用程序,概述了这个问题: https :

我们将调查是否有解决此问题的方法。 但是,Fresco 需要手动内存管理,我们依靠 Drawable 可见性来重新请求图像,所以我不确定是否有比上述解决方法更好的修复方法。

我切换到壁画没有意识到这个问题。 我渲染了大量的 gif,效果很好,但我也依赖这些动画进行导航。 我已经能够使用上面提到的技巧,但是在返回动画时,图像会消失。

实际失效或者View.setVisibility不能显示drawable,需要直接调用Drawable.setVisible(true, true)。
我在 A Activity#OnCreate 中添加这些代码,它工作正常:

ActivityCompat.setExitSharedElementCallback(this, new SharedElementCallback() {
            <strong i="7">@Override</strong>
            public void onSharedElementEnd(List<String> sharedElementNames, List<View> sharedElements, List<View> sharedElementSnapshots) {
                super.onSharedElementEnd(sharedElementNames, sharedElements, sharedElementSnapshots);
                if (FP.empty(sharedElements)) {
                    return;
                }
                for (View view : sharedElements) {
                    if (view instanceof SimpleDraweeView) {
                        ((SimpleDraweeView) view).getDrawable().setVisible(true, true);
                    }
                }
            }
        });

@oprisnik在您的非壁画示例应用程序中,您将转换设置ChangeImageTransform起作用时,能见度会正确恢复。 是否可以让壁画图像与ChangeImageTransform

@RainFool是对的。 simpleDraweeView.getVisibility() 是VISIBLE ,但 simpleDraweeView.getDrawable().isVisible() 是false

是的,这是 Android 框架中的一个错误,其中 View 可见性(准确地说是 ImageView)没有传播到 Drawable,因此您必须手动更新可见性。 请在此处为 Android 错误报告加注星标,以便获得更多可见性: https :

此页面是否有帮助?
0 / 5 - 0 等级

相关问题

hanhmh1203 picture hanhmh1203  ·  4评论

ykostova picture ykostova  ·  3评论

hbzhzw picture hbzhzw  ·  3评论

eldk picture eldk  ·  3评论

cococool picture cococool  ·  4评论