最近写了一个基于webview和zxing,sqlite实现的一款浏览器
主要功能有:扫描二维码以及打开本地二维码加载网页,书签和历史记录管理,无痕浏览,分享网址,分享网址二维码,浏览器出错自定义等功能。
源码地址:此资源解压后用Android可直接打开
说一说踩到的几个坑:
1.二维码分享界面。
本来是打算传url给下一个activity,在一个新线程里面添加一个300ms的对话框(增加用户体验),再生成二维码,结果写成3000ms,然后没有更新成功;于是改成300ms,就更新成功了,感觉很奇怪。
在网上找了一下原因是:
android中相关的view和控件不是线程安全的,Android会禁止在非UI线程更新UI,对于显式的非法操作,比如说直接在Activity里创建子线程,然后直接在子线程中操作UI等,Android会直接异常退出,并提示should run on UIThread之类的错误日志信息。而对于隐式的非法操作,App不会直接简单粗暴地异常退出,只是出现奇怪的结果,Only the original thread that created a view hierarchy can touch its views便是一个例子,字面意思是只有创建视图层次结构的原始线程才能操作它的View。
回到话题,那怎么会300ms就能更新成功了呢?原因是这个时候UI thread还没有初始化完成,而3000ms后 UI thread肯定初始化完成了,这个时候系统就会像上面说的那样,不能让你更新UI了。详见:Android为什么在非UI线程中运行UI操作而不报错
正确的做法是:在主线程中创建handler,用handler进行线程间通信把更新UI操作放进main thread(UI thread),或者直接在主线程中更新UI
2.加载两次历史记录。
我在webview的setWebViewClient类面的onPageFinished()方法里设置了添加历史记录的函数,这样每次一个页面加载完成以后就会自动添加进历史记录,但我发现有时候会连续添加两次相同的记录,后来查阅资料,发现webview原来还有个重定位机制,这个重定位机制会导致重复加载一个页面,连续两次执行onPageFinished()方法,于是我在设置了一个全局的boolean变量if_load,在onPageStarted()设为true,在onPageFinished()方法里作出判断,
if(if_load&&) {
addinfo_history(view.copyBackForwardList().getCurrentItem().getTitle(), view.copyBackForwardList().getCurrentItem().getUrl());
if_load=false;
}
if_load为true时才添加进历史记录,并且同时把if_load置为false。这样就避免了重定位导致的连续两次添加历史记录
参考这篇文章:WebView 重定向行为导致的多次加载问题
1.底部弹出菜单。
本来我是用的viewstub制作的一个菜单页面,点击出现,再点击消失。虽然viewstub能在你不用的时候就隐形,不占内存。但慢慢的我发现这个viewstub给人的使用体验很不好,不能在点击除菜单栏以外其他的地方自动消失,后来就想到了干脆用一个自定义的底部弹出对话框来改善用户体验效果
2.点击书签或历史记录进入加载页面。
刚开始我是另外写了一个页面B,点击书签或历史记录就跳转到页面B,在页面B里面执行加载,后来发现这样对用户的体验也不好,用户返回的时候,还是会经历书签的页面再返回到主页,而且返回到主页时无法点击前进按钮返回刚刚浏览过的页面,因为这个Activity B已经出栈,后来想想为什么不用
startActivityForResult()
这个呢,这样点击书签或历史记录后就直接返回url给MainActivity,加载url。
3.没有书签或历史记录时,页面为空白。
本来我在书签或历史记录页面的内容就是从sqlite数据库中加载出数据,再呈现给用户,没有数据时当然为空白,但这样给用户的体验很不好,于是我在刷新listview之前作出了一个判断,如果数据库为空,则加载默认的提示语,提示没有数据,如下:
if_exsit=false;
HashMap map = new HashMap();
map.put("title", "您没有添加书签,可在主页添加");
map.put("url", "此处是存放您书签的地方");
listItem.add(map);
//new String 数据来源, new int 数据到哪去
SimpleAdapter mSimpleAdapter = new SimpleAdapter(this,listItem,R.layout.item_list,
new String[] {"title","url"},
new int[] {R.id.textView2,R.id.textView3});
lv.setAdapter(mSimpleAdapter);//为ListView绑定适配器
4.扫描二维码界面。
我刚开始下载的zxing是只有一个扫描二维码的功能,页面非常空,后来我自己又添加了闪光灯,以及打开本地相册二维码等功能。可以参考我的这篇文章:Android利用zxing用相机扫描识别二维码(添加闪光灯和本地二维码)超详细教程
未完待续。。
附:webview错误码整理