解决Cordova多页面注册backbutton事件,一个页面响应过事件以后,其他页面不响应的问题
来源:互联网 发布:淘宝买电视没有合格证 编辑:程序博客网 时间:2024/05/19 23:56
开发环境:
Android Studio,Cordova5.3.3
问题描述:
页面1:
<html><script type="text/javascript" src="cordova.js"></script><script>document.addEventListener('deviceready', function(){document.addEventListener("backbutton", onBackKeyDown, false);},false);function onBackKeyDown(){//}</script></html>页面2:
<html><script type="text/javascript" src="cordova.js"></script><script>document.addEventListener('deviceready', function(){document.addEventListener("backbutton", onBackKeyDown, false);},false);function onBackKeyDown(){//}</script></html>当我在第一个界面点击返回键,程序正常响应,跳转到第二个页面时,再次点击返回键无效果,甚至连音量加减键都不能使用。然而第一个界面不触发返回事件,跳转第二个界面正常响应。网上也有朋友遇到类似的问题,但是均没有得到解决。
问题分析:
还是相信那句话,在源码面前没有秘密,所以我从源码着手查找问题原因及解决办法。
首先我从cordova.js进行分析,因为我们是通过这个文件注册backbutton事件的。cordova.js 1532行:
var APP_PLUGIN_NAME = Number(cordova.platformVersion.split('.')[0]) >= 4 ? 'CoreAndroid' : 'App'; // Inject a listener for the backbutton on the document. var backButtonChannel = cordova.addDocumentEventHandler('backbutton'); backButtonChannel.onHasSubscribersChange = function() { // If we just attached the first handler or detached the last handler, // let native know we need to override the back button. exec(null, null, APP_PLUGIN_NAME, "overrideBackbutton", [this.numHandlers == 1]); };可以看出4.x版本以上,cordova.js是采用CoreAndroid进行返回键注册的,调用的方法是overrideBackbutton方法。
下面看CoreAndroid.java,231行:
public void overrideBackbutton(boolean override) { LOG.i("App", "WARNING: Back Button Default Behavior will be overridden. The backbutton event will be fired!"); webView.setButtonPlumbedToJs(KeyEvent.KEYCODE_BACK, override); }可以看出,已将backbutton事件注册了,具体注册源码可自行查看。
下面看下返回事件是如何从native传到webview的。
public Boolean onDispatchKeyEvent(KeyEvent event) - CordovaWebViewImpl.java
private void sendJavascriptEvent(String event) - CordovaWebViewImpl.java
public void fireJavascriptEvent(String action) - CoreAndroid.java
private void sendEventMessage(String action) - CoreAndroid.java
public void sendPluginResult(PluginResult pluginResult) - CallbackContext.java
webView.sendPluginResult(pluginResult, callbackId);//最终就是调用这句代码向webview发送backbutton事件的。
当我跟踪调试代码的时候时,我发现第二次未响应的时候,上面的代码确实执行了,但callbackId还是之前的值。callbackId是每次cordova.js初始化的时候生成的,并且我还发现,每次切换界面的时候,CoreAndroid等所有插件都是重新初始化的,一会儿拿出证据来。下面看代码:
private void sendJavascriptEvent(String event) { if (appPlugin == null) { appPlugin = (CoreAndroid)pluginManager.getPlugin(CoreAndroid.PLUGIN_NAME); } if (appPlugin == null) { LOG.w(TAG, "Unable to fire event without existing plugin"); return; } appPlugin.fireJavascriptEvent(event);}
这里可以看出,只要调用过一次sendJavascriptEvent()方法后,appPlugin对象就已经存在了CordovaWebViewImpl对象里面了,那么上面的出现问题的原因也就解释清楚了。
解决办法:
在CordovaWebViewImpl.java的public void loadUrlIntoView(final String url, boolean recreatePlugins)中,
public void loadUrlIntoView(final String url, boolean recreatePlugins) { LOG.d(TAG, ">>> loadUrl(" + url + ")"); if (url.equals("about:blank") || url.startsWith("javascript:")) { engine.loadUrl(url, false); return; } recreatePlugins = recreatePlugins || (loadedUrl == null); if (recreatePlugins) { // Don't re-initialize on first load. if (loadedUrl != null) { resetCoreAndroidPlugin(); pluginManager.init(); } loadedUrl = url; }此处可以看出每次加载页面时,使用pluginManager.init();方法来初始化插件。
这里我是用我自己添加的resetCoreAndroidPlugin()方法,来重置CordovaWebViewImpl里面的appPlugin变量,resetCoreAndroidPlugin()方法实现如下
public void resetCoreAndroidPlugin(){ appPlugin = null; }
我在github上fork了cordova-android源码,已经pull request,点击查看
文笔不好,如有不明白之处可以共同探讨。才疏学浅,如有不对的地方,请指正!
请关注我的新浪微博
- 解决Cordova多页面注册backbutton事件,一个页面响应过事件以后,其他页面不响应的问题
- js 页面不响应回车事件
- 页面添加蒙版,但是不影响页面其他事件响应
- 不刷新页面响应超链接a标签的点击事件
- 键盘响应页面按钮事件
- jQuery页面加载响应事件
- 响应web页面上的回车键事件。。。
- 一个页面响应不能结束的问题
- 重写Cordova的backbutton事件
- UIWebView与javascript交互二通过页面的响应事件获取页面输入框内的值
- 解决通过UIAlertView按钮点击事件pop回上级页面键盘会响应问题
- phonegap监听backbutton点击事件后,其他页面点击回退键出现无反应现象
- 网页中嵌入flash 设置了wmode=transparent,页面的flash不响应事件
- VBS和页面中响应COM的事件
- asp.net中页面指定回车的响应事件
- 页面响应事件跳转的两种方法
- js响应刷新页面或者关闭页面事件
- jquery页面加载响应事件$(document).ready()与js页面加载响应事件window.onload()的区别
- iOS中邮箱-电话号码-身份证号码等的验证代码
- UEFI模式安装win8,让开机速度快如闪电!
- Day 2: AngularJS —— 对AngularJS的初步认识
- A child container failed during start 错误解决方法
- 微信“公众平台测试账号”接口接入指南
- 解决Cordova多页面注册backbutton事件,一个页面响应过事件以后,其他页面不响应的问题
- extends和implements区别-Android学习笔记
- 关于”error conflicting types for function”编译错误的分析
- photoShop支持retina显示屏
- nginx 源码学习笔记(二十)—— event 模块(一) ——初始化
- 使用 virtualenvwrapper 隔离 python 项目的库依赖
- 漫游问题
- FormBean拷贝到JavaBean日期的转换
- 【Leetcode】之Search Insert Position