Android中WebView中执行JavaScript获取页面的宽高都是0的问题

最近使用Android中的WebView开发应用,结果在实际使用的时候,前端开发的网页展现的时候,总是什么都看不到,结果跟踪分析发现,页面在加载完成后,就去获取页面的宽高,然后根据页面的宽高进行页面的渲染,但是页面加载完成后JavaScript中得到的页面的宽高都是0,结果就导致整个的页面被渲染成了空页面。

项目是使用一个Dialog里面嵌入WebView的方式进行处理的,当网页加载完成之前,是不显示出来的,只有当网页加载完成后,页面才会展现出来。

实际的情况是,如果先展示Dialog,等整个Dialog已经完全展现出来之后,再去加载页面,这个时候,JavaScript代码是可以获取到正确的宽高的。但是,如果先加载页面,然后等待页面的加载完成通知,再去显示页面的时候,这个时候,由于Dialog还没有显示出来,此时内嵌的WebView并没有得到实际的宽度高度,因此只能获得到0。

示例工程的代码如下:

布局文件layout_webview.xml

对话框代码WebViewDialog.java

主界面代码MainActivity.java

主界面布局文件activity_main.xml

完整运行整个例子,会发现最后输出的屏幕的宽高信息都是0。

这个问题发生的原因是由于界面在页面加载之后才会显示,由于页面还没有显示,因此从JavaScript中获取页面的大小的时候,只能获取到0.

这个问题如果要求页面解决的话,那么编写网页的开发人员,只要监听window.onsize事件即可。

如果要求WebView的开发者来解决的话,则其解决方式如下:

1.修改WebViewDialog初始化网页时候的策略,初始化时候禁止JavaScript执行。WebViewDialog构造函数中的mWebView.getSettings().setJavaScriptEnabled(true);调整成mWebView.getSettings().setJavaScriptEnabled(false);

2.页面加载逻辑照旧执行。

3.实现DialogonAttachedToWindow函数,在这个函数中重新加载数据

最终的WebViewDialog.Java的代码如下:

Android Studio升级到2.2正式版本后,在Windows命令行中执行“gradlew build”时,报告错误“Unsupported major.minor version 52.0”

Android Studio升级到2.2正式版本后,在Android Studio中编译一切正常。但是在Windows命令行中执行“gradlew build”时,报告如下错误:

这个原因,目前本人遇到的原因是,机器上同时安装了jdk1.7.0_80jdk1.8.0_73两个版本的JDK,而环境变量中的JAVA_HOME指向的是jdk1.7.0_80

解决方法就是修改JAVA_HOME指向jdk1.8.0_73即可。

注意,修改完成环境变量后,需要重启一下Android Studio,以及Windows命令行窗口。否则环境变量不生效。

Android真机使用Mockito-1.10.19+Dexmaker-1.2在Mock仅包内可见类时报告错误“java.lang.UnsupportedOperationException: cannot proxy inaccessible class ***”

Android真机使用Mockito-1.10.19+Dexmaker-1.2Mock仅包内可见类时报告如下错误:

被测试类代码如下:

注意上述被测试类前面没有声明public,因此默认是default访问,也就是包内可见。我们下面的测试代码跟被测试类属于同一个包名package com.yunos.tv.shake.biz,因此,按理说,是可以正常访问的。
测试类的代码如下:

这个问题只在ART虚拟机下面发生异常,相同的代码在Dalvik下面是完全正常的。
问题发生的原因暂时还不能确定,应该是ART虚拟机实现功能的时候的不兼容导致的。
解决方法为在测试代码中声明一个继承被测试类的子类,并且把子类声明成public
如下:

修改后的测试代码如下:

即可解决上述问题。

Android ContentProvider使用时出现的错误“java.lang.SecurityException: Permission Denial: opening provider ***”

AndroidAPK上自定义了一个ContentProvider,但是在调用者使用时出现的错误"java.lang.SecurityException: Permission Denial: opening provider ***"。

查询了半天才发现是由于在声明ContentProvider的时候没有声明android:exported="true"导致的。

从目前的测试情况来看,跟Android的版本有关系,目前看到在低版本的Android系统上面,这个如果不设置,默认是自动导出的,但是在高版本的Android上面,默认就是不导出了,这就导致一个问题,就是相同的APK在不同系统上面会出现不同的行为。因此要求必须显示指定这个字段

注意如下说明:

参考链接


Android真机使用Mockito-1.10.19+Dexmaker-1.2在Mock继承抽象父类的子类时报告错误“java.lang.AbstractMethodError: abstract method not implemented”

Android真机使用Mockito-1.10.19+Dexmaker-1.2Mock继承抽象父类的子类时报告如下错误:

父类代码如下:

子类代码如下:

测试代码如下:

在项目的build.gradle中的声明如下:

