Fresco: AndroidNでSharedElementReturnTransitionを実行した後に共有要素がなくなりました

作成日 2016年08月31日  ·  70コメント  ·  ソース: facebook/fresco

SharedElement Transitionの作業を行うために最新のフレスココードを使用しています。これは、Android L、Mで正常に動作しますが、AndroidNではうまくいきません。

移行前
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には、同じtransitionNameを持つ同じSimpleDraweeViewがあります
そして、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はAndroidNでは機能しません。トランジションリスナーにログを追加しました。AndroidNではonTransitionStartとonTransitionEndはトリガーされませんが、Android M&Lでは問題なく機能します。
Frescoライブラリcom.facebookの最新バージョンを使用しています。 fresco:fresco :0.14.1 withcom.facebook。 fresco:imagepipeline-okhttp3 :0.14.1
画像の読み込みにPicassoライブラリを使用している場合、この問題は発生しません。
シナリオは似ています:gridView、gridItemは別のアクティビティに移動します(この部分ではすべて問題ありません)が、戻ると、再入力はなく、画像が点滅して再読み込みされます(プレースホルダー画像も表示されていなかった画像も表示されません)すでにロードされています)。 これはAndroidN(7.0)でのみ発生します

この問題に関する更新はありますか?

FrescoからPicassoに切り替えて、問題を解決しました。 残念ながら、このライブラリは、リリースされる新しいAndroidOSバージョンで必要とされるほど頻繁に維持されていません。

この問題は「needs-details」として誤ってマークされているようです。 この問題は、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 API25でのみ発生します

この問題に関する更新があれば、私はそれを高く評価します。

ここ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が表示されることに気付きました。

私は同じ問題を抱えていました、そしてそれはこの2つの呼び出しの後に修正されました:

  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内のアイテムである場合、API24以降でこれがまだ発生しています。
このチケットに記載されている回避策はどれも私には効果がありませんでした(ビューが最初から非表示/なくなったように設定されることはありません)。
エンタートランジションとリターントランジションの両方にDraweeTransition.createTransitionSet()を使用しています。
recyclerviewがスクロールされるまで画像が消えたり、しばらくするとちらつきが戻ったりすることがあります(notifyDataSetChanged()が呼び出されたことが原因である可能性があります)。

これが役立つかどうかはわかりませんが、2番目のアクティビティが閉じられ、共有要素がその位置に戻ったときのログによると、これは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

これは、ビットマップが再び表示されたときに発生します。
ビットマップが表示されていない場合は、最後の2つのイベントが発生しません。

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}}}

ビュー自体がRecyclerViewにある場合、 SimpleDraweeViewdoDetach() doAttach()メソッドと
最後に、これは私にとってはうまくいきました(遷移が生成されるアクティビティに追加されました)が、非常にクリーンではありません:

        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回避策を見つけてよかったです! Genymotion with Android 7で実行されているShowcaseアプリでこの特定の問題を再現しようとしましたが、うまくいきませんでした。

recyclerviewのアイテムビューはどのように見えますか? 私の場合、それはSimpleDraweeViewをラップする単なるFrameLayoutでした。

@marcosalisあなたのソリューションは少し変更を加えて私のために働き、forサイクルを削除しました:

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バージョンを間もなくリリースする予定です。

うん、ありがとう! これで問題が解決することを確認しました。 更新されたバージョンを楽しみにしています。

上記の修正を含むFrescov1.4.0をリリースしsimpleDraweeView.setLegacyVisibilityHandlingEnabled(true);電話するだけで、すぐに機能するはずです。

また、これらの変更を反映するようにShowcaseトランジションサンプルを更新しました。

この修正のおかげで、私の場合は完璧に機能しました。 1つの質問、デフォルトでsetGlobalLegacyVisibilityHandlingEnabledtrueしないのはなぜですか? パフォーマンスの問題はありますか?

可視性の処理はAndroidNで変更されました。私の変更は、動作をN以前に戻すことです。 すべての画像でこの動作を変更すると、他の予期しない問題が発生する可能性があるため、デフォルトではまだオンにしないことにしました。 副作用がないことを確認したら、デフォルトでオンにすることを検討します。
自由にtrueに設定して、発生した問題を報告してください。

ezgif com-resize

この修正はランダムに機能しないようです。 setGlobalLegacyVisibilityHandlingEnabledをtrueに設定していますが、数回クリックすると、返される画像が空白になります。

Fresco 1.5.0、オレオ

編集:さらに数日開発し、いくつかのビューを移動した後、Oreoピクセルデバイスでは問題がまったく発生しないことがわかりました。 エミュレートされたNexus5x API 24では、終了アニメーションの後、画像は常に空白になります。

setLegacyVisibilityHandlingEnabledでも同じ問題が発生しています。 true設定すると、ほとんどの場合機能しますが、ランダムに、リターントランジション後に画像が消えることがあります。

@marcosalisは、オレオまたはヌガーでのみ発生しますか?

こんにちは@oprisnik私はAPI26のエミュレーターでランダムに再現することができました。デバッグに役立つかどうか教えてください。

おかげで、もう少し時間があれば再現しようと思います

@oprisnik
ほとんどの場合、その仕事をしていないように見えることを確認できます(API24 + API25)

しかし、私は次のハックを使用してそれをいくらか機能させることができました:

        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
別の回避策を見つけましたか?

