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

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( )即可获得屏幕宽高

代码如下:

		WindowManager windowManager = (WindowManager) getSystemService(Context.WINDOW_SERVICE);
		setTitle(windowManager.getDefaultDisplay().getWidth() + "*" + windowManager.getDefaultDisplay().getHeight());

运行截图:

②Android悬浮框的实现:

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

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

实现流程解析:

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

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

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

<service android:name=".MyWindowService"/>

另外还需要加上下述两个权限:

    <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
    <uses-permission android:name="android.permission.GET_TASKS" />

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

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

package com.jay.example.windowmanagerdemo1;

import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.Toast;

public class MainActivity extends Activity {

	private Button btnShow;
	private Button btnClose;

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);

		btnShow = (Button) findViewById(R.id.btnShow);
		btnClose = (Button) findViewById(R.id.btnClose);

		btnShow.setOnClickListener(new OnClickListener() {
			@Override
			public void onClick(View v) {
				Intent show = new Intent(MainActivity.this, MyWindowService.class);
				show.putExtra(MyWindowService.OPERATION, MyWindowService.OPERATION_SHOW);
		        startService(show);
		        Toast.makeText(MainActivity.this,"悬浮框已开启~", Toast.LENGTH_SHORT).show();
			}
		});

		btnClose.setOnClickListener(new OnClickListener() {
			@Override
			public void onClick(View v) {
				Intent hide = new Intent(MainActivity.this, MyWindowService.class);
				hide.putExtra(MyWindowService.OPERATION, MyWindowService.OPERATION_HIDE);
		        startService(hide);
		        Toast.makeText(MainActivity.this,"悬浮框已开启~", Toast.LENGTH_SHORT).show();
			}
		});
	}
}

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

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

悬浮框的View!

// 定义一个创建悬浮框的方法:
	private void createWindowView() {
		btnView = new Button(getApplicationContext());
		btnView.setBackgroundResource(R.drawable.pig);
		windowManager = (WindowManager) getApplicationContext()
				.getSystemService(Context.WINDOW_SERVICE);
		params = new WindowManager.LayoutParams();

		// 设置Window Type
		params.type = WindowManager.LayoutParams.TYPE_SYSTEM_ALERT;
		// 设置悬浮框不可触摸
		params.flags = WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
				| WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
		// 悬浮窗不可触摸,不接受任何事件,同时不影响后面的事件响应
		params.format = PixelFormat.RGBA_8888;
		// 设置悬浮框的宽高
		params.width = 200;
		params.height = 200;
		params.gravity = Gravity.LEFT;
		params.x = 200;
		params.y = 000;
		// 设置悬浮框的Touch监听
		btnView.setOnTouchListener(new OnTouchListener() {
			//保存悬浮框最后位置的变量
			int lastX, lastY;
			int paramX, paramY;
			@Override
			public boolean onTouch(View v, MotionEvent event) {
				switch (event.getAction()) {
				case MotionEvent.ACTION_DOWN:
					lastX = (int) event.getRawX();
					lastY = (int) event.getRawY();
					paramX = params.x;
					paramY = params.y;
					break;
				case MotionEvent.ACTION_MOVE:
					int dx = (int) event.getRawX() - lastX;
					int dy = (int) event.getRawY() - lastY;
					params.x = paramX + dx;
					params.y = paramY + dy;
					// 更新悬浮窗位置
					windowManager.updateViewLayout(btnView, params);
					break;
				}
				return true;
			}
		});
		windowManager.addView(btnView, params);
        isAdded = true;
	}

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

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

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

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

