【mie haha的博客】转载请注明出处(万分感谢!):
https://blog.csdn.net/qq_40315080/article/details/98610748
写一个测试各个app/手机性能的小工具app。
功能:
- 打开app得到手机中已有的应用列表,点击可以跳转进入。
- 上方标题栏上有选择菜单,可以选择打开,刷新,关闭浮窗,浮窗可以拖动。
- 打开浮窗后,浮窗将显示顶层(当前所在)app的cpu占用、内存、流量,手机总cpu占用、电量数据,每几秒实时更新数据。
- 一个开关按钮,点击控制数据导入数据库和SD卡或停止导入。(可选)
- 一个选择按钮,点击控制监测限定某个app或监测顶层app的数据。(可选)
- 点击浮窗返回该小工具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;
}
@Override
public 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() {
@Override
public 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 {
//不跳转,记录当前点击的app
MainActivity.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;
@Override
public 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 null
if (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 block
e.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() {
//更新信息
@Override
public 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() {
//更新信息
@Override
public 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/总cpu
cv.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()) {// 目录存在返回false
path.mkdirs();// 创建一个目录
}
if (!f.exists()) {// 文件存在返回false
try {
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() {
//更新信息
@Override
public 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/总cpu
cv.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()) {// 目录存在返回false
path.mkdirs();// 创建一个目录
}
if (!f.exists()) {// 文件存在返回false
try {
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)