【mie haha的博客】转载请注明出处(万分感谢!):
https://blog.csdn.net/qq_40315080/article/details/98610748

写一个测试各个app/手机性能的小工具app。

功能:

  1. 打开app得到手机中已有的应用列表,点击可以跳转进入。
  2. 上方标题栏上有选择菜单,可以选择打开,刷新,关闭浮窗,浮窗可以拖动。
  3. 打开浮窗后,浮窗将显示顶层(当前所在)app的cpu占用、内存、流量,手机总cpu占用、电量数据,每几秒实时更新数据。
  4. 一个开关按钮,点击控制数据导入数据库和SD卡或停止导入。(可选)
  5. 一个选择按钮,点击控制监测限定某个app或监测顶层app的数据。(可选)
  6. 点击浮窗返回该小工具app界面。(可选)

(标记可选的与主要功能无关,只是使使用稍微更方便,可以选择性添加)

主要功能代码:

首先小工具app打开是手机中app列表,需要先得到app列表。

1.获取app列表:

每个app有它对应的名称,包名,进程号(pid),uid。
【pid:每个app运行时都会开启一个进程来实际运行,用pid来标识这个进程,有的app可能会开启多个进程。
在利用android自带的方法获得数据时都是通过pid获取数据,对于多进程app需要把所有进程的数据相加。】
【uid:像一个身份证,唯一地标识某个app。】
【一般包名和名称相比pid和uid更容易得到。】

将app的信息封装在一个类中方便使用。再用该类创建一个列表来保存所有的app信息。最后将这个列表显示在界面上即可得到app列表。

(1)封装app信息:

