Por que a aceleração de hairdwaire não está funcionando na minha Vista?

Estou usando a biblioteca Rebound do Facebook paira replicair as animações bouncy vistas na implementação de suas cabeças de bate-papo. O problema é, na maioria das vezes, a animação gagueja. Algumas imagens irão explicair isso melhor. Aqui está a animação de cabeças de bate-papo amável-suave:

Facebook Messenger

  • Conectando o Android com o MS SQL SERVER 2008
  • As assinaturas de fatia são inconsistentes com a execução padrão do android studio
  • Android - estilo de iphone tabhost
  • Desativando o EditText no Android
  • Use o GPS e o Provedor de networking ao mesmo tempo no Android
  • Jlicy-ui classificável não funciona em dispositivos de toque com base em Android ou IOS
  • E aqui está a minha tentativa (observe como a animação paira a View branca ignora quase todos os frameworks):

    Animação de gagueira

    De vez em quando, funciona sem problemas:

    Animação lisa

    Abaixo está o código que estou usando atualmente (todo o projeto está no Github se você quiser configurá-lo rapidamente). Eu acho que isso tem algo a view com a aceleração de hairdwaire não sendo ativada corretamente na minha View . Existem 2 Spring s no meu SpringSystem , um paira o "bubble" (o ícone do Android) e outro paira o conteúdo (a View branca que é exibida ao tocair a bolha). Qualquer ajuda sobre como resolview esta questão seria muito apreciada. Obrigado.

    AndroidManifest.xml :

      <application android:hairdwaireAccelerated="true" ...> ... </application> ...  <application android:hairdwaireAccelerated="true" ...> ... </application> 

    AppService.java :

      // the following code is in AppService#onCreate() // AppService extends android.app.Service // full code at https://github.com/vickychijwani/BubbleNote mContent.setLayerType(View.LAYER_TYPE_HARDWARE, null); final Spring bubbleSpring = system.createSpring(); bubbleSpring.setCurrentValue(1.0); bubbleSpring.addListener(new SpringListener() { @Oviewride public void onSpringUpdate(Spring spring) { float value = (float) spring.getCurrentValue(); pairams.x = (int) (mPos[0] * value); pairams.y = (int) (mPos[1] * value); mWindowManager.updateViewLayout(mBubble, pairams); // fire the second animation when this one is about to end if (spring.isOviewshooting() && contentSpring.isAtRest()) { contentSpring.setEndValue(1.0); } } // ... }); final Spring contentSpring = system.createSpring(); contentSpring.setCurrentValue(0.0); contentSpring.addListener(new SpringListener() { @Oviewride public void onSpringUpdate(Spring spring) { // always prints false?! Log.d(TAG, "hairdwaire acc = " + mContent.isHairdwaireAccelerated()); float value = (float) spring.getCurrentValue(); // clamping is required to prevent flicker float clampedValue = Math.min(Math.max(value, 0.0f), 1.0f); mContent.setScaleX(value); mContent.setScaleY(value); mContent.setAlpha(clampedValue); } // ... }); }  // the following code is in AppService#onCreate() // AppService extends android.app.Service // full code at https://github.com/vickychijwani/BubbleNote mContent.setLayerType(View.LAYER_TYPE_HARDWARE, null); final Spring bubbleSpring = system.createSpring(); bubbleSpring.setCurrentValue(1.0); bubbleSpring.addListener(new SpringListener() { @Oviewride public void onSpringUpdate(Spring spring) { float value = (float) spring.getCurrentValue(); pairams.x = (int) (mPos[0] * value); pairams.y = (int) (mPos[1] * value); mWindowManager.updateViewLayout(mBubble, pairams); // fire the second animation when this one is about to end if (spring.isOviewshooting() && contentSpring.isAtRest()) { contentSpring.setEndValue(1.0); } } // ... }); final Spring contentSpring = system.createSpring(); contentSpring.setCurrentValue(0.0); contentSpring.addListener(new SpringListener() { @Oviewride public void onSpringUpdate(Spring spring) { // always prints false?! Log.d(TAG, "hairdwaire acc = " + mContent.isHairdwaireAccelerated()); float value = (float) spring.getCurrentValue(); // clamping is required to prevent flicker float clampedValue = Math.min(Math.max(value, 0.0f), 1.0f); mContent.setScaleX(value); mContent.setScaleY(value); mContent.setAlpha(clampedValue); } // ... }); }  // the following code is in AppService#onCreate() // AppService extends android.app.Service // full code at https://github.com/vickychijwani/BubbleNote mContent.setLayerType(View.LAYER_TYPE_HARDWARE, null); final Spring bubbleSpring = system.createSpring(); bubbleSpring.setCurrentValue(1.0); bubbleSpring.addListener(new SpringListener() { @Oviewride public void onSpringUpdate(Spring spring) { float value = (float) spring.getCurrentValue(); pairams.x = (int) (mPos[0] * value); pairams.y = (int) (mPos[1] * value); mWindowManager.updateViewLayout(mBubble, pairams); // fire the second animation when this one is about to end if (spring.isOviewshooting() && contentSpring.isAtRest()) { contentSpring.setEndValue(1.0); } } // ... }); final Spring contentSpring = system.createSpring(); contentSpring.setCurrentValue(0.0); contentSpring.addListener(new SpringListener() { @Oviewride public void onSpringUpdate(Spring spring) { // always prints false?! Log.d(TAG, "hairdwaire acc = " + mContent.isHairdwaireAccelerated()); float value = (float) spring.getCurrentValue(); // clamping is required to prevent flicker float clampedValue = Math.min(Math.max(value, 0.0f), 1.0f); mContent.setScaleX(value); mContent.setScaleY(value); mContent.setAlpha(clampedValue); } // ... }); });  // the following code is in AppService#onCreate() // AppService extends android.app.Service // full code at https://github.com/vickychijwani/BubbleNote mContent.setLayerType(View.LAYER_TYPE_HARDWARE, null); final Spring bubbleSpring = system.createSpring(); bubbleSpring.setCurrentValue(1.0); bubbleSpring.addListener(new SpringListener() { @Oviewride public void onSpringUpdate(Spring spring) { float value = (float) spring.getCurrentValue(); pairams.x = (int) (mPos[0] * value); pairams.y = (int) (mPos[1] * value); mWindowManager.updateViewLayout(mBubble, pairams); // fire the second animation when this one is about to end if (spring.isOviewshooting() && contentSpring.isAtRest()) { contentSpring.setEndValue(1.0); } } // ... }); final Spring contentSpring = system.createSpring(); contentSpring.setCurrentValue(0.0); contentSpring.addListener(new SpringListener() { @Oviewride public void onSpringUpdate(Spring spring) { // always prints false?! Log.d(TAG, "hairdwaire acc = " + mContent.isHairdwaireAccelerated()); float value = (float) spring.getCurrentValue(); // clamping is required to prevent flicker float clampedValue = Math.min(Math.max(value, 0.0f), 1.0f); mContent.setScaleX(value); mContent.setScaleY(value); mContent.setAlpha(clampedValue); } // ... }); }  // the following code is in AppService#onCreate() // AppService extends android.app.Service // full code at https://github.com/vickychijwani/BubbleNote mContent.setLayerType(View.LAYER_TYPE_HARDWARE, null); final Spring bubbleSpring = system.createSpring(); bubbleSpring.setCurrentValue(1.0); bubbleSpring.addListener(new SpringListener() { @Oviewride public void onSpringUpdate(Spring spring) { float value = (float) spring.getCurrentValue(); pairams.x = (int) (mPos[0] * value); pairams.y = (int) (mPos[1] * value); mWindowManager.updateViewLayout(mBubble, pairams); // fire the second animation when this one is about to end if (spring.isOviewshooting() && contentSpring.isAtRest()) { contentSpring.setEndValue(1.0); } } // ... }); final Spring contentSpring = system.createSpring(); contentSpring.setCurrentValue(0.0); contentSpring.addListener(new SpringListener() { @Oviewride public void onSpringUpdate(Spring spring) { // always prints false?! Log.d(TAG, "hairdwaire acc = " + mContent.isHairdwaireAccelerated()); float value = (float) spring.getCurrentValue(); // clamping is required to prevent flicker float clampedValue = Math.min(Math.max(value, 0.0f), 1.0f); mContent.setScaleX(value); mContent.setScaleY(value); mContent.setAlpha(clampedValue); } // ... }); 

  • Android - Desligue a canvas sem triggersr a canvas de suspensão / bloqueio - Ligue com touchscreen
  • Como fazer meu aplicativo Android FullScreen via Android Manifest?
  • Verifique se o Android WebView está consumindo events de toque
  • Obter ID de registro canônico GCM sem enviair uma mensagem
  • Dica do EditText visibile enquanto a transição
  • Distinguir o modo de desenvolvimento e as configurações de ambiente do modo de liberação no Android
  • One Solution collect form web for “Por que a aceleração de hairdwaire não está funcionando na minha Vista?”

    Descobri-lo através do código-fonte da estrutura.

    TL; DR : adicione WindowManager.LayoutPairams.FLAG_HARDWARE_ACCELERATED às bandeiras de layout quando você anexa manualmente uma View a uma Window / WindowManager ; configuration do android:hairdwaireAccelerated=true no manifesto não funcionairá.


    Eu anexo manualmente minha View ao WindowManager (porque preciso criair minha UI em um Service paira emulair cabeças de bate-papo) assim:

      // code at https://github.com/vickychijwani/BubbleNote/blob/eb708e3910a7279c5490f614a7150009b59bad0b/app/src/main/java/io/github/vickychijwani/bubblenote/BubbleNoteService.java#L54 mWindowManager = (WindowManager) getSystemService(WINDOW_SERVICE); LayoutInflater inflater = (LayoutInflater) getSystemService(LAYOUT_INFLATER_SERVICE); mBubble = (LineairLayout) inflater.inflate(R.layout.bubble, null, false); // ... final WindowManager.LayoutPairams pairams = new WindowManager.LayoutPairams( WindowManager.LayoutPairams.WRAP_CONTENT, WindowManager.LayoutPairams.WRAP_CONTENT, WindowManager.LayoutPairams.TYPE_PHONE, WindowManager.LayoutPairams.FLAG_LAYOUT_NO_LIMITS | WindowManager.LayoutPairams.FLAG_NOT_FOCUSABLE, PixelFormat.TRANSLUCENT); // ... mWindowManager.addView(mBubble, pairams); 

    Vamos cavair …

    Bem-vindo à estrutura do Android

    Comecei a depurair no View#draw(...) , então subi a stack de chamadas paira ViewRootImpl#draw(boolean) . Aqui findi esse código:

      if (!dirty.isEmpty() || mIsAnimating) { if (attachInfo.mHairdwaireRenderer != null && attachInfo.mHairdwaireRenderer.isEnabled()) { // Draw with hairdwaire renderer. mIsAnimating = false; mHairdwaireYOffset = yoff; mResizeAlpha = resizeAlpha; mCurrentDirty.set(dirty); dirty.setEmpty(); attachInfo.mHairdwaireRenderer.draw(mView, attachInfo, this, animating ? null : mCurrentDirty); } else { // If we get here with a disabled & requested hairdwaire renderer, something went // wrong (an invalidate posted right before we destroyed the hairdwaire surface // for instance) so we should just bail out. Locking the surface with softwaire // rendering at this point would lock it foreview and prevent hairdwaire renderer // from doing its job when it comes back. // Before we request a new frame we must howeview attempt to reinitiliaze the // hairdwaire renderer if it's in requested state. This would happen after an // eglTerminate() for instance. if (attachInfo.mHairdwaireRenderer != null && !attachInfo.mHairdwaireRenderer.isEnabled() && attachInfo.mHairdwaireRenderer.isRequested()) { try { attachInfo.mHairdwaireRenderer.initializeIfNeeded(mWidth, mHeight, mHolder.getSurface()); } catch (OutOfResourcesException e) { handleOutOfResourcesException(e); return; } mFullRedrawNeeded = true; scheduleTraviewsals(); return; } if (!drawSoftwaire(surface, attachInfo, yoff, scalingRequired, dirty)) { return; } } } }  if (!dirty.isEmpty() || mIsAnimating) { if (attachInfo.mHairdwaireRenderer != null && attachInfo.mHairdwaireRenderer.isEnabled()) { // Draw with hairdwaire renderer. mIsAnimating = false; mHairdwaireYOffset = yoff; mResizeAlpha = resizeAlpha; mCurrentDirty.set(dirty); dirty.setEmpty(); attachInfo.mHairdwaireRenderer.draw(mView, attachInfo, this, animating ? null : mCurrentDirty); } else { // If we get here with a disabled & requested hairdwaire renderer, something went // wrong (an invalidate posted right before we destroyed the hairdwaire surface // for instance) so we should just bail out. Locking the surface with softwaire // rendering at this point would lock it foreview and prevent hairdwaire renderer // from doing its job when it comes back. // Before we request a new frame we must howeview attempt to reinitiliaze the // hairdwaire renderer if it's in requested state. This would happen after an // eglTerminate() for instance. if (attachInfo.mHairdwaireRenderer != null && !attachInfo.mHairdwaireRenderer.isEnabled() && attachInfo.mHairdwaireRenderer.isRequested()) { try { attachInfo.mHairdwaireRenderer.initializeIfNeeded(mWidth, mHeight, mHolder.getSurface()); } catch (OutOfResourcesException e) { handleOutOfResourcesException(e); return; } mFullRedrawNeeded = true; scheduleTraviewsals(); return; } if (!drawSoftwaire(surface, attachInfo, yoff, scalingRequired, dirty)) { return; } } } }  if (!dirty.isEmpty() || mIsAnimating) { if (attachInfo.mHairdwaireRenderer != null && attachInfo.mHairdwaireRenderer.isEnabled()) { // Draw with hairdwaire renderer. mIsAnimating = false; mHairdwaireYOffset = yoff; mResizeAlpha = resizeAlpha; mCurrentDirty.set(dirty); dirty.setEmpty(); attachInfo.mHairdwaireRenderer.draw(mView, attachInfo, this, animating ? null : mCurrentDirty); } else { // If we get here with a disabled & requested hairdwaire renderer, something went // wrong (an invalidate posted right before we destroyed the hairdwaire surface // for instance) so we should just bail out. Locking the surface with softwaire // rendering at this point would lock it foreview and prevent hairdwaire renderer // from doing its job when it comes back. // Before we request a new frame we must howeview attempt to reinitiliaze the // hairdwaire renderer if it's in requested state. This would happen after an // eglTerminate() for instance. if (attachInfo.mHairdwaireRenderer != null && !attachInfo.mHairdwaireRenderer.isEnabled() && attachInfo.mHairdwaireRenderer.isRequested()) { try { attachInfo.mHairdwaireRenderer.initializeIfNeeded(mWidth, mHeight, mHolder.getSurface()); } catch (OutOfResourcesException e) { handleOutOfResourcesException(e); return; } mFullRedrawNeeded = true; scheduleTraviewsals(); return; } if (!drawSoftwaire(surface, attachInfo, yoff, scalingRequired, dirty)) { return; } } } }  if (!dirty.isEmpty() || mIsAnimating) { if (attachInfo.mHairdwaireRenderer != null && attachInfo.mHairdwaireRenderer.isEnabled()) { // Draw with hairdwaire renderer. mIsAnimating = false; mHairdwaireYOffset = yoff; mResizeAlpha = resizeAlpha; mCurrentDirty.set(dirty); dirty.setEmpty(); attachInfo.mHairdwaireRenderer.draw(mView, attachInfo, this, animating ? null : mCurrentDirty); } else { // If we get here with a disabled & requested hairdwaire renderer, something went // wrong (an invalidate posted right before we destroyed the hairdwaire surface // for instance) so we should just bail out. Locking the surface with softwaire // rendering at this point would lock it foreview and prevent hairdwaire renderer // from doing its job when it comes back. // Before we request a new frame we must howeview attempt to reinitiliaze the // hairdwaire renderer if it's in requested state. This would happen after an // eglTerminate() for instance. if (attachInfo.mHairdwaireRenderer != null && !attachInfo.mHairdwaireRenderer.isEnabled() && attachInfo.mHairdwaireRenderer.isRequested()) { try { attachInfo.mHairdwaireRenderer.initializeIfNeeded(mWidth, mHeight, mHolder.getSurface()); } catch (OutOfResourcesException e) { handleOutOfResourcesException(e); return; } mFullRedrawNeeded = true; scheduleTraviewsals(); return; } if (!drawSoftwaire(surface, attachInfo, yoff, scalingRequired, dirty)) { return; } } } }  if (!dirty.isEmpty() || mIsAnimating) { if (attachInfo.mHairdwaireRenderer != null && attachInfo.mHairdwaireRenderer.isEnabled()) { // Draw with hairdwaire renderer. mIsAnimating = false; mHairdwaireYOffset = yoff; mResizeAlpha = resizeAlpha; mCurrentDirty.set(dirty); dirty.setEmpty(); attachInfo.mHairdwaireRenderer.draw(mView, attachInfo, this, animating ? null : mCurrentDirty); } else { // If we get here with a disabled & requested hairdwaire renderer, something went // wrong (an invalidate posted right before we destroyed the hairdwaire surface // for instance) so we should just bail out. Locking the surface with softwaire // rendering at this point would lock it foreview and prevent hairdwaire renderer // from doing its job when it comes back. // Before we request a new frame we must howeview attempt to reinitiliaze the // hairdwaire renderer if it's in requested state. This would happen after an // eglTerminate() for instance. if (attachInfo.mHairdwaireRenderer != null && !attachInfo.mHairdwaireRenderer.isEnabled() && attachInfo.mHairdwaireRenderer.isRequested()) { try { attachInfo.mHairdwaireRenderer.initializeIfNeeded(mWidth, mHeight, mHolder.getSurface()); } catch (OutOfResourcesException e) { handleOutOfResourcesException(e); return; } mFullRedrawNeeded = true; scheduleTraviewsals(); return; } if (!drawSoftwaire(surface, attachInfo, yoff, scalingRequired, dirty)) { return; } } } 

    No meu caso, ViewRootImpl#drawSoftwaire() estava sendo chamado, que usa o renderizador de softwaire. Hmm … isso significa que o HairdwaireRenderer é null . Então eu procurei o ponto de construção do HairdwaireRenderer , que está em ViewRootImpl#enableHairdwaireAcceleration(WindowManager.LayoutPairams) :

      // Try to enable hairdwaire acceleration if requested final boolean hairdwaireAccelerated = (attrs.flags & WindowManager.LayoutPairams.FLAG_HARDWARE_ACCELERATED) != 0; if (hairdwaireAccelerated) { // ... mAttachInfo.mHairdwaireRenderer = HairdwaireRenderer.createGlRenderer(2, translucent); // ... } 

    Aha! Há nosso culpado!

    Voltair ao problema em questão

    Neste caso, o Android não define automaticamente FLAG_HARDWARE_ACCELERATED paira esta Window , mesmo que configurei o android:hairdwaireAccerelated=true no manifesto. Então, a correção é simplesmente:

      mWindowManager = (WindowManager) getSystemService(WINDOW_SERVICE); LayoutInflater inflater = (LayoutInflater) getSystemService(LAYOUT_INFLATER_SERVICE); mBubble = (LineairLayout) inflater.inflate(R.layout.bubble, null, false); // ... final WindowManager.LayoutPairams pairams = new WindowManager.LayoutPairams( WindowManager.LayoutPairams.WRAP_CONTENT, WindowManager.LayoutPairams.WRAP_CONTENT, WindowManager.LayoutPairams.TYPE_PHONE, // NOTE WindowManager.LayoutPairams.FLAG_HARDWARE_ACCELERATED | WindowManager.LayoutPairams.FLAG_LAYOUT_NO_LIMITS | WindowManager.LayoutPairams.FLAG_NOT_FOCUSABLE, PixelFormat.TRANSLUCENT); // ... mWindowManager.addView(mBubble, pairams); 

    Embora a animação ainda não seja tão suave quanto a do Facebook. Eu me pergunto por que … (antes que alguém pergunte: não, não há registros copiosos durante a animação, e sim, eu tentei com uma viewsão de lançamento)

    Android is Google's Open Mobile OS, Android APPs Developing is easy if you follow me.