我通过查看框架源代码已经弄清楚了。
TL;DR: add WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED
当您手动附加一个布局标志时View
to a Window
/ WindowManager
;环境android:hardwareAccelerated=true
在清单中将不起作用。
I'm 手动附加我的View to the WindowManager https://github.com/vickychijwani/BubbleNote/blob/eb708e3910a7279c5490f614a7150009b59bad0b/app/src/main/java/io/github/vickychijwani/bubblenote/BubbleNoteService.java#L54(因为我需要在Service
模拟聊天头),如下所示:
// 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(...) http://grepcode.com/file/repository.grepcode.com/java/ext/com.google.android/android/4.4.4_r1/android/view/View.java?av=f#14069,然后向上调用堆栈ViewRootImpl#draw(boolean) http://grepcode.com/file/repository.grepcode.com/java/ext/com.google.android/android/4.4.4_r1/android/view/ViewRootImpl.java?av=f#2280。在这里我遇到了这段代码:
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() http://grepcode.com/file/repository.grepcode.com/java/ext/com.google.android/android/4.4.4_r1/android/view/ViewRootImpl.java?av=f#2420被调用,它使用软件渲染器。嗯……这意味着HardwareRenderer
is null
。所以我去寻找建造的点HardwareRenderer
,这是在ViewRootImpl#enableHardwareAcceleration(WindowManager.LayoutParams) http://grepcode.com/file/repository.grepcode.com/java/ext/com.google.android/android/4.4.4_r1/android/view/ViewRootImpl.java?av=f#681:
// 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不会自动设置FLAG_HARDWARE_ACCELERATED
为了这Window
,尽管我已经设置了android:hardwareAccerelated=true
在清单中。所以修复方法很简单:
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的流畅。我想知道为什么......(在有人问之前:不,动画期间没有大量日志;是的,我尝试过发布版本)