Android Framework架构浅析之【近期任务】

来源:互联网 发布:图书馆借书数据流程图 编辑:程序博客网 时间:2024/06/10 16:15
分类:             Android Framework                  89人阅读     评论(0)    收藏     举报    

近期任务框(就是近期打开过的应用)其实也就是一个系统级别的对话框,就是长按手机的HOME键弹出的视图。

源码中的路径为:D:\tools\android4.0.1\frameworks\base\policy\src\com\android\internal\policy\impl\RecentApplicationsDialog.java

 

1,显示方式,该对话框在PhoneWindowManager (路径和RecentApplicationsDialog.java同样)类中的showRecentAppsDialog方法

[java] view plaincopyprint?
  1. /** 
  2.    * Create (if necessary) and launch the recent apps dialog, or hide it if it is 
  3.    * already shown. 
  4.    */  
  5.   void showOrHideRecentAppsDialog(final int heldModifiers, final boolean dismissIfShown) {  
  6.       mHandler.post(new Runnable() {  
  7.           @Override  
  8.           public void run() {  
  9.               if (mRecentAppsDialog == null) {  
  10.                   mRecentAppsDialog = new RecentApplicationsDialog(mContext);  
  11.               }  
  12.               if (mRecentAppsDialog.isShowing()) {  
  13.                   if (dismissIfShown) {  
  14.                       mRecentAppsDialog.dismiss();  
  15.                   }  
  16.               } else {  
  17.                   mRecentAppsDialog.setHeldModifiers(heldModifiers);  
  18.                   mRecentAppsDialog.show();  
  19.               }  
  20.           }  
  21.       });  
  22.   }  

 

2,创建对话框时配置一些参数:比如填充父窗体,没有标题,更重要的一点就是设成系统级别的对话框。

 

[java] view plaincopyprint?
  1. /** 
  2.      * 我们创建最近的应用程序对话框只是一次,它会留下(隐藏),直到用户激活。 
  3.      *  
  4.      * @see 调用显示是在这个类里(PhoneWindowManager#showRecentAppsDialog) 
  5.      */  
  6.     @Override  
  7.     protected void onCreate(Bundle savedInstanceState) {  
  8.         super.onCreate(savedInstanceState);  
  9.   
  10.         Context context = getContext();  
  11.   
  12.         if (sStatusBar == null) {  
  13.             sStatusBar = (StatusBarManager) context  
  14.                     .getSystemService(Context.STATUS_BAR_SERVICE);  
  15.         }  
  16.           
  17.         //获取窗体,注意:window是整个手机屏幕的窗体,而不仅仅但是对话框的窗体  
  18.         Window window = getWindow();  
  19.         //设置无标题  
  20.         window.requestFeature(Window.FEATURE_NO_TITLE);  
  21.         //将该对话框设置成系统级别对话框  
  22.         window.setType(WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG);  
  23.         window.setFlags(WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM,  
  24.                 WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM);  
  25.         window.setTitle("Recents");  
  26.   
  27.         setContentView(com.android.internal.R.layout.recent_apps_dialog);  
  28.           
  29.         //设置对话框的参数:宽、高为填充父窗体  
  30.         final WindowManager.LayoutParams params = window.getAttributes();  
  31.         params.width = WindowManager.LayoutParams.MATCH_PARENT;  
  32.         params.height = WindowManager.LayoutParams.MATCH_PARENT;  
  33.         window.setAttributes(params);  
  34.         window.setFlags(0, WindowManager.LayoutParams.FLAG_DIM_BEHIND);  
  35.           
  36.         mIcons[0] = (TextView) findViewById(com.android.internal.R.id.button0);  
  37.         mIcons[1] = (TextView) findViewById(com.android.internal.R.id.button1);  
  38.         mIcons[2] = (TextView) findViewById(com.android.internal.R.id.button2);  
  39.         mIcons[3] = (TextView) findViewById(com.android.internal.R.id.button3);  
  40.         mIcons[4] = (TextView) findViewById(com.android.internal.R.id.button4);  
  41.         mIcons[5] = (TextView) findViewById(com.android.internal.R.id.button5);  
  42.         mIcons[6] = (TextView) findViewById(com.android.internal.R.id.button6);  
  43.         mIcons[7] = (TextView) findViewById(com.android.internal.R.id.button7);  
  44.         mNoAppsText = findViewById(com.android.internal.R.id.no_applications_message);  
  45.           
  46.         //为每个TextView设置点击事件  
  47.         for (TextView b : mIcons) {  
  48.             b.setOnClickListener(this);  
  49.         }  
  50.     }  


