安卓编程技巧总结(7) 性能检测代码分析


安卓性能分析的工具有很多,其中,较好用的工具,
如:AndroidStudio自带的Android Monitor(内存、网络、cpu、gpu)、腾讯的GT、第三方测试平台等。
如要使用第三方工具进行检测,请自行查询资料。

当然,也可以自己写代码进行测试。
本章,只是把各类性能检测分析的核心代码放出。
下面的代码经过测试,与Android Monitor、GT输出的结果一致:

  1. 内存
/**
 * 类:MemoryUtils
 * 作者: qxc
 * 日期:2017/12/15.
 */
public class MemoryUtils {
    private Context context;
    private Sampler sampler;
    private int timer;
    private String pageName;
    private String methodName;

    //数据结构:
    public static MemoryUtils memoryUtils;

    public static MemoryUtils getInstance() {
        if (memoryUtils == null) {
            synchronized (MemoryUtils.class) {
                if (memoryUtils == null) {
                    memoryUtils = new MemoryUtils();
                }
            }
        }
        return memoryUtils;
    }

    public void statMemory(Context context, int timer) {
        try {
            this.context = context;
            this.timer = timer;
            //按照设置timer开始监听内存变化
            if(sampler == null){
                sampler = new Sampler();
            }
            sampler.start();
        }catch (Exception ex){
            ex.printStackTrace();
        }
    }

    /**
     * 设置页面名称、方法名称
     * @param pageName 页面名称
     * @param methodName 方法名称
     */
    public void setPageInfo(String pageName, String methodName){
        this.pageName = pageName;
        this.methodName = methodName;
    }

    class Sampler implements Runnable {
        private ScheduledExecutorService scheduler;
        private Sampler() {
            scheduler = Executors.newSingleThreadScheduledExecutor();
        }

        public void start() {
            scheduler.scheduleWithFixedDelay(this, 0L, timer, TimeUnit.MILLISECONDS);
        }

        @Override
        public void run() {
            try {
                double memory = getMemory();
                Log.i(PerformanceConst.Tag, "@@ Sampler 记录内存");
                PageAnalysisStore.getInstance().storePageMemory(memory);
            }catch (Exception ex){
                ex.printStackTrace();
            }
        }

        //获取内存
        private double getMemory() {
            double totalMemory = Runtime.getRuntime().totalMemory() * 1.0 / (1024 * 1024);
            double freeMemory = Runtime.getRuntime().freeMemory() * 1.0 / (1024 * 1024);
            return totalMemory - freeMemory;
        }
    }
}

调用:

//开启Memory监控
MemoryUtils.getInstance().statMemory(context, timer);
  1. CPU
/**
 * 类:CpuUtils
 * 作者: qxc
 * 日期:2017/12/15.
 */
public class CpuUtils {
    private Context context;
    private String pageName;
    private String methodName;
    private Sampler sampler;
    private int timer;

    //数据结构:
    public static CpuUtils cpuUtils;
    public static CpuUtils getInstance(){
        if(cpuUtils==null){
            synchronized (CpuUtils.class) {
                if(cpuUtils==null) {
                    cpuUtils = new CpuUtils();
                }
            }
        }
        return cpuUtils;
    }

    public void statCpu(Context context, int timer){
        try {
            this.context = context;
            this.timer = timer;
            //按照设置timer开始监听cpu变化
            if(sampler == null){
                sampler = new Sampler();
            }
            sampler.start();
        }catch (Exception ex){
            ex.printStackTrace();
        }
    }

    class Sampler implements Runnable {
        private ScheduledExecutorService scheduler;
        private Long lastCpuTime;
        private Long lastAppCpuTime;
        private RandomAccessFile procStatFile;
        private RandomAccessFile appStatFile;
        private DecimalFormat df2 = new DecimalFormat("0.00");

        private Sampler() {
            scheduler = Executors.newSingleThreadScheduledExecutor();
        }

        public void start() {
            scheduler.scheduleWithFixedDelay(this, 0L, timer, TimeUnit.MILLISECONDS);
        }

        @Override
        public void run() {
            try {
                double cpu = sampleCPU();
                Log.i(PerformanceConst.Tag, "@@ Sampler 记录CPU");
                PageAnalysisStore.getInstance().storePageCpu(cpu);
            }catch (Exception ex){
                ex.printStackTrace();
            }
        }

