在Activity,Service,Window中监听Home键和返回键的一些思考,如何把事件传递出来的做法!
一.Activity监听返回键
这个其实大家都知道,首先我们要了解流程,你要屏蔽这个返回键,那你就要拿到这个返回键的事件了,所以我们要监听了,而在Activity中,有两种做法,首先,系统是提供了返回键的监听的
/
返回键监听
/
@Override
publicvoidonBackPressed(){
//super.onBackPressed();
}
我们只要不让使用父类的onBackPressed方法,那返回键就没作用了,还有一种办法就是系统提供的按键监听的方法了
/
按键监听
@paramkeyCode
@paramevent
@return
/
@Override
publicbooleanonKeyDown(intkeyCode,KeyEventevent){
switch(keyCode){
caseKeyEvent.KEYCODE_BACK:
//返回键
Toast.makeText(this,"返回键",Toast.LENGTH_SHORT).show();
break;
}
returnsuper.onKeyDown(keyCode,event);
}
onKeyDown是按下的动作,键盘按下的动作就可以,他可以监听到很多的按键,比如数字键,当然,现在数字键的手机还是比较少的,KeyEvent为我们封装了绝大多数的监听,我们来看一下演示的效果
二.Service中监听Home键
onKeyDown中有监听Home键的方法,但是你会发现监听起来是无效的,这里其实可以通过广播的形式来监听Home键,不光适用在Service,同样的也可以适用在Activity中,我们新建一个HomeService
packagecom.liuguilin.keyevevtsample;
/
项目名:KeyEvevtSample
包名:com.liuguilin.keyevevtsample
文件名:HomeService
创建者:LGL
创建时间:2016/8/2011:00
描述:Home键监听
/
importandroid.app.Service;
importandroid.content.BroadcastReceiver;
importandroid.content.Context;
importandroid.content.Intent;
importandroid.content.IntentFilter;
importandroid.os.IBinder;
importandroid.widget.Toast;
publicclassHomeServiceextendsService{
//监听Home
privateHomeWatcherReceivermHomeKeyReceiver;
publicstaticfinalStringSYSTEM_DIALOG_REASON_KEY="reason";
publicstaticfinalStringSYSTEM_DIALOG_REASON_HOME_KEY="homekey";
@Override
publicIBinderonBind(Intentintent){
returnnull;
}
@Override
publicvoidonCreate(){
super.onCreate();
//注册Home监听广播
mHomeKeyReceiver=newHomeWatcherReceiver();
finalIntentFilterhomeFilter=newIntentFilter(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
registerReceiver(mHomeKeyReceiver,homeFilter);
}
@Override
publicvoidonDestroy(){
super.onDestroy();
//取消监听
unregisterReceiver(mHomeKeyReceiver);
}
/
监听Home键
/
classHomeWatcherReceiverextendsBroadcastReceiver{
@Override
publicvoidonReceive(Contextcontext,Intentintent){
Stringaction=intent.getAction();
if(action.equals(Intent.ACTION_CLOSE_SYSTEM_DIALOGS)){
Stringreason=intent.getStringExtra(SYSTEM_DIALOG_REASON_KEY);
if(SYSTEM_DIALOG_REASON_HOME_KEY.equals(reason)){
Toast.makeText(context,"Home按键",Toast.LENGTH_SHORT).show();
}
}
}
}
}
OK,为了测试,我们加上两个button
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:orientation="vertical"
android:padding="10dp">
同时增加两个点击事件
findViewById(R.id.openHome).setOnClickListener(newView.OnClickListener(){
@Override
publicvoidonClick(Viewview){
startService(newIntent(MainActivity.this,HomeService.class));
}
});
findViewById(R.id.closeHome).setOnClickListener(newView.OnClickListener(){
@Override
publicvoidonClick(Viewview){
stopService(newIntent(MainActivity.this,HomeService.class));
}
});
对了,别忘记了注册一下Service
好的,我们来检验一下效果吧
OK
三.在Window中监听返回键
这里,其实也是我项目中的一个需求,首选,我们先不说逻辑,先把window写好,我们为了阅读性,我们再新建一个Service——WindowService,同时去注册一下
1
1
而我们的需求,就是启动一个service,service里加载一个window,但是这样做其实是拿不到我们的按键时间的,都给其他人拿走了,但是这些都是后话了,我们先把window的代码写好
packagecom.liuguilin.keyevevtsample;
/
项目名:KeyEvevtSample
包名:com.liuguilin.keyevevtsample
文件名:WindowService
创建者:LGL
创建时间:2016/8/2011:11
描述:窗口服务
/
importandroid.app.Service;
importandroid.content.Context;
importandroid.content.Intent;
importandroid.graphics.PixelFormat;
importandroid.os.IBinder;
importandroid.view.View;
importandroid.view.WindowManager;
importandroid.widget.Button;
publicclassWindowServiceextendsServiceimplementsView.OnClickListener{
//窗口管理器
privateWindowManagerwm;
//view
privateViewmView;
//布局参数
privateWindowManager.LayoutParamslayoutParams;
//取消window
privateButtonbtnCloseWindow;
@Override
publicIBinderonBind(Intentintent){
returnnull;
}
@Override
publicvoidonCreate(){
super.onCreate();
initWindow();
}
/
初始化Window
/
privatevoidinitWindow(){
//窗口管理器
wm=(WindowManager)getApplicationContext().getSystemService(Context.WINDOW_SERVICE);
//布局参数
layoutParams=newWindowManager.LayoutParams();
layoutParams.width=WindowManager.LayoutParams.MATCH_PARENT;
layoutParams.height=WindowManager.LayoutParams.MATCH_PARENT;
layoutParams.flags=
//WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE|不能触摸
WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON|WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH;
//格式
layoutParams.format=PixelFormat.TRANSLUCENT;
//类型
layoutParams.type=WindowManager.LayoutParams.TYPE_PHONE;
mView=View.inflate(getApplicationContext(),R.layout.layout_window_item,null);
btnCloseWindow=(Button)mView.findViewById(R.id.btnCloseWindow);
btnCloseWindow.setOnClickListwww.hunanwang.netener(this);
}
@Override
publicintonStartCommand(Intentintent,intflags,intstartId){
//显示window
wm.addView(mView,layoutParams);
returnSTART_STICKY;
}
@Override
publicvoidonDestroy(){
super.onDestroy();
}
/
点击事件
@paramview
/
@Override
publicvoidonClick(Viewview){
switch(view.getId()){
caseR.id.btnCloseWindow:
//取消window
wm.removeView(mView);
break;
}
}
}
这里有一点要注意的地方,首先,window是需要权限的
好的,为了测试,我们些个按钮
android:id="@+id/openWindow"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="打开Window"
android:textAllCaps="false"/>
同时给他加上点击事件
findViewById(R.id.openWindow).setOnClickListener(newView.OnClickListener(){
@Override
publicvoidonClick(Viewview){
startService(newIntent(MainActivity.this,WindowService.class));
}
});
OK,到这里,我们的window算是写好了,但是写好了,也就出来我们今天要探讨的问题了
你这个Window,拿不到返回事件,所以我按返回键的时候Activity退出了,window还在,那window就是没有拿到这个事件了,那我们应该怎么去拿到这个事件呢?我们怎么按返回键先退出Window再退出Activity呢?其实我们只要注意这行代码
mView=View.inflate(getApplicationContext(),R.layout.layout_window_item,null);
1
1
我们这里也是有一个View的,我们可用把这个事件给拦截过来,这都是有可能的,想到了就去做,那我们最终要怎么去做?我们可用重写这个view,把事件通过接口的方式绑定在这个window上,如果不听不明白,你可以跟我一起来看下这段代码,我们这个view,我给他一个容器,那我们就重写LinearLayout
packagecom.liuguilin.keyevevtsample;
/
项目名:KeyEvevtSample
包名:com.liuguilin.keyevevtsample
文件名:SessionLinearLayout
创建者:LGL
创建时间:2016/8/2011:33
描述:事件分发/拦截返回按钮
/
importandroid.content.Context;
importandroid.util.AttributeSet;
importandroid.view.KeyEvent;
importandroid.widget.LinearLayout;
publicclassSessionLinearLayoutextendsLinearLayout{
privateDispatchKeyEventListenermDispatchKeyEventListener;
publicSessionLinearLayout(Contextcontext){
super(context);
}
publicSessionLinearLayout(Contextcontext,AttributeSetattrs){
super(context,attrs);
}
publicSessionLinearLayout(Contextcontext,AttributeSetattrs,intdefStyleAttr){
super(context,attrs,defStyleAttr);
}
@Override
publicbooleandispatchKeyEvent(KeyEventevent){
if(mDispatchKeyEventListener!=null){
returnmDispatchKeyEventListener.dispatchKeyEvent(event);
}
returnsuper.dispatchKeyEvent(event);
}
publicDispatchKeyEventListenergetDispatchKeyEventListener(){
returnmDispawww.shanxiwang.nettchKeyEventListener;
}
publicvoidsetDispatchKeyEventListener(DispatchKeyEventListenermDispatchKeyEventListener){
this.mDispatchKeyEventListener=mDispatchKeyEventListener;
}
//监听接口
publicstaticinterfaceDispatchKeyEventListener{
booleandispatchKeyEvent(KeyEventevent);
}
}
我在这里,只是把他作为一个中转站,把事件给传递出来就好了,那我们现在window加载的layout的根布局就是他了
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:alpha="0.3"
android:background="@color/colorAccent"
android:gravity="center"
android:orientation="vertical">
android:id="@+id/btnCloseWindow"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="关闭窗口"/>
那我们的View也是他了,我们直接来看详细的代码吧
packagecom.liuguilin.keyevevtsample;
/
项目名:KeyEvevtSample
包名:com.liuguilin.keyevevtsample
文件名:WindowService
创建者:LGL
创建时间:2016/8/2011:11
描述:窗口服务
/
importandroid.app.Service;
importandroid.content.Context;
importandroid.content.Intent;
importandroid.graphics.PixelFormat;
importandroid.os.IBinder;
importandroid.view.KeyEvent;
importandroid.view.View;
importandroid.view.WindowManager;
importandroid.widget.Button;
publicclassWindowServiceextendsServiceimplementsView.OnClickListener{
//窗口管理器
privateWindowManagerwm;
//view
privateSessionLinearLayoutmView;
//布局参数
privateWindowManager.LayoutParamslayoutParams;
//取消window
privateButtonbtnCloseWindow;
@Override
publicIBinderonBind(Intentintent){
returnnull;
}
@Override
publicvoidonCreate(){
super.onCreate();
initWindow();
}
/
初始化Window
/
privatevoidinitWindow(){
//窗口管理器
wm=(WindowManager)getApplicationContext().getSystemService(Context.WINDOW_SERVICE);
//布局参数
layoutParams=newWindowManager.LayoutParams();
layoutParams.width=WindowManager.LayoutParams.MATCH_PARENT;
layoutParams.height=WindowManager.LayoutParams.MATCH_PARENT;
layoutParams.flags=
//WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE|不能触摸
WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON|WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH
;
//格式
layoutParams.format=PixelFormat.TRANSLUCENT;
//类型
layoutParams.type=WindowManager.LayoutParams.TYPE_PHONE;
mView=(SessionLinearLayout)View.inflate(getApplicationContext(),R.layout.layout_window_item,null);
btnCloseWindow=(Button)mView.findViewById(R.id.btnCloseWindow);
btnCloseWindow.setOnClickListener(this);
//监听返回键
mView.setDispatchKeyEventListener(mDispatchKeyEventListener);
}
/
返回鍵监听
/
privateSessionLinearLayout.DispatchKeyEventListenermDispatchKeyEventListener=newSessionLinearLayout.DispatchKeyEventListener(){
@Override
publicbooleandispatchKeyEvent(KeyEventevent){
if(event.getKeyCode()==KeyEvent.KEYCODE_BACK){
if(mView.getParent()!=null){
wm.removeView(mView);
}
returntrue;
}
returnfalse;
}
};
@Override
publicintonStartCommand(Intentintent,intflags,intstartId){
//显示window
wm.addView(mView,layoutParams);
returnSTART_STICKY;
}
@Override
publicvoidonDestroy(){
super.onDestroy();
}
/
点击事件
@paramview
/
@Override
publicvoidonClick(Viewview){
switch(view.getId()){
caseR.id.btnCloseWindow:
//取消window
wm.removeView(mView);
break;
}
}
}
OK,我们这里只是用了一个小技巧而已,但是在实际开发当中还是很实用的,我们直接来看效果
|
|