gpt4 book ai didi

android - 为什么硬件加速在我的 View 上不起作用?

转载 作者:塔克拉玛干 更新时间:2023-11-01 22:06:58 26 4
gpt4 key购买 nike

我正在使用 Facebook's Rebound library复制在他们的聊天头实现中看到的有弹性的动画。问题是,大多数时候动画会卡顿。一些图片将更好地解释这一点。这是黄油般流畅的聊天头像动画:

Facebook Messenger

这是我的尝试(注意白色 View 的动画如何跳过几乎所有帧):

Stuttering animation

偶尔它能顺利运行:

Smooth animation

下面是我目前使用的代码(如果您想快速设置,整个项目是 up on Github)。我猜这与我的 View 上未正确启用硬件加速有关。我的 SpringSystem 中有 2 个 Spring,一个用于“气泡”(Android 图标),另一个用于内容(白色的 View点击气泡时显示)。任何有关如何解决此问题的帮助将不胜感激。谢谢。

AndroidManifest.xml:

    <application android:hardwareAccelerated="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() {
@Override
public void onSpringUpdate(Spring spring) {
float value = (float) spring.getCurrentValue();
params.x = (int) (mPos[0] * value);
params.y = (int) (mPos[1] * value);
mWindowManager.updateViewLayout(mBubble, params);
// fire the second animation when this one is about to end
if (spring.isOvershooting() && contentSpring.isAtRest()) {
contentSpring.setEndValue(1.0);
}
}

// ...
});

final Spring contentSpring = system.createSpring();
contentSpring.setCurrentValue(0.0);
contentSpring.addListener(new SpringListener() {
@Override
public void onSpringUpdate(Spring spring) {
// always prints false?!
Log.d(TAG, "hardware acc = " + mContent.isHardwareAccelerated());
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);
}

// ...
});

最佳答案

我已经通过浏览框架源代码弄明白了。

TL;DR:当您手动将 View 附加到 Window 时,将 WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED 添加到布局标志/窗口管理器;在 list 中设置 android:hardwareAccelerated=true 将不起作用。


我是 manually attaching my View to the WindowManager (因为我需要在 Service 中创建我的 UI 来模拟聊天头)像这样:

    // 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 = (LinearLayout) inflater.inflate(R.layout.bubble, null, false);
// ...
final WindowManager.LayoutParams params = new WindowManager.LayoutParams(
WindowManager.LayoutParams.WRAP_CONTENT,
WindowManager.LayoutParams.WRAP_CONTENT,
WindowManager.LayoutParams.TYPE_PHONE,
WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE,
PixelFormat.TRANSLUCENT);
// ...
mWindowManager.addView(mBubble, params);

让我们去挖掘...

欢迎使用 Android 框架

我在 View#draw(...) 开始调试, 然后将调用堆栈上升到 ViewRootImpl#draw(boolean) .在这里我遇到了这段代码:

    if (!dirty.isEmpty() || mIsAnimating) {
if (attachInfo.mHardwareRenderer != null && attachInfo.mHardwareRenderer.isEnabled()) {
// Draw with hardware renderer.
mIsAnimating = false;
mHardwareYOffset = yoff;
mResizeAlpha = resizeAlpha;

mCurrentDirty.set(dirty);
dirty.setEmpty();

attachInfo.mHardwareRenderer.draw(mView, attachInfo, this,
animating ? null : mCurrentDirty);
} else {
// If we get here with a disabled & requested hardware renderer, something went
// wrong (an invalidate posted right before we destroyed the hardware surface
// for instance) so we should just bail out. Locking the surface with software
// rendering at this point would lock it forever and prevent hardware renderer
// from doing its job when it comes back.
// Before we request a new frame we must however attempt to reinitiliaze the
// hardware renderer if it's in requested state. This would happen after an
// eglTerminate() for instance.
if (attachInfo.mHardwareRenderer != null &&
!attachInfo.mHardwareRenderer.isEnabled() &&
attachInfo.mHardwareRenderer.isRequested()) {

try {
attachInfo.mHardwareRenderer.initializeIfNeeded(mWidth, mHeight,
mHolder.getSurface());
} catch (OutOfResourcesException e) {
handleOutOfResourcesException(e);
return;
}

mFullRedrawNeeded = true;
scheduleTraversals();
return;
}

if (!drawSoftware(surface, attachInfo, yoff, scalingRequired, dirty)) {
return;
}
}
}

以我为例 ViewRootImpl#drawSoftware()被调用,它使用软件渲染器。嗯...这意味着 HardwareRenderernull。所以我去寻找HardwareRenderer的构造点,它在ViewRootImpl#enableHardwareAcceleration(WindowManager.LayoutParams)中。 :

    // Try to enable hardware acceleration if requested
final boolean hardwareAccelerated =
(attrs.flags & WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED) != 0;
if (hardwareAccelerated) {
// ...
mAttachInfo.mHardwareRenderer = HardwareRenderer.createGlRenderer(2, translucent);
// ...
}

啊哈!这是我们的罪魁祸首!

回到手头的问题

在这种情况下,Android 不会自动为这个 Window 设置 FLAG_HARDWARE_ACCELERATED,即使我已经在显现。所以修复很简单:

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

虽然动画还是不如Facebook的流畅。我想知道为什么......(在有人问之前:不,动画期间没有大量日志;是的,我已经尝试过发布版本)

关于android - 为什么硬件加速在我的 View 上不起作用?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25713219/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com