安卓內存優(yōu)化是一個很重要的話題聋涨,有很多方面可以考慮,比如避免內存泄漏溉躲、減少內存抖動榜田、優(yōu)化圖片加載、使用緩存和對象池等锻梳。下面我舉一些代碼案例箭券,分別展示不合適的寫法和高性能的寫法。
歡迎評論區(qū)留言指正和補充唱蒸。
使用靜態(tài)內部類或者弱引用來避免非靜態(tài)內部類持有外部類的引用邦鲫,造成內存泄漏。
// 不合適的寫法
public class MainActivity extends AppCompatActivity {
private MyTask task;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
task = new MyTask();
task.execute();
}
private class MyTask extends AsyncTask<Void, Void, Void> {
// 這是一個非靜態(tài)內部類,它會隱式地持有外部類的引用
@Override
protected Void doInBackground(Void... params) {
// do some background work
return null;
}
}
}
// 高性能的寫法
public class MainActivity extends AppCompatActivity {
private MyTask task;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
task = new MyTask(this);
task.execute();
}
private static class MyTask extends AsyncTask<Void, Void, Void> {
// 這是一個靜態(tài)內部類庆捺,它不會持有外部類的引用
private WeakReference<MainActivity> activityRef;
public MyTask(MainActivity activity) {
activityRef = new WeakReference<>(activity);
}
@Override
protected Void doInBackground(Void... params) {
// do some background work
return null;
}
}
}
這樣做可以避免內存泄漏古今,因為如果MainActivity被銷毀,而MyTask還在后臺運行滔以,那么非靜態(tài)內部類會導致MainActivity無法被回收捉腥,而靜態(tài)內部類或者弱引用則不會。這樣可以節(jié)省內存空間你画,并提高性能抵碟。
使用單例模式時,注意使用Application的Context坏匪,而不是Activity的Context拟逮,避免Activity無法被回收。
// 不合適的寫法
public class MySingleton {
private static MySingleton instance;
private Context context;
private MySingleton(Context context) {
this.context = context;
}
public static MySingleton getInstance(Context context) {
if (instance == null) {
instance = new MySingleton(context); // 這里使用了Activity的Context适滓,會導致Activity無法被回收
}
return instance;
}
}
// 高性能的寫法
public class MySingleton {
private static MySingleton instance;
private Context context;
private MySingleton(Context context) {
this.context = context.getApplicationContext(); // 這里使用了Application的Context敦迄,不會導致Activity無法被回收
}
public static MySingleton getInstance(Context context) {
if (instance == null) {
instance = new MySingleton(context);
}
return instance;
}
}
這樣做可以避免內存泄漏,因為如果Activity被銷毀凭迹,而MySingleton還在使用它的Context罚屋,那么Activity無法被回收,而Application的Context則不會嗅绸。這樣可以節(jié)省內存空間脾猛,并提高性能。
使用Proguard或者R8等工具來混淆和壓縮代碼鱼鸠,減少方法數(shù)和字節(jié)碼大小猛拴。例如:
android {
buildTypes {
release {
minifyEnabled true // 這里開啟了代碼混淆和壓縮
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
shrinkResources true // 這里開啟了資源文件壓縮
}
}
}
這樣做可以減少APK的體積,提高應用的安全性和運行效率瞧柔。
使用Lint工具來檢測和移除無用的資源文件漆弄,減少APK的體積。例如:
android {
lintOptions {
checkReleaseBuilds true // 這里開啟了Lint檢查
abortOnError true // 這里設置了如果發(fā)現(xiàn)錯誤就終止編譯
}
}
這樣做可以減少APK的體積造锅,提高應用的運行效率和質量。
使用inBitmap選項來復用Bitmap的內存空間廉邑,減少內存分配哥蔚。例如:
// 不合適的寫法
BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = false;
Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.image, options); // 這里沒有使用inBitmap選項,會導致每次都分配新的內存空間
// 高性能的寫法
BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = false;
options.inBitmap = reusableBitmap; // 這里使用了inBitmap選項蛛蒙,會復用已有的內存空間糙箍,reusableBitmap是一個合適大小的位圖對象
Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.image, options);
這樣做可以減少內存分配和回收的次數(shù),提高性能和流暢度牵祟。
使用inSampleSize選項來按比例縮放圖片深夯,避免加載過大的圖片。例如:
// 不合適的寫法
BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = false;
Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.image, options); // 這里沒有使用inSampleSize選項,會加載原始大小的圖片咕晋,占用內存空間雹拄,并可能導致OOM
// 高性能的寫法
BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeResource(getResources(), R.drawable.image, options); // 這里先獲取圖片的原始寬高,不加載圖片到內存中
int width = options.outWidth;
int height = options.outHeight;
int inSampleSize = 1; // 這里根據(jù)需要計算一個合適的縮放比例掌呜,例如根據(jù)視圖的大小和屏幕密度等因素
options.inJustDecodeBounds = false;
options.inSampleSize = inSampleSize; // 這里使用inSampleSize選項滓玖,會按比例縮放圖片,節(jié)省內存空間质蕉,并避免OOM
Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.image, options);
這樣做可以避免加載過大的圖片势篡,節(jié)省內存空間,并提高圖片加載的效率和質量模暗。
優(yōu)化布局文件禁悠,減少布局層級和冗余控件,使用include兑宇、merge绷蹲、ViewStub等標簽來復用和延遲加載布局。例如:
<!-- 不合適的寫法 -->
<LinearLayout android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<TextView android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Title" />
<LinearLayout android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<ImageView android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/icon" />
<TextView android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Content" />
</LinearLayout>
</LinearLayout>
<!-- 高性能的寫法 -->
<merge xmlns:android="http://schemas.android.com/apk/res/android">
<TextView android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Title" />
<ImageView android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/icon" />
<TextView android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Content" />
</merge>
這樣做可以減少布局層級和冗余控件顾孽,提高布局加載和渲染的效率和流暢度祝钢。如果想要復用和延遲加載布局,可以使用include若厚、merge拦英、ViewStub等標簽來實現(xiàn)。