publicvoidonTrimMemory() { mContent.setVisibility(GONE); // Clear the widget pages of all their subviews - this will trigger the widget previews // to delete their bitmaps mPagedView.clearAllWidgetPages(); }
AppsCustomizePagedView.java:
1 2 3 4 5 6 7 8 9 10 11
public void clearAllWidgetPages() { cancelAllTasks(); int count = getChildCount(); for (int i = 0; i < count; i++) { View v = getPageAt(i); if (v instanceof PagedViewGridLayout) { ((PagedViewGridLayout) v).removeAllViewsOnPage(); mDirtyPageContent.set(i, true); } } }
@Override public void onTrimMemory(int level) { if (level >= ComponentCallbacks2.TRIM_MEMORY_MODERATE) { // Clear the caches. Note all pending requests will be removed too. clear(); } }
public void clear() { mPendingRequests.clear(); mBitmapHolderCache.evictAll(); mBitmapCache.evictAll(); }
/** * Free the native object associated with this bitmap, and clear the * reference to the pixel data. This will not free the pixel data synchronously; * it simply allows it to be garbage collected if there are no other references. * The bitmap is marked as "dead", meaning it will throw an exception if * getPixels() or setPixels() is called, and will draw nothing. This operation * cannot be reversed, so it should only be called if you are sure there are no * further uses for the bitmap. This is an advanced call, and normally need * not be called, since the normal GC process will free up this memory when * there are no more references to this bitmap. */ publicvoidrecycle() { if (!mRecycled) { if (nativeRecycle(mNativeBitmap)) { // return value indicates whether native pixel object was actually recycled. // false indicates that it is still in use at the native level and these // objects should not be collected now. They will be collected later when the // Bitmap itself is collected. mBuffer = null; mNinePatchChunk = null; } mRecycled = true; } }
...... //如果使用过程中抛出异常的判断 if (bitmap.isRecycled()) { thrownewRuntimeException("Canvas: trying to use a recycled bitmap " + bitmap); }
“If you can measure it, you can optimize it” is a common term in the computing world, and for Android’s rendering system, the same thing holds true. In order to optimize your pipeline to be more efficient for rendering, you need a tool to give you feedback on where the current perf problems lie.
And in this video, +Colt McAnlis walks you through an on-device tool that’s built for this exact reason. “Profile GPU Rendering” will help you understand the stages of the rendering pipeline, and also get a chance to see what portions of it might be taking too long, and what you can do about it for your application.
Unbeknown to most developers, there’s a simple hardware design that defines everything about how fast your application can draw things to the screen.
You may have heard the term VSYNC - VSYNC stands for vertical synchronization and it’s an event that happens every time your screen starts to refresh the content it wants to show you.
Effectively, VSYNC is the product of two components Refresh Rate (how fast the hardware can refresh the screen), and Frames Per Second (how fast the GPU can draw images), and in this video +Colt McAnlis walks through each of these topics, and discusses where VSYNC (and the 16ms rendering barrier) comes from, and why it’s critical to understand if you want a silky smooth application.
One of the most problematic performance problems on Android is the easiest to create; thankfully, it’s also easy to fix.
OVERDRAW is a term used to describe how many times a pixel has been re-drawn in a single frame of rendering. It’s a troublesome issue, because in most cases, pixels that are overdrawn do not end up contributing to the final rendered image. As such, it amounts to wasted work for your GPU and CPU.
Fixing overdraw has everything to do with using the available on-device tools, like Show GPU Overdraw, and then adjusting your view hierarchy in order to reduce areas where it may be occurring.
Rendering performance is all about how fast you can draw your activity, and get it updated on the screen. Success here means your users feeling like your application is smooth and responsive, which means that you’ve got to get all your logic completed, and all your rendering done in 16ms or less, each and every frame. But that might be a bit more difficult than you think.
In this video, +Colt McAnlis takes a look at what “rendering performance” means to developers, alongside some of the most common pitfalls that are ran into; and let’s not forget the important stuff: the tools that help you track down, and fix these issues before they become large problems.
Android Performance Patterns is a collection of videos focused entirely on helping developers write faster, more performant Android Applications. On one side, it’s about peeling back the layers of the Android System, and exposing how things are working under the hood. On the other side, it’s about teaching you how the tools work, and what to look for in order to extract the right perf out of your app. But at the end of the day, Android Performance Patterns is all giving you the right resources, at the right time to help make the fastest, smoothest, most awesome experience for your users. And that’s the whole point, right?
/** * Backing buffer for the Bitmap. * Made public for quick access from drawing methods -- do NOT modify * from outside this class * * @hide */ @SuppressWarnings("UnusedDeclaration")// native code only publicbyte[] mBuffer;
其值是保存在byte数组中的, 我们需要的就是这个byte数组中的内容. 在Inspector窗口的mBuffer这一栏或者Dominator Tree视图的Bitmap这一栏点开下一级,都可以看到这个byte数组的内容. 鼠标右键选择Copy –>Save Value To File. 弹出如下对话框:
List objects -> with incoming references:查看这个对象持有的外部对象引用
List objects -> with outcoming references:查看这个对象被哪些外部对象引用
Path To GC Roots -> exclude all phantim/weak/soft etc. references:查看这个对象的GC Root,不包含虚、弱引用、软引用,剩下的就是强引用。从GC上说,除了强引用外,其他的引用在JVM需要的情况下是都可以 被GC掉的,如果一个对象始终无法被GC,就是因为强引用的存在,从而导致在GC的过程中一直得不到回收,因此就内存溢出了。
Path To GC Roots -> exclude weak/soft references:查看这个对象的GC Root,不含弱引用和软引用所有的引用.
**Merge Shortest path to GC root **:找到从GC根节点到一个对象或一组对象的共同路径
Displays memory accumulation points in the dominator tree. Displayed are objects with a big difference between the retained size of the parent and the children and the first “interesting” dominator of the accumulation point. These are places where the memory of many small objects is accumulated under one object.
之后我打开了另一个强大的工具却很少用到的工具:Tracer for OpenGL 。我之前的那篇文章解释了如何使用工具获得更多细节。你首先需要知道的是这个工具收集了所有UI界面发给GPU的绘制命令。
Android 4.3 and up: Tracer has unfortunately become a little more difficult to use since Android 4.3 when we introducedreordering and merging of drawing commands. It’s an amazingly useful optimization but it prevents Tracer from grouping drawing commands by view. You can restore the old behavior by disabling display lists optimization using the following command (before you start your application)(意思是说Android4.3之后,这个工具不太好用了,因为有reordering and merging 机制的引进)
Reading OpenGL traces: Commands shown in blue are GL operations that draw pixels on screen. All other commands are used to transfer data or set state and can easily be ignored. Every time you click on one of the blue commands, Tracer will update the Details tab and show you the content of the current render target right after the command you clicked is executed. You can thus reconstruct a frame by clicking on each blue command one after another. It’s pretty much how I analyze performance issues with Tracer. Seeing how a frame is rendered gives a lot of insight on what the application is doing.(意思是说只蓝色的行是真正进行绘制的命令,点击可以看到绘制的这一帧的图像,其他的命令都是一些数据的转换)
我和Chet 在很多演示中解释过为什么你应该 use alpha with care,每次UI控件使用一个临时的Layer,绘制命令会发送不同的渲染目标,对GPU来说,切换渲染目标是很昂贵的操作,这对于使用tiling/deferred架构的GPU(ImaginationTech’s SGX, Qualcomm’s Adreno, etc)等是硬伤,直接渲染架构的GPU,比如 Nvidia,则会好一点。因为我和Joaquim 使用的是搭载高通处理器的Moto X 2014版本,所以使用多个临时硬件层是最有可能的性能问题的根源。
Use a customizable “inactive” color instead of setting an opacity on the View( 使用动态的“inactive”颜色(即根据状态来设置View的颜色)而不是设置透明度。)
Return false from hasOverlappingRendering() and the framework will set the proper alpha on the Paint for you(使hasOverlappingRendering()返回false,这样系统会设置适当的alpha,关于这个的用法,这篇文章中有提到:同时Android提供了hasOverlappingRendering()接口,通过重写该接口可以告知系统当前View是否存在内容重叠的情况,帮助系统优化绘制流程,原理是这样的:对于有重叠内容的View,系统简单粗暴的使用 offscreen buffer来协助处理。当告知系统该View无重叠内容时,系统会分别使用合适的alpha值绘制每一层。)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
/** * Returns whether this View has content which overlaps. This function, intended to be * overridden by specific View types, is an optimization when alpha is set on a view. If * rendering overlaps in a view with alpha < 1, that view is drawn to an offscreen buffer * and then composited it into place, which can be expensive. If the view has no overlapping * rendering, the view can draw each primitive with the appropriate alpha value directly. * An example of overlapping rendering is a TextView with a background image, such as a * Button. An example of non-overlapping rendering is a TextView with no background, or * an ImageView with only the foreground image. The default implementation returns true; * subclasses should override if they have cases which can be optimized. * * @return true if the content in this view might overlap, false otherwise. */ publicbooleanhasOverlappingRendering() { returntrue; }
Return true from onSetAlpha() and set an alpha on the Paint used to draw the “gray” circles(使onSetAlpha() 返回True并对Paint设置alpha来绘制“gray”圆圈)