在Activity,Service,Window中监听Home键和返回键的一些思考,如何把事件传递出来的做法!
在Activity,Service,Window中监听Home键和返回键的一些思考,如何把事件传递出来的做法!
其实像按键的监听,我相信很多人都很熟练了,我肯定也不会说这些基础的东西,所以,前期,还是一笔带过一下,我们重点说下后半部分吧
一.Activity监听返回键
这个其实大家都知道,首先我们要了解流程,你要屏蔽这个返回键,那你就要拿到这个返回键的事件了,所以我们要监听了,而在Activity中,有两种做法,首先,系统是提供了返回键的监听的
/**
* 返回键监听
*/
@Override
public void onBackPressed() {
//super.onBackPressed();
}
我们只要不让使用父类的onBackPressed方法,那返回键就没作用了,还有一种办法就是系统提供的按键监听的方法了
/**
* 按键监听
* @param keyCode
* @param event
* @return
*/
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
switch (keyCode) {
case KeyEvent.KEYCODE_BACK:
//返回键
Toast.makeText(this,"返回键",Toast.LENGTH_SHORT).show();
break;
}
return super.onKeyDown(keyCode, event);
}
onKeyDown是按下的动作,键盘按下的动作就可以,他可以监听到很多的按键,比如数字键,当然,现在数字键的手机还是比较少的,KeyEvent 为我们封装了绝大多数的监听,我们来看一下演示的效果
二.Service中监听Home键
onKeyDown中有监听Home键的方法,但是你会发现监听起来是无效的,这里其实可以通过广播的形式来监听Home键,不光适用在Service,同样的也可以适用在Activity中,我们新建一个HomeService
package com.liuguilin.keyevevtsample;
/*
* 项目名: KeyEvevtSample
* 包名: com.liuguilin.keyevevtsample
* 文件名: HomeService
* 创建者: LGL
* 创建时间: 2016/8/20 11:00
* 描述: Home键监听
*/
import android.app.Service;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.IBinder;
import android.widget.Toast;
public class HomeService extends Service {
//监听Home
private HomeWatcherReceiver mHomeKeyReceiver;
public static final String SYSTEM_DIALOG_REASON_KEY = "reason";
public static final String SYSTEM_DIALOG_REASON_HOME_KEY = "homekey";
@Override
public IBinder onBind(Intent intent) {
return null;
}
@Override
public void onCreate() {
super.onCreate();
//注册Home监听广播
mHomeKeyReceiver = new HomeWatcherReceiver();
final IntentFilter homeFilter = new IntentFilter(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
registerReceiver(mHomeKeyReceiver, homeFilter);
}
@Override
public void onDestroy() {
super.onDestroy();
//取消监听
unregisterReceiver(mHomeKeyReceiver);
}
/**
* 监听Home键
*/
class HomeWatcherReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (action.equals(Intent.ACTION_CLOSE_SYSTEM_DIALOGS)) {
String reason = intent.getStringExtra(SYSTEM_DIALOG_REASON_KEY);
if (SYSTEM_DIALOG_REASON_HOME_KEY.equals(reason)) {
Toast.makeText(context, "Home按键", Toast.LENGTH_SHORT).show();
}
}
}
}
}
OK,为了测试,我们加上两个button
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
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">
<Button
android:id="@+id/openHome"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="打开Home监听"/>
<Button
android:id="@+id/closeHome"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="关闭Home监听"/>
</LinearLayout>
同时增加两个点击事件
findViewById(R.id.openHome).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
startService(new Intent(MainActivity.this,HomeService.class));
}
});
findViewById(R.id.closeHome).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
stopService(new Intent(MainActivity.this,HomeService.class));
}
});
对了,别忘记了注册一下Service
<service android:name=".HomeService"/>
好的,我们来检验一下效果吧
OK
三.在Window中监听返回键
这里,其实也是我项目中的一个需求,首选,我们先不说逻辑,先把window写好,我们为了阅读性,我们再新建一个Service——WindowService,同时去注册一下
<service android:name=".WindowService"/>
而我们的需求,就是启动一个service,service里加载一个window,但是这样做其实是拿不到我们的按键时间的,都给其他人拿走了,但是这些都是后话了,我们先把window的代码写好
package com.liuguilin.keyevevtsample;
/*
* 项目名: KeyEvevtSample
* 包名: com.liuguilin.keyevevtsample
* 文件名: WindowService
* 创建者: LGL
* 创建时间: 2016/8/20 11:11
* 描述: 窗口服务
*/
import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.graphics.PixelFormat;
import android.os.IBinder;
import android.view.View;
import android.view.WindowManager;
import android.widget.Button;
public class WindowService extends Service implements View.OnClickListener {
//窗口管理器
private WindowManager wm;
//view
private View mView;
//布局参数
private WindowManager.LayoutParams layoutParams;
//取消window
private Button btnCloseWindow;
@Override
public IBinder onBind(Intent intent) {
return null;
}
@Override
public void onCreate() {
super.onCreate();
initWindow();
}
/**
* 初始化Window
*/
private void initWindow() {
//窗口管理器
wm = (WindowManager) getApplicationContext().getSystemService(Context.WINDOW_SERVICE);
//布局参数
layoutParams = new WindowManager.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.setOnClickListener(this);
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
//显示window
wm.addView(mView, layoutParams);
return START_STICKY;
}
@Override
public void onDestroy() {
super.onDestroy();
}
/**
* 点击事件
*
* @param view
*/
@Override
public void onClick(View view) {
switch (view.getId()) {
case R.id.btnCloseWindow:
//取消window
wm.removeView(mView);
break;
}
}
}
这里有一点要注意的地方,首先,window是需要权限的
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>
好的,为了测试,我们些个按钮
<Button
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(new View.OnClickListener() {
@Override
public void onClick(View view) {
startService(new Intent(MainActivity.this, WindowService.class));
}
});
OK,到这里,我们的window算是写好了,但是写好了,也就出来我们今天要探讨的问题了
你这个Window,拿不到返回事件,所以我按返回键的时候Activity退出了,window还在,那window就是没有拿到这个事件了,那我们应该怎么去拿到这个事件呢?我们怎么按返回键先退出Window再退出Activity呢?其实我们只要注意这行代码
mView = View.inflate(getApplicationContext(), R.layout.layout_window_item, null);
我们这里也是有一个View的,我们可用把这个事件给拦截过来,这都是有可能的,想到了就去做,那我们最终要怎么去做?我们可用重写这个view,把事件通过接口的方式绑定在这个window上,如果不听不明白,你可以跟我一起来看下这段代码,我们这个view,我给他一个容器,那我们就重写LinearLayout
package com.liuguilin.keyevevtsample;
/*
* 项目名: KeyEvevtSample
* 包名: com.liuguilin.keyevevtsample
* 文件名: SessionLinearLayout
* 创建者: LGL
* 创建时间: 2016/8/20 11:33
* 描述: 事件分发/拦截返回按钮
*/
import android.content.Context;
import android.util.AttributeSet;
import android.view.KeyEvent;
import android.widget.LinearLayout;
public class SessionLinearLayout extends LinearLayout {
private DispatchKeyEventListener mDispatchKeyEventListener;
public SessionLinearLayout(Context context) {
super(context);
}
public SessionLinearLayout(Context context, AttributeSet attrs) {
super(context, attrs);
}
public SessionLinearLayout(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
@Override
public boolean dispatchKeyEvent(KeyEvent event) {
if (mDispatchKeyEventListener != null) {
return mDispatchKeyEventListener.dispatchKeyEvent(event);
}
return super.dispatchKeyEvent(event);
}
public DispatchKeyEventListener getDispatchKeyEventListener() {
return mDispatchKeyEventListener;
}
public void setDispatchKeyEventListener(DispatchKeyEventListener mDispatchKeyEventListener) {
this.mDispatchKeyEventListener = mDispatchKeyEventListener;
}
//监听接口
public static interface DispatchKeyEventListener {
boolean dispatchKeyEvent(KeyEvent event);
}
}
我在这里,只是把他作为一个中转站,把事件给传递出来就好了,那我们现在window加载的layout的根布局就是他了
<?xml version="1.0" encoding="utf-8"?>
<com.liuguilin.keyevevtsample.SessionLinearLayout
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">
<Button
android:id="@+id/btnCloseWindow"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="关闭窗口"/>
</com.liuguilin.keyevevtsample.SessionLinearLayout>
那我们的View也是他了,我们直接来看详细的代码吧
package com.liuguilin.keyevevtsample;
/*
* 项目名: KeyEvevtSample
* 包名: com.liuguilin.keyevevtsample
* 文件名: WindowService
* 创建者: LGL
* 创建时间: 2016/8/20 11:11
* 描述: 窗口服务
*/
import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.graphics.PixelFormat;
import android.os.IBinder;
import android.view.KeyEvent;
import android.view.View;
import android.view.WindowManager;
import android.widget.Button;
public class WindowService extends Service implements View.OnClickListener {
//窗口管理器
private WindowManager wm;
//view
private SessionLinearLayout mView;
//布局参数
private WindowManager.LayoutParams layoutParams;
//取消window
private Button btnCloseWindow;
@Override
public IBinder onBind(Intent intent) {
return null;
}
@Override
public void onCreate() {
super.onCreate();
initWindow();
}
/**
* 初始化Window
*/
private void initWindow() {
//窗口管理器
wm = (WindowManager) getApplicationContext().getSystemService(Context.WINDOW_SERVICE);
//布局参数
layoutParams = new WindowManager.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);
}
/**
* 返回鍵监听
*/
private SessionLinearLayout.DispatchKeyEventListener mDispatchKeyEventListener = new SessionLinearLayout.DispatchKeyEventListener() {
@Override
public boolean dispatchKeyEvent(KeyEvent event) {
if (event.getKeyCode() == KeyEvent.KEYCODE_BACK) {
if (mView.getParent() != null) {
wm.removeView(mView);
}
return true;
}
return false;
}
};
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
//显示window
wm.addView(mView, layoutParams);
return START_STICKY;
}
@Override
public void onDestroy() {
super.onDestroy();
}
/**
* 点击事件
*
* @param view
*/
@Override
public void onClick(View view) {
switch (view.getId()) {
case R.id.btnCloseWindow:
//取消window
wm.removeView(mView);
break;
}
}
}
OK,我们这里只是用了一个小技巧而已,但是在实际开发当中还是很实用的,我们直接来看效果
好的,本篇博文就先到这里,感谢你的耐心阅读,觉得不错的haunted赞一个哟,有不足的地方也请指正
Demo下载:http://download.csdn.net/detail/qq_26787115/9608248
我的群:555974449欢迎一起进来交流!
在Activity,Service,Window中监听Home键和返回键的一些思考,如何把事件传递出来的做法!的更多相关文章
- 在 React 组件中监听 android 手机物理返回/回退/back键事件
当前端页面嵌入到 webview 中运行时,有时会需要监听手机的物理返回按键事件来做一些自定义的操作. 比如我最近遇到的,在一个页面里面有批量选择的功能,当点击手机的返回键时,清除页面上的选中状态.我 ...
- 从网页监听Android设备的返回键
最近搞Android项目的时候,遇到一个比较蛋疼的需求,需要从Client App调用系统浏览器打开一个页面,进行杂七杂八的一些交互之后,返回到App.如何打开浏览器和如何返回App这里就不说了,有兴 ...
- HTML5 监听移动端浏览器返回键兼容版本
// 往windosw对象中的历史记录注入URL的方法 function addUrl() { var state = { title: "title", url: "# ...
- vue里监听安卓的物理返回键
Hybrid App中,原生内嵌H5单页,由于安卓是有物理返回键的,按安卓物理返回键的时候会返回到上一个路由. 实际中需求是:当有弹层的时候,按物理返回键是关闭弹层,是页面的时候才执行返回上一个路由, ...
- Cocos Creator 监听安卓屏幕下方返回键
addEscEvent = function(node){ cc.eventManager.addListener({ event: cc.EventListener.KEYBOARD, onKeyP ...
- Android-服务中监听电源键和Home键的广播、在锁屏下仍然工作的方法
Android-服务中监听电源键和Home键的广播 http://blog.csdn.net/u014657752/article/details/49512485 Android开发之如何监听让服 ...
- Fragment中监听onKey事件,没你想象的那么难。
项目中越来越多的用到Fragment,在用Fragment取代TabHost的时候遇到了一个问题,我们都知道,TabHost的Tab为Activity实例,有OnKey事件,但是Fragment中没有 ...
- window.onresize监听事件
window.onresize监听事件 onresize 事件会在窗口或框架被调整大小时发生. 支持onresize的标签:<a>, <address>, <b>, ...
- 在vue中监听storage的变化
1.首先在main.js中给Vue.protorype注册一个全局方法,其中,我们约定好了想要监听的sessionStorage的key值为’watchStorage’,然后创建一个StorageEv ...
随机推荐
- ●BZOJ 3640 JC的小苹果
题链: http://www.lydsy.com/JudgeOnline/problem.php?id=3640题解: 期望dp,高斯消元 设dp[i][h]在i位置且血量为h这个状态的期望经过次数. ...
- 【网络流】【BZOJ1221】【HNOI2001】软件开发
原题链接:http://www.lydsy.com/JudgeOnline/problem.php?id=1221 题意:你有3种方法进行对毛巾的处理,不同的处理方法有不同的cost,问你要如何规划才 ...
- hdu 5437Alisha’s Party(优先队列)
题意:邀请k个朋友,每个朋友带有礼物价值不一,m次开门,每次开门让一定人数p(如果门外人数少于p,全都进去)进来,当所有人到时会再开一次,每次都是礼物价值高的人先进. /*小伙伴最开始gg了,结果发现 ...
- bzoj4596[Shoi2016]黑暗前的幻想乡 Matrix定理+容斥原理
4596: [Shoi2016]黑暗前的幻想乡 Time Limit: 20 Sec Memory Limit: 256 MBSubmit: 464 Solved: 264[Submit][Sta ...
- ORACLE 启动过程
1 STARTUP NOMOUNT 1.读取环境变量下dbs目录下的参数文件(spfile/pfile) 查找参数文件的顺序如上面列表的,读取优先级: spfilechongshi.ora > ...
- WebService接口与HTTP接口的联系
1 WebService有很多协议,为什么HTTP比较流行? WebService是个很重型的规范,它的应用协议是SOAP(简单对象访问协议),它所依赖的下层通信方式不单单是HTTP,也有SOAP o ...
- 了解ASCII、gb系列、Unicode、UTF-8的区别
转自:http://www.douban.com/note/334994123/?type=rec ● 为什么有这么多编码? ● UTF-8和GB2312有什么区别? ● 我们在国内做网站是用UTF- ...
- 反射获取 Class
原文链接:https://www.codemore.top/cates/Backend/post/2018-04-26/reflect-class 类 Java中每个类型要么是引用类型,要么是原生类型 ...
- Go 语言类型转换
类型转换用于将一种数据类型的变量转换为另外一种类型的变量.Go 语言类型转换基本格式如下: type_name(expression) type_name 为类型,expression 为表达式. 实 ...
- Docker常见仓库Ubuntu
Ubuntu 基本信息 Ubuntu 是流行的 Linux 发行版,其自带软件版本往往较新一些. 该仓库提供了 Ubuntu从12.04 ~ 14.10 各个版本的镜像. 使用方法 默认会启动一个最小 ...