public class AppInfo  {public Drawable mappimage = null;public String mappname = "";public String mpackagename = "";//构造方法public AppInfo(Drawable appimage,String appname,String packagename){this.mappimage=appimage;this.mappname=appname;this.mpackagename=packagename;}public String getMappname(){return this.mappname;}public String getMpackagename(){return this.mpackagename;}}

(2)创建列表,把获得的app信息加入列表(以下代码写在MainActivity中):


//app信息列表
public static ArrayList<AppInfo> applist = new ArrayList<AppInfo>();//获取app列表
public void getAppProcessName(Context context) {final Intent mainIntent = new Intent(Intent.ACTION_MAIN, null);mainIntent.addCategory(Intent.CATEGORY_LAUNCHER);final List<ResolveInfo> apps = packageManager.queryIntentActivities(mainIntent, 0);for (int i = 0; i < apps.size(); i++) {Drawable imageicon = apps.get(i).activityInfo.loadIcon(packageManager); //图标String appname = apps.get(i).activityInfo.applicationInfo.loadLabel(packageManager).toString(); //名称String packagname = apps.get(i).activityInfo.packageName; //包名AppInfo appinfo = new AppInfo(imageicon, appname, packagname);  //appinfo对象applist.add(appinfo);  //加入队列Log.i("NAME", "getAppProcessName: " + appname);  //打印日志输出得到的app名字检查一下}
}

app信息列表用LisView来显示,每一项包括app图标,app名称,包名。这需要给ListView添加适配器,用适配器来指定每一项的形式和内容。

(3)适配器:

//适配器类
public class MyAdapter extends ArrayAdapter<AppInfo> {private Context mContext;private int mresource;private List<AppInfo> list;private Activity selectmain;private Intent jumpintent;public MyAdapter(Context context,int resource,List<AppInfo> data,Activity selectmain,Intent jumpintent){super(context,resource,data);this.mContext=context;this.mresource=resource;this.list=data;this.selectmain=selectmain;this.jumpintent=jumpintent;}@Overridepublic View getView(int position, View convertView, ViewGroup parent){ViewHolder holder=null;if(convertView==null){holder=new ViewHolder();convertView= LayoutInflater.from(mContext).inflate(mresource,null);holder.image=(ImageView) convertView.findViewById(R.id.appimage);holder.title=(TextView) convertView.findViewById(R.id.appname);holder.text=(TextView)convertView.findViewById(R.id.packagname);// holder.button=(Button)convertView.findViewById(R.id.appbutton);convertView.setTag(holder);}else{holder=(ViewHolder)convertView.getTag();}holder.image.setImageDrawable(getItem(position).mappimage);holder.title.setText(getItem(position).mappname);final String m_appname = getItem(position).mappname;holder.text.setText(getItem(position).mpackagename);holder.text.setSelected(true);//包名太长,走马灯显示final String m_packagename = getItem(position).mpackagename;public class ViewHolder{ImageView image;TextView title;TextView text;// Button button;}//跳转进入应用private void launch(String packagename) {if(Build.VERSION.SDK_INT>=Build.VERSION_CODES.LOLLIPOP){selectmain.startActivity(new Intent(Settings.ACTION_USAGE_ACCESS_SETTINGS));}Intent intent = selectmain.getPackageManager().getLaunchIntentForPackage(packagename);//非空跳转if (intent != null) {selectmain.startActivity(intent);} else {// 没有安装要跳转的应用Toast.makeText(selectmain.getApplicationContext(), "没有找到app", Toast.LENGTH_LONG).show();}}}

并给ListView列表添加适配器:

ListView listView=(ListView)findViewById(R.id.applist);  //找到ListView
MyAdapter arrayAdapter=new MyAdapter(this,R.layout.applistform,applist,this,jumpintent);
listView.setAdapter(arrayAdapter);  //添加适配器

(4)最后,实现点击跳转,需要给ListView添加点击监听器:

listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Overridepublic void onItemClick(AdapterView<?> adapterView, View view, int position, long id) {Log.e("listview","点击了");AppInfo oneapp = applist.get(position);String name = oneapp.getMappname();String pname = oneapp.getMpackagename();Toast.makeText(MainActivity.this,"已选择: "+name,Toast.LENGTH_SHORT).show();//mode=0原来的跳转if(MainActivity.mode==0) {launch(pname);Log.e("switch","选择:跳转");}else {//不跳转,记录当前点击的appMainActivity.testpackagename = pname;Log.e("switch","选择:不跳转");}}
});

2. 打开,关闭,刷新浮窗(可拖动):

(1)首先把打开浮窗,浮窗显示信息,浮窗跟随手移动都写在一个方法中,这样在界面上直接调用这个方法就好。

在浮窗上显示信息其实就是在浮窗上显示一个文本框TextView,可被拖动就是给TextView添加触摸监听器,每次得到手触摸的位置坐标并按照该坐标更新TextView的显示坐标即可。

//打开浮窗
private void openwindow(Context context){lp.type = WindowManager.LayoutParams.TYPE_SYSTEM_ALERT | WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY;lp.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL;lp.gravity = Gravity.LEFT | Gravity.TOP;  //显示在屏幕左上角//显示位置与指定位置的相对位置差lp.x = 0;lp.y = 0;//悬浮窗的宽高(直接设置为WRAP_CONTENT恰好与显示内容一样大比较方便,也可以自己试试设置为合理的确定大小如500,400)lp.width = WindowManager.LayoutParams.WRAP_CONTENT;lp.height = WindowManager.LayoutParams.WRAP_CONTENT;//lp.width = 500;//lp.height = 400;//设置浮窗背景色为透明lp.format = PixelFormat.TRANSLUCENT;//移除窗口if (mtextView != null) {windowManager.removeView(mtextView);}//创建要在浮窗上显示的文本框,来显示信息mtextView = new TextView(getApplicationContext());mtextView.setTextColor(Color.rgb(255, 251, 240));mtextView.setBackgroundColor(Color.parseColor("#BFA9A9A9")); //设置textview颜色为半透明灰色,前两位‘BF’表示透明度windowManager.addView(mtextView, lp); //把textview添加到浮窗上//显示位置与指定位置的相对位置差imagelp.x = lp.x+lp.width;imagelp.y = lp.y+lp.height;//悬浮窗的宽高imagelp.width = WindowManager.LayoutParams.WRAP_CONTENT;imagelp.height = WindowManager.LayoutParams.WRAP_CONTENT;windowManager.addView(imageback,imagelp);/* 这里是用来不断生成实时数据的,下面会具体说到,所以这里先注释掉了。完整代码中是有这两句的!!!!CPUThread cpuThread = new CPUThread(mtextView,this,mActivityManager);cpuThread.start();*///textview触摸监听,实现浮窗可被拖动mtextView.setOnTouchListener(new View.OnTouchListener() {private float lastX, lastY;private float nowX, nowY;private float tranX, tranY;@Overridepublic boolean onTouch(View v, MotionEvent event) {boolean ret = false;switch (event.getAction()) {//按下case MotionEvent.ACTION_DOWN://上次位置lastX = event.getRawX();lastY = event.getRawY();ret = true;break;//拖动case MotionEvent.ACTION_MOVE://当前目标位置nowX = event.getRawX();nowY = event.getRawY();tranX = nowX - lastX;tranY = nowY - lastY;//移动lp.x += tranX;lp.y += tranY;//更新位置windowManager.updateViewLayout(mtextView, lp);//记录当前坐标作为下一次计算的上一次移动的位置坐标lastX = nowX;lastY = nowY;break;//手抬起不操作case MotionEvent.ACTION_UP:break;}return ret;}});}

(2)完成了打开浮窗的方法,接下来调用即可。但不是所有手机都可以允许app打开浮窗,这需要提前判断是否有打开浮窗的权限,如果没有权限,需要跳转到权限界面打开权限,再打开浮窗;如果有打开权限直接打开。

手机安装的sdk版本不同,有不同的默认权限设置。sdk高于23的手机一般默认没有打开浮窗权限,需要跳转权限界面打开。低于23的手机一般有权限,可直接打开。

 //检查sdk版本
if (Build.VERSION.SDK_INT >= 23) {//浮窗权限判断if (Settings.canDrawOverlays(MainActivity.this)) {//打开浮窗openwindow(MainActivity.this);} else {//若没有权限,提示获取.Intent intent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION);intent.setPackage(getPackageName());Toast.makeText(MainActivity.this, "需要取得权限以使用悬浮窗", Toast.LENGTH_SHORT).show();startService(intent);}} else {//低级sdk打开浮窗openwindow(MainActivity.this);}Toast.makeText(this, "打开浮窗", Toast.LENGTH_SHORT).show();

浮窗已经有了雏形,但是缺少数据信息来显示。
因为要检测顶层app(即当前app)的数据,需要得到顶层app。

3. 获得顶层app:

因为不同信息获取要用到的app信息不一样,取得顶层app时要取得app包名,名称,pid。uid。

包名:

//得到顶层应用包名
private String getForegroundApp() {boolean isInit = true;UsageStatsManager usageStatsManager = (UsageStatsManager) mainactivity.getApplication().getSystemService(Context.USAGE_STATS_SERVICE);long ts = System.currentTimeMillis();List<UsageStats> queryUsageStats =usageStatsManager.queryUsageStats(UsageStatsManager.INTERVAL_BEST, 0, ts);UsageEvents usageEvents = usageStatsManager.queryEvents(isInit ? 0 : ts-5000, ts);if (usageEvents == null) {return null;}UsageEvents.Event event = new UsageEvents.Event();UsageEvents.Event lastEvent = null;while (usageEvents.getNextEvent(event)) {// if from notification bar, class name will be nullif (event.getPackageName() == null || event.getClassName() == null) {continue;}if (lastEvent == null || lastEvent.getTimeStamp() < event.getTimeStamp()) {lastEvent = event;}}if (lastEvent == null) {return null;}return lastEvent.getPackageName();}

名称:

/得到顶层应用名
public static String getProgramNameByPackageName(Context context, String packageName) {PackageManager pm = context.getPackageManager();String name = null;try {name = pm.getApplicationLabel(pm.getApplicationInfo(packageName, PackageManager.GET_META_DATA)).toString();} catch (PackageManager.NameNotFoundException e) {e.printStackTrace();}return name;}

pid:

//得到顶层pid
private int forespid(String baoming){int getforepid=0;List<ActivityManager.RunningAppProcessInfo> runningAppsInfo = new ArrayList<ActivityManager.RunningAppProcessInfo>();PackageManager pm = mainactivity.getPackageManager();ActivityManager am = (ActivityManager) mainactivity.getSystemService(Context.ACTIVITY_SERVICE);List<ActivityManager.RunningServiceInfo> runningServices = am.getRunningServices(Integer.MAX_VALUE);for(ActivityManager.RunningServiceInfo service: runningServices) {String pkgName = service.process.split(":")[0];ActivityManager.RunningAppProcessInfo item = new ActivityManager.RunningAppProcessInfo();item.pkgList = new String[] { pkgName };item.pid = service.pid;int pid=item.pid;item.processName = service.process;String processname =item.processName;for(String apakagename : item.pkgList){Log.e("新方法找到pid","             当前遍历的包名:"+apakagename+"顶层包名:"+baoming);Log.e("新方法找到pid","             当前遍历的包名:"+processname+"顶层包名:"+baoming);if(baoming.equals(apakagename)) {Log.e("新方法找到pid", "!!!!!!!!!!!!!!!!!!!!!" + baoming+"pid:  "+pid);getforepid = pid;}}}return getforepid;
}

uid:

//包名获得uid
public int foreUID(String pn){PackageManager mPm = mainactivity.getPackageManager();int uuid = 0;try {ApplicationInfo applicationInfo = mPm.getApplicationInfo(pn, 0);uuid = applicationInfo.uid;Toast.makeText(mainactivity, "", Toast.LENGTH_SHORT).show();}catch (Exception e){e.printStackTrace();}Log.e("找uid:",uuid+"");return uuid;
}

4. 获得cpu总占用率:

获得总体cpu占用率比获取某个app的cpu占用率简单。手机的性能数据都保存在系统中,我们只需要输入命令来调取即可。先来看一下系统中怎么保存的cpu信息:

我们需要的数据信息全部保存在/proc文件下。数据根据系统自动更新。
连接手机,在命令行输入adb shell进入shell模式,再输入cat进行 /proc/stat文件 的查看。可以看到:

(图片来自https://www.jianshu.com/p/6bf564f7cdf0)

第一行是总cpu使用情况。一个手机可能有多个cpu,下面几行是多个cpu的各自使用情况。由cpu0—cpu3可知该连接的手机共有4个cpu处理内核。cpu数据的单位是jiffies,jiffies 是内核中的一个全局变量,用来记录系统启动以来产生的节拍数,根据不同的linux系统在1ms 到 10ms 之间。

用获取的信息计算使用率:

公式:totalCPUrate = (非空闲cpu时间2-非空闲cpu时间1)/(cpu总时间2-cpu总时间1)x100%

一般在较短时间内进行2次取样,计算。
取得的cpu数据是10元组,包括user、nice、system、idle、iowait、irq、softirq、stealstolen、guest、guest_nice。

代码:

//计算cpu总占用率
public static String getCPURateDesc_All(){String path = "/proc/stat";// 系统CPU信息文件long totalJiffies[]=new long[2];long totalIdle[]=new long[2];int firstCPUNum=0;//设置这个参数,这要是防止两次读取文件获知的CPU数量不同,导致不能计算。这里统一以第一次的CPU数量为基准FileReader fileReader = null;BufferedReader bufferedReader = null;Pattern pattern=Pattern.compile(" [0-9]+");for(int i=0;i<2;i++) {totalJiffies[i]=0;totalIdle[i]=0;try {fileReader = new FileReader(path);bufferedReader = new BufferedReader(fileReader, 8192);int currentCPUNum=0;String str;while ((str = bufferedReader.readLine()) != null&&(i==0||currentCPUNum<firstCPUNum)) {if (str.toLowerCase().startsWith("cpu")) {currentCPUNum++;int index = 0;Matcher matcher = pattern.matcher(str);while (matcher.find()) {try {long tempJiffies = Long.parseLong(matcher.group(0).trim());totalJiffies[i] += tempJiffies;if (index == 3) {//空闲时间为该行第4条栏目totalIdle[i] += tempJiffies;}index++;} catch (NumberFormatException e) {e.printStackTrace();}}}if(i==0){firstCPUNum=currentCPUNum;try {//暂停50毫秒,等待系统更新信息。Thread.sleep(50);} catch (InterruptedException e) {e.printStackTrace();}}}} catch (IOException e) {// TODO Auto-generated catch blocke.printStackTrace();} finally {if (bufferedReader != null) {try {bufferedReader.close();} catch (IOException e) {e.printStackTrace();}}}}//计算double rate=-1;if (totalJiffies[0]>0&&totalJiffies[1]>0&&totalJiffies[0]!=totalJiffies[1]){rate=1.0*((totalJiffies[1]-totalIdle[1])-(totalJiffies[0]-totalIdle[0]))/(totalJiffies[1]-totalJiffies[0]);}Log.d("CpuUtils","zrx---- cpu_rate:"+rate);return String.format("cpu:%.2f %s",rate*100,"%");
}

5. 获得某个app的cpu占用率:

用获取到的顶层cpu信息,取相应的数据获得某app的cpu使用率。

2.中已经得到了顶层app的pid,用pid获取该app的cpu信息:

private double sampleCPU(int pid) {long cpuTime;long appTime;double sampleValue = 0.0D;try {if (procStatFile == null || appStatFile == null) {procStatFile = new RandomAccessFile("/proc/stat", "r");appStatFile = new RandomAccessFile("/proc/" + pid+ "/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;}Log.e("thiscpu","分子"+(double) (appTime - lastAppCpuTime)+"");Log.e("thiscpu","分母"+ (double) (cpuTime - lastCpuTime)+"");this.dbthiscpu = (double) (appTime - lastAppCpuTime);  //db显示当前进程cpu消耗this.dball = (double) (cpuTime - lastCpuTime);  //db显示整体cpu消耗sampleValue =  100D * ((double) (appTime - lastAppCpuTime) / (double) (cpuTime - lastCpuTime));lastCpuTime = cpuTime;lastAppCpuTime = appTime;Log.e("ppp",pid+"");Log.e("ppp","正常");} catch (Exception e) {Log.e("ppp",pid+"");Log.e("ppp","异常");e.printStackTrace();}return sampleValue;
}

最后规定下显示的小数形式。

DecimalFormat df = new DecimalFormat("0.000");
Double d = sampleCPU(forepid);  //forpid是顶层app的pid,由2.知可由包名得到
this.thiscpu = "cpu:"+df.format(d)+"%";

6. 获得某个app的内存:

由app的包名得到app占用的全部内存:

//包名得到内存占用
private double getMem(String pn) {double allmem = 0;String ppn = null;List<AppInfo> resule = new ArrayList<AppInfo>();ActivityManager am = (ActivityManager) mainactivity.getSystemService(Context.ACTIVITY_SERVICE);PackageManager pm = mainactivity.getPackageManager();AppUtils proutils = new AppUtils(mainactivity);List<AndroidAppProcess> listInfo = ProcessManager.getRunningAppProcesses();if(listInfo.isEmpty() || listInfo.size() == 0){}if(listInfo!=null){ }for (AndroidAppProcess info : listInfo) {ApplicationInfo app = proutils.getApplicationInfo(info.name);ppn = info.getPackageName();if(ppn.equals(pn)){// 计算应用所占内存大小int[] myMempid = new int[] { info.pid };Debug.MemoryInfo[] memoryInfo = am.getProcessMemoryInfo(myMempid);double memSize = memoryInfo[0].dalvikPrivateDirty / 1024.0;this.dbthismemory= allmem + memoryInfo[0].dalvikPrivateDirty;//数据库显示的当前进程内存占用原始数据int temp = (int) (memSize * 100);memSize = temp / 100.0;allmem = allmem+memSize;}}Log.e("hhh",allmem+"        "+ppn);return allmem;
}

7. 获得某个app的流量:

流量是接受量和发送量的总和。

由app的uid获得流量使用量:

//得到流量
public long FFlow(int uid) {long rx = TrafficStats.getUidRxBytes(uid);// 总接收量long tx = TrafficStats.getUidTxBytes(uid);// 总发送量Log.e("FFlow","包名:"+this.packagename+"uid:" +uid+" 接收:"+rx+" 发送:"+tx);this.dbflow = rx+tx+"";return (rx+tx)/1024;   //单位是MB}

(app的uid的获得方法在2.中)

8. 把数据信息显示到浮窗,并实时刷新:

要实时刷新,就是要不停重新获取数据。这就需要使用线程,把设置显示信息的语句放到线程中执行。安卓中不能直接写在Thread的run()方法中然后调用.start(),而要借助Handler,把更新数据语句写在的post()方法中,再调用.start()。否则会卡顿严重。

代码:

private Runnable mainRunnable = new Runnable() {//更新信息@Overridepublic void run() {time = System.currentTimeMillis();MainActivity.mcpumemssage=cpu1;tvDate.setText(mobileInfor.getForename()+'\n'+mobileInfor.getAllcpu()+'\n'+mobileInfor.getThiscpu()+'\n'+mobileInfor.getFlow()+'\n'+mobileInfor.getmemoryinfo()+'\n'+"内存限制:"+mobileInfor.getmemorylimit()+"M"+'\n'+"电量/总电量:"+MainActivity.intLevel+"/"+MainActivity.intScale);try{if(MainActivity.StartorEnd%2==1){}} catch (Exception e){Log.e("异常","开始");e.printStackTrace();Log.e("异常","结束");} finally {}}
};//重写run方法
@Override
public void run() {// mainactivity.registerReceiver(mBatInfoReveiver, new IntentFilter(Intent.ACTION_BATTERY_CHANGED));mobileInfor = new MobileInfor(mainactivity,mActivityManager);//计算数据do {try {Thread.sleep(2000);}mobileInfor.setAllcpu();mobileInfor.setForename();mobileInfor.setPackagename();mobileInfor.setUid();mobileInfor.setForepid();mobileInfor.setMemoryinfo();mobileInfor.setThiscpu();mobileInfor.getRate();mobileInfor.setFlow();mobileInfor.setThismemory();mHandler.post(mainRunnable);} catch (InterruptedException e) {e.printStackTrace();}} while (true);
}

然后在主界面(MainActivity)调用,开始线程即可:

CPUThread cpuThread = new CPUThread(mtextView,this,mActivityManager);
cpuThread.start();

9. 把数据导入数据库:

导入数据库是指以数据库文件.db形式导入到手机sd卡中,没有安装查看软件的手机无法直接点开.db文件查看,但是可以方柏霓导出到其他设备进行分析。

因为信息是实时更新,实时更新是在线程中实现的,所以导入数据库的语句也写在线程中。

把7.中的run方法稍作修改:

private Runnable mainRunnable = new Runnable() {//更新信息@Overridepublic void run() {time = System.currentTimeMillis();MainActivity.mcpumemssage=cpu1;tvDate.setText(mobileInfor.getForename()+'\n'+mobileInfor.getAllcpu()+'\n'+mobileInfor.getThiscpu()+'\n'+mobileInfor.getFlow()+'\n'+mobileInfor.getmemoryinfo()+'\n'+"内存限制:"+mobileInfor.getmemorylimit()+"M"+'\n'+"电量/总电量:"+MainActivity.intLevel+"/"+MainActivity.intScale);try{//名为String的名值对ContentValues cv = new ContentValues();//获取时间SimpleDateFormat dff = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");dff.setTimeZone(TimeZone.getTimeZone("GMT+08"));String ee = dff.format(new Date());//存在数据库中cv.put("Times",ee);cv.put("Name",mobileInfor.getForename());cv.put("Packagename",mobileInfor.getForename());cv.put("Pid",mobileInfor.getForepid());cv.put("ALL_CPU", mobileInfor.getAllcpu());cv.put("Rate",mobileInfor.getRate());  //当前进程cpu/总cpucv.put("THIS_CPU", mobileInfor.getThiscpu());cv.put("THIS_Flow",mobileInfor.getdbflow()); //当前进程消耗原始流量cv.put("THIS_Memory",mobileInfor.getdbthismemory()); //当前进程占用原始内存cv.put("Memory_Limit",mobileInfor.getmemorylimit());long insert = mysql.insert("mobile", null, cv);Log.e("sqlite","success"); //打印日志标志导入结束}} catch (Exception e){Log.e("异常","开始");e.printStackTrace();Log.e("异常","结束");} finally {}}
};//重写run方法
@Override
public void run() {// mainactivity.registerReceiver(mBatInfoReveiver, new IntentFilter(Intent.ACTION_BATTERY_CHANGED));mobileInfor = new MobileInfor(mainactivity,mActivityManager);//计算数据do {try {Thread.sleep(2000);//StartorEnd=0结束,关闭游标、数据库if(MainActivity.StartorEnd%2==0){if(mysql!=null)mysql.close();}//开始录入数据,创建数据库else if (MainActivity.StartorEnd%2==1){  //我添加了一个控制开始和停止导入数据的按钮,每点击一次MainActivity.StartorEnd+1,奇偶交替变化,如果不想加这个控制按钮,该if条件可删去//保存到sd卡if (!path.exists()) {// 目录存在返回falsepath.mkdirs();// 创建一个目录}if (!f.exists()) {// 文件存在返回falsetry {f.createNewFile();// 创建文件} catch (IOException e) {e.printStackTrace();}}//创建实例mysql = SQLiteDatabase.openOrCreateDatabase(f, null);//创建数据库String sql = "create table if not exists mobile(_id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,Times Text,Name Text,Packagename Text,Pid Text,All_CPU Text,Rate Text,THIS_CPU Text,THIS_Flow Text,THIS_Memory Text,Memory_Limit Text)";System.out.println("创建:" + sql);//执行mysql.execSQL(sql);}mobileInfor.setAllcpu();mobileInfor.setForename();mobileInfor.setPackagename();mobileInfor.setUid();mobileInfor.setForepid();mobileInfor.setMemoryinfo();mobileInfor.setThiscpu();mobileInfor.getRate();mobileInfor.setFlow();mobileInfor.setThismemory();mHandler.post(mainRunnable);} catch (InterruptedException e) {e.printStackTrace();}} while (true);
}

10. 把数据以.txt形式导入手机sd卡:

比数据库文件形式导入更简单:

//字符串txt保存在sd卡
public static void stringTxt(String str){try {FileWriter fw = new FileWriter("/sdcard/himi" + "/himi.txt");//SD卡中的路径fw.flush();fw.write(str);fw.close();} catch (Exception e) {e.printStackTrace();}
}

仍然在线程中修改,添加如下语句:

//.txt转存在手机中
result = result + ee + "   "+mobileInfor.getForename()+"                   "+mobileInfor.getPackagename()+"               "+mobileInfor.getForepid()+"               "+mobileInfor.getAllcpu()+"          "+mobileInfor.getRate()+"               "+mobileInfor.getThiscpu()+"          "+mobileInfor.getdbflow()+"          "+mobileInfor.getThisMemory()+"          "+mobileInfor.getmemorylimit()+'\n';
stringTxt(result);
Log.e("txt","成功");

修改后的导入.db和.txt文件到sd卡的线程代码:

private Runnable mainRunnable = new Runnable() {//更新信息@Overridepublic void run() {time = System.currentTimeMillis();MainActivity.mcpumemssage=cpu1;tvDate.setText(mobileInfor.getForename()+'\n'+mobileInfor.getAllcpu()+'\n'+mobileInfor.getThiscpu()+'\n'+mobileInfor.getFlow()+'\n'+mobileInfor.getmemoryinfo()+'\n'+"内存限制:"+mobileInfor.getmemorylimit()+"M"+'\n'+"电量/总电量:"+MainActivity.intLevel+"/"+MainActivity.intScale);try{//名为String的名值对ContentValues cv = new ContentValues();//获取时间SimpleDateFormat dff = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");dff.setTimeZone(TimeZone.getTimeZone("GMT+08"));String ee = dff.format(new Date());Log.e("txt","要开始2txt");//写入部分,StartOrEnd==1执行录入信息if(MainActivity.StartorEnd%2==1){//转存在手机中result = result + ee + "   "+mobileInfor.getForename()+"                   "+mobileInfor.getPackagename()+"               "+mobileInfor.getForepid()+"               "+mobileInfor.getAllcpu()+"          "+mobileInfor.getRate()+"               "+mobileInfor.getThiscpu()+"          "+mobileInfor.getdbflow()+"          "+mobileInfor.getThisMemory()+"          "+mobileInfor.getmemorylimit()+'\n';stringTxt(result);Log.e("txt","成功");//存在数据库中cv.put("Times",ee);cv.put("Name",mobileInfor.getForename());cv.put("Packagename",mobileInfor.getForename());cv.put("Pid",mobileInfor.getForepid());cv.put("ALL_CPU", mobileInfor.getAllcpu());cv.put("Rate",mobileInfor.getRate());  //当前进程cpu/总cpucv.put("THIS_CPU", mobileInfor.getThiscpu());cv.put("THIS_Flow",mobileInfor.getdbflow()); //当前进程消耗原始流量cv.put("THIS_Memory",mobileInfor.getdbthismemory()); //当前进程占用原始内存cv.put("Memory_Limit",mobileInfor.getmemorylimit());long insert = mysql.insert("mobile", null, cv);Log.e("sqlite","success");}} catch (Exception e){Log.e("异常","开始");e.printStackTrace();Log.e("异常","结束");} finally {}Log.i(TAG,"time print " +(System.currentTimeMillis() - time));Log.e("StartOrEnd",MainActivity.StartorEnd+"");}
};//重写run方法
@Override
public void run() {// mainactivity.registerReceiver(mBatInfoReveiver, new IntentFilter(Intent.ACTION_BATTERY_CHANGED));mobileInfor = new MobileInfor(mainactivity,mActivityManager);//计算数据do {try {Thread.sleep(2000);//StartorEnd=0结束,关闭游标、数据库if(MainActivity.StartorEnd%2==0){if(mysql!=null)mysql.close();}//开始录入数据,创建数据库else if (MainActivity.StartorEnd%2==1){//保存到sd卡if (!path.exists()) {// 目录存在返回falsepath.mkdirs();// 创建一个目录}if (!f.exists()) {// 文件存在返回falsetry {f.createNewFile();// 创建文件} catch (IOException e) {e.printStackTrace();}}//创建实例mysql = SQLiteDatabase.openOrCreateDatabase(f, null);//创建数据库String sql = "create table if not exists mobile(_id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,Times Text,Name Text,Packagename Text,Pid Text,All_CPU Text,Rate Text,THIS_CPU Text,THIS_Flow Text,THIS_Memory Text,Memory_Limit Text)";System.out.println("创建:" + sql);//执行mysql.execSQL(sql);}mobileInfor.setAllcpu();mobileInfor.setForename();mobileInfor.setPackagename();mobileInfor.setUid();mobileInfor.setForepid();mobileInfor.setMemoryinfo();mobileInfor.setThiscpu();mobileInfor.getRate();mobileInfor.setFlow();mobileInfor.setThismemory();mHandler.post(mainRunnable);} catch (InterruptedException e) {e.printStackTrace();}} while (true);
}

测试手机/某app性能的小工具完成。

以上代码全部完整,工程代码已上传。

仍在入门,如有错误,欢迎指出

主要参考:https://www.jianshu.com/p/6bf564f7cdf0 (简书 作者:隋胖胖LoveFat)

Android 性能测试小工具 (cpu,内存,电量,流量数据浮窗显示,信息导入数据库、sd卡)相关推荐

  1. 脚本实现监控APP的专项数据:CPU 内存 电量 流量

    296 lines (263 sloc) 12.2 KB #/user/bin/python #encoding:utf-8 import os import time import csv impo ...

  2. Android 性能测试小工具 Emmagee

    Emmagee 是一个性能测试小工具 用来监控指定被测应用在使用过程中占用机器的CPU, 内存,流量资源的性能小工具 Emmagee 介绍 Emmagee是网易杭州研究院QA团队开发的一个简单易上手的 ...

  3. Android XML小工具

    Android XML小工具 一.概述 XML与Object互相转化,支持8种基本类型.String和byte[].byte[]需要经由base64编码(API8以后才有,之前版本可以自己拷入). 更 ...

  4. Windows 7环境下网站性能测试小工具 Apache Bench 和 Webbench使用和下载

    1.简要说明: Apache Bench 是Apache的网站性能测试小程序,Windows平台下的程序名简称ab.exe,要想获得这个80k的可执行程序,用户需要下载整个Apache Httpd软件 ...

  5. app的性能测试小工具monkey使用教程

    Monkey app的性能测试小工具monkey使用教程 功能: 是一个稳定性测试(疲劳测试)小工具: 也可以是随机测试小工具 Monkey工具使用过程: A)使用adb shell命令进入到安卓手机 ...

  6. 通过bginfo小工具让用户自己查看用户名与IP地址信息

    通过bginfo小工具让用户自己查看用户名与IP地址信息 https://blog.51cto.com/wangzhaowei/1337848 王兆伟1390人评论3390人阅读2013-12-07 ...

  7. android 5.1.1 sd卡权限,android - 适用于Android 5.1.1及更高版本的Cordova的外部存储路径(SD卡) - 堆栈内存溢出...

    从Android 5.0开始,外部(可移动)SD的位置不再是固定路径. 而是在路径中使用SD卡的序列号. 例如,在运行Android 7.1.1的Samsung Galaxy S4上,物理外部可移动S ...

  8. Android将应用调试log信息保存在SD卡

    转载:http://blog.csdn.net/way_ping_li/article/details/8487866 把自己应用的调试信息写入到SD卡中. package com.sdmc.hote ...

  9. Android性能测试②-三种必备内存CPU测试的方法

    Android用户也许会经常碰到以下的问题: 1)应用后台开着,手机很快没电了--应用耗电大: 2)首次/非首次启动应用,进入应用特别慢--应用启动慢: 3)应用使用过程中,越来越卡--CPU能力不足 ...

最新文章

  1. 学习超大神经网络,CPU超越V100 GPU,靠的居然是哈希?
  2. 什么是反射?反射的用法?实例说明。
  3. 手动添加linux用户,Linux入门教程:如何手动创建一个Linux用户
  4. 什么是存储过程,存储过程的作用及好处
  5. 转【是什么浪费了我的时间 】
  6. 在HDFS集群中优化secondary namenode到datanode1节点上,并做重启hdfs集群后,datanode1启动失败...
  7. 人工神经网络方法学习步长_人工神经网络-一种直观的方法第1部分
  8. 【python】编码
  9. 如何从0开始编写一个网络爬虫?
  10. Springboot+微信小程序自习室管理系统毕业设计源码221535
  11. ECMWF ERA-interim数据下载——手动下载
  12. cc共享许可协议_如何以及为何使用知识共享许可的作品
  13. 五步移相法matlab程序_基于结构光的相移法三维重建matlab
  14. 各向同性+随动硬化+过应力-vumat-理论推导
  15. 软考高级系统架构设计师系列论文三十五:论企业应用集成
  16. java 仿qq庅_iQQ-开源Java版qq客户端
  17. Firefox全面兼容中国银联“在线支付”
  18. doc转docx文件会乱吗_docx怎么转换成doc?docx转doc方法汇总
  19. 折腾日记:树莓派如何硬盘、u盘启动 (usb boot)
  20. 下个月去北京了,心如一团乱麻好多事情要解决,但是不知道从哪里开始,还是顺其自然吧,一件件的解决...

热门文章

  1. JavaSE版QQ设计文档
  2. android最新版本9.1,MyDigi下载-MyDigi安卓版下载9.1.3-西西软件下载
  3. oracle中如何去掉重复的数据库,关于如何删除Oracle数据库中重复记录
  4. 蝶变 java_蝶变(Debian)_Xfce_新立得软件管理_安装不上软件了,怎么处理?
  5. 浏览器本地mysql_浏览器访问本地数据库
  6. 新解决方案销售之四:定义痛苦或关键业务问题
  7. UITextField前面空几格
  8. python关于hasattr和getattr的理解
  9. linux中chgrp参数,linux chgrp命令参数及用法详解--变更文件或目录的所属群组
  10. 阿里企业邮箱开通流程