这个问题只在Dalvik虚拟机下面发生异常,相同的代码在ART下面是完全正常的。
导致问题发生的原因是Google提供的dexmaker库存在BUG导致的,而这个库,从Maven Center上看,自从2012年开始就没有提供过任何的更新了。
解决方法是不使用Google提供的dexmaker,而是使用com.crittercism.dexmaker修正过这个BUG的版本。

com.crittercism.dexmaker项目的GitHub地址是https://github.com/crittercism/dexmaker

Android上使用Mockito+Dexmaker报告错误“java.lang.IllegalArgumentException: dexcache == null (and no default could be found; consider setting the 'dexmaker.dexcache' system property) ”

Android上使用Mockito+Dexmaker,测试用例运行时,报告错误:

解决方法就是在调用Mockito之前设置环境变量"dexmaker.dexcache",如下:

参考链接


Mockito + Dexmaker on Android

Android Studio编译出的APK中一直包含android:debuggable="true"

最近遇到一个比较奇葩的事情,就是编译出来的APKAndroidManifest.xml中的application标签中一直包含android:debuggable="true"。不管是release版本,还是debug版本,不管如何设置,最终生成的文件中的调试选项一直是处于开启状态。

一时间竟然有些无从下手的感觉。首先确认我们自己的配置文件是没有问题的,那么这个现象一定是引入了某个aar中引入的AndroidManifest.xml中存在这个android:debuggable="true",导致Android Studio在最终合并AndroidManifest.xml文件的时候,把这个选项给合并进来了。

那么我们既然已经知道引入的地方,因此就只需要针对这种情况进行剖析即可了。

执行gradlew build之后,我们在app\build\intermediates\exploded-aar目录下面可以找到我们引入的全部的依赖的aar。我们只需要逐个分析引入的aar包的AndroidManifest.xml文件即可。

那么比较奇葩,是奇葩在哪里呢? 正常情况下,我们引入一个aar包,需要在build.gradle中声明如下:

但是我们从真正的配置选项中看到的却是

按照一般的理解,我们如果没有设置@aar,那么Android Studio应该去下载对应的jar包才对。但是我们从实际的编译过程中看到,Android Studio在没有指定@aar的情况下,依旧默认去服务器上先尝试下载对应的aar,只有当aar找不到的时候才会去下载对应的jar包。而恰好,我们服务器上面两者都是存在的。于是出现了乌龙事件,本来只是需要下载jar包,结果却引入了一个莫名的aar包。而这个aar的开发同学又没有考虑到这种情况,以为用户只会用他提供的jar包。
解决方法还是比较简单的,就是明确告知Android Studio,我们需要的是jar包,也就是增加@jar。如下:

相关参考链接


Android Studio: Why is Release Build debuggable?

Android Studio 2.1.3配置Robolectric-3.0,Powermock-1.6.5单元测试环境

Android Studio提供了比较方便的单元测试,但是由于Android系统的限制(ClassloaderGoogle自己实现的,Powermock无法修改底层的bytecode),目前Powermock还没办法直接在设备上执行测试,但是我们代码中难免存在一些静态对象,需要测试的时候,只能求助于PowermockRobolectric的组合。
具体的配置如下:
1.首先在需要测试的项目的build.gradle中声明需要使用PowermockRobolectric

2.定义测试基类,在基类中声明一些必备的设置
AbsRobolectricPowerMockTest.java

3.定义真正的测试子类
DeckardActivityTest.java

注意,参考链接中的内容不可完全相信,按照参考链接中的配置(Robolectric-3.1.2+PowerMock-1.6.5),一般会遇到如下问题(看上去很怪异,其实是由于不同的classloader同时加载了相同的类,导致尽管类名是相同的,但是依旧无法进行类型转换):

参考链接


Android中对SD卡/U盘挂载和卸载的监听

Android系统中,当SD卡挂载在电脑上时候,如果手动将语音备忘录中的录音删除的时,那么相应数据库中的数据也是需要修改的。此时实现需要对挂载进行监听,需要继承BroadcastReceiver类,实现其中的onRecieve(Context context, Intent inten)方法。代码如下:

此时须在Manifest中进行注册:

参考链接


android中对SD卡挂载和卸载的监听

Android获取外接SD卡或者U盘路径方法

最近在开发Android时遇到插U盘获取U盘内容的需求,但是按照传统的Environment.getExternalStorageDirectory()只能读取到插入的SD卡的路径,如果是U盘的话无法读出U盘的路径。

最终在一个在CSDN的论坛里找到相关的东西,就试了下直接通过StorageManager获取存储路径的。

核心如下,volumePaths的数组就是系统外接设备的路径,经过测试的确是挂载的路径。不过有些是不可用的,它只是列出了系统可支持的外接路径。

参考链接


android获取外接SD卡或者U盘路径方法