Android 项目优化

性能优化:

1、对项目中的大图进行压缩处理

首先进入到 https://tinypng.com/ (提供图片压缩的网站)

然后将需要进行压缩的大图进行压缩处理

未压缩时的内存消耗:

图片未压缩之前

压缩后的内存消耗:

图片压缩之后

2、尽量避免使用加号的方式拼接字符串

通过StringBuilder 来代替字符串的拼接

优化之前:

mTv_totalIndex.setText(datas.size()+"");

优化之后:

StringBuilder stringBuilder = new StringBuilder();
stringBuilder.append(datas.size());
stringBuilder.append("");
mTv_totalIndex.setText(stringBuilder.toString());

如若是TextView 需要设置多个字符串片段,那么可以使用textView.append()来进行拼接

3、for 循环优化

优化之前:

String[] data = {"张三","李四","王五"};
for (int i = 0; i <data.length ; i++) {
String str = data[i];
Log.i("TAG",str);
}

优化之后:

在循环之前,首先获取数组的长度,而不用每次遍历一遍的时候调用一次获取长度的函数,减少一次内存消耗

String[] data = {"张三","李四","王五"};
int length = data.length;
for (int i = 0; i <length ; i++) {
String str = data[i];
Log.i("TAG",str);
}

4、 使用 ArrayMap、SparseArray代替HashMap

注意:当前的ArrayMap 是 android.util.ArrayMap; 包下的类

ArrayMap 和 HashMap的在内存的使用上,更加高效。

ArrayMap实现上有两个数组,一个数组是保存key hash,另一个数组保存value,ArrayMap通过二分法(binary search)来进行查找的。

HashMap通过一个数组来实现的,key hash作为数组的索引,这样就需要更大的内存来减少key hash的冲突,key hash就是数组的索引,所以查找效率很高。

使用建议:

1、 当数据量比较小的时候(小于1000),优先使用ArrayMap,否则使用HashMap。

2、 map里嵌套map。

使用方法:

1、 ArrayMap和HashMap的使用方法都是一样的,ArrayMap也实现了Map接口。

2、 另外,ArrayMap可以通过keyAt(index)方法来获取第index位置的key,keyValue(int index)同理。但是HashMap是不可以的。

arrayMap.keyAt(0);
arrayMap.valueAt(0);

SparseArray和ArrayMap非常像,它们都是通过两种紧密包装的数组,而不是一个大的哈希散列,从而减少了整个内存的覆盖区。但是查询的速度就慢了。

只不过SparseArray和ArrayMap最大的区别是SparseArray的key是一个基本类型。

SparseArray的key是int类型,而不是Integer。像以前使用HashMap的时候,如果key是整形,必须是Integer。

Integer占16个字节,int只占4个字节,如果元素比较多,从而可以很好的减少内存的占用。

除了SparseArray类还有如下类可供使用:

 SparseBooleanMap <boolean,Object>
 SparseIntMap <int,Object>
 SparseLongMap <long,Object> 

SparseArray和ArrayMap的使用建议 和 使用方法都是一样的。

5、Thread与Thread Pool

在android开发中,一些耗时的操作都会放到后台线程去执行,比如:网络、本地文件、数据库等。

new Thread() {
    @Override
    public void run() {
        // 耗时操作      
    }
}.start();

每个线程至少消耗64k的内存,如果你在某个时间点,迅速开启了很多线程(比如加载列表图片,然后用户滑动列表),这个时候可能内存使用量就会飙升。

1、 会出现内存抖动(memory churn),因为短时间开启了很多线程,完成任务后,这些线程都会被回收。内存表现为:低-高-低。甚至可能出现OOM。

2、 一个系统所能处理的线程数量是有限的,如果超多了最大承载量,性能会受到很大的影响。而且可能还会影响用户的后续操作。

这时候Thread Pool线程池的作用就凸显出来了。

Java为我们提供了操作线程池的api ThreadPoolExecutor ,ExecutorService是一个接口,相关的线程池的类都实现了该接口,如 ThreadPoolExecutor 。

创建一个线程池可以通过 ThreadPoolExecutor类来实现。

package com.itheima.googleplay74.manager;

import java.util.concurrent.Executors;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.ThreadPoolExecutor.AbortPolicy;
import java.util.concurrent.TimeUnit;

/**
 * 线程管理器
 * 
 * @author Kevin
 * @date 2015-11-4
 */
public class ThreadManager {


    //利用单例模式中的懒汉式设计线程池(以确保内存中只有一个对象,节约系统资源同时提高系统的性能)
   //2.声明一个静态的ThreadPool类以确保对象唯一,private是为了防止外界修改ThreadPool类对象的值
   private static ThreadPool mThreadPool;

