shouldOverrideUrlLoading在次回调函数里判断getHitTestResult是不是为空来过滤自动跳转url,因为用户点击跳转的url获取的WebHitTestResult对象是不为空的。实例代码:
<pre name="code" class="java">/** * 左上角和回退按键的点击:true为退出应用,false为回退到上一页 */ private boolean setBackFinish = true; private String lastRedirectUrl; private long lastRedirectTime = 0; private Map<String, Long> redirectUrls = new HashMap<>();</pre><pre name="code" class="java">//被点击的是链接或者自动跳转时,此方法被调用 @Override public boolean shouldOverrideUrlLoading(WebView view, String url) { AppLog.d("WebViewClient shouldOverrideUrlLoading " + url); if (url == null) { AppLog.i("override url is null"); return true; } WebView.HitTestResult hitTestResult = wView.getHitTestResult(); if (hitTestResult != null) { AppLog.e("shouldOverrideUrlLoading has a hittest: " + hitTestResult.getExtra() + " " + hitTestResult.getType()); } else { //没有点击说明是跳转url WebActivity.this.redirectUrls.put(WebActivity.this.lastRedirectUrl, WebActivity.this.lastRedirectTime); } //记录跳转网页url和时间 WebActivity.this.lastRedirectUrl = url; WebActivity.this.lastRedirectTime = SystemClock.currentThreadTimeMillis(); if (URLUtil.isNetworkUrl(url)) { view.loadUrl(url);// 在当前的webview中跳转到新的url return false; } }
回退处理:
@Override public void onBackPressed() { if (willFinish()) super.onBackPressed(); } @Override protected boolean willFinish() { if (!wView.canGoBack() || setBackFinish) { return true; } //wifi网速优时,根据页面停留时间长短过滤中间页 WebBackForwardList list = wView.copyBackForwardList(); int i = list.getCurrentIndex(); for (; i > 0; i--) { String url = list.getItemAtIndex(i).getUrl(); if (!redirectUrls.containsKey(url) && !url.equals(wView.getUrl())) { //找到一个非跳转url,回退到此 wView.goBackOrForward(-(list.getCurrentIndex() - i)); return false; } else if (i == 1) { //没找到合适的非跳转url,直接跳转到首页 wView.goBackOrForward(-list.getCurrentIndex()); return false; } } return true; }
2,android studio混淆
1),在build.grandle添加,其中规则写在proguard-rules.pro中,也可以自定义一个文件,将其代替,比如eclipse常用的 proguard-project.txt
buildTypes { release { signingConfig signingConfigs.release minifyEnabled true proguardFiles getDefaultProguardFile(‘proguard-android.txt‘), ‘proguard-rules.pro‘ } }2),在proguard-rules.pro中加入以下代码,基本可以涵盖所有-optimizationpasses 5 # 指定代码的压缩级别 -dontusemixedcaseclassnames # 是否使用大小写混合 -dontpreverify # 混淆时是否做预校验 -verbose # 混淆时是否记录日志 -optimizations !code/simplification/arithmetic,!field/*,!class/merging/* # 混淆时所采用的算法 -keep public class * extends android.app.Activity # 保持哪些类不被混淆 -keep public class * extends android.app.Application # 保持哪些类不被混淆 -keep public class * extends android.app.Service # 保持哪些类不被混淆 -keep public class * extends android.content.BroadcastReceiver # 保持哪些类不被混淆 -keep public class * extends android.content.ContentProvider # 保持哪些类不被混淆 -keep public class * extends android.app.backup.BackupAgentHelper # 保持哪些类不被混淆 -keep public class * extends android.preference.Preference # 保持哪些类不被混淆 -keep public class com.android.vending.licensing.ILicensingService # 保持哪些类不被混淆 -keepclasseswithmembernames class * { # 保持 native 方法不被混淆 native <methods>; } -keepclasseswithmembers class * { # 保持自定义控件类不被混淆 public <init>(android.content.Context, android.util.AttributeSet); } -keepclasseswithmembers class * {# 保持自定义控件类不被混淆 public <init>(android.content.Context, android.util.AttributeSet, int); } -keepclassmembers class * extends android.app.Activity { # 保持自定义控件类不被混淆 public void *(android.view.View); } -keepclassmembers enum * { # 保持枚举 enum 类不被混淆 public static **[] values(); public static ** valueOf(java.lang.String); } -keep class * implements android.os.Parcelable { # 保持 Parcelable 不被混淆 public static final android.os.Parcelable$Creator *; }3),通过 Android Studio进行 混淆代码时,默认已经将 lib目录中的 jar 都已经添加到打包脚本中,所以不需要再次手动添加,否则会出现“ java.io.IOException: The same input jar is specified twice” 错误。
3,比较完整的Activity和Fragment生命周期图(非官方):
原图参照:https://github.com/xxv/android-lifecycle
4,scrollview(listview...)的overscrollmode属性: always(默认值,总是允许过滚动)、never(只有当视图可以滚动时,才可以设置视图的过滚动模式)、if_content_scrolls(视图内容大于容器时允许过滚动)。这个属性主要设置的是当滚动条滑动到边界的时候,如果再滑动,就会有一个边界就会有一个发光效果,即边界回弹。
5,android配置中的category讲解
CATEGORY_ALTERNATIVE 设置这个activity是否可以被认为是用户正在浏览的数据的一个可选择的action CATEGORY_APP_BROWSER 和ACTION_MAIN一起使用,用来启动浏览器应用程序 CATEGORY_APP_CALCULATOR 和ACTION_MAIN一起使用,用来启动计算器应用程序 CATEGORY_APP_CALENDAR 和ACTION_MAIN一起使用,用来启动日历应用程序 CATEGORY_APP_CONTACTS 和ACTION_MAIN一起使用,用来启动联系人应用程序 CATEGORY_APP_EMAIL 和ACTION_MAIN一起使用,用来启动邮件应用程序 CATEGORY_APP_GALLERY 和ACTION_MAIN一起使用,用来启动图库应用程序 CATEGORY_APP_MAPS 和ACTION_MAIN一起使用,用来启动地图应用程序 CATEGORY_APP_MARKET 这个activity允许用户浏览和下载新的应用程序 CATEGORY_APP_MESSAGING 和ACTION_MAIN一起使用,用来启动短信应用程序 CATEGORY_APP_MUSIC 和ACTION_MAIN一起使用,用来启动音乐应用程序 CATEGORY_BROWSABLE 能够被浏览器安全调用的activity必须支持这个category CATEGORY_DEFAULT 设置这个activity对于默认的action是否是一个可选的 CATEGORY_EMBED 可以运行在父activity容器内 CATEGORY_HOME 主activity,当应用程序启动时,它是第一个显示的activity CATEGORY_LAUNCHER 应该在上层的启动列表里显示 CATEGORY_MONKEY 这个activity可能被monkey或者其他的自动测试工具执行 CATEGORY_OPENABLE 用来指示一个GET_CONTENT意图只希望ContentResolver.openInputStream能够打开URI CATEGORY_PREFERENCE 这个activity是一个选项卡 CATEGORY_SAMPLE_CODE 作为一个简单的代码示例使用(一般情况下不使用) CATEGORY_SELECTED_ALTERNATIVE 设置这个activity是否可以被认为是用户当前选择的数据的一个可选择的action CATEGORY_TAB 想要在已有的TabActivity内部作为一个Tab使用 CATEGORY_TEST 供测试使用(一般情况不使用) CATEGORY_UNIT_TEST 联合测试使用
6,使用Message.obtain(Handler h, int what,int arg1, int arg2, Object obj)比Handler实例创建Message方便