        private double sampleCPU() {
            long cpuTime;
            long appTime;
            double sampleValue = 0.0D;
            try {
                if (procStatFile == null || appStatFile == null) {
                    procStatFile = new RandomAccessFile("/proc/stat", "r");
                    appStatFile = new RandomAccessFile("/proc/" + android.os.Process.myPid() + "/stat", "r");
                } else {
                    procStatFile.seek(0L);
                    appStatFile.seek(0L);
                }
                String procStatString = procStatFile.readLine();
                String appStatString = appStatFile.readLine();
                String procStats[] = procStatString.split(" ");
                String appStats[] = appStatString.split(" ");
                cpuTime = Long.parseLong(procStats[2]) + Long.parseLong(procStats[3])
                        + Long.parseLong(procStats[4]) + Long.parseLong(procStats[5])
                        + Long.parseLong(procStats[6]) + Long.parseLong(procStats[7])
                        + Long.parseLong(procStats[8]);
                appTime = Long.parseLong(appStats[13]) + Long.parseLong(appStats[14]);
                if (lastCpuTime == null && lastAppCpuTime == null) {
                    lastCpuTime = cpuTime;
                    lastAppCpuTime = appTime;
                    return sampleValue;
                }
                sampleValue = ((double) (appTime - lastAppCpuTime) / (double) (cpuTime - lastCpuTime)) * 100D;
                lastCpuTime = cpuTime;
                lastAppCpuTime = appTime;
            } catch (Exception e) {
                e.printStackTrace();
            }
            return sampleValue;
        }
    }
}

调用

//开启CPU监测
CpuUtils.getInstance().statCpu(context, timer);
  1. Network
我们主要拦截的是URL请求数、重复请求数、超时请求数、请求时长、是否走缓存等等,用于分析网络执行情况。这个没什么技术点,请自行去做!!!
我们用的xUtils,自己做的拦截(不建议),后期,我们会更换到OkHttp或Retrofit;
如果网络库是OKHttp,自带了拦截,可根据需要自行统计,请自行查询资料;

/**
 * 类:NetworkUtils
 * 作者: qxc
 * 日期:2017/12/15.
 */
public class NetworkUtils {
    public static NetworkUtils networkUtils;
    public static NetworkUtils getInstance() {
        if (networkUtils == null) {
            synchronized (NetworkUtils.class) {
                if (networkUtils == null) {
                    networkUtils = new NetworkUtils();
                }
            }
        }
        return networkUtils;
    }

    public void statNetwork(String url, Long startTime,Long endTime,int responseCode) {
        try {
            Log.i(PerformanceConst.Tag, "@@ Sampler 记录网络");
            PageAnalysisStore.getInstance().storePageNetwork(url,startTime,endTime,responseCode);
        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }
}

4.Fps(帧率,页面卡顿情况)

/**
 * 类:FpsUtils
 * 作者: qxc
 * 日期:2017/12/15.
 */

public class FpsUtils{
    //数据结构:
    public static FpsUtils fpsUtils;
    public static FpsUtils getInstance(){
        if(fpsUtils==null){
            synchronized (FpsUtils.class){
                if(fpsUtils==null) {
                    fpsUtils = new FpsUtils();
                }
            }
        }
        return fpsUtils;
    }

    @TargetApi(Build.VERSION_CODES.JELLY_BEAN)
    public void statFPS(Context context, int timer){
        try {
            if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.JELLY_BEAN) {
                Choreographer.getInstance().postFrameCallback(new FPSFrameCallback(timer));
            }
        }catch (Exception ex){
            ex.printStackTrace();
        }
    }
}
/**
 * 类:FPSFrameCallback
 * 作者: qxc
 * 日期:2018/1/2.
 */
@TargetApi(Build.VERSION_CODES.JELLY_BEAN)
public class FPSFrameCallback implements Choreographer.FrameCallback{
    private static final String TAG = "FPS_TEST";
    private ExecutorService executorService;
    private long lastTime = 0;
    private int timer = 1000;
    private float minFps = 60;

    public FPSFrameCallback(int timer) {
        this.timer = timer;
        lastTime = System.nanoTime();//获得当前时刻(纳秒)
        executorService = Executors.newCachedThreadPool();//初始化缓存线程池
        handler.postDelayed(runnable, timer);//计时开始
    }

    @Override
    public void doFrame(long l) {
        try {
            if (lastTime > 0) {
                float time = l - lastTime;//计算两帧之间的时间差
                float frame = 1000000000 / time;//计算界面实时帧数
                if (frame < minFps) {
                    minFps = frame;//获得1s内的最小帧
                }
                lastTime = l;
            }
            //注册下一帧回调
            Choreographer.getInstance().postFrameCallback(this);
        }catch (Exception ex){
            ex.printStackTrace();
        }
    }

