Optimization caused by one OOM
I have recently studied an application with simple functions, so I want to work hard on the UI.
Thoughts on the interface:
Page a adds, deletes, and modifies a certain type of data items and saves them to the database. Page B displays the existing data items in the database in a custom view (one data item corresponds to one view) to implement a layout similar to the Metro style.
Implementation
- It is not difficult to customize the view. It is a beginner, so it may be time-consuming in data adapter display and size calculation.
- The original idea was to extend a linearlayout class to adapt and display the list data. However, you still need to learn about custom viewgroup, so you have to write an adapter that inherits the baseadapter.
The implementation principle is basically like this in XML, but it is implemented by code in the adapter...
<Linearlayout root node, vertical in the direction> <linearlayout primary node, horizontal in the direction> <myview> </linearlayout> <linearlayout primary node, direction: horizontal> <myview> </linearlayout>... </linearlayout>
At first, I felt that the efficiency would be very low... After all, this layer of layout is nested.
OOM
Sure enough. Unexpectedly, it took three seconds to enter the page, card, and refresh the custom view layout .. the display Metro layout is in one fragment. When switching to another fragment and then switching back, the program crashes due to re-reading data, adapting and refreshing the UI, check the log. It's oom.
Try 1:
Read and adapt data to sub-threads, and only refresh data in the UI thread.
The result is that the UI is not very slow when you enter the fragment, but there is no obvious effect on OOM.The reason for oom is that the custom view is refreshed repeatedly.
Try 2:
An ID variable is added to the refresh thread and handler class that is responsible for refreshing the UI to monitor whether the data source has changed. If there is any data change in the data source, the next time you enter the fragment, You need to retrieve data, adapt to, and refresh the view; otherwise, the view remains unchanged.
As a result, there is no problem in switching back and forth between fragment, but when the other activity jumps back to the specific fragment in the main activity (that is, the activity that holds the fragment), oom... In addition, when the data source changes and the view is refreshed again, the same OOM...It indicates that the memory space occupied by the previous several times has not been cleared by GC because of the loss of reference... Therefore, the result of multiple refreshes is that the memory is used up.
Try 3:
In my sleep, I suddenly thought that I could read, adapt, and refresh the custom view in the main activity and directly pass the view to fragment for direct display? In this way, when the main activity is returned from another activity and a specific fragment is displayed, the oncreateview method of fragment does not need to refresh the custom view repeatedly. After all, the returned value of this method is a view.
However, the results are useless...The reason is that the constructor of fragment is either default, or the parameter can only be of the bundle type, but the bundle type parameter cannot pass the view object...
Try 4:
Since all the wonderful tricks are useless, we can only look at how to reduce the memory usage of the custom view during the rendering process...
1. Idea 1: Reduce the image size. In a custom view, a PNG image with a size of 100*100 is required. narrowing down the size of a single image may be helpful.
2. Idea 2. I remember reading a blog (Android performance optimization model (II) the night before. [http://android.jobbole.com/80938/here I talked about some things in the east and west... The following are some examples
"In general, for an opaque view, it only needs to be rendered once, but if the view is set with an Alpha value, it will need to be rendered at least twice. The reason is that a view containing alpha needs to know in advance what the next layer of the mixed view is, and then perform blend mixed color Processing Based on The View on the upper layer ."
"Do not execute operations that cause memory allocation in the ondraw () method. The ondraw () method is executed in the UI thread. do not perform any operations that may affect performance in the UI thread. Although the memory allocation operation does not require too much system resources, it does not mean that there is no cost for free. The device has a certain refresh frequency. As a result, the ondraw method of the view is frequently called. If the ondraw method is inefficient, the problem of low efficiency will be extended due to the effect of frequent refresh accumulation, then it will have a serious impact on the performance. If you execute the memory allocation operation in ondraw, it will easily lead to memory jitter and frequent GC triggering, although GC was later improved to be executed in another background thread (GC operations were synchronized before 2.3, followed by concurrency), frequent GC operations will still affect the CPU, affects power consumption."
"Minimizing the size of PNG images is an important criterion in Android. Compared with JPEG, PNG can provide clear and lossless images, but the images in PNG format are larger, occupying more disk space. Whether to use PNG or JPEG requires careful measurement by the designer. If JPEG can be used to achieve the visual effect, you can use JPEG ."
"Re-using bitmaps"
So I made the following changes:
- Since the background color does not require transparency, I changed the original argb format to the RGB format.
- I have read a bitmap cache method before. I used soft references and searched for it online for further study. Below is the code
Package COM. mmrx. health. util; import android. content. context; import android. graphics. bitmap; import android. graphics. bitmapfactory; import Java. lang. ref. referencequeue; import Java. lang. ref. softreference; import Java. util. hashtable;/*** created by mmrx on 2015/5/7. */public class bitmapcache {static private bitmapcache cache;/** used for cache content storage */private hashtable <integer, mysoftref> hashrefs;/** junk ref Erence Queue (if the referenced object has been recycled, the reference is stored in the queue) */private referencequeue <bitmap> q;/*** inherits softreference, each instance is identified. */Private class mysoftref extends softreference <bitmap> {private integer _ key = 0; Public mysoftref (bitmap BMP, referencequeue <bitmap> q, int key) {super (BMP, q); _ key = Key ;}/// private constructor private bitmapcache () {hashrefs = new hashtable <integer, mysoftref> (); Q = new referencequeue <bitmap> () ;}/ *** get the cache instance **/public static bitmapcache getinstance () {If (Cache = NULL) cache = new bitmapcache (); RET Urn cache;}/*** reference a bitmap object instance in soft reference mode and save the reference */private void addcachebitmap (bitmap BMP, integer key) {// clear cleancache (); mysoftref ref = new mysoftref (BMP, Q, key); hashrefs. put (Key, ref);}/*** according to the ID of the image resource under the specified drawable (you can obtain it from the network or local path as needed) * Re-obtain the instance of the corresponding bitmap object */Public bitmap getbitmap (INT resid, context) {bitmap BMP = NULL; // check whether soft references of the bitmap instance exist in the cache, if yes, obtain if (hashrefs. contains Key (resid) {mysoftref ref = (mysoftref) hashrefs. get (resid); BMP = (Bitmap) ref. get ();} // if there is no soft reference, or the Instance obtained from the soft reference is null, re-build an instance, // Save the soft reference if (BMP = NULL) {BMP = bitmapfactory for the new instance. decodestream (context. getresources (). openrawresource (resid); this. addcachebitmap (BMP, resid);} return BMP;} private void cleancache () {mysoftref ref = NULL; while (ref = (mysoftref) Q. poll ())! = NULL) hashrefs. remove (ref. _ key);}/*** clear all content in the cache */Public void prepare AchE () {cleancache (); hashrefs. clear (); system. GC (); system. runfinalization ();}}
After the above two tricks are used, it will be easy to use ~ The custom view refresh waist is no longer sour and does not hurt, so hurry and replace the just-arrived key hat ~~
Summary
All the difficulties are paper tigers (if you find the correct solution )... OOM is mostly caused by bitmap!
Optimization caused by one OOM