安卓内存优化案例二

安卓内存优化是一个很重要的话题,有很多方面可以考虑,比如避免内存泄漏、减少内存抖动、优化图片加载、使用缓存和对象池等。下面我举一些代码案例,分别展示不合适的写法和高性能的写法。
欢迎评论区留言指正和补充。

11. 避免使用 AsyncTask 来执行异步任务。

AsyncTask 的内部实现是使用一个线程池和一个消息队列来管理任务,这会占用内存空间,并可能导致内存泄漏和并发问题。如果需要执行异步任务,可以使用 RxJava 或者 Coroutine 等库来代替。例如:

// 不合适的写法
private class MyTask extends AsyncTask<Void, Void, String> {

    private WeakReference<Context> contextRef;

    public MyTask(Context context) {
        contextRef = new WeakReference<>(context);
    }

    @Override
    protected String doInBackground(Void... params) {
        // do some background work
        return "result";
    }

    @Override
    protected void onPostExecute(String result) {
        Context context = contextRef.get();
        if (context != null) {
            // do something with result and context
        }
    }
}

// 高性能的写法
private fun doAsyncTask(context: Context) {
    CoroutineScope(Dispatchers.IO).launch {
        // do some background work
        val result = "result"
        withContext(Dispatchers.Main) {
            // do something with result and context
        }
    }
}

这样做可以避免不必要的内存分配和回收,避免内存泄漏和并发问题,并提高异步任务的管理和调度。

12. 避免使用 BitmapFactory 来加载图片。

BitmapFactory 的内部实现是使用 nativeDecodeStream 方法来解码图片,这会消耗较多的内存空间,并可能导致OOM。如果需要加载图片,可以使用 Glide 或者 Picasso 等库来代替。例如:

// 不合适的写法
ImageView imageView = findViewById(R.id.image_view);
Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.image); // 这会创建一个原始大小的位图对象,占用内存空间,并可能导致OOM
imageView.setImageBitmap(bitmap);

// 高性能的写法
ImageView imageView = findViewById(R.id.image_view);
Glide.with(this).load(R.drawable.image).into(imageView); // 这会根据视图的大小和屏幕密度来加载合适大小的位图对象,节省内存空间,并避免OOM

这样做可以避免不必要的位图对象的创建,节省内存空间,并提高图片加载的效率和质量。

13. 避免使用 Serializable 接口来实现序列化。

Serializable 接口的内部实现是使用反射机制来序列化和反序列化对象,这会消耗较多的CPU和内存资源,并可能导致性能下降。如果需要实现序列化,可以使用 Parcelable 接口或者 ProtoBuf 等库来代替。例如:

// 不合适的写法
public class User implements Serializable {
    private String name;
    private int age;

    public User(String name, int age) {
        this.name = name;
        this.age = age;
    }

    // getter and setter methods
}

// 高性能的写法
public class User implements Parcelable {
    private String name;
    private int age;

    public User(String name, int age) {
        this.name = name;
        this.age = age;
    }

    // getter and setter methods

    @Override
    public int describeContents() {
        return 0;
    }

    @Override
    public void writeToParcel(Parcel dest, int flags) {
        dest.writeString(name);
        dest.writeInt(age);
    }

    public static final Parcelable.Creator<User> CREATOR = new Parcelable.Creator<User>() {

        @Override
        public User createFromParcel(Parcel source) {
            return new User(source.readString(), source.readInt());
        }

        @Override
        public User[] newArray(int size) {
            return new User[size];
        }
    };
}

这样做可以避免不必要的反射操作,节省CPU和内存资源,并提高序列化和反序列化的效率。

14. 避免使用 LinkedList 来存储数据。

LinkedList 的内部实现是使用一个双向链表来存储数据,这会占用较多的内存空间,并且可能导致内存碎片。如果需要存储数据,可以使用 ArrayList 或者 ArrayDeque 来代替。例如:

// 不合适的写法
LinkedList<String> list = new LinkedList<>();
list.add("a");
list.add("b");
list.add("c");

// 高性能的写法
ArrayList<String> list = new ArrayList<>();
list.add("a");
list.add("b");
list.add("c");

这样做可以节省内存空间,因为 ArrayListArrayDeque 的内部实现是使用一个数组来存储数据,没有额外的开销。另外,它们还可以提供更快的随机访问和迭代的性能。

15. 避免使用 StringTokenizer 来分割字符串。

StringTokenizer 的内部实现是使用一个字符数组来存储字符串,并且每次调用 nextToken() 方法都会创建一个新的字符串对象,这会消耗较多的CPU和内存资源,并可能导致GC。如果需要分割字符串,可以使用 split() 方法或者 Scanner 类来代替。例如:

// 不合适的写法
StringTokenizer st = new StringTokenizer("Hello World!");
while (st.hasMoreTokens()) {
    String token = st.nextToken(); // 每次调用都会创建一个新的字符串对象
    // do something with token
}

// 高性能的写法
String[] tokens = "Hello World!".split(" "); // 这只会创建一个字符串数组对象
for (String token : tokens) {
    // do something with token
}

这样做可以避免不必要的字符串对象的创建,节省CPU和内存资源,并提高字符串分割的效率。

16. 避免使用 SimpleDateFormat 来格式化日期和时间。

