Fresco: Elemento de compartilhamento desaparecido depois de SharedElementReturnTransition no Android N

Criado em 31 ago. 2016  ·  70Comentários  ·  Fonte: facebook/fresco

Eu uso o código fresco mais recente para fazer o trabalho de Transição de SharedElement, ele funciona bem no Android L 、 M , Mas no Android N, dá errado

antes da transição
screenshot0

depois da transição
screenshot0

bug help wanted

Comentários muito úteis

Basta adicionar este código na atividade de chamada , + 1 se isso puder ajudá-lo !!! @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);
                    }
                }
            }
        });

Todos 70 comentários

Você pode, por favor, mostrar como você faz a parte de transição usando o aplicativo de demonstração da Fresco?

activity_main.xml e activity_detail tem o mesmo SimpleDraweeView com o mesmo nome de transição
e no método onCreate de DetailActivity como abaixo:

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 () {
@Sobrepor
public void onClick (Ver v) {
Toast.makeText (DetailActivity.this, "dsasa", Toast.LENGTH_LONG) .show ();
}
});
}

addTransitionListener () não faz nada, apenas imprime o log

então eu uso a maneira errada de fazer a transição?

Isso está acontecendo comigo também.

Eu tenho o seguinte no método onCreate () antes de super.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);

Estou tendo o mesmo problema. O setSharedElementReturnTransition não está funcionando no Android N. Eu adicionei logs aos ouvintes de transição e o onTransitionStart e onTransitionEnd não são acionados no Android N, mas no Android M & L funciona bem.
Estou usando a versão mais recente da biblioteca do Fresco com.facebook. fresco: fresco : 0.14.1 com com.facebook. fresco: imagepipeline-okhttp3 : 0.14.1
Não tenho esse problema se usar a biblioteca do Picasso para carregar a imagem.
O cenário é semelhante: gridView, gridItem navega para outra Activity (está tudo bem nesta parte), mas quando eu volto, não há reentrada, a imagem pisca e é recarregada (a imagem do placeholder não está visível nem a imagem que estava já carregado). Isso só acontece no Android N (7.0)

Alguma atualização sobre este problema?

Mudou de Fresco para Picasso e o problema foi resolvido. Uma pena que esta biblioteca não seja mantida com a freqüência exigida pelas novas versões do sistema operacional Android que são lançadas.

Parece que esse problema está marcado incorretamente como 'detalhes necessários'. Esse problema também existe no Android 7.1.1 (API de nível 25).

Obrigado, vamos dar uma olhada

Também estou enfrentando o mesmo problema, portanto, +1 meu para corrigi-lo.

mesmo aqui

Faça isso. Faça isso. ;-)

Sim, por favor, faça isso.

Por favor...

+1

Me pergunto por que isso não é uma alta prioridade ..

+1

Quando eu rolar para a posição do elemento compartilhado em onActivityReenter o item desaparecido está voltando, embora com uma pequena cintilação branca:

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

Se alguém souber de uma solução melhor, eu agradeceria se você pudesse compartilhá-la.

Olá, estou tendo o mesmo problema, mas apenas no Android 7.1.1 API 25

Se houver atualizações sobre o problema, eu ficaria muito grato.

mesmo aqui no emu com 7.x, mas eu uso o onWindowFocusChanged para ser imersivo, quando terminar a imagem vai desaparecer mas reaparecer instantaneamente.

Mesmo aqui. Chamar requestLayout na View que contém o SimpleDraweeView parece consertá-lo com alguma cintilação. Por favor informar

Basta adicionar este código na atividade de chamada , + 1 se isso puder ajudá-lo !!! @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);
                    }
                }
            }
        });

mesmo problema aqui ... @antxyz Coloquei seu código nas atividades de chamada e callee no método onCreate, mas sem sucesso. A imagem do elemento compartilhado ainda é invisível após o retorno da transição.

Não sei se pode ajudar a encontrar uma solução, mas percebi que quando o softkeyboard é aberto, o SimpleDraweeView fica visível.

