前面那张hybrid开发心得 有人问 怎样处理不用onJsPrompt 来回调js函数的问题。其实很简单,就是在在你的jscalljava回调函数内 另外开个线程去load js代码就可:wb.post(new Runnable() { @Override public void run() { wb.loadUrl("javascript:display_alert()"); } });
好,而后开始说一下webview。webview其实我一直都很痛恨这个控件,你又不能不用,但是一旦大规模测试起来 你就发现这个webview真是坑。。。各种你想不到的错误 在各种奇怪的手机,各种不一样的版本里
出现各种难以意料的问题。再加上monkey 时不时的 帮你跑点crush,乌云平台时不时给你爆点漏洞,感觉webview天生就是在考验开发者的奇技淫巧。我自己也总结了下webview 下面的开发注意事项,现在总结出来,
希望能给你今后webview开发中 扫平少量障碍 提供少量帮助。
1.WebView的内存泄露。
关于这个问题,我很难给你一个清晰的形容,你在谷歌里搜 webview lead memory 能搜到很多结果 甚至还有给谷歌提交的issue 哈哈,我也无法给出一个清晰的答案 在什么时候 什么版本那些手机上肯定会出现内存泄露,
但是根据我自己的monkey结果来看,有时,webview内存泄露的情况还是很严重的,尤其是当你加载的页面比较庞大的时候。处理方案 我查了很多也用了很多,但是都不太理想,最后看了下微信和qq的做法,试了一下是目前效果最好的,
就是 当你要用webview的时候,记得最好 另外单独开一个进程 去使用webview 并且当这个 进程结束时,请手动调用System.exit(0)。
这是目前对于webview 内存泄露 最好的处理方案。使用此方法 所有由于webview引发的 资源无法释放等问题 一律可以处理。
2.getSettings().setBuiltInZoomControls(true) 引发的crush。
这个方法调用以后 假如你触摸屏幕 弹出那个提醒框还没消失的时候 你假如activity结束了 就会报错了。3.0以上 4.4以下很多手机会出现这种情况
所以为了规避他,我们通常是在activity的onDestroy方法里手动的将webiew设置成 setVisibility(View.GONE)
3.onPageFinished 函数究竟有用没有?
多数开发者都是参考的http://stackoverflow.com/questions/3149216/how-to-listen-for-a-webview-finishing-loading-a-url-in-android 这个上面的高票答案。
但其实根据我自己观察,这个函数并没有什么卵用,有的时候是提前结束,有的时候就迟迟无法结束,你信这个函数 还不如信上帝,甚至于onProgressChanged这个函数
都比onPageFinished 要准少量。假如你的产品经理坚持你肯定要实现这种功能的话,我建议你 提早结束他,否则卡在那客户迟迟动不了 这种体验不好。
有空的同学可以跟一下源码,onPageFinished 在不同的内核里 调用的时机都不一样。说实话 我也很醉。。。这个问题 有完美处理方案的 请知会我一下。。。
4.后端无法释放js 导致耗电。
这个可能很少有人知道,我也是被投诉过 才理解,在有的手机里,你假如webview加载的html里 有少量js 一直在执行比方动画之类的东西,假如此刻webview 挂在了后端
这些资源是不会被释放 客户也无法感知。。。导致一直占有cpu 耗电特别快,所以大家记住了,假如遇到这种情况 请在onstop和onresume里分别把setJavaScriptEnabled();
给设置成false和true。
5.假如实在不想用开额外进程的方式处理webview 内存泄露的问题,那么下面的方法很大程度上可以避免这种情况public void releaseAllWebViewCallback() { if (android.os.Build.VERSION.SDK_INT < 16) { try { Field field = WebView.class.getDeclaredField("mWebViewCore"); field = field.getType().getDeclaredField("mBrowserFrame"); field = field.getType().getDeclaredField("sConfigCallback"); field.setAccessible(true); field.set(null, null); } catch (NoSuchFieldException e) { if (BuildConfig.DEBUG) { e.printStackTrace(); } } catch (IllegalAccessException e) { if (BuildConfig.DEBUG) { e.printStackTrace(); } } } else { try { Field sConfigCallback = Class.forName("android.webkit.BrowserFrame").getDeclaredField("sConfigCallback"); if (sConfigCallback != null) { sConfigCallback.setAccessible(true); sConfigCallback.set(null, null); } } catch (NoSuchFieldException e) { if (BuildConfig.DEBUG) { e.printStackTrace(); } } catch (ClassNotFoundException e) { if (BuildConfig.DEBUG) { e.printStackTrace(); } } catch (IllegalAccessException e) { if (BuildConfig.DEBUG) { e.printStackTrace(); } } } }
在webview的 destroy方法里 调用这个方法就行了。
6.另外很多人 不知道webview 实际上有自己一套完整的cookie机制的,利用好这个 可以大大添加对用户端的访问速度。
image
image
image
实际上cookie就是存放在这个表里的。
很多人都想要一个效果:网页升级cookie 设置完cookie以后 不刷新页面就可生效。这个在2.3以下和2.3以上要实现的方法不太一样,所以要做一次兼容public void updateCookies(String url, String value) { if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.GINGERBREAD_MR1) { // 2.3及以下 CookieSyncManager.createInstance(getContext().getApplicationContext()); } CookieManager cookieManager = CookieManager.getInstance(); cookieManager.setAcceptCookie(true); cookieManager.setCookie(url, value); if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.GINGERBREAD_MR1) { CookieSyncManager.getInstance().sync(); } }