まだ、Googleがビューの可視性の動作を変更したため、これを修正するのは難しいです。これにより、フレスコの可視性の処理(メモリ管理に必要)が壊れます。また、近い将来、これを調べる時間もあまりありません。 。 ただし、このスレッドで言及されている問題を修正するいくつかの代替手段があります(手動で可視性を設定する@MartBからの回避策など)。

誰かがこれを調べたい場合は、プルreuqestsはいつでも大歓迎です! :)

@ oprisnikreact-native-mapsモジュールもこの問題の影響を受けます。
回避策として、RootDrawable.javaファイルでこれらの行をコメントとしてマークしました。
それらの行をコメント行としてマークすることに関連する大きな問題を覚えていますか/知っていますか?

@efkanと同じ問題が

彼らの解決策は私が抱えていたすべての問題を修正しました。

@efkan正確にはわかりません。 代替の修正を探していたときにこれも調べたのを覚えていますが、却下しました。 これらのチェックを削除する際の問題の1つは、基になるビットマップが解放され(ビューが表示されなくなったため)、 BitmapDrawableが表示されないため、描画しようとするとjava.lang.RuntimeException: Canvas: trying to use a recycled bitmap ...がスローされることだと思います。健全性チェックを実行します。

ImageView自体にも同じバグがあり、ドローアブルのドローアブルの可視性が適切に復元されませんが、ほとんどのドローアブルは可視性チェックを行わず、手動のメモリ管理がないため、引き続き機能します-および基になるビットマップまだ有効です。

@oprisnikは、これらすべての説明に

これが機能するかどうかをテストするために、これを設定としてGenericDraweeHierarchyBuilderに追加するのはかなり簡単です。それに応じて、 RootDrawableGenericDraweeHierarchy作成されます)の可視性チェックを無視します。 、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

デバイス:Lenovo、android 7.1.1

_さらに詳しい情報が必要な場合はお知らせください。

@ babyblue1314動画やトランジション関連のコードにトランジションが表示されません。 同じ問題について話していると確信していますか?

@oprisnik申し訳ありませんが、この移行の問題が私の問題とは異なることに気づきました。
現象が私のものと似ているのを見たので……
新しい問題を開始する必要がありますか?

@ babyblue1314はい、お願いします。これはまったく関係がないようです。

@oprisnik私はついに私の問題の原因を見つけました。
他の人を誤解している場合に備えて、私はいくつかの説明をするためにここにいます。
私の問題は画像フォーマットと関係があります。
PNG形式でimageRequestBuilder.setProgressiveRenderingEnabled(true)メソッドを使用すると、問題はいつでも再現できます。
PNG形式でメソッドをimageRequestBuilder.setProgressiveRenderingEnabled(false)に変更すると、すべて正常に機能します。
@oprisnikしばらくお待ちいただき、ありがとうございます。

この問題を修正してください...

Fresco1.9.0は​​問題を適切に修正しません。
このスレッドの提案を組み合わせると、デバイスに応じて修正されます。

そのため、コード内で安全を確保するために、コード内で両方の回避策を使用しており、うまくいけば、すべてをカバーしています。 @oprisnik修正を見つけたら、PRを送信して、問題をよりよく理解するために少し時間を費やします。

ええ、残念ながら、このスレッドで言及されているすべての解決策がいずれかの方法で失敗するため、この問題に対する適切な修正はまだありません。 誰かがこれを適切に修正する方法についてアイデアを持っている場合は、私たちに知らせてください、またはさらに良いことに、PRを提出してください:)

それでも、react-native-mapsコンポーネントに関するこの問題。 私はそれが同時の問題だと思いますか?
どこに問題があるのか​​分かりますか?

問題の特定に進展はありますか? 4月以来何も聞こえていないようです。

ここで何が起こっているのかをさらに調査する時間はまだありませんでした。 問題を調べて、プルリクエストを送信してください。

前述のように、根本的な問題は、移行から戻ったときにImageViewが基礎となるDrawableの可視性を適切に復元しないAndroidフレームワークのバグのようです。

ここにAndroidのバグレポートを提出しました: https

また、問題の概要を説明する(フレスコ画以外の)サンプルアプリを作成しました: https

この問題の回避策があるかどうかを調査します。 ただし、Frescoは手動のメモリ管理を必要とし、画像を再リクエストするためにDrawableの可視性に依存しているため、上記の回避策よりも優れた修正があるかどうかはわかりません。

この問題に気づかずにフレスコ画に切り替えました。 私はたくさんのgifをレンダリングし、それは素晴らしい仕事をしますが、ナビゲーションのためにこれらのアニメーションにも依存しています。 上記のハックを使用することができましたが、リターンアニメーションで画像が消えます。

実際に無効にするか、View.setVisibilityがdrawableを表示できないため、Drawable.setVisible(true、true)を直接呼び出す必要があります。
これらのコードを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フレスコ画以外のサンプルアプリで、トランジションをChangeBoundsに設定します。 この行を削除するとバグは発生しますか? ChangeImageTransformが機能していると、可視性が正しく復元されると思います。 フレスコ画をChangeImageTransform動作させることは可能ですか?

@RainFoolは正しいです。 simpleDraweeView.getVisibility()はVISIBLEですが、simpleDraweeView.getDrawable()。isVisible()はfalseです。

はい、これはAndroidフレームワークのバグであり、ビューの可視性(正確にはImageView)がDrawableに伝達されないため、可視性を手動で更新する必要があります。 Androidのバグレポートにスターを付けて、可視性を高めてください//issuetracker.google.com/issues/111293868

このページは役に立ちましたか?
0 / 5 - 0 評価