Android提供的系统服务之--WindowManager(窗口管理服务)

                                                          ——转载请注明出处:coder-pig


本节引言:

本节我们来探讨下这个Android系统服务中的WindowManager(窗口管理服务),

他是显示View的最底层,好像我们的Actviity和Dialog,以及Toast的底层实现都用到

这个WindowManager,他是全局的!核心其实就是WindowManager调用addView,

removeView,updateViewLayout这几个方法来显示View;还有WindowManager.LayoutParams

这个API来设置相关的属性!本节我们就写两个关于WindowManger的实用例子吧:

分别是获取屏幕宽高,以及弄一个Android的悬浮框!还有保持屏幕的常亮以及全屏设置

好了,开始本节内容!



本节正文:

1.相关概念图:


   


2.使用例子:

①获取手机屏幕宽高:

我们通过调用getDefaultDisplay( )可以获得默认的Display显示对象,接着调用getWidth( )

getHeight( )即可获得屏幕宽高

代码如下:

[java]   view plain  copy  print ?
  1. WindowManager windowManager = (WindowManager) getSystemService(Context.WINDOW_SERVICE);  
  2. setTitle(windowManager.getDefaultDisplay().getWidth() + "*" + windowManager.getDefaultDisplay().getHeight());  

运行截图:





②Android悬浮框的实现:

先来看下效果图吧,这里只是一个简单的按钮,大家可以按自己的需求来自定义~

后面还提供一个类似于QQ悬浮发射小火箭的demo,有需要的可以下载来自己研究研究~



实现流程解析:

step 1:我们需要一个后台的Service在后台等待我们的操作,比如完成,View的绘制,移除等~

我们先创建一个空的Service类:MyWindowService继承Service,然后我们需要在

AndroidManifest.xml为这个Service来进行注册!

[html]   view plain  copy  print ?
  1. <service android:name=".MyWindowService"/>  
另外还需要加上下述两个权限:

[html]   view plain  copy  print ?
  1. <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />  
  2. <uses-permission android:name="android.permission.GET_TASKS" />  



step 2:在我们的MainActivity中设置两个按钮的点击事件,我们还要为intent写入

一个extra,根据这个值,我们在Service进行判断,是开启悬浮框,还是关闭悬浮框

[java]   view plain  copy  print ?
  1. package com.jay.example.windowmanagerdemo1;  
  2.   
  3. import android.app.Activity;  
  4. import android.content.Intent;  
  5. import android.os.Bundle;  
  6. import android.view.View;  
  7. import android.view.View.OnClickListener;  
  8. import android.widget.Button;  
  9. import android.widget.Toast;  
  10.   
  11. public class MainActivity extends Activity {  
  12.   
  13.     private Button btnShow;  
  14.     private Button btnClose;  
  15.       
  16.       
  17.     @Override  
  18.     protected void onCreate(Bundle savedInstanceState) {  
  19.         super.onCreate(savedInstanceState);  
  20.         setContentView(R.layout.activity_main);  
  21.           
  22.         btnShow = (Button) findViewById(R.id.btnShow);  
  23.         btnClose = (Button) findViewById(R.id.btnClose);  
  24.           
  25.         btnShow.setOnClickListener(new OnClickListener() {  
  26.             @Override  
  27.             public void onClick(View v) {  
  28.                 Intent show = new Intent(MainActivity.this, MyWindowService.class);  
  29.                 show.putExtra(MyWindowService.OPERATION, MyWindowService.OPERATION_SHOW);  
  30.                 startService(show);   
  31.                 Toast.makeText(MainActivity.this,"悬浮框已开启~", Toast.LENGTH_SHORT).show();  
  32.             }  
  33.         });  
  34.           
  35.         btnClose.setOnClickListener(new OnClickListener() {  
  36.             @Override  
  37.             public void onClick(View v) {  
  38.                 Intent hide = new Intent(MainActivity.this, MyWindowService.class);  
  39.                 hide.putExtra(MyWindowService.OPERATION, MyWindowService.OPERATION_HIDE);  
  40.                 startService(hide);  
  41.                 Toast.makeText(MainActivity.this,"悬浮框已开启~", Toast.LENGTH_SHORT).show();  
  42.             }  
  43.         });  
  44.     }  
  45. }  


step 3:接下来就需要开始编写我们的Service类了,我们想想这个Service需要干嘛?

①肯定需要一个创建View的方法啦,于是乎,我们定义一个createWindowView( )方法用于创建

悬浮框的View!

