編輯:關於Android編程
如今,基於Android平台的應用越來越多,不乏這樣一些應用程序,這些應用可以多手機中的進程,內存和任務列表進行管理。Android系統中沒有自帶的應用程序對這些數據進行管理。大家不禁會說,Android的應用設置裡面有這些功能啊!是的,雖然應用設置裡面有,但是我們如果想看一下系統的進程,還要跑到系統設置裡面去看嗎?這樣是不是很麻煩?是不是很挫呢?那獲取Android系統的進程總數、內存、任務列表是怎樣實現的呢?親們,別著急,下面我們就一起來實現這些功能吧!注意看哦,不要偷懶!
首先,我們還是要來說說這些所謂的原理級別的東東吧,不然說了半天,大家可能也是一知半解的。
任務盡可能長時間的保存一個應用。內存出現不足的時候,就會去由操作系統殺死進程:
進程的重要級別:
1 Foreground process 前台進程
1.1 activity onResume()
1.2 一個前台進程的activity綁定了另外一個進程的service
1.3 service裡面調用startForeground
1.4 service onCreate() onStart() onDestory()
1.5 BroadcastReceiver onReceive()
2 Visible process 可視進程
2.1 activity onPause()
2.2 一個可視的activity綁定了另一進程的服務
3 Service process 服務進程
後台的服務 播放器 下載 復制文件
4 Background process 後台進程
任務棧裡面還有activity實例的引用,但是該應用在後台
5 Empty process 空進程
1 如果是去獲取系統裡面安裝的信息,這個信息不是動態變化的 PackageManager
2 如果該信息是變化的 ActivityManager 任務管理器
在這個示例中,我們會通過List將獲取到的任務進程列表顯示到UI上。
好了,原理啰嗦完了,這裡的原理我不同於以往的寫法,而是將重要的知識點列出來了,親們,是不是很簡單?看完原理,咱們一起實現這些功能吧。
考慮到我們獲取內存大小,和每個任務進程占用的內存大小時,會出現數據單位不統一的情況,這時,我們自己定義一個數據格式化類,來幫助我們實現數據單位的格式化。
具體代碼如下:
package cn.lyz.mobilesafe.utils; import java.text.DecimalFormat; /** * 文本格式化工具類 * @author liuyazhuang * */ public class TextFormat { /** * 格式化數據 * @param data * @return */ public static String formatByte(long data){ DecimalFormat format = new DecimalFormat(##.##); if(data < 1024){ return data+bytes; }else if(data < 1024 * 1024){ return format.format(data/1024f) +KB; }else if(data < 1024 * 1024 * 1024){ return format.format(data/1024f/1024f) +MB; }else if(data < 1024 * 1024 * 1024 * 1024){ return format.format(data/1024f/1024f/1024f) +GB; }else{ return 超出統計范圍; } } }
在我們這個任務列表中會顯示的內容有圖標、名稱、每個應用占用的內存、包名、進程id等信息,為了使程序更加面向對象化,也更加體現面向對象的封裝性,我將這些信息封裝為一個java實體類。
具體實現代碼如下:
package cn.lyz.mobilesafe.domain; import android.graphics.drawable.Drawable; /** * 任務信息 * @author liuyazhuang * */ public class TaskInfo { //圖標 private Drawable task_icon; //名稱 private String task_name; //占用的內存 private long task_memory; //包名 private String packageName; //進程id private int pid; public TaskInfo() { super(); // TODO Auto-generated constructor stub } public TaskInfo(Drawable task_icon, String task_name, long task_memory, String packageName, int pid) { super(); this.task_icon = task_icon; this.task_name = task_name; this.task_memory = task_memory; this.packageName = packageName; this.pid = pid; } public Drawable getTask_icon() { return task_icon; } public void setTask_icon(Drawable task_icon) { this.task_icon = task_icon; } public String getTask_name() { return task_name; } public void setTask_name(String task_name) { this.task_name = task_name; } public long getTask_memory() { return task_memory; } public void setTask_memory(long task_memory) { this.task_memory = task_memory; } public String getPackageName() { return packageName; } public void setPackageName(String packageName) { this.packageName = packageName; } public int getPid() { return pid; } public void setPid(int pid) { this.pid = pid; } @Override public String toString() { return TaskInfo [task_icon= + task_icon + , task_name= + task_name + , task_memory= + task_memory + , packageName= + packageName + , pid= + pid + ]; } }
我把獲取進程與內存信息的方法全部封裝在了TaskUtils類中。
具體實現代碼如下:
package cn.lyz.mobilesafe.utils; import java.util.ArrayList; import java.util.List; import android.app.ActivityManager; import android.app.ActivityManager.MemoryInfo; import android.app.ActivityManager.RunningAppProcessInfo; import android.content.Context; import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; import android.content.pm.PackageManager.NameNotFoundException; import android.graphics.drawable.Drawable; import cn.lyz.mobilesafe.R; import cn.lyz.mobilesafe.domain.TaskInfo; /** * 任務相關工具類 * @author liuyazhuang * */ public class TaskUtils { /** * 獲取當前正在進行的進程數 * @param context * @return */ public static int getRunningAppProcessInfoSize(Context context){ ActivityManager am = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE); return am.getRunningAppProcesses().size(); } /** * 獲取系統可用內存 * @param context * @return */ public static long getAvailMem(Context context){ ActivityManager am = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE); //得到可用內存 MemoryInfo outInfo = new MemoryInfo(); am.getMemoryInfo(outInfo); long availMem = outInfo.availMem; //單位是byte return availMem; } /** * 獲取系統所有的進程信息列表 * @param context * @return */ public static ListgetTaskInfos(Context context){ List taskInfos = new ArrayList (); PackageManager pm = context.getPackageManager(); ActivityManager am = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE); List runningAppProcesses = am.getRunningAppProcesses(); for(RunningAppProcessInfo info : runningAppProcesses){ TaskInfo taskInfo = new TaskInfo(); //進程名稱 String packageName = info.processName; taskInfo.setPackageName(packageName); try { ApplicationInfo applicationInfo = pm.getApplicationInfo(packageName, 0); //圖標 Drawable task_icon = applicationInfo.loadIcon(pm); if(task_icon == null){ taskInfo.setTask_icon(context.getResources().getDrawable(R.drawable.ic_launcher)); }else{ taskInfo.setTask_icon(task_icon); } //名稱 String task_name = applicationInfo.loadLabel(pm).toString(); taskInfo.setTask_name(task_name); } catch (NameNotFoundException e) { // TODO Auto-generated catch block e.printStackTrace(); } //進程id int pid = info.pid; taskInfo.setPid(pid); //獲取進程占用的內存 android.os.Debug.MemoryInfo[] processMemoryInfo = am.getProcessMemoryInfo(new int[]{pid}); android.os.Debug.MemoryInfo memoryInfo = processMemoryInfo[0]; long totalPrivateDirty = memoryInfo.getTotalPrivateDirty(); //KB taskInfo.setTask_memory(totalPrivateDirty); taskInfos.add(taskInfo); } return taskInfos; } }
這個類中的內容比較多,我們分解來看吧。
以下代碼是我們這個類中,所有的屬性字段
protected static final int SUCCESS_GETTASKINFO = 0; private TextView tv_task_manager_task_count; private TextView tv_task_manager_task_memory; private ListView lv_taskmanage; private RelativeLayout rl_loading; private ProgressBar pb; private ListtaskInfos; private TaskManagerAdapter mAdapter;
我在TaskManagerActivity類中,自定義了ListView的適配器。這裡我用到了ListView的優化策略,使用了ViewHolder來優化ListView。有關ListView優化的策略,大家可以參考《Android之——ListView優化》一文。
具體代碼如下:
/** * 自定義適配器 * @author liuyazhuang * */ private class TaskManagerAdapter extends BaseAdapter{ private LayoutInflater mInflater; public TaskManagerAdapter(){ mInflater = getLayoutInflater(); } @Override public int getCount() { return taskInfos.size(); } @Override public Object getItem(int position) { return taskInfos.get(position); } @Override public long getItemId(int position) { return position; } @Override public View getView(int position, View convertView, ViewGroup parent) { View view = null; ViewHolder holder = null; if(convertView != null){ view = convertView; holder = (ViewHolder) view.getTag(); }else{ view = mInflater.inflate(R.layout.task_manager_item, null); holder = new ViewHolder(); holder.iv_task_manager_icon = (ImageView) view.findViewById(R.id.iv_task_manager_icon); holder.iv_task_manager_name = (TextView) view.findViewById(R.id.tv_task_manager_name); holder.iv_task_manager_memory = (TextView) view.findViewById(R.id.tv_task_manager_memory); view.setTag(holder); } TaskInfo taskInfo = taskInfos.get(position); holder.iv_task_manager_icon.setImageDrawable(taskInfo.getTask_icon()); holder.iv_task_manager_memory.setText(占用的內存:+TextFormat.formatByte(taskInfo.getTask_memory()*1024)); holder.iv_task_manager_name.setText(taskInfo.getTask_name()); return view; } } static class ViewHolder{ ImageView iv_task_manager_icon; TextView iv_task_manager_name; TextView iv_task_manager_memory; }
這個方法主要實現的是,UI控件的初始化,由於或許進程列表是一個耗時的操作,所以我將它放在一個線程中,獲取到進程信息後通過Handler將信息傳遞到UI線程顯示數據。
具體實現代碼如下:
@Override protected void onCreate(Bundle savedInstanceState) { // TODO Auto-generated method stub super.onCreate(savedInstanceState); setContentView(R.layout.task_manager); tv_task_manager_task_count = (TextView) findViewById(R.id.tv_task_manager_task_count); tv_task_manager_task_memory = (TextView) findViewById(R.id.tv_task_manager_task_memory); lv_taskmanage = (ListView) findViewById(R.id.lv_taskmanage); rl_loading = (RelativeLayout) findViewById(R.id.rl_loading); pb = (ProgressBar) findViewById(R.id.pb); //獲取ActivityManager系統服務 int size = TaskUtils.getRunningAppProcessInfoSize(this); tv_task_manager_task_count.setText(進程數:+size); new Thread(new Runnable() { @Override public void run() { taskInfos = TaskUtils.getTaskInfos(getApplicationContext()); Message msg = new Message(); msg.what = SUCCESS_GETTASKINFO; mHandler.sendMessage(msg); } }).start(); }
用於接收子線程傳遞過來的數據。
具體代碼實現如下:
private Handler mHandler = new Handler(){ public void handleMessage(android.os.Message msg) { switch (msg.what) { case SUCCESS_GETTASKINFO: long total = TaskUtils.getAvailMem(TaskManagerActivity.this); for(TaskInfo info : taskInfos){ total += info.getTask_memory() * 1024; } //可用內存 String availMemStr = TextFormat.formatByte(TaskUtils.getAvailMem(TaskManagerActivity.this)); //總內存 String totalMemStr = TextFormat.formatByte(total); tv_task_manager_task_memory.setText(可用/總內存:+availMemStr+/+totalMemStr); mAdapter = new TaskManagerAdapter(); rl_loading.setVisibility(View.GONE); lv_taskmanage.setAdapter(mAdapter); break; default: break; } }; };
package cn.lyz.mobilesafe.activity; import java.util.List; import android.app.Activity; import android.os.Bundle; import android.os.Handler; import android.os.Message; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.BaseAdapter; import android.widget.ImageView; import android.widget.ListView; import android.widget.ProgressBar; import android.widget.RelativeLayout; import android.widget.TextView; import cn.lyz.mobilesafe.R; import cn.lyz.mobilesafe.domain.TaskInfo; import cn.lyz.mobilesafe.utils.TaskUtils; import cn.lyz.mobilesafe.utils.TextFormat; /** * 任務管理 * @author liuyazhuang * */ public class TaskManagerActivity extends Activity { protected static final int SUCCESS_GETTASKINFO = 0; private TextView tv_task_manager_task_count; private TextView tv_task_manager_task_memory; private ListView lv_taskmanage; private RelativeLayout rl_loading; private ProgressBar pb; private ListtaskInfos; private TaskManagerAdapter mAdapter; private Handler mHandler = new Handler(){ public void handleMessage(android.os.Message msg) { switch (msg.what) { case SUCCESS_GETTASKINFO: long total = TaskUtils.getAvailMem(TaskManagerActivity.this); for(TaskInfo info : taskInfos){ total += info.getTask_memory() * 1024; } //可用內存 String availMemStr = TextFormat.formatByte(TaskUtils.getAvailMem(TaskManagerActivity.this)); //總內存 String totalMemStr = TextFormat.formatByte(total); tv_task_manager_task_memory.setText(可用/總內存:+availMemStr+/+totalMemStr); mAdapter = new TaskManagerAdapter(); rl_loading.setVisibility(View.GONE); lv_taskmanage.setAdapter(mAdapter); break; default: break; } }; }; @Override protected void onCreate(Bundle savedInstanceState) { // TODO Auto-generated method stub super.onCreate(savedInstanceState); setContentView(R.layout.task_manager); tv_task_manager_task_count = (TextView) findViewById(R.id.tv_task_manager_task_count); tv_task_manager_task_memory = (TextView) findViewById(R.id.tv_task_manager_task_memory); lv_taskmanage = (ListView) findViewById(R.id.lv_taskmanage); rl_loading = (RelativeLayout) findViewById(R.id.rl_loading); pb = (ProgressBar) findViewById(R.id.pb); //獲取ActivityManager系統服務 int size = TaskUtils.getRunningAppProcessInfoSize(this); tv_task_manager_task_count.setText(進程數:+size); new Thread(new Runnable() { @Override public void run() { taskInfos = TaskUtils.getTaskInfos(getApplicationContext()); Message msg = new Message(); msg.what = SUCCESS_GETTASKINFO; mHandler.sendMessage(msg); } }).start(); } /** * 自定義適配器 * @author liuyazhuang * */ private class TaskManagerAdapter extends BaseAdapter{ private LayoutInflater mInflater; public TaskManagerAdapter(){ mInflater = getLayoutInflater(); } @Override public int getCount() { return taskInfos.size(); } @Override public Object getItem(int position) { return taskInfos.get(position); } @Override public long getItemId(int position) { return position; } @Override public View getView(int position, View convertView, ViewGroup parent) { View view = null; ViewHolder holder = null; if(convertView != null){ view = convertView; holder = (ViewHolder) view.getTag(); }else{ view = mInflater.inflate(R.layout.task_manager_item, null); holder = new ViewHolder(); holder.iv_task_manager_icon = (ImageView) view.findViewById(R.id.iv_task_manager_icon); holder.iv_task_manager_name = (TextView) view.findViewById(R.id.tv_task_manager_name); holder.iv_task_manager_memory = (TextView) view.findViewById(R.id.tv_task_manager_memory); view.setTag(holder); } TaskInfo taskInfo = taskInfos.get(position); holder.iv_task_manager_icon.setImageDrawable(taskInfo.getTask_icon()); holder.iv_task_manager_memory.setText(占用的內存:+TextFormat.formatByte(taskInfo.getTask_memory()*1024)); holder.iv_task_manager_name.setText(taskInfo.getTask_name()); return view; } } static class ViewHolder{ ImageView iv_task_manager_icon; TextView iv_task_manager_name; TextView iv_task_manager_memory; } }
具體代碼如下:
<framelayout android:layout_height="fill_parent" android:layout_width="fill_parent"> </framelayout>
具體代碼如下:
我們在這個文件中定義了一些樣式,具體代碼如下:
最後別忘了,在 AndroidManifest.xml進行權限注冊。
具體如下:
本實例中,為了方面,我把一些文字直接寫在了布局文件中和相關的類中,大家在真實的項目中要把這些文字寫在string.xml文件中,在外部引用這些資源,切記,這是作為一個Android程序員最基本的開發常識和規范,我在這裡只是為了方便直接寫在了類和布局文件中。
背景: 在做android客戶端測試的時候,有時候需要監控cpu/mem/電量消耗/界面加載時間/流量等等指標。於是俺們就上下求索,網友告訴我
我們在進行項目開發時,為了提高項目開發效率,方便項目測試中的局部代碼功能測試會用到單元測試。這樣就不用重新運行一遍整個項目。長期以此我們會就節省大量的時間去做其他的事。首
2、如果有個100M大的文件,需要上傳至服務器中,而服務器form表單最大只能上傳2M,可以用什麼方法。個人理解:所謂表單最大只能上傳2M,是不是指一個表單中附件只能上傳
(一).前言: 話說RecyclerView已經面市很久,也在很多應用中得到廣泛的使用,在整個開發者圈子裡面也擁有很不錯的口碑,那說明RecyclerVi