    Handler handler = new Handler();
    Runnable runnable = new Runnable() {
        @Override
        public void run() {
            try {
                executorService.execute(new Runnable() {
                    @Override
                    public void run() {
                        //存储FPS
                        Log.i(TAG, "存储FPS: "+ minFps);
                        PageAnalysisStore.getInstance().storePageFps(minFps);
                    }
                });

                handler.postDelayed(this, timer);
                minFps = 60;//设置为初始值
            }catch (Exception ex){
                ex.printStackTrace();
            }
        }
    };
}

调用:

//开启FPS监测
FpsUtils.getInstance().statFPS(context, timer);
  1. 电量变化(测试时,不能插USB充电,否则无法测试,腾讯GT也是如此)
/**
 * 描述:
 * 作者:小辉
 * 时间:2017/12/220931
 */
public class BatteryService extends Service {
    BatteryReceiver batteryReceiver;
    IntentFilter intentFilter;
    private int startBattery = 0;
    private String startTime = "";
    private String endTime = "";
    private int endBattery = 0;
    private boolean isCharge = true;

    /**
     * 广播接受者
     */
    class BatteryReceiver extends BroadcastReceiver {
        @Override
        public void onReceive(Context context, Intent intent) {
            //判断它是否是为电量变化的Broadcast Action
            if (Intent.ACTION_BATTERY_CHANGED.equals(intent.getAction())) {
                //获取当前电量
                int level = intent.getIntExtra("level", 0);
                //电量的总刻度
                // int scale = intent.getIntExtra("scale", 100);
                //电池状态,返回是一个数字
                // BatteryManager.BATTERY_STATUS_NOT_CHARGING 未充电
                int status = intent.getIntExtra("status", BatteryManager.BATTERY_STATUS_UNKNOWN);
//                Toast.makeText(BatteryService.this, "电量状态", Toast.LENGTH_SHORT).show();
//                Log.e("杀死服务", "电量状态");
                endTime = getTime();
                if (!isCharge) {//不统计电量
                    Performance.getInstance().onBattery(0, 0, startTime, endTime);
//                    Toast.makeText(BatteryService.this, "不统计电量" + status, Toast.LENGTH_SHORT).show();
                } else {
                    if (status == 4) {//APP未充电状态
                        if (startBattery == 0) {
                            startBattery = level;
                        }
                        endBattery = level;
                        Performance.getInstance().onBattery(startBattery, endBattery, startTime, endTime);
//                        Toast.makeText(BatteryService.this, "统计电量" + "统计电量", Toast.LENGTH_SHORT).show();
                    } else {
                        isCharge = false;
                        Performance.getInstance().onBattery(0, 0, startTime, endTime);
//                        Toast.makeText(BatteryService.this, "APP充电状态不统计电量", Toast.LENGTH_SHORT).show();
                    }
                }
            }
        }
    }

    @Override
    public void onCreate() {
        super.onCreate();
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        startBattery = 0;
        //注册广播接受者java代码
        intentFilter = new IntentFilter(Intent.ACTION_BATTERY_CHANGED);
        //创建广播接受者对象
        batteryReceiver = new BatteryReceiver();
        if (startTime.equals("")) {
            startTime = getTime();
        }
        //注册receiver
        registerReceiver(batteryReceiver, intentFilter);
        return super.onStartCommand(intent, flags, startId);
    }

    @Override
    public void onDestroy() {
        if (batteryReceiver != null) {
            this.unregisterReceiver(batteryReceiver);
        }
        super.onDestroy();
    }

    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }

    private String getTime() {
        long time = System.currentTimeMillis();
        return String.valueOf(time);
    }
}

第一篇: 安卓编程技巧总结(1) 资源与UI布局处理

https://www.jianshu.com/p/ff97b15d5c9d

第二篇: 安卓编程技巧总结(2) 基础组件开发

https://www.jianshu.com/p/b05752377887

第三篇:安卓编程技巧总结(3) 进程与线程处理

https://www.jianshu.com/p/7d05c8a368bd

第四篇:安卓编程技巧总结(4) 数据文件处理

https://www.jianshu.com/p/0515df3b697d

第五篇:安卓编程技巧总结(5) 图片处理

https://www.jianshu.com/p/76690b2ba310

第六篇:安卓编程技巧总结(6) APP安全分析

https://www.jianshu.com/p/4347ff392122

第七篇:安卓编程技巧总结(7) 性能检测代码分析

https://www.jianshu.com/p/687f3c641408

你可能感兴趣的:(安卓编程技巧总结(7) 性能检测代码分析)