3,为八个按钮载入最近的活动,如果最近打过的应用任务栈中超过8个也只能取八个

[java] view plaincopyprint?
  1. /** 
  2.      * 为八个按钮载入最近的活动,如果最近打过的应用任务栈中超过8个也只能取八个, 
  3.      */  
  4.     private void reloadButtons() {  
  5.   
  6.         final Context context = getContext();  
  7.         final PackageManager pm = context.getPackageManager();  
  8.           
  9.         final ActivityManager am = (ActivityManager) context  
  10.                 .getSystemService(Context.ACTIVITY_SERVICE);  
  11.         //这里是获取近期打开过的应用的RecentTaskInfo  
  12.         final List<ActivityManager.RecentTaskInfo> recentTasks = am  
  13.                 .getRecentTasks(MAX_RECENT_TASKS,  
  14.                         ActivityManager.RECENT_IGNORE_UNAVAILABLE);  
  15.   
  16.         ActivityInfo homeInfo = new Intent(Intent.ACTION_MAIN).addCategory(  
  17.                 Intent.CATEGORY_HOME).resolveActivityInfo(pm, 0);  
  18.   
  19.         IconUtilities iconUtilities = new IconUtilities(getContext());  
  20.           
  21.         // 性能注意:android性能指南推荐迭代器来遍历集合,因为知道getRecentTasks()总是返回一个ArrayList  
  22.         // < >,我们将使用一个简单的指数相反。  
  23.         int index = 0;  
  24.         int numTasks = recentTasks.size();  
  25.         for (int i = 0; i < numTasks && (index < NUM_BUTTONS); ++i) {  
  26.             final ActivityManager.RecentTaskInfo info = recentTasks.get(i);  
  27.   
  28.             // 目的用于调试,但不允许第一个结果创建一个空的列表  
  29.             if (DBG_FORCE_EMPTY_LIST && (i == 0))  
  30.                 continue;  
  31.   
  32.             Intent intent = new Intent(info.baseIntent);  
  33.             if (info.origActivity != null) {  
  34.                 intent.setComponent(info.origActivity);  
  35.             }  
  36.   
  37.             // 跳过当前Launcher数据,就是不把当前launcher作为近期打开过的任务。  
  38.             if (homeInfo != null) {  
  39.                 if (homeInfo.packageName.equals(intent.getComponent()  
  40.                         .getPackageName())  
  41.                         && homeInfo.name.equals(intent.getComponent()  
  42.                                 .getClassName())) {  
  43.                     continue;  
  44.                 }  
  45.             }  
  46.             //下面做的其实就是封装一些数据给每一个对应的TextView  
  47.             intent.setFlags((intent.getFlags() & ~Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED)  
  48.                     | Intent.FLAG_ACTIVITY_NEW_TASK);  
  49.             final ResolveInfo resolveInfo = pm.resolveActivity(intent, 0);  
  50.             if (resolveInfo != null) {  
  51.                 final ActivityInfo activityInfo = resolveInfo.activityInfo;  
  52.                 final String title = activityInfo.loadLabel(pm).toString();  
  53.                 Drawable icon = activityInfo.loadIcon(pm);  
  54.   
  55.                 if (title != null && title.length() > 0 && icon != null) {  
  56.                     final TextView tv = mIcons[index];  
  57.                     tv.setText(title);  
  58.                     icon = iconUtilities.createIconDrawable(icon);  
  59.                     tv.setCompoundDrawables(null, icon, nullnull);  
  60.                     RecentTag tag = new RecentTag();  
  61.                     tag.info = info;  
  62.                     tag.intent = intent;  
  63.                     //关于setTag这个是view中集成的一个神奇的东西,后面我会专门表述一下我的见解  
  64.                     tv.setTag(tag);  
  65.                     tv.setVisibility(View.VISIBLE);  
  66.                     tv.setPressed(false);  
  67.                     tv.clearFocus();  
  68.                     ++index;  
  69.                 }  
  70.             }  
  71.         }  
  72.   
  73.         // 处理没有图标的  
  74.         mNoAppsText.setVisibility((index == 0) ? View.VISIBLE : View.GONE);  
  75.   
  76.         // 隐藏其他的图标  
  77.         for (; index < NUM_BUTTONS; ++index) {  
  78.             mIcons[index].setVisibility(View.GONE);  
  79.         }  
  80.     }  


