標籤:android 進程 應用 分離
轉載請註明出處:http://blog.csdn.net/l1028386804/article/details/47282031
在上一篇博文《Android之——殺死使用者選中的進程最佳化》一文中,我向大家介紹了如何最佳化使用者的體驗,那麼這篇博文中,我將向大家介紹如何進行系統進程與使用者進程的分離操作。同樣,這篇博文是基於上一篇博文改進的。如果大家還沒有閱讀上一篇博文,請大家先閱讀上一篇博文《Android之——殺死使用者選中的進程最佳化》一文。好了,咱們直接進入主題吧。
一、原理
老規矩,我們還是先談談原理層級的東西吧。
首先,我們根據當前應用是使用者安裝的還是系統內建的,把應用分為使用者應用和系統應用,使用者應用對應的進程就是使用者進程,系統應用對應的進程就是系統進程。大家不禁會說,這不廢話嗎?是的,這就是最基礎的原理。下面我們來繼續說UI顯示的問題,首先,給大家獻上一張圖來說明一下,看圖:
,我們要實現的效果如左面的圖示所示,首先,在ListView的最上方顯示使用者進程(使用者進程數量),然後下面是使用者進程的列表資訊,然後下面顯示系統進程(系統進程數量),然後下面緊接著顯示的是系統進程列表資訊。當然,這樣的設計會使得自訂配接器類改動稍大。這裡,我們不妨假定,使用者進程集合為userTaskInfos,系統進程集合為systemTaskInfos,首先,自訂配接器中返回的資料集合大小應該是使用者進程集合大小加上系統進程集合大小再加上2,也就是userTaskInfo.size()+systemTaskInfos.size()+2,不明白的童鞋請看圖仔細分析下。在這個ListView的第一個位置上,也就是position為0的位置,是一個TextView提示使用者進程(使用者進程數量),下面從position為1的位置一直到使用者進程大小的位置上,一直顯示的是使用者進程的資訊,這些位置返回的具體進程資訊是,userTaskInfo.get(position-1);當position為userTaskInfo.size()+1的時候,又是一個TextView,提示的是系統進程(系統進程數量),下面列出的都是系統進程的資訊,這些位置返回的具體進程資訊是,systemTaskInfos.get(position - userTaskInfo.size() - 2)。這就是我們介面上要顯示的原理。請沒有看明白的童鞋,仔細閱讀幾遍,若還是不明白,請在下面留言。我看到後會及時回複大家。
二、實現1、更新進程資訊實體類TaskInfo
在這個類中新增一個boolean類型的欄位isUserTask,標識當前進程是否是使用者進程
具體代碼實現如下:
//是否是使用者進程private boolean isUserTask = false;public boolean isUserTask() {return isUserTask;}public void setUserTask(boolean isUserTask) {this.isUserTask = isUserTask;}
2、更新進程工具類TaskUtils1)新增判斷是否是使用者進程的方法
在這個類中新增一個方法判斷當前進程是否是使用者進程,是返回true,不是返回false
具體代碼實現如下:
//判斷應用程式是否是使用者程式 public static boolean filterApp(ApplicationInfo info) { //原來是系統應用,使用者手動升級 if ((info.flags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) != 0) { return true; //使用者自己安裝的應用程式 } else if ((info.flags & ApplicationInfo.FLAG_SYSTEM) == 0) { return true; } return false; }
2)擷取系統所有的進程資訊列表的方法
在這個方法的迴圈中,我們調用新增的判斷是否是使用者進程的方法,來判斷當前進程是不是使用者進程,並把判斷結果設定到實體類的isUserTask屬性中。
具體代碼如下:
/** * 擷取系統所有的進程資訊列表 * @param context * @return */public static List<TaskInfo> getTaskInfos(Context context){List<TaskInfo> taskInfos = new ArrayList<TaskInfo>();PackageManager pm = context.getPackageManager();ActivityManager am = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);List<RunningAppProcessInfo> 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);//判斷是否是使用者程式boolean isUserTask = filterApp(applicationInfo);//設定是否是使用者程式taskInfo.setUserTask(isUserTask);} catch (NameNotFoundException e) {// TODO Auto-generated catch blocke.printStackTrace();taskInfo.setTask_icon(context.getResources().getDrawable(R.drawable.ic_launcher));taskInfo.setTask_name(packageName);}//進程idint 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(); //KBtaskInfo.setTask_memory(totalPrivateDirty);taskInfos.add(taskInfo);}return taskInfos;}
3、更新TaskManagerActivity1)新增屬性欄位
在這個類中,首先,我們新增兩個屬性欄位,來封裝所有的使用者進程和所有的系統進程。
具體代碼如下:
private List<TaskInfo> userTaskInfos;private List<TaskInfo> systemTaskInfos;
2)在oncreate子線程更新集合
在onCreate的子線程中,我們擷取到所有的進程集合,同時我在這裡執行個體化userTaskInfos和systemTaskInfos集合,遍曆擷取到的集合資訊,根據進程資訊中的isUserTask屬性來區分是否是使用者進程,來給userTaskInfos和systemTaskInfos集合添加資料,如果是使用者進程,則添加到userTaskInfos集合,如果不是使用者進程,則添加到systemTaskInfos集合。
具體代碼如下:
new Thread(new Runnable() {@Overridepublic void run() {taskInfos = TaskUtils.getTaskInfos(getApplicationContext());//分離使用者程式和系統程式userTaskInfos = new ArrayList<TaskInfo>();systemTaskInfos = new ArrayList<TaskInfo>();for(TaskInfo taskInfo : taskInfos){if(taskInfo.isUserTask()){userTaskInfos.add(taskInfo);}else{systemTaskInfos.add(taskInfo);}}//發送訊息機制Message msg = new Message();msg.what = SUCCESS_GETTASKINFO;mHandler.sendMessage(msg);}}).start();
4、自訂配接器類TaskManagerAdapter
使用者進程集合為userTaskInfos,系統進程集合為systemTaskInfos,首先,自訂配接器中返回的資料集合大小應該是使用者進程集合大小加上系統進程集合大小再加上2,也就是userTaskInfo.size()+systemTaskInfos.size()+2,不明白的童鞋請看圖仔細分析下。在這個ListView的第一個位置上,也就是position為0的位置,是一個TextView提示使用者進程(使用者進程數量),下面從position為1的位置一直到使用者進程大小的位置上,一直顯示的是使用者進程的資訊,這些位置返回的具體進程資訊是,userTaskInfo.get(position-1);當position為userTaskInfo.size()+1的時候,又是一個TextView,提示的是系統進程(系統進程數量),下面列出的都是系統進程的資訊,這些位置返回的具體進程資訊是,systemTaskInfos.get(position - userTaskInfo.size() - 2)。同時為了屏蔽掉列表中的兩個TextView的點擊事件,我們複寫了BaseAdapter中的isEnabled方法,這個方法要傳遞一個position參數,它的作用就是判定當前位置是否可以點擊,當返回true時,可以點擊,當返回false時,不可以點擊。同時,為了不緩衝textView我在這裡作了判斷,過濾掉緩衝TextView的操作。
具體代碼實現如下:
/** * 自訂配接器 * @author liuyazhuang * */private class TaskManagerAdapter extends BaseAdapter{private LayoutInflater mInflater;private List<TaskInfo> infos;public void setInfos(List<TaskInfo> infos) {this.infos = infos;}public TaskManagerAdapter(){mInflater = getLayoutInflater();}@Overridepublic boolean isEnabled(int position) {// TODO Auto-generated method stubif(position == 0){return false;}else if(position == userTaskInfos.size() + 1){return false;}return super.isEnabled(position);}@Overridepublic int getCount() {//return infos.size();return userTaskInfos.size() + systemTaskInfos.size() + 2;}@Overridepublic Object getItem(int position) {if(position == 0){return null;}else if(position <= userTaskInfos.size()){return userTaskInfos.get(position - 1);}else if(position == userTaskInfos.size() +1){return null;}else{return systemTaskInfos.get(position - userTaskInfos.size() -2);}//return infos.get(position);}@Overridepublic long getItemId(int position) {return position;}@Overridepublic View getView(int position, View convertView, ViewGroup parent) {View view = null;ViewHolder holder = null;if(position == 0){ //顯示使用者進行提示TextView tv = new TextView(TaskManagerActivity.this);tv.setText("使用者進程"+"(" + userTaskInfos.size() + ")");tv.setTextSize(20);tv.setBackgroundColor(Color.GRAY);return tv;}else if(position <= userTaskInfos.size()){//顯示使用者進程的列表if(convertView != null && !(convertView instanceof TextView)){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);//擷取到UI上的CheckBox控制項holder.cb_task_manager_selected = (CheckBox) view.findViewById(R.id.cb_task_manager_selected);view.setTag(holder);}TaskInfo taskInfo = userTaskInfos.get(position - 1);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());String packageName = taskInfo.getPackageName();//應用程式是當前啟動並執行程式if(packageName.equals(getPackageName())){holder.cb_task_manager_selected.setVisibility(View.GONE);}else{holder.cb_task_manager_selected.setVisibility(View.VISIBLE);}//擷取條目的選中狀態boolean isChecked = taskInfo.isChecked();if(isChecked){holder.cb_task_manager_selected.setChecked(true);}else{holder.cb_task_manager_selected.setChecked(false);}return view;}else if(position == userTaskInfos.size() + 1){ //顯示系統進程提示TextView tv = new TextView(TaskManagerActivity.this);tv.setText("系統進程"+"(" + systemTaskInfos.size() + ")");tv.setTextSize(20);tv.setBackgroundColor(Color.GRAY);return tv;}else{//顯示系統進程列表if(convertView != null && !(convertView instanceof TextView)){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);//擷取到UI上的CheckBox控制項holder.cb_task_manager_selected = (CheckBox) view.findViewById(R.id.cb_task_manager_selected);view.setTag(holder);}TaskInfo taskInfo = systemTaskInfos.get(position - userTaskInfos.size() - 2);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());String packageName = taskInfo.getPackageName();//應用程式是當前啟動並執行程式if(packageName.equals(getPackageName())){holder.cb_task_manager_selected.setVisibility(View.GONE);}else{holder.cb_task_manager_selected.setVisibility(View.VISIBLE);}//擷取條目的選中狀態boolean isChecked = taskInfo.isChecked();if(isChecked){holder.cb_task_manager_selected.setChecked(true);}else{holder.cb_task_manager_selected.setChecked(false);}return view;}}}代碼有點長,請大家耐心看完,其實很多代碼是相同的,我在這裡沒有做代碼的重構作業,有興趣的童鞋可以自己嘗試下哦,加油!!
5、更新“一鍵清理”點擊事件
這個方法中現在要對userTaskInfos和systemTaskInfos兩個集合進行操作,我在這裡的邏輯主要是,建立一個集合killTaskInfos表示要殺死的進程集合,分別遍曆兩個集合,判斷集合裡面的進程是否被選中,如果被選中,則調用ActivityManager的killBackgroundProcesses方法殺掉進程,同時將殺掉的進程添加到killTaskInfos集合中。最後再寫一個迴圈遍曆killTaskInfos,分別判斷進程資訊的isUserTask屬性,若為true則將其從userTaskInfos中移出,若為false,則從systemTaskInfos中移出,調用ListVIew的notifyDataSetChanged()方法更新UI。
具體代碼實現如下:
/** * 殺死進程 * @param v */public void kill_process(View v){//存放殺死的進程資訊List<TaskInfo> killTaskInfos = new ArrayList<TaskInfo>();for(TaskInfo taskInfo : userTaskInfos){if(taskInfo.isChecked()){//殺死選中的進程am.killBackgroundProcesses(taskInfo.getPackageName());killTaskInfos.add(taskInfo);}}for(TaskInfo taskInfo : systemTaskInfos){if(taskInfo.isChecked()){//殺死選中的進程am.killBackgroundProcesses(taskInfo.getPackageName());killTaskInfos.add(taskInfo);}}//移出殺死的進程for(TaskInfo taskInfo : killTaskInfos){if(taskInfo.isUserTask()){userTaskInfos.remove(taskInfo);}else{systemTaskInfos.remove(taskInfo);}}mAdapter.notifyDataSetChanged();}
三、運行效果
四、溫馨提示
本執行個體中,為了方面,我把一些文字直接寫在了布局檔案中和相關的類中,大家在真實的項目中要把這些文字寫在string.xml檔案中,在外部參考這些資源,切記,這是作為一個Android程式員最基本的開發常識和規範,我在這裡只是為了方便直接寫在了類和布局檔案中。
著作權聲明:本文為博主原創文章,未經博主允許不得轉載。
Android之——系統進程與使用者進程分離