判断:

	/**
	 * 判断当前界面是否是桌面
	 */
	public boolean isHome(){
		if(mActivityManager == null) {
			mActivityManager = (ActivityManager)getSystemService(Context.ACTIVITY_SERVICE);
		}
	    List<RunningTaskInfo> rti = mActivityManager.getRunningTasks(1);
	    return homeList.contains(rti.get(0).topActivity.getPackageName());
	}

	/**
	 * 获得属于桌面的应用的应用包名称
	 * @return 返回包含所有包名的字符串列表
	 */
	private List<String> getHomes() {
		List<String> names = new ArrayList<String>();
	    PackageManager packageManager = this.getPackageManager();
	    // 属性
	    Intent intent = new Intent(Intent.ACTION_MAIN);
	    intent.addCategory(Intent.CATEGORY_HOME);
	    List<ResolveInfo> resolveInfo = packageManager.queryIntentActivities(intent,
	            PackageManager.MATCH_DEFAULT_ONLY);
	    for(ResolveInfo ri : resolveInfo) {
	        names.add(ri.activityInfo.packageName);
	    }
	    return names;
	}

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

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

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

//定义一个更新界面的Handler
	private Handler mHandler = new Handler() {
		@Override
		public void handleMessage(Message msg) {
			switch(msg.what) {
			case HANDLE_CHECK_ACTIVITY:
				if(isHome()) {
					if(!isAdded) {
						windowManager.addView(btnView, params);
						isAdded = true;
					new Thread(new Runnable() {
						public void run() {
							for(int i=0;i<10;i++){
								try {
									Thread.sleep(1000);
								} catch (InterruptedException e) {e.printStackTrace();}
								Message m = new Message();
								m.what=2;
								mHandler.sendMessage(m);
							}
						}
					}).start();}
				} else {
					if(isAdded) {
						windowManager.removeView(btnView);
						isAdded = false;
					}
				}
				mHandler.sendEmptyMessageDelayed(HANDLE_CHECK_ACTIVITY, 0);
				break;
			}
		}
	};

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

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

@Override
	public int onStartCommand(Intent intent, int flags, int startId) {
		int operation = intent.getIntExtra(OPERATION, OPERATION_SHOW);
		switch(operation) {
		case OPERATION_SHOW:
			mHandler.removeMessages(HANDLE_CHECK_ACTIVITY);
			mHandler.sendEmptyMessage(HANDLE_CHECK_ACTIVITY);
			break;
		case OPERATION_HIDE:
			mHandler.removeMessages(HANDLE_CHECK_ACTIVITY);
			break;
		}
		return super.onStartCommand(intent, flags, startId);
	}

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

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

③设置窗口全屏显示:

		getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
				WindowManager.LayoutParams.FLAG_FULLSCREEN);

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

	public void setKeepScreenOn(Activity activity,boolean keepScreenOn)
	{
		if(keepScreenOn)
		{
			activity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
		}else{
			activity.getWindow().clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
		}
	}

最后说几句:

好了,关于这个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

~好了,最后祝大家元宵节快乐~

时间: 2024-10-12 04:53:50

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

Android提供的系统服务之--AudioManager(音频管理器)

Android提供的系统服务之--AudioManager(音频管理器) ----转载请注明出处:coder-pig AudioManager相关简介与常用方法图: 简单的使用例子: 使用Mediaplayer播放音乐,通过AudioManager调节音量大小与静音: 这里,我们需要把要播放的音频文件放到res下的raw文件夹,这个文件夹默认是没有的,需要自己创建哦! 用来放原生资源的,就是打包编译的时候不会把他变成二进制文件!!! 先来看看效果图吧: 就是播放音乐,然后调高音量的时候可以看到滑

Android提供的系统服务之--TelephonyManager(电话管理器)