4,设置和显示最近的活动对话框。

 

[java] view plaincopyprint?
  1. /** 
  2.      * 设置和显示最近的活动对话框。 
  3.      */  
  4.     @Override  
  5.     public void onStart() {  
  6.         super.onStart();  
  7.         reloadButtons();  
  8.         //禁止状态栏  
  9.         if (sStatusBar != null) {  
  10.             sStatusBar.disable(StatusBarManager.DISABLE_EXPAND);  
  11.         }  
  12.   
  13.         // 注册接收广播  
  14.         getContext().registerReceiver(mBroadcastReceiver,  
  15.                 mBroadcastIntentFilter);  
  16.   
  17.         mHandler.removeCallbacks(mCleanup);  
  18.     }  


 

5,处理手指按下的动作

[java] view plaincopyprint?
  1. /** 
  2.      * 处理手指按下时的程序 
  3.      */  
  4.     @Override  
  5.     public boolean onKeyDown(int keyCode, KeyEvent event)   


 

6,处理手指离开的动作

 

[java] view plaincopyprint?
  1. /** 
  2.      * 处理手指抬起时的程序 
  3.      */  
  4.     @Override  
  5.     public boolean onKeyUp(int keyCode, KeyEvent event)  


 

7,处理用户单击事件

[java] view plaincopyprint?
  1. /** 
  2.      * 用户单击处理程序。如果一个按钮被单击时,启动相应的活动。 
  3.      */  
  4.     @Override  
  5.     public void onClick(View v) {  
  6.         for (TextView b : mIcons) {  
  7.             if (b == v) {  
  8.                 RecentTag tag = (RecentTag) b.getTag();  
  9.                 switchTo(tag);  
  10.                 break;  
  11.             }  
  12.         }  
  13.         dismiss();  
  14.     }  


8,切换到所点击的应用

[java] view plaincopyprint?
  1. /** 
  2.      * 切换到所点击的应用 
  3.      *  
  4.      * @param tag 
  5.      */  
  6.     private void switchTo(RecentTag tag) {  
  7.         if (tag.info.id >= 0) {  
  8.             // 这是一个活跃的任务,所以把它移动到最近任务的前面  
  9.             final ActivityManager am = (ActivityManager) getContext()  
  10.                     .getSystemService(Context.ACTIVITY_SERVICE);  
  11.             am.moveTaskToFront(tag.info.id, ActivityManager.MOVE_TASK_WITH_HOME);  
  12.         } else if (tag.intent != null) {  
  13.             tag.intent.addFlags(Intent.FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY  
  14.                     | Intent.FLAG_ACTIVITY_TASK_ON_HOME);  
  15.             try {  
  16.                 getContext().startActivity(tag.intent);  
  17.             } catch (ActivityNotFoundException e) {  
  18.                 Log.w("Recent""Unable to launch recent task", e);  
  19.             }  
  20.         }  
  21.     }  


 

9,处理接收关闭对话框的广播

[java] view plaincopyprint?
  1. /** 
  2.      * 这是监听关闭系统对话框意图的广播。收到广播后立即关闭自己,为了允许高优先级的UI来接管(如电话收到了)。 
  3.      */  
  4.     private BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {  
  5.         @Override  
  6.         public void onReceive(Context context, Intent intent) {  
  7.             String action = intent.getAction();  
  8.             if (Intent.ACTION_CLOSE_SYSTEM_DIALOGS.equals(action)) {  
  9.                 String reason = intent  
  10.                         .getStringExtra(PhoneWindowManager.SYSTEM_DIALOG_REASON_KEY);  
  11.                 if (!PhoneWindowManager.SYSTEM_DIALOG_REASON_RECENT_APPS  
  12.                         .equals(reason)) {  
  13.                     dismiss();  
  14.                 }  
  15.             }  
  16.         }  
  17.     };  


 

如果有需要从别的应用中关闭这个对话框,那么向系统发送一个广播即可:

[java] view plaincopyprint?
  1. Intent i = new Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);  
  2.         this.sendBroadcast(i);  

原创粉丝点击