安卓性能分析的工具有很多,其中,较好用的工具,
如:AndroidStudio自带的Android Monitor(内存、网络、cpu、gpu)、腾讯的GT、第三方测试平台等。
如要使用第三方工具进行检测,请自行查询资料。
当然,也可以自己写代码进行测试。
本章,只是把各类性能检测分析的核心代码放出。
下面的代码经过测试,与Android Monitor、GT输出的结果一致:
- 内存
/**
* 类: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);
- 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);
- 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);
- 电量变化(测试时,不能插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