Eu estava tendo o mesmo problema e foi corrigido após essas duas ligações:

  1. Pouco antes de 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. Dentro de onCreate da nova atividade:
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 alguma atualização sobre isso? É uma pena que ainda não tenha sido corrigido.
Ainda estou experimentando isso com a API 24+, quando o elemento compartilhado é um item dentro de um RecyclerView .
Nenhuma das soluções alternativas listadas neste tíquete funcionou para mim (a exibição nunca é definida como invisível / desapareceu em primeiro lugar).
Estou usando DraweeTransition.createTransitionSet() para a transição de entrada e de retorno.
Às vezes, a imagem desaparece até que a visualização de reciclagem seja rolada, às vezes ela volta com uma cintilação depois de um tempo (pode ser devido à chamada de NoticeDataSetChanged ()).

Não tenho certeza se isso ajuda, mas é o que está acontecendo no Fresco de acordo com os registros quando a segunda atividade é fechada e o elemento compartilhado retorna à sua posição:

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

Isso acontece quando o bitmap é mostrado novamente.
Quando o bitmap não é mostrado, os dois últimos eventos não ocorrem:

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

@marcosalis Ao retornar à primeira atividade (com o recyclerView). Isso sempre dispara um notificarDataSetChanged ()?

@erikandre obrigado pela resposta;)
Depois de alguns testes, posso confirmar que notificarDataSetChanged () não é chamado, mesmo quando o bitmap é mostrado sozinho.

Este é o estado de SimpleDraweeView se eu colocar um ponto de interrupção em SharedElementCallback.onSharedElementEnd() na atividade de chamada.

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

Eu acho que pode ter algo a ver com os métodos doDetach() e doAttach() em SimpleDraweeView , quando a própria visão está em RecyclerView .
Finalmente, funcionou para mim (adicionado à Activity de onde a transição é gerada), embora não seja extremamente limpo:

        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 Que bom que você encontrou uma solução alternativa! Tentei reproduzir esse problema específico no aplicativo Showcase em execução no Genymotion com Android 7, mas sem sorte.

Qual é a aparência das visualizações de item para a visualização de reciclagem? No meu caso, era apenas um FrameLayout envolvendo um SimpleDraweeView.

@marcosalis sua solução funcionou para mim com uma pequena mudança, removendo o ciclo 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();
                        }
                    }
            );

Acabei de encontrar o mesmo problema ao brincar com as transições entre atividades. Nenhuma das soluções alternativas propostas acima parecia funcionar. (API 25) Esta é a aparência: https://vimeo.com/225497240

Acho que encontramos uma solução alternativa e espero que uma correção esteja disponível em breve.

A solução alternativa pode ser encontrada em dc7ec2436fc9b639fe1a39398712c360b16da468.

Por enquanto, você deve configurar o primeiro DraweeView onde a transição está começando para usar o tratamento de visibilidade legado chamando simpleDraweeView.setLegacyVisibilityHandlingEnabled(true); (como você pode ver no exemplo de transição em nosso aplicativo de amostra Showcase) .

Você pode verificar se isso resolve os problemas para você? Vamos lançar uma nova versão do Fresco que contém essa correção muito em breve.

Sim, obrigado! Confirmado que isso resolve o problema. Ansioso por uma versão atualizada.

Lançamos o Fresco v1.4.0 , que inclui a correção mencionada acima. Basta ligar para simpleDraweeView.setLegacyVisibilityHandlingEnabled(true); e deve funcionar agora.

Também atualizamos o exemplo de transição do

Obrigado por essa correção, funcionou perfeitamente no meu caso. Uma pergunta, por que não colocar setGlobalLegacyVisibilityHandlingEnabled em true por padrão? Existe algum problema de desempenho?

O manuseio da visibilidade mudou com o Android N e minha mudança é (meio que) reverter o comportamento para pré-N. Alterar esse comportamento para todas as imagens pode levar a outros problemas inesperados e é por isso que decidimos não ativá-lo por padrão ainda. Depois de verificarmos que não há efeitos colaterais, consideraremos ativá-lo por padrão.
Sinta-se à vontade para defini-lo como true e relatar quaisquer problemas que encontrar.

ezgif com-resize

Esta correção parece não funcionar aleatoriamente. Estou definindo setGlobalLegacyVisibilityHandlingEnabled como true, mas depois de alguns cliques, a imagem retornada está em branco.

Fresco 1.5.0, Oreo

