按关键词阅读: CPU 安卓 GPU 飞利浦·斯塔克
$ adb shell setprop debug.mono.profile log:callsalloc
我们可以看到该方法在每次调用时都花费时间:
Method call summary Total(ms) Self(ms) Calls Method name 782 5 100 MyApp.MainActivity:Log (stringobject[
) 775 3 100 Android.Util.Log:Debug (stringstringobject[
) 634 10 100 Android.Util.Log:Debug (stringstring)
在这里定位到我们的日志记录花费了大量时间 , 我们的下一步方向可能需要改进单个调用 , 或者寻求全新的解决方案 。
log:alloc还让我们看到内存分配;日志调用直接导致了大量的不合理内存分配:
Allocation summary Bytes Count Average Type name 41784 839 49 System.String 4280 144 29 System.Object[
硬件加速 最后尝试引入硬件加速 , 获得了一个新的绘图模型来将应用程序渲染到屏幕上 。 它引入了DisplayList 结构并且记录视图的绘图命令以加快渲染速度 。
同时 , 可以将 View 渲染到屏幕外缓冲区并随心所欲地修改它而不用担心被引用的问题 。 此功能主要适用于动画 , 非常适合解决我们的帧率问题可以更快地为复杂的视图设置动画 。
如果没有图层 , 在更改动画属性后 , 动画视图将使其无效 。 对于复杂的视图 , 这种失效会传播到所有的子视图 , 它们反过来会重绘自己 。
在使用由硬件支持的视图层后 , GPU 会为视图创建纹理 。 因此我们可以在我们的屏幕上为复杂的视图设置动画 , 并且使动画更加流畅 。
代码示例:
// Using the Object animator view.setLayerType(View.LAYER_TYPE_HARDWARE null); ObjectAnimator objectAnimator = ObjectAnimator.ofFloat(view View.TRANSLATION_X 20f); objectAnimator.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { view.setLayerType(View.LAYER_TYPE_NONE null);); objectAnimator.start(); // Using the Property animator view.animate().translationX(20f).withLayer().start();
另外还有几点在使用硬件层中仍需注意:
(1)在使用之后进行清理:
硬件层会占用GPU上的空间 。 在上面的 ObjectAnimator代码中 , 侦听器会在动画结束时移除图层 。 在 Property animator 示例中 , withLayers() 方法会在开始时自动创建图层并在动画结束时将其删除 。
(2)需要将硬件层更新可视化:
使用开发人员选项 , 可以启用“显示硬件层更新” 。 如果在应用硬件层后更改视图 , 它将使硬件层无效并将视图重新渲染到该屏幕外缓冲区 。
硬件加速优化 但是由此带来了一个问题是 , 在不需要快速渲染的界面 , 比如滚动栏 硬件层也会更快地渲染它们 。 当将 ViewPager 滚动到两侧时 , 它的页面在整个滚动阶段会以绿色突出显示 。
因此当我滚动 ViewPager 时 , 我使用 DDMS 运行 TraceView , 按名称对方法调用进行排序 , 搜索“android/view/View.setLayerType” , 然后跟踪它的引用:
ViewPager#enableLayers(): private void enableLayers(boolean enable) { final int childCount = getChildCount(); for (int i = 0; ichildCount; i++) { final int layerType = enable ? ViewCompat.LAYER_TYPE_HARDWARE : ViewCompat.LAYER_TYPE_NONE; ViewCompat.setLayerType(getChildAt(i) layerType null);
该方法负责为 ViewPager 的孩子启用/禁用硬件层 。 它从 ViewPaper#setScrollState() 调用一次:
private void setScrollState(int newState) { if (mScrollState == newState) { return;mScrollState = newState; if (mPageTransformer != null) { enableLayers(newState != SCROLL_STATE_IDLE);if (mOnPageChangeListener != null) { mOnPageChangeListener.onPageScrollStateChanged(newState);
正如代码中所示 , 当滚动状态为 IDLE 时硬件被禁用 , 否则在 DRAGGING 或 SETTLING 时启用 。 PageTransformer 旨在“使用动画属性将自定义转换应用于页面视图”(Source) 。
基于我们的需求 , 只在渲染动画的时候启用硬件层 , 所以我想覆盖ViewPager 方法 , 但由于它们是私有的 , 我们无法修改这个方法 。
所以我采取了另外的解决方案:在 ViewPage#setScrollState() 上 , 在调用enableLayers() 之后 , 我们还会调用OnPageChangeListener#onPageScrollStateChanged() 。 所以我设置了一个监听器 , 当 ViewPager 的滚动状态不同于 IDLE 时 , 它将所有 ViewPager 的孩子的图层类型重置为 NONE:
@Override public void onPageScrollStateChanged(int scrollState) { // A small hack to remove the HW layer that the viewpager add to each page when scrolling. if (scrollState != ViewPager.SCROLL_STATE_IDLE) { final int childCount =your_viewpager.getChildCount(); for (int i = 0; ichildCount; i++)your_viewpager.getChildAt(i).setLayerType(View.LAYER_TYPE_NONE null);
这样 , 在 ViewPager#setScrollState() 为页面设置了一个硬件层之后——我将它们重新设置为 NONE , 这将禁用硬件层 , 因此而导致的帧率区别主要显示在 Nexus上 。
稿源:(阿里云云栖号)
【傻大方】网址:http://www.shadafang.com/c/11159615462021.html
标题:GPU|如何用 GPU硬件层加速优化Android系统的游戏流畅度( 二 )