It has been more than a year since I joined the company in July last year (2018/7/13) and now (2019/8/15). In this year, I have learned a lot from being a rookie. I have recorded the code optimization and performance optimization experience in the development process, which is convenient for others to avoid detour.
Performance optimization
1. Memory consumption caused by packing
Boolean isShow =new Boolean(true);Copy the code
The above code causes the following problems:
//boolean
Boolean isShow =Boolean.TRUE ;
//integer
Integer i= 2;
Copy the code
SharedPreferences uses commit to block threads
final SharedPreferences.Editor edit = settings.edit();
edit.putBoolean(TIPS, true);
edit.commit();
Copy the code
The above code causes the following problems:
Error location of selector item
error
<?xml version="1.0" encoding="utf-8"? >
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@drawable/normal" />
<item android:drawable="@drawable/pressed" android:state_pressed="true"/>
</selector>
Copy the code
The selector above causes the following problem
<?xml version="1.0" encoding="utf-8"? >
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@drawable/pressed" android:state_pressed="true"/>
<item android:drawable="@drawable/normal" />
</selector>
Copy the code
If none of the previous items match, the last item will be selected.
Memory leak caused by context
public static WifiManager getWIFIManager(Context ctx) {
WifiManager wm = (WifiManager) ctx.getSystemService(Context.WIFI_SERVICE);
}
Copy the code
The above code directly uses the context to get the system’s WiFi service, causing the following problems
public static WifiManager getWIFIManager(Context ctx) {
WifiManager wm = (WifiManager) ctx.getApplicationContext().getSystemService(Context.WIFI_SERVICE);
}
Copy the code
Why not use the activity context instead of the application context? Since the context life cycle of an activity is the same as that of an activity, the context should also be released when the activity is released. In this case, because the context is held by wifiManager, the activity cannot be released, resulting in a memory leak. The context life cycle of an application is consistent with the application life cycle. So when retrieving resources that are not related to the current activity lifecycle but related to the entire application lifecycle, use the application context.
public Context getApplicationContext (a)
/*Return the context of the single, global Application object of the current process. This generally should only be used if you need a Context whose lifecycle is separate from the current context, that is tied to the lifetime of the process rather than the current component.
*/
Copy the code
5. Use SparseArray instead of HashMap
In Android, SparseArray can be used to replace HashMap if the key in <key,value> is the basic data type: int, Long, etc., to avoid memory consumption caused by automatic packing and entry in HashMap. There are several types of <key,value> that can be replaced by SparseArray:
SparseArray <Integer, Object>
SparseBooleanArray <Integer, Boolean>
SparseIntArray <Integer, Integer>
SparseLongArray <Integer, Long>
LongSparseArray <Long, Object>
LongSparseLongArray <Long, Long> //this is not a public class
Copy the code
Compare SparseIntArray with HashMap<Integer, Integer> as follows: SparseIntArray
SparseIntArray
class SparseIntArray {
int[] keys;
int[] values;
int size;
}
Copy the code
Class = 12 + 3 * 4 = 24 bytes Array = 20 + 1000 * 4 = 4024 bytes Total = 8,072 bytes
HashMap
class HashMap<K.V> {
Entry<K, V>[] table;
Entry<K, V> forNull;
int size;
int modCount;
int threshold;
Set<K> keys
Set<Entry<K, V>> entries;
Collection<V> values;
}
Copy the code
Class = 12 + 8 x 4 = 48 bytes Entry = 32 + 16 + 16 = 64 bytes Array = 20 + 1000 x 64 = 64024 bytes Total = 64,136 bytes As you can see, HashMap takes up almost eight times as much memory as SparseIntArray for the same elements.
The disadvantage of SparseIntArray
SparseIntArray uses binary lookup to find keys, so it can’t find an element as fast as a Hashmap. Therefore, SparseIntArray can be used when the amount of data is small, but hashMap can be used when the amount of data is very large, resulting in higher search speed.
6, custom view in layout, draw, onMeasue in the new object
The problem code
pubic class myview extends View
{
public myview(Context context) {
super(context);
}
@Override
protected void onDraw(Canvas canvas)
{
super.onDraw(canvas);
int x=80;
int y=80;
int radius=40;
Paint paint=new Paint();
// Use Color.parseColor to define HTML colors
paint.setColor(Color.parseColor("#CD5C5C")); canvas.drawCircle(x,x, radius, paint); }}Copy the code
The onLayout,onDraw, and onMeasue methods are often overridden for custom views, but be aware that new objects in these methods have the following problems
Optimize the code
public class myview extends View
{
int x;
int y;
intradius; Paint Paint.public myview(Context context) {
super(context);
init();
}
@Override
protected void onDraw(Canvas canvas)
{
super.onDraw(canvas);
// Use Color.parseColor to define HTML colors
paint.setColor(Color.parseColor("#CD5C5C"));
canvas.drawCircle(x,x, radius, paint);
}
private voidInit () {x=80;
y=80;
radius=40;
paint=newPaint(); }}Copy the code
The onLayout,onDraw, and onMeasue methods cannot be used to execute new objects and initialize them.
Creating objects ahead of time is an important optimization. Views are redrawn very frequently, and many drawing objects require expensive initialization. Creating drawing objects within your onDraw() method significantly reduces performance and can make your UI appear sluggish.
To summarize, it is best to initialize and new objects in advance when customizing a view, because onDraw, onMeasure, and onLayout methods are called frequently. If you initialize and new objects in this view, frequent GC operations will seriously affect performance and may cause frame drop.
Ondraw is called when the view is initialized. 2. When the view’s invalidate() method is called. When is the invalidate() method called? The onDraw method is called when the view state needs to change, such as when botton is clicked, editText is typed, etc.
Memory leaks caused by static variables
The problem code
public class MyDlg extends Dialog {
private View mDialog;
private static MyDlg sInstance;
public MyDlg(Context context) {
super(context);
sInstance = this;
init();
}
private void init(a) {
mDialog = LayoutInflater.from(mCtx).inflate(R.layout.dialog_app_praise, null);
setContentView(mDialog);
}
Copy the code
The above code causes the following problems:
8. Overdraw problem
The problem code
<?xml version="1.0" encoding="UTF-8"? >
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical"
android:background="@drawable/layout_content_bkg" >
<include layout="@layout/title_bar" />
<ScrollView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="12dip"
android:scrollbars="vertical" >
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:background="@drawable/layout_content_bkg"
android:layout_marginTop="14dip"
android:paddingLeft="13dip"
android:paddingRight="13dip" >.</LinearLayout>
</ScrollView>
</LinearLayout>
Copy the code
The background of the linearLayout in the above code is the same as the background in the ScrollView. You just need to keep the background in the parent LinearLayout, otherwise you will draw more than once, which will cause the overdraw problem.
9. Inefficent Layout weight
The problem code
<LinearLayout
android:layout_width="match_parent"
android:layout_height="48dp"
android:layout_gravity="bottom"
android:background="@color/white"
android:gravity="center_vertical"
android:orientation="horizontal"
>
<TextView
android:layout_weight="1"
android:id="@+id/text"
android:layout_width="165dp"
android:layout_height="wrap_content"
android:layout_marginLeft="15dp"
android:textSize="15sp" />
<android.support.v7.widget.SwitchCompat
android:checked="true"
android:id="@+id/0checkbox"
android:layout_width="wrap_content"
android:layout_height="36dp"
android:layout_marginEnd="15dp" />
</LinearLayout>
Copy the code
Textview layout_weight=”1″. Textview layout_width=”165dp”. This brings up the following questions
10, string operation optimization
String text="bitch";/ / 1
StringBuilder.append(" fuck " + text);
/ / 2
mStringBuilder.append(" fuck ").append(text);
Copy the code
Which code, 1 or 2, performs better? The second method performs better. The first method creates a new “fuck” +text string and appends it to StringBuilder, while the second method does not create a new string, so it performs better.
Code optimization
1, Eliminate redundant “collection.addall ()”
Original code:
ArrayList<BaseFile> lists = null;
if(getImages() ! =null) {
lists = new ArrayList<>();
lists .addAll(getImages());
}
Copy the code
Optimized code:
ArrayList<BaseFile> lists = null;
if(getImages() ! =null) {
lists = new ArrayList<>(getImages());
}
Copy the code
2. Use the array copy method
Original code:
for(int i=0; i<ITEM_SIZE; i++){ mContentsArray[i] = contents[i]; }Copy the code
Optimized code:
System.arraycopy(contents, 0, mContentsArray, 0, ITEM_SIZE);
Copy the code
reference
1, stackoverflow.com/questions/5…
2, stackoverflow.com/questions/4…
3 developer.android.com/reference/a…
4, stackoverflow.com/questions/2…
5, developer.android.com/training/cu… 6, stackoverflow.com/questions/1…