Android性能优化之内存优化解析

86 阅读2分钟

1. 避免内存泄漏

内存泄漏通常是由于长生命周期对象持有短生命周期对象的引用导致的。可以使用静态代码分析工具(如LeakCanary)检测内存泄漏。

// 避免
public class MyActivity extends AppCompatActivity {
    private MyObject myObject;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_my);
        myObject = new MyObject();
        // ...
    }
}

// 推荐
public class MyActivity extends AppCompatActivity {
    private MyObject myObject;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_my);
        myObject = new MyObject();
        // ...
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        if (myObject != null) {
            myObject = null; // 显式设置为null,避免内存泄漏
        }
    }
}

2. 使用合适的数据结构

选择合适的数据结构可以减少内存使用,例如使用SparseArray替代HashMap来存储键值对。

// 使用SparseArray替代HashMap
private SparseArray<MyObject> sparseArray = new SparseArray<>();
sparseArray.put(key, value);

3. 图片内存优化

使用图像处理库(如Glide或Picasso)加载和缩放图片,并注意复用Bitmap。

// 使用Glide加载图片,并设置合适的内存和磁盘缓存
Glide.with(this)
    .load("https://example.com/image.jpg")
    .diskCacheStrategy(DiskCacheStrategy.ALL)
    .into(imageView);

4. 优化Bitmap内存使用

加载大型图片时,使用inSampleSize来降低图片的采样率,减少内存使用。

public Bitmap decodeSampledBitmapFromResource(Resources res, int resId, int reqWidth, int reqHeight) {
    final BitmapFactory.Options options = new BitmapFactory.Options();
    options.inJustDecodeBounds = true;
    BitmapFactory.decodeResource(res, resId, options);
    options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);
    options.inJustDecodeBounds = false;
    return BitmapFactory.decodeResource(res, resId, options);
}

public int calculateInSampleSize(BitmapFactory.Options options, int reqWidth, int reqHeight) {
    int width = options.outWidth;
    int height = options.outHeight;
    int inSampleSize = 1;

    if (width > reqWidth || height > reqHeight) {
        int halfWidth = width / 2;
        int halfHeight = height / 2;
        while ((halfWidth / inSampleSize) >= reqWidth && (halfHeight / inSampleSize) >= reqHeight) {
            inSampleSize *= 2;
        }
    }
    return inSampleSize;
}

5. 避免在静态实例中持有上下文

静态实例如果持有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);
        }
        return instance;
    }
}

// 推荐
public class MySingleton {
    private static MySingleton instance;

    private MySingleton() {
        // 不持有Context引用
    }

    public static MySingleton getInstance() {
        if (instance == null) {
            instance = new MySingleton();
        }
        return instance;
    }
}

6. 使用WeakReference

对于不是必须强引用的对象,可以使用WeakReference来减少内存泄漏的风险。

private WeakReference<MyObject> weakReference;

public void setMyObject(MyObject myObject) {
    weakReference = new WeakReference<>(myObject);
}

public MyObject getMyObject() {
    return weakReference != null ? weakReference.get() : null;
}

7. 避免使用大型数据集和大型对象

尽量使用更小的对象和集合,避免一次性加载过多数据。

8. 及时释放资源

在不需要时,及时释放对象资源,如关闭CursorStream等。

cursor.close();

9. 使用ProGuard

使用ProGuard移除无用的代码和Lint工具检查潜在的内存问题。

<!-- proguard-rules.pro -->
-keep class com.example.** { *; }
-dontwarn com.example.**

10. 避免使用finalize方法

finalize方法在对象被垃圾收集器回收时调用,可能导致不确定性和性能问题。

// 避免
@Override
protected void finalize() throws Throwable {
    super.finalize();
    // 清理资源
}

// 推荐
@Override
protected void onDestroy() {
    super.onDestroy();
    // 清理资源
}

更多Android教程见公主号:Android老皮