[java]   view plain  copy  print ?
  1. // 定义一个创建悬浮框的方法:  
  2.     private void createWindowView() {  
  3.         btnView = new Button(getApplicationContext());  
  4.         btnView.setBackgroundResource(R.drawable.pig);  
  5.         windowManager = (WindowManager) getApplicationContext()  
  6.                 .getSystemService(Context.WINDOW_SERVICE);  
  7.         params = new WindowManager.LayoutParams();  
  8.   
  9.         // 设置Window Type  
  10.         params.type = WindowManager.LayoutParams.TYPE_SYSTEM_ALERT;  
  11.         // 设置悬浮框不可触摸  
  12.         params.flags = WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL  
  13.                 | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;  
  14.         // 悬浮窗不可触摸,不接受任何事件,同时不影响后面的事件响应  
  15.         params.format = PixelFormat.RGBA_8888;  
  16.         // 设置悬浮框的宽高  
  17.         params.width = 200;  
  18.         params.height = 200;  
  19.         params.gravity = Gravity.LEFT;  
  20.         params.x = 200;  
  21.         params.y = 000;  
  22.         // 设置悬浮框的Touch监听  
  23.         btnView.setOnTouchListener(new OnTouchListener() {  
  24.             //保存悬浮框最后位置的变量  
  25.             int lastX, lastY;  
  26.             int paramX, paramY;  
  27.             @Override  
  28.             public boolean onTouch(View v, MotionEvent event) {  
  29.                 switch (event.getAction()) {  
  30.                 case MotionEvent.ACTION_DOWN:  
  31.                     lastX = (int) event.getRawX();  
  32.                     lastY = (int) event.getRawY();  
  33.                     paramX = params.x;  
  34.                     paramY = params.y;  
  35.                     break;  
  36.                 case MotionEvent.ACTION_MOVE:  
  37.                     int dx = (int) event.getRawX() - lastX;  
  38.                     int dy = (int) event.getRawY() - lastY;  
  39.                     params.x = paramX + dx;  
  40.                     params.y = paramY + dy;  
  41.                     // 更新悬浮窗位置  
  42.                     windowManager.updateViewLayout(btnView, params);  
  43.                     break;  
  44.                 }  
  45.                 return true;  
  46.             }  
  47.         });  
  48.         windowManager.addView(btnView, params);  
  49.         isAdded = true;  
  50.     }  


②这个时候我们只需在OnCreate( )方法中调用上述的createWindowView( )方法即可启动加载悬浮框了

但是,我们发现一点...这玩意貌似关不掉啊,卧槽,好吧,接下来我们就要分析下需求了!当处于手机的普通界面,

即桌面的时候,这玩意才显示,而当我们启动其他App时,这个悬浮框应该消失不见,当我们推出app又回到

桌面,这个悬浮框又要重新出现!那么我们首先需要判断App是否位于桌面,我们通过下面的代码就可以完成这个

判断:

[java]   view plain  copy  print ?
  1. /**  
  2.  * 判断当前界面是否是桌面  
  3.  */    
  4. public boolean isHome(){    
  5.     if(mActivityManager == null) {  
  6.         mActivityManager = (ActivityManager)getSystemService(Context.ACTIVITY_SERVICE);    
  7.     }  
  8.     List rti = mActivityManager.getRunningTasks(1);    
  9.     return homeList.contains(rti.get(0).topActivity.getPackageName());    
  10. }  
  11.   
  12. /**  
  13.  * 获得属于桌面的应用的应用包名称  
  14.  * @return 返回包含所有包名的字符串列表  
  15.  */  
  16. private List getHomes() {  
  17.     List names = new ArrayList();    
  18.     PackageManager packageManager = this.getPackageManager();    
  19.     // 属性    
  20.     Intent intent = new Intent(Intent.ACTION_MAIN);    
  21.     intent.addCategory(Intent.CATEGORY_HOME);    
  22.     List resolveInfo = packageManager.queryIntentActivities(intent,    
  23.             PackageManager.MATCH_DEFAULT_ONLY);    
  24.     for(ResolveInfo ri : resolveInfo) {    
  25.         names.add(ri.activityInfo.packageName);    
  26.     }  
  27.     return names;    
  28. }  

③好了,接下来我们需要每隔一段时间来进行一系列的判断,比如:是否在桌面,是否已加载悬浮框,否则加载;

否则,如果加载了,就将这个悬浮框移除!这里我们使用handler~,因为不能在子线程直接更新UI,所以,你懂的

所以我们自己写一个handler来完成上述的操作:


[java]   view plain  copy  print ?
  1. //定义一个更新界面的Handler  
  2.     private Handler mHandler = new Handler() {  
  3.         @Override  
  4.         public void handleMessage(Message msg) {  
  5.             switch(msg.what) {  
  6.             case HANDLE_CHECK_ACTIVITY:  
  7.                 if(isHome()) {  
  8.                     if(!isAdded) {  
  9.                         windowManager.addView(btnView, params);  
  10.                         isAdded = true;  
  11.                     new Thread(new Runnable() {  
  12.                         public void run() {  
  13.                             for(int i=0;i<10;i++){  
  14.                                 try {  
  15.                                     Thread.sleep(1000);  
  16.                                 } catch (InterruptedException e) {e.printStackTrace();}  
  17.                                 Message m = new Message();  
  18.                                 m.what=2;  
  19.                                 mHandler.sendMessage(m);  
  20.                             }  
  21.                         }  
  22.                     }).start();}  
  23.                 } else {  
  24.                     if(isAdded) {  
  25.                         windowManager.removeView(btnView);  
  26.                         isAdded = false;  
  27.                     }  
  28.                 }  
  29.                 mHandler.sendEmptyMessageDelayed(HANDLE_CHECK_ACTIVITY, 0);  
  30.                 break;  
  31.             }  
  32.         }  
  33.     };  

④最后要做的一件事,就是重写Service的onStartCommand( )方法了,就是做判断,取出Intent中的

数据,判断是需要添加悬浮框,还是要移除悬浮框!


[java]   view plain  copy  print ?
  1. @Override  
  2.     public int onStartCommand(Intent intent, int flags, int startId) {  
  3.         int operation = intent.getIntExtra(OPERATION, OPERATION_SHOW);  
  4.         switch(operation) {  
  5.         case OPERATION_SHOW:  
  6.             mHandler.removeMessages(HANDLE_CHECK_ACTIVITY);  
  7.             mHandler.sendEmptyMessage(HANDLE_CHECK_ACTIVITY);  
  8.             break;  
  9.         case OPERATION_HIDE:  
  10.             mHandler.removeMessages(HANDLE_CHECK_ACTIVITY);  
  11.             break;  
  12.         }  
  13.         return super.onStartCommand(intent, flags, startId);  
  14.     }  


好了,这个程序的实现流程就这是这样,一次看不懂看多几遍就能了解了!




最后还献上WindowManager的两个常用实例吧:

③设置窗口全屏显示:

[java]   view plain  copy  print ?
  1. getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,  
  2.         WindowManager.LayoutParams.FLAG_FULLSCREEN);  


④保持窗口打开,即屏幕常亮:

[java]   view plain  copy  print ?
  1. public void setKeepScreenOn(Activity activity,boolean keepScreenOn)  
  2. {  
  3.     if(keepScreenOn)  
  4.     {  
  5.         activity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);  
  6.     }else{  
  7.         activity.getWindow().clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);  
  8.     }  
  9. }  


最后说几句:

好了,关于这个WindowManager就写到这里!

本节实例代码下载:

1.利用WindowManager实现简单的悬浮框:http://pan.baidu.com/s/1pJiHSXP

2.Android模仿QQ小火箭:http://pan.baidu.com/s/1eQeW2um




ps:对于WindowManager.LayoutParams的相关标记可见下述链接,有需要的自己查,笔者就不在这里详述了:

Android官方:http://developer.android.com/reference/android/view/WindowManager.LayoutParams.html

csdn别人写的一篇blog:http://blog.csdn.net/chenyafei617/article/details/6577940

更多相关文章

  1. [置顶] Android点击Button实现功能的几种方法
  2. Android加载SVG实现交互式地图绘制
  3. Android架构实例分析之注册hello HAL的JNI方法表
  4. 经典Android试题及答案
  5. android 程序中运行main方法
  6. [Android] 单独编译生成boot.img时mkbootfs: No such file or di
  7. ContentProvider详解
  8. Android(安卓)button 性能探讨
  9. 安卓(Android)实现选择时间功能

随机推荐

  1. 【CSS入门】学习CSS盒模型及常用样式属性
  2. 基于ThinkPHP6.0的一个通用后台管理系统
  3. 学习Python一般使用什么操作系统?首选Lin
  4. Linux系统sersync数据实时同步
  5. 好用的Python编辑器有哪些?五大工具!
  6. Linux常见的开发命令有哪些?分类介绍!
  7. prometheus监控系统
  8. 培训web前端开发无法胜任工作怎么办?
  9. 思迈特软件的企业级商业智能应用案例
  10. 用 WebRTC 打造一个音乐教育 App,要解决哪