Edit: Depois de desenvolver mais alguns dias e mover algumas visualizações, descobri que o problema não acontece mais no meu dispositivo de pixel Oreo. No meu Nexus 5x API 24 emulado, a imagem está sempre em branco após a animação de saída.

Estou tendo o mesmo problema com setLegacyVisibilityHandlingEnabled . Definir como true funciona na maioria das vezes, mas às vezes, apenas aleatoriamente, a imagem desaparece após a transição de retorno.

@marcosalis só acontece no Oreo ou também no Nougat?

Olá @oprisnik , consegui reproduzi-lo aleatoriamente em um Samsung S7 (Nougat) e em um emulador API 26. Me diga se posso ajudar na depuração.

Obrigado, tentarei reproduzir quando tiver um pouco mais de tempo

@oprisnik
Pode confirmar que não parece estar fazendo seu trabalho na maioria das vezes (API24 + API25)

No entanto, consegui fazê-lo funcionar um pouco usando o seguinte 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();
                        });
                    }
                }
            }
        });

Eu fui capaz de reproduzir. Para mim, ocorre apenas raramente. Vou verificar se consigo encontrar uma solução alternativa diferente para corrigir isso.

Olá @oprisnik ,
Você encontrou uma solução alternativa diferente?

Ainda não, isso é difícil de corrigir, já que o Google alterou o comportamento de visibilidade do View, que interrompe o tratamento de visibilidade do Fresco (que precisamos para o gerenciamento de memória) e também não terei muito tempo para analisar isso no futuro próximo . No entanto, há várias alternativas mencionadas neste tópico que corrigem o problema (como a solução alternativa de @MartB que define manualmente a visibilidade).

Se alguém quiser investigar isso, os pedidos de pull são sempre bem-vindos! :)

@oprisnik , react-native-maps também afetado por este problema.
Marquei essas linhas como comentários no arquivo RootDrawable.java como uma solução alternativa.
Você se lembra / conhece algum grande problema relacionado à marcação dessas linhas como linhas de comentário?

O mesmo problema que o @efkan parece estar afetando um grande número de dispositivos Android (Android Nougat 7.1 API 25 e superior).

A solução deles corrigiu todos os problemas que eu estava tendo.

@efkan não sei exatamente. Lembro que também examinei isso quando estava procurando soluções alternativas, mas ignorei. Acho que um problema com a remoção dessas verificações é que o bitmap subjacente foi liberado (já que a Visualização não é mais visível) e tentar desenhá-lo geraria um java.lang.RuntimeException: Canvas: trying to use a recycled bitmap ... já que BitmapDrawable não execute quaisquer verificações de sanidade.

ImageView si tem o mesmo bug onde não restaura adequadamente a visibilidade do Drawable de qualquer drawable, mas ainda funciona, uma vez que a maioria dos Drawables não faz a verificação de visibilidade e não há gerenciamento manual de memória - e o Bitmap subjacente ainda seria válido.

Obrigado @oprisnik por todas essas explicações.

