編輯:關於Android編程
在上一篇博文《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)。這就是我們界面上要顯示的原理。請沒有看明白的童鞋,仔細閱讀幾遍,若還是不明白,請在下面留言。我看到後會及時回復大家。
在這個類中新增一個boolean類型的字段isUserTask,標識當前進程是否是用戶進程
具體代碼實現如下:
//是否是用戶進程 private boolean isUserTask = false; public boolean isUserTask() { return isUserTask; } public void setUserTask(boolean isUserTask) { this.isUserTask = isUserTask; }
在這個類中新增一個方法判斷當前進程是否是用戶進程,是返回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; }
在這個方法的循環中,我們調用新增的判斷是否是用戶進程的方法,來判斷當前進程是不是用戶進程,並把判斷結果設置到實體類的isUserTask屬性中。
具體代碼如下:
/** * 獲取系統所有的進程信息列表 * @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); //判斷是否是用戶程序 boolean isUserTask = filterApp(applicationInfo); //設置是否是用戶程序 taskInfo.setUserTask(isUserTask); } catch (NameNotFoundException e) { // TODO Auto-generated catch block e.printStackTrace(); taskInfo.setTask_icon(context.getResources().getDrawable(R.drawable.ic_launcher)); taskInfo.setTask_name(packageName); } //進程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; }
在這個類中,首先,我們新增兩個屬性字段,來封裝所有的用戶進程和所有的系統進程。
具體代碼如下:
private ListuserTaskInfos; private List systemTaskInfos;
在onCreate的子線程中,我們獲取到所有的進程集合,同時我在這裡實例化userTaskInfos和systemTaskInfos集合,遍歷獲取到的集合信息,根據進程信息中的isUserTask屬性來區分是否是用戶進程,來給userTaskInfos和systemTaskInfos集合添加數據,如果是用戶進程,則添加到userTaskInfos集合,如果不是用戶進程,則添加到systemTaskInfos集合。
具體代碼如下:
new Thread(new Runnable() { @Override public void run() { taskInfos = TaskUtils.getTaskInfos(getApplicationContext()); //分離用戶程序和系統程序 userTaskInfos = new ArrayList(); systemTaskInfos = new ArrayList (); 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();
用戶進程集合為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代碼有點長,請大家耐心看完,其實很多代碼是相同的,我在這裡沒有做代碼的重構操作,有興趣的童鞋可以自己嘗試下哦,加油!!infos; public void setInfos(List infos) { this.infos = infos; } public TaskManagerAdapter(){ mInflater = getLayoutInflater(); } @Override public boolean isEnabled(int position) { // TODO Auto-generated method stub if(position == 0){ return false; }else if(position == userTaskInfos.size() + 1){ return false; } return super.isEnabled(position); } @Override public int getCount() { // return infos.size(); return userTaskInfos.size() + systemTaskInfos.size() + 2; } @Override public 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); } @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(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; } } }
這個方法中現在要對userTaskInfos和systemTaskInfos兩個集合進行操作,我在這裡的邏輯主要是,創建一個集合killTaskInfos表示要殺死的進程集合,分別遍歷兩個集合,判斷集合裡面的進程是否被選中,如果被選中,則調用ActivityManager的killBackgroundProcesses方法殺掉進程,同時將殺掉的進程添加到killTaskInfos集合中。最後再寫一個循環遍歷killTaskInfos,分別判斷進程信息的isUserTask屬性,若為true則將其從userTaskInfos中移出,若為false,則從systemTaskInfos中移出,調用ListVIew的notifyDataSetChanged()方法更新UI。
具體代碼實現如下:
/** * 殺死進程 * @param v */ public void kill_process(View v){ //存放殺死的進程信息 ListkillTaskInfos = new ArrayList (); 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程序員最基本的開發常識和規范,我在這裡只是為了方便直接寫在了類和布局文件中。
效果圖: 如何解析以下的xml: (#大笑) (#微笑) (#親親) (#抱抱) (#色色) (#好失望喲) 這樣來解析: public class
什麼是AIDLaidl是 Android Interface definition language的縮寫,也就是安卓接口定義語言為什麼要有AIDLAIDL允許你定義客戶
界面文件activity_main.xml 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 1
本節引言: 上一節,我們學習了Xfermode中的三兒子:PorterDuffXfermode構造方法中的為一個參數: PorterDuf