SimpleDateFormat 的内部实现是使用一个 Calendar 对象来存储日期和时间,并且每次调用 format() 方法都会创建一个新的 Date 对象,这会消耗较多的CPU和内存资源,并可能导致GC。如果需要格式化日期和时间,可以使用 DateTimeFormatter 或者 FastDateFormat 等库来代替。例如:

// 不合适的写法
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
Date date = new Date();
String formattedDate = sdf.format(date); // 每次调用都会创建一个新的日期对象

// 高性能的写法
DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
LocalDateTime date = LocalDateTime.now();
String formattedDate = dtf.format(date); // 这不会创建任何新的对象

这样做可以避免不必要的日期对象的创建,节省CPU和内存资源,并提高日期和时间格式化的效率。

17. 避免使用 SparseIntArray 来存储稀疏矩阵。

SparseIntArray 的内部实现是使用两个数组来存储键和值,这会占用较多的内存空间,并且可能导致数组扩容和复制。如果需要存储稀疏矩阵,可以使用 SparseMatrix 或者 EJML 等库来代替。例如:

// 不合适的写法
SparseIntArray matrix = new SparseIntArray();
matrix.put(0, 1);
matrix.put(1, 2);
matrix.put(2, 3);

// 高性能的写法
SparseMatrix matrix = new SparseMatrix(3, 3);
matrix.set(0, 0, 1);
matrix.set(1, 1, 2);
matrix.set(2, 2, 3);

这样做可以节省内存空间,因为 SparseMatrixEJML 的内部实现是使用一个链表或者一个哈希表来存储非零元素,没有额外的开销。另外,它们还可以提供更快的矩阵运算和转置的性能。

18. 避免使用 JSONObject 来解析JSON字符串。

JSONObject 的内部实现是使用一个 HashMap 来存储键值对,这会占用较多的内存空间,并且可能导致哈希冲突和扩容。如果需要解析JSON字符串,可以使用 Gson 或者 Moshi 等库来代替。例如:

// 不合适的写法
String json = "{\"name\":\"Alice\",\"age\":18}";
JSONObject jsonObject = new JSONObject(json); // 这会创建一个哈希表对象,占用内存空间,并可能导致哈希冲突和扩容
String name = jsonObject.getString("name");
int age = jsonObject.getInt("age");

// 高性能的写法
String json = "{\"name\":\"Alice\",\"age\":18}";
Gson gson = new Gson();
User user = gson.fromJson(json, User.class); // 这会直接创建一个用户对象,节省内存空间,并提高JSON解析的效率
String name = user.getName();
int age = user.getAge();

这样做可以避免不必要的哈希表对象的创建,节省内存空间,并提高JSON解析的效率和质量。

19. 避免使用 Random 类来生成随机数。

Random 类的内部实现是使用一个线性同余发生器来生成随机数,这会导致随机数的质量不高,并且可能导致并发问题。如果需要生成随机数,可以使用 ThreadLocalRandom 或者 SecureRandom 等类来代替。例如:

// 不合适的写法
Random random = new Random();
int n = random.nextInt(10); // 这会生成一个不太随机的整数,并且可能导致并发问题

// 高性能的写法
int n = ThreadLocalRandom.current().nextInt(10); // 这会生成一个更随机的整数,并且避免并发问题

这样做可以提高随机数的质量和安全性,并避免并发问题。

20. 避免使用 Log 类来打印日志。

Log 类的内部实现是使用一个 PrintStream 对象来输出日志到控制台或者文件,这会消耗较多的CPU和内存资源,并且可能导致IO阻塞和性能下降。如果需要打印日志,可以使用 Timber 或者 Logger 等库来代替。例如:

// 不合适的写法
Log.d("TAG", "Hello World!"); // 这会输出一条日志到控制台或者文件,消耗CPU和内存资源,并且可能导致IO阻塞和性能下降

// 高性能的写法
Timber.d("Hello World!"); // 这会输出一条日志到控制台或者文件,节省CPU和内存资源,并提高日志输出的效率和质量

这样做可以避免不必要的IO操作,节省CPU和内存资源,并提高日志输出的效率和质量。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,233评论 6 495
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,357评论 3 389
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 159,831评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,313评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,417评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,470评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,482评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,265评论 0 269
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,708评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,997评论 2 328
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,176评论 1 342
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,827评论 4 337
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,503评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,150评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,391评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,034评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,063评论 2 352

推荐阅读更多精彩内容

  • 安卓内存优化是一个很重要的话题,有很多方面可以考虑,比如避免内存泄漏、减少内存抖动、优化图片加载、使用缓存和对象池...
    长点点阅读 145评论 0 1
  • 内存优化前我们先了解一些和内存相关的概念: 垃圾回收 内存抖动 四种引用 内存泄露 下面我们回到正题, 讲一下如何...
    MZzF2HC阅读 1,687评论 0 6
  • 通常情况下我们说的内存是指手机的RAM,它主要包括一下几个部分1.寄存器 :速度最快的存储场所,因为寄存器位于...
    gogoingmonkey阅读 1,328评论 1 10
  • 内存泄露产生的原因:短生命周期对象被长生命周期对象引用,短生命周期对象功能周期结束后,长生命周期对象还没有释放该引...
    carlwu_186阅读 918评论 0 0
  • Bitmap内存优化:Bitmap是内存消耗大户,绝大多数的OOM崩溃都是在操作Bitmap时产生的,下面来看看如...
    一航jason阅读 438评论 0 0