Para testar se isso funciona, é bastante fácil adicionar isso como uma configuração para GenericDraweeHierarchyBuilder e, dependendo disso, ignore a verificação de visibilidade em RootDrawable (que é criada em GenericDraweeHierarchy , consulte https://github.com/facebook/fresco/blob/master/drawee/src/main/java/com/facebook/drawee/generic/GenericDraweeHierarchy.java#L155).

Sinta-se à vontade para enviar um PR que adiciona essa configuração para que você possa habilitá-la para seus aplicativos e ver se há efeitos colaterais.

O mesmo problema aparece apenas em dispositivos com Android 7.1 (ou superior).
Nenhuma das soluções acima funciona.
O problema sempre aparece quando a rede é limitada a 10 kb / s.

@ babyblue1314 - A mudança RootDrawable mencionada acima também não corrige isso para você?

@oprisnik Obrigado pela sua resposta rápida!
Em ... Suponho que sim, a alteração do RootDrawable mencionada acima também não corrige isso para mim.
Não sei se o usei de maneira errada. Aqui está o que parece:

Antes de usar a alteração RootDrawable:

Depois de usar a alteração RootDrawable:

_ Devo dizer que a rede está limitada a 10kb / s. _
E mais, isso não aparece apenas em ListView, mas também em RecyclerView e GridView, conforme mostrado abaixo:

Meu código é:

  1. ListViewAdapter (ou RecyclerViewAdapter ou 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);

Fresco 1.5.0

Dispositivo: Lenovo, android 7.1.1

_Por favor, deixe-me saber se precisar de mais informações.

@ babyblue1314 Não vejo nenhuma transição em seus vídeos ou código relacionado à transição. Tem certeza de que está falando sobre o mesmo problema?

@oprisnik Desculpe, acabei de perceber que esse problema de transição é diferente do meu.
Eu vi que o fenômeno é semelhante ao meu, então ...
Devo começar um novo problema?

@ babyblue1314 sim, por favor, isso parece não ter nenhuma relação.

@oprisnik Finalmente encontrei a causa do meu problema.
Em caso de incompreensão de outras pessoas, estou aqui para dar algumas explicações.
Meu problema tem tudo a ver com o formato da imagem.
Se eu usar o método imageRequestBuilder.setProgressiveRenderingEnabled(true) com formato PNG, meu problema sempre pode se reproduzir.
Se eu mudar o método para imageRequestBuilder.setProgressiveRenderingEnabled(false) com formato PNG, tudo funcionará bem.
@oprisnik Obrigado novamente por sua paciência!

Corrija este problema ...

Fresco 1.9.0 não corrige o problema corretamente.
Uma combinação das proposições neste tópico corrige o problema dependendo do dispositivo:

Portanto, estou usando ambas as soluções alternativas em meu código para estar seguro em meu código e espero que isso cubra tudo. @oprisnik Vou dedicar algum tempo para tentar entender melhor o problema, se eu encontrar uma solução,

Sim, infelizmente ainda não temos uma boa solução para esse problema, pois todas as soluções mencionadas neste tópico falham de uma ou outra maneira. Se alguém tiver uma ideia de como consertar isso corretamente, por favor nos avise ou, melhor ainda, envie um PR :)

Ainda assim, esse problema no componente react-native-maps. Eu imagino que seja um problema simultâneo?
Você tem ideia de onde está o problema?

Algum progresso em localizar o problema? Parece que não ouvimos nada desde abril.

Ainda não tivemos tempo para investigar melhor o que está acontecendo aqui. Sinta-se à vontade para analisar o problema e enviar uma solicitação de pull!

Conforme mencionado anteriormente, o problema subjacente parece ser um bug da estrutura do Android em que ImageView não restaura adequadamente a visibilidade do Drawable subjacente ao retornar da transição.

Eu preenchi um relatório de bug do Android aqui: https://issuetracker.google.com/issues/111293868

Também criei um aplicativo de amostra (não Fresco) que descreve o problema: https://github.com/oprisnik/VisibilityPlayground

Investigaremos se há uma solução alternativa para esse problema. No entanto, o Fresco requer gerenciamento manual de memória e contamos com a visibilidade do Drawable para solicitar novamente a imagem, então não tenho certeza se há uma solução melhor do que as soluções alternativas descritas acima.

Mudei para o afresco sem estar ciente desse problema. Eu renderizo muitos gifs e isso faz um ótimo trabalho, mas também dependo dessas animações para navegação. Consegui usar os hacks mencionados acima, mas em uma animação de retorno, a imagem desaparecerá.

Na verdade, invalidate ou View.setVisibility não pode mostrar drawable, você precisa chamar Drawable.setVisible (true, true) diretamente.
Eu adiciono esses códigos em A Activity # OnCreate, funciona bem:

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 Em seu aplicativo de amostra não fresco, você define a transição para ChangeBounds . O bug acontece se você remover esta linha? Acho que a visibilidade é restaurada corretamente quando ChangeImageTransform está em jogo. É possível fazer imagens de afresco funcionarem com ChangeImageTransform ?

@RainFool está certo. simpleDraweeView.getVisibility () é VISIBLE , mas simpleDraweeView.getDrawable (). isVisible () é false .

Sim, este é um bug na estrutura do Android onde a visibilidade do View (ImageView para ser mais preciso) não é propagada para o Drawable, então você tem que atualizar manualmente a visibilidade. Marque o relatório de bug do Android com uma estrela aqui para obter mais visibilidade: https://issuetracker.google.com/issues/111293868

Esta página foi útil?
0 / 5 - 0 avaliações