   //3.向外界暴露一个实例化ThreadPool类的方法
   public static ThreadPool getThreadPool() {
      //4.判断对象为空时就创建一个ThreadPool类的对象以确保该类只创建一次
      if (mThreadPool == null) {
         //6.同步锁是为了防止多个线程同时进入而导致同时创建多个对象的BUG
         synchronized (ThreadManager.class) {
            if (mThreadPool == null) {
               int cpuCount = Runtime.getRuntime().availableProcessors();// 获取cpu数量
               System.out.println("cup个数:" + cpuCount);

               // int threadCount = cpuCount * 2 + 1;//线程个数
               int threadCount = 10;
               mThreadPool = new ThreadPool(threadCount, threadCount, 1L);
            }
         }
      }

      //5.如果mThreadPool对象不为空那么就返回全局已经创建了的对象,共享这一个对象即可
      return mThreadPool;
   }

   // 线程池
   public static class ThreadPool {

      private int corePoolSize;// 核心线程数
      private int maximumPoolSize;// 最大线程数
      private long keepAliveTime;// 休息时间

      private ThreadPoolExecutor executor;

      //1.ThreadPool类的构造私有化使外界无法实例化该类
      private ThreadPool(int corePoolSize, int maximumPoolSize,
            long keepAliveTime) {
         this.corePoolSize = corePoolSize;
         this.maximumPoolSize = maximumPoolSize;
         this.keepAliveTime = keepAliveTime;
      }

      // 线程池几个参数的理解:
      // 比如去火车站买票, 有10个售票窗口, 但只有5个窗口对外开放. 那么对外开放的5个窗口称为核心线程数,
      // 而最大线程数是10个窗口.
      // 如果5个窗口都被占用, 那么后来的人就必须在后面排队, 但后来售票厅人越来越多, 已经人满为患, 就类似于线程队列已满.
      // 这时候火车站站长下令, 把剩下的5个窗口也打开, 也就是目前已经有10个窗口同时运行. 后来又来了一批人,
      // 10个窗口也处理不过来了, 而且售票厅人已经满了, 这时候站长就下令封锁入口,不允许其他人再进来, 这就是线程异常处理策略.
      // 而线程存活时间指的是, 允许售票员休息的最长时间, 以此限制售票员偷懒的行为.
      public void execute(Runnable r) {
         if (executor == null) {
            executor = new ThreadPoolExecutor(corePoolSize,
                  maximumPoolSize, keepAliveTime, TimeUnit.SECONDS,
                  new LinkedBlockingQueue<Runnable>(),
                  Executors.defaultThreadFactory(), new AbortPolicy());
            // 参1:核心线程数;参2:最大线程数;参3:线程休眠时间;参4:时间单位;参5:线程队列;参6:生产线程的工厂;参7:线程异常处理策略
         }

         // 线程池执行一个Runnable对象, 具体运行时机线程池说了算
         executor.execute(r);
      }

      // 取消任务
      public void cancel(Runnable r) {
         if (executor != null) {
            // 从线程队列中移除对象
            executor.getQueue().remove(r);
         }
      }

   }
}

6、通过AndroidStudio 中的 Profiler 工具对APP的内存使用情况进行分析

APK瘦身

参见 https://chiclaim.blog.csdn.net/article/details/105189854

1、通过 AndroidStudio 移除未使用的资源

手动移除资源有两个好处:一个是减少安装包的体积,另一个是减少源代码的体积。

在 AndroidStudio 中有两种方式帮我们找到未使用的资源:

1、Analyze -> Inspect Code,实际上就是通过 lint 工具帮我们找不用的资源,除了图片资源,还会帮我找到代码中存在的潜在问题,运行效果如下图所示:

2、双击 shift,输入 Remove Unused Resources,然后回车。由于上面的方式不仅找出未使用到的资源,还会检测代码,所以运行的比较耗时。如果你仅仅只想找出未使用的资源,可以使用双击 shift 的方式,它们检测的结果都是一样的。

Remove Unused Resources
Remove Unused Resources

2、分析APK包

在Android Studio 工具栏中的,打开 build>>Analyze APK ,然后选择要分析的APK包,然后就可以看到该APK中具体信息,如下图:

res res 是 resource 的缩写,这个目录存放资源文件,会自动生成对应的 ID 并映射到 .R 文件中,访问直接使用资源ID。

META-INF 保存应用的签名信息,签名信息可以验证 APK 文件的完整性。

AndroidManifest.xml 这个文件用来描述 Android 应用的配置信息,一些组件的注册信息、可使用权限等。

classes.dex Dalvik 字节码程序,让 Dalvik 虚拟机可执行,一般情况下,Android 应用在打包时通过Android SDK 中的 dx 工具将 Java 字节码转换为 Dalvik 字节码。

resources.arsc 记录着资源文件和资源 ID 之间的映射关系,用来根据资源 ID 寻找资源。

基于上面的组成部分,那么优化也可以从以下几个方面着手:

代码混淆 使用proGuard 代码混淆器工具,它包括压缩、优化、混淆等功能。

资源优化 比如使用 Android Lint 删除冗余资源,资源文件最少化等。

图片优化 比如利用 AAPT 工具对 PNG 格式的图片做压缩处理,降低图片色彩位数等。也可以通过 在线压缩工具

如果觉得文章有帮助到你,可以扫描以下二维码
   请本文作者 喝一杯
pay_weixin pay_weixin

发表评论

电子邮件地址不会被公开。 必填项已用*标注