Android提供的系统服务之--TelephonyManager(电话管理器) 转载请注明出处--coder-pig TelephonyManager的作用: 用于管理手机通话状态,获取电话信息(设备信息.sim卡信息以及网络信息), 侦听电话状态(呼叫状态服务状态.信号强度状态等)以及可以调用电话拨号器拨打电话! 如何获得TelephonyManager的服务对象: TelephonyManager tManager = (TelephonyManager)getSystemService(

Android提供的系统服务之--SmsManager(短信管理器)

Android提供的系统服务之--SmsManager(短信管理器) --转载请注明出处:coder-pig SmsManager相关介绍以及使用图解: 当然为了方便各位,把代码粘一粘吧,就不用麻烦大家写代码了: 有需要的时候就复制粘贴下吧! 1)调用系统发送短信的功能: public void SendSMSTo(String phoneNumber,String message){ //判断输入的phoneNumber是否为合法电话号码 if(PhoneNumberUtils.isGloba

ANDROID窗口管理服务实现机制和架构分析

 一.功能 窗口管理是ANDROID框架一个重要部分,主要包括如下功能: (1)Z-ordered的维护 (2)窗口的创建.销毁 (3)窗口的绘制.布局 (4)Token管理,AppToken (5)活动窗口管理(FocusWindow) (6)活动应用管理(FocusAPP) (7)输入法管理 (8)系统消息收集与分发 这些功能主要由一个窗口管理服务和相应的客户端来实现的,客户端通过BINDER机制与服务实现交互.       窗口管理服务端负责主要的窗口管理功能,由一个WindowMan

Android窗口管理服务WindowManagerService对壁纸窗口(Wallpaper Window)的管理分析

文章转载至CSDN社区罗升阳的安卓之旅,原文地址:http://blog.csdn.net/luoshengyang/article/details/8550820 Android系统中,壁纸窗口和输入法窗口一样,都是一种特殊类型的窗口,而且它们都是喜欢和一个普通的Activity窗口缠绵在一起.大家可 以充分地想象这样的一个3W场景:输入法窗口在上面,壁纸窗口在下面,Activity窗口夹在它们的中间.在前面一篇文章中,我们已经分析过输入法窗口 是如何压在Activity窗口上面的了.在这篇文

Android提供的系统服务之--PowerManager(电源服务)

Android提供的系统服务之--PowerManager(电源服务) --转载请注明出处:coder-pig 本节引言: 本节主要讲解的Android为我们提供的系统服务中的:PowerManager电源管理的一个API, 用于管理CPU运行,键盘或者屏幕亮起来;不过,除非是迫不得已吧,不然的话,否则应该尽量避免 使用这个类,并且使用完以后一定要及时释放!本节并不太深入的去讲解,因为这个设计到底层的 一些东西,以后需要用到再深入研究,到时再另外写一篇blog总结!所以本节介绍的主要是 一些基本

Android提供的系统服务之--AlarmManager(闹钟服务)

Android提供的系统服务之--AlarmManager(闹钟服务) --转载请注明出处:coder-pig 本节引言: 本节主要介绍的是Android系统服务中的---AlarmManager(闹钟服务), 除了开发手机闹钟外,更多的时候是作为一个全局的定时器,通常与Service 结合,在特定时间启动其他的组件!本节就来对这个AlarmManager来进行解析 同时通过小闹钟与自动换壁纸来演示这个AlarmManager的用法,好了,开始本节的 内容吧! 本节正文: 1.概念与相关属性方法

Android窗口管理服务WindowManagerService对输入法窗口(Input Method Window)的管理分析

文章转载至CSDN社区罗升阳的安卓之旅,原文地址:http://blog.csdn.net/luoshengyang/article/details/8526644 在Android系统中,输入法窗口是一种特殊类型的窗口,它总是位于需要使用输入法的窗口的上面.也就是说,一旦 WindowManagerService服务检测到焦点窗口需要使用输入法,那么它就会调整输入法窗口在窗口堆栈中的位置,使得输入法窗口位于在焦点窗 口的上面,这样用户可以通过输入法窗口来录入字母或者文字.本文就将详细分析Win

Android窗口管理服务WindowManagerService显示Activity组件的启动窗口(Starting Window)的过程分析

文章转载至CSDN社区罗升阳的安卓之旅,原文地址:http://blog.csdn.net/luoshengyang/article/details/8577789 在Android系统中,Activity组件在启动之后,并且在它的窗口显示出来之前,可以显示一个启动窗口.这个启动窗口可以看作是 Activity组件的预览窗口,是由WindowManagerService服务统一管理的,即由WindowManagerService服务负责 启动和结束.在本文中,我们就详细分析WindowManag