经过几天的探索和反复的尝试,终于有了一点点进展了。
http://johncookie.iteye.com/blog/1182459
http://developer.android.com/reference/android/webkit/WebSettings.html#setAppCachePath(java.lang.String)
这2篇里说的细节帮我解决了一个大问题。
http://www.2cto.com/kf/201302/188431.html
http://blog.csdn.net/moubenmao/article/details/9076917
这篇写的特别好,很多细节的点。
https://code.google.com/p/android/issues/detail?id=24180
github上一篇,可以作为参考的:
https://gist.github.com/jaydeepw/3594828
下面的都是我一点点看过的,也很用的。
http://stackoverflow.com/search?q=android+webview+html5+cache
http://stackoverflow.com/questions/8911666/storing-a-webview-for-offline-browsing-android/8911966#8911966
http://stackoverflow.com/questions/14348118/how-to-check-for-availability-before-automatic-refresh/14348234#14348234
http://stackoverflow.com/questions/12510038/android-webview-application-clears-html5-cached-data-on-force-close-reboot
http://hulucat.com/tech/html5-webview%E7%9A%84%E6%9C%AC%E5%9C%B0%E5%AD%98%E5%82%A8%E4%BC%98%E5%8C%96/
http://www.eoeandroid.com/thread-239818-1-1.html
http://www.w3school.com.cn/html5/html_5_app_cache.asp
http://www.cnblogs.com/nuliniaoboke/archive/2012/12/03/2799772.html
http://www.jiangkunlun.com/tag/html5/
http://www.cnblogs.com/andriod-html5/archive/2012/06/06/2537850.html
http://stackoverflow.com/questions/14908533/android-webview-not-loading-second-page-from-cache?rq=1
http://www.html5rocks.com/en/tutorials/appcache/beginner/
http://blog.sethladd.com/2010/10/proposal-to-enhance-html5-app-cache.html
http://stackoverflow.com/questions/1998400/data-directory-have-no-read-write-permission-in-android
http://www.fengfly.com/plus/view-211735-1.html
http://blog.csdn.net/changemyself/article/details/8838499
补充一下:
1.使用localStorage一定要设置下面两个属性,我开始就设置了第一行,但是当我杀死应用进程后,在进入,保留的localStorage的内容就没有了。
mWebview.getSettings().setDomStorageEnabled(true);
String dir = mWebview.getContext().getDir("database", Context.MODE_PRIVATE)
.getPath();
mWebview.getSettings().setDatabasePath(dir);
如果需要存储一些简单的用key/value对即可解决的数据,DOM Storage是非常完美的方案。根据作用范围的不同,有Session Storage和Local Storage两种,分别用于会话级别的存储(页面关闭即消失)和本地化存储(除非主动删除,否则数据永远不会过期)。
在Android中可以手动开启DOM Storage(setDomStorageEnabled),设置存储路径(setDatabasePath)
Android中Webkit会为DOM Storage产生两个文件(my_path/localstorage/http_h5.m.taobao.com_0.localstorage和my_path/localstorage/Databases.db)。
另外,在Android中清除缓存时,如果需要清除Local Storage的话,仅仅删除Local Storage的本地存储文件是不够的,内存里面有缓存数据。如果再次进入页面,Local Storage中的缓存数据同样存在。需要杀死程序运行的当前进程再重新启动才可以。
2.AppCache使我们能够有选择的缓冲web浏览器中所有的东西,从页面、图片到脚本、css等等。尤其在涉及到应用于网站的多个页面上的CSS和JavaScript文件的时候非常有用。其大小目前通常是5M。(大小这个,经过我的实际测试,设置1G都没有问题,并且对于资源来说,我用20M的图片资源都可以缓存下来,所以大小应该不用担心,不要放过大的文件,比如单个文件好几百M的就行)
在Android上需要手动开启(setAppCacheEnabled),并设置路径(setAppCachePath)和容量(setAppCacheMaxSize)
Android中Webkit使用一个db文件来保存AppCache数据(my_path/ApplicationCache.db)
因为appCache的缓存路径是可以设置的,所以,我们可以放到SD卡的一个路径上,防止用户清除缓存后,把缓存数据删掉。那么第一次无网络情况下,进入应用怎么办呢?我现在使用的一个办法就是先在有网络的情况下,使用一次,会缓存所有文件到一个ApplicationCache.db这个文件中,然后把这个db文件放到我们自己设置的路径下,并设置appCache的缓存路径为这个,这样,在用户第一次无网络使用的时候就可以看到有数据了。不过有个问题就是,一般的应用是无法内置这个初始数据的,除非大的应用和厂商有合作关系的,但是这太少了。
3.appCache缓存的时候,如果文件有更新,就返回200,如果某个文件没有更改,就返回304,表示没有更新,这样可以节省流量,对304的理解需要仔细思考:http://www.cnblogs.com/elaborateday/archive/2011/04/06/2007019.html
-------------------------------------------------------------------------------------------------------------------
今天测试的时候发现一个大问题,之前测试的时候,缓存文件只会生成一个Application.db文件,但是用有的手机测试会生成3个文件:Application.db, Application.db-shm, Application.db-wal。我尝试过删除后面2个文件都没有什么影响,但是不知道这2个文件是干什么的。
http://blog.csdn.net/zhjp4295216/article/details/7729429
http://www.cnblogs.com/mengshu-lbq/archive/2011/12/10/2283146.html
http://www.gsdtarena.com/a/Androidjc/285.html
准确的说应该是android2.3的就多了这两个文件了,可以直接删除,不影响的,这两个文件具体是干什么的,还没有弄明白,在sqlite的官网上找到答案了,地址 http://www.sqlite.org/fileformat2.html |
我通过adb进入手机app的db存储目录,目录下除了有xx.db文件外,还存在xx.db-wal和xx.db-shm文件(模拟器中没有)。
以settings为例:
/data/data/com.android.providers.settings/databases 目录下有 settings.db、settings.db-shm、settings.db-wal 三个文件。
本人对数据库不了解,请高手下面疑惑:
1. xx.db-wal和xx.db-shm什么情况下会产生?
2. xx.db-wal和xx.db-shm的作用是什么?
android 2.3 sqlite WAL 机制 询问
我现在需要在2.3的downloadprovider进程里去打开browser的webview.db 这个数据库,这个数据库我已经在创建的时候 给他设置了一个 world_readable的权限,但是在Downloadprovider进程里 区打开的时候 始终打不开,爆出的错是sqlite3_exec to set WAL journal_mode = WAL failed
这个可以在 /frameworks/base/core/jni/android_database_SQLiteDatabase.cpp 中找到
.我尝试过用 同样的方法载browser进程里打开是很方便的.
现在还是打不开,不知道哪位大侠是否有知道这个WAL 机制的,我也尝试看过WAL 的机制 一知半解,希望有人能指点一下 不胜感激.
使用WLA,必须要以读写的模式打开数据库文件。不然是无法使用WAL的。因为在WAL模式设置之前,会对数据库文件属性进行判断,只有是读写的情况下,才能设置。
===========================================================================================
android sqlite db-journal文件产生原因及说明
分类: android
2012-08-06 11:18
2778人阅读
收藏
举报
sqlite android 数据库 磁盘 google 文档
今天在android中将sqlite的数据库文件生成在SD卡上的过程中,发现生成的.db文件的旁边
生成了一个大小为0的与数据库文件同名的.db-journal文件,不明白此文件的用途,于是
google了sqlite的官方文档,发现该文件的用途如下:
该文件是sqlite的一个临时的日志文件,主要用于sqlite事务回滚机制,在事务开始时产生,
在事务结束时删除;当程序发生崩溃或者系统断电时该文件将留在磁盘上,以便下次程序运行
时进行事务回滚。
但是我创建数据库时将事务结束了,同时程序也没有崩溃,为什么还是会在磁盘上产生
.db-journal文件呢?
深入研究,发现这是sqlite生成日志文件的不同模式造成的,在android采用的这种模式下,
.db-journal文件是永久的留在磁盘上不会被自动清除的,如果没有发生事务回滚那么.db-journal
文件的大小为0,这样就避免了每次生成和删除.db-journal文件的开销。
到此,所有的疑惑解开了。
=================================================================================
具体做法:
So last post was about HTML5 and WebViews but it didn’t cover offline usage and especially caching.
HTML5 is cool. It can work offline once cached by the browser. The main mechanism for offline HTML5 is the so called Manifest. Basically it’s a file which lists entries (js files, pictures, css, etc.) to be cached by the browser.
To enable cache in Android’s WebView we must do at least the following:
-
webView.
setWebChromeClient
(
new WebChromeClient
(
)
{
-
@Override
-
public
void onReachedMaxAppCacheSize
(
long spaceNeeded,
long totalUsedQuota,
-
WebStorage.
QuotaUpdater quotaUpdater
)
-
{
-
quotaUpdater.
updateQuota
(spaceNeeded
*
2
)
;
-
}
-
}
)
;
-
-
webView.
getSettings
(
).
setDomStorageEnabled
(
true
)
;
-
-
// Set cache size to 8 mb by default. should be more than enough
-
webView.
getSettings
(
).
setAppCacheMaxSize
(
1024
*
1024
*
8
)
;
-
-
// This next one is crazy. It's the DEFAULT location for your app's cache
-
// But it didn't work for me without this line.
-
// UPDATE: no hardcoded path. Thanks to Kevin Hawkins
-
String appCachePath = getApplicationContext
(
).
getCacheDir
(
).
getAbsolutePath
(
)
;
-
webView.
getSettings
(
).
setAppCachePath
(appCachePath
)
;
-
webView.
getSettings
(
).
setAllowFileAccess
(
true
)
;
-
webView.
getSettings
(
).
setAppCacheEnabled
(
true
)
;
This will work. Well, this will make your WebView support caching.. doesn’t mean it will actually work.
You can tune cache policies using the following code, even though it’s not required to make it work:
-
webView.
getSettings
(
).
setCacheMode
(WebSettings.
LOAD_DEFAULT
)
;
Now when all the cache is setup we would like to see our HTML5 site working in pure offline mode.. but we don’t!
Why? well.. if it’s not working for you it probably means that the site you load up with the following call is actually redirecting you somewhere else:
-
webView.
loadUrl
(
"http://myHTML5app.com/app/"
)
;
If /app/ is resolving to a redirect – you are in trouble, sir.
The Cache mechanism will cache the actual RESULT of the redirect and sure it will map it to the url you are being REDIRECTED to, not the one you originally called. So once you are offline – the cache has no clue about the /app/ url and thus you are simply given the default android “can’t open page” replacement.
There are at least two ways to solve this issue..
Get rid of the redirect on the server
Re-redirect on android side The first option is bad because you typically don’t want to mess with the working HTML5 site which is working on pure Browsers (iPhone, desktop, etc.).
To implement the second option I used the following code in the WebViewClient implementation:
-
@Override
-
public
void onReceivedError
(WebView view,
int errorCode,
-
String description,
String failingUrl
)
-
{
-
// The magic redirect
-
if
(
"http://HTML5app.com/app/".
equals
(failingUrl
)
)
{
-
// main.html is the place we are redirected to by the server if we are online
-
mWebView.
loadUrl
(
"http://HTML5app.com/app/main.html"
)
;
-
return
;
-
}
-
else
if
(
"http://HTML5app.com/app/main.html".
equals
(failingUrl
)
)
{
-
// The cache failed – We don't have an offline version to show
-
-
// This code removes the ugly android's "can't open page"
-
// and simply shows a dialog stating we have no network
-
view.
loadData
(
"",
"text/html",
"UTF-8"
)
;
-
showDialog
(DIALOG_NONETWORK
)
;
-
}
-
}
Good luck!
Tags: Android, cache, HTML5, hybrid, java
Posted in Development | 26 Comments »
Android, Hybrid apps and HTML5 databases
Friday, November 5th, 2010
If you use HTML5, most likely you are developing some web app which is supposed to support offline mode and most likely uses a local database.
Usually you create your HTML5 app for a browser and it works great as long as you run it in a real browser. But once you want a hybrid app things can really get painful.
A WebView is typically the heart of any hybrid app.. you have all of your HTML5 running in there but the really fancy or just platform dependent stuff can be done on the native side. Communication between Javascript and Native (Java on Android) is likely to be implemented using a bridge API or a local HTTP server which you will query using AJAX.
Android features a bridge API called JavascriptInterface which you can simply attach to a WebView and all the methods of the class you passed to it will be available in javascript under ‘window.$NAME.$method(…)’ where $NAME is the JavascriptInterface name you specified in your WebView setup code and $method is the Java method you can now simply call from JavaScript. Neat huh?
However, back to databases.
A very straightforward setup scenario with Javascript and Databases in mind:
-
WebView webView =
new WebView
(
this
)
;
-
-
// Out of scope. Just bare in mind that you wont be able
-
// to use your WebView without this
-
// as any request (intent) will be driven through Android system
-
// and will be opened in the default browser
-
// instead of your WebView.
-
webView.
setWebViewClient
(
new MyWebViewClient
(
)
)
;
-
-
webView.
getSettings
(
).
setJavaScriptEnabled
(
true
)
;
-
webView.
getSettings
(
).
setDatabaseEnabled
(
true
)
;
This will fail to enable Database usage.
To make it all work together you will definitely need to enable DOM storage:
-
webView.
getSettings
(
).
setDomStorageEnabled
(
true
)
;
You also will need to specify the file of the DB..:
-
webView.
getSettings
(
).
setDatabasePath
(
"/data/data/org.tapmania.alex.myapp/database"
)
;
But even that is not enough.
You will need to tell Android that your quota for the database is at least twice as big as it is once it’s expired… now don’t ask me what that means but just stare at this code until fully satisfied:
-
webView.
setWebChromeClient
(
new WebChromeClient
(
)
{
-
@Override
-
public
void onExceededDatabaseQuota
(
String url,
-
String databaseIdentifier,
-
long currentQuota,
-
long estimatedSize,
-
long totalUsedQuota,
-
WebStorage.
QuotaUpdater quotaUpdater
)
-
{
-
quotaUpdater.
updateQuota
(estimatedSize
*
2
)
;
-
}
-
}
)
;
In fact, this code will automatically update the quota and thus allow us to actually write a database file to disk and thus make the database work at all.
Cheers.
=================================================================================================
资源来自于www.mhtml5.com 杨丰盛老师成都场的PPT分享 一个很简明的demo 可以作为入门基础
学习的过程中做了点笔记 整理如下 虽然内容比较简单 但是数量还是比较多的 所以分了3篇
(上)包括Android设备多分辨率的问题,Android中构建HTML5应用程序基础
(中)包括Android与JS之间的互动,Android处理JS的警告对话框等,Android中的调试
(下)包括本地储存在Android中的应用,地理位置的应用,离线应用的构建
—————————————————————————————— 分割线 ————————————————————————————————————————
进入正题
● HTML5本地存储在Android中的应用
HTML5提供了2种客户端存储数据新方法:
localStorage 没有时间限制
sessionStorage 针对一个Session的数据存储
- <script type="text/javascript">
- localStorage.lastname="Smith";
- document.write(localStorage.lastname);
- </script>
- <script type="text/javascript">
- sessionStorage.lastname="Smith";
- document.write(sessionStorage.lastname);
- </script>
WebStorage的API:
-
- localStorage.clear();
-
- localStorage.setItem(“yarin”,“yangfegnsheng”);
-
- localStorage.getItem(“yarin”);
-
- localStorage.key(0);
-
- localStorage.removeItem(“yarin”);
- 注意一定要在设置中开启哦
- setDomStorageEnabled(true)
在Android中进行操作
-
- webSettings.setDatabaseEnabled(true);
- String dir = this.getApplicationContext().getDir("database", Context.MODE_PRIVATE).getPath();
-
- webSettings.setDatabasePath(dir);
-
- webSettings.setDomStorageEnabled(true);
-
- public void onExceededDatabaseQuota(String url, String databaseIdentifier, long currentQuota,
- long estimatedSize, long totalUsedQuota, WebStorage.QuotaUpdater quotaUpdater) {
- quotaUpdater.updateQuota(estimatedSize * 2);
- }
在JS中按常规进行数据库操作
- function initDatabase() {
- try {
- if (!window.openDatabase) {
- alert('Databases are not supported by your browser');
- } else {
- var shortName = 'YARINDB';
- var version = '1.0';
- var displayName = 'yarin db';
- var maxSize = 100000;
- YARINDB = openDatabase(shortName, version, displayName, maxSize);
- createTables();
- selectAll();
- }
- } catch(e) {
- if (e == 2) {
-
- console.log("Invalid database version.");
- } else {
- console.log("Unknown error "+ e +".");
- }
- return;
- }
- }
-
- function createTables(){
- YARINDB.transaction(
- function (transaction) {
- transaction.executeSql('CREATE TABLE IF NOT EXISTS yarin(id INTEGER NOT NULL PRIMARY KEY, name TEXT NOT NULL,desc TEXT NOT NULL);', [], nullDataHandler, errorHandler);
- }
- );
- insertData();
- }
-
- function insertData(){
- YARINDB.transaction(
- function (transaction) {
-
- var data = ['1','yarin yang','I am yarin'];
-
- transaction.executeSql("INSERT INTO yarin(id, name, desc) VALUES (?, ?, ?)", [data[0], data[1], data[2]]);
- }
- );
- }
-
- function errorHandler(transaction, error){
- if (error.code==1){
-
- } else {
-
- console.log('Oops. Error was '+error.message+' (Code '+error.code+')');
- }
- return false;
- }
-
-
- function nullDataHandler(){
- console.log("SQL Query Succeeded");
- }
-
- function selectAll(){
- YARINDB.transaction(
- function (transaction) {
- transaction.executeSql("SELECT * FROM yarin;", [], dataSelectHandler, errorHandler);
- }
- );
- }
-
- function dataSelectHandler(transaction, results){
-
- for (var i=0; i<results.rows.length; i++) {
- var row = results.rows.item(i);
- var newFeature = new Object();
- newFeature.name = row['name'];
- newFeature.decs = row['desc'];
-
- document.getElementById("name").innerHTML="name:"+newFeature.name;
- document.getElementById("desc").innerHTML="desc:"+newFeature.decs;
- }
- }
-
- function updateData(){
- YARINDB.transaction(
- function (transaction) {
- var data = ['fengsheng yang','I am fengsheng'];
- transaction.executeSql("UPDATE yarin SET name=?, desc=? WHERE id = 1", [data[0], data[1]]);
- }
- );
- selectAll();
- }
-
- function ddeleteTables(){
- YARINDB.transaction(
- function (transaction) {
- transaction.executeSql("DROP TABLE yarin;", [], nullDataHandler, errorHandler);
- }
- );
- console.log("Table 'page_settings' has been dropped.");
- }
- 注意onLoad中的初始化工作
- function initLocalStorage(){
- if (window.localStorage) {
- textarea.addEventListener("keyup", function() {
- window.localStorage["value"] = this.value;
- window.localStorage["time"] = new Date().getTime();
- }, false);
- } else {
- alert("LocalStorage are not supported in this browser.");
- }
- }
-
- window.onload = function() {
- initDatabase();
- initLocalStorage();
- }
● HTML5地理位置服务在Android中的应用
Android中
-
- webSettings.setGeolocationEnabled(true);
-
- webSettings.setGeolocationDatabasePath(dir);
-
-
- public void onGeolocationPermissionsShowPrompt(String origin,
- GeolocationPermissions.Callback callback) {
- callback.invoke(origin, true, false);
- super.onGeolocationPermissionsShowPrompt(origin, callback);
- }
在Manifest中添加权限
- <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
- <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
HTML5中 通过navigator.geolocation对象获取地理位置信息
常用的navigator.geolocation对象有以下三种方法:
-
- navigator.geolocation.getCurrentPosition(success_callback_function, error_callback_function, position_options)
-
- navigator.geolocation.watchPosition(success_callback_function, error_callback_function, position_options)
-
- navigator.geolocation.clearWatch(watch_position_id)
其中success_callback_function为成功之后处理的函数,error_callback_function为失败之后返回的处理函数,参数position_options是配置项
在JS中的代码
-
- function get_location() {
- if (navigator.geolocation) {
- navigator.geolocation.getCurrentPosition(show_map,handle_error,{enableHighAccuracy:false,maximumAge:1000,timeout:15000});
- } else {
- alert("Your browser does not support HTML5 geoLocation");
- }
- }
-
- function show_map(position) {
- var latitude = position.coords.latitude;
- var longitude = position.coords.longitude;
- var city = position.coords.city;
-
-
-
-
- document.getElementById("Latitude").innerHTML="latitude:"+latitude;
- document.getElementById("Longitude").innerHTML="longitude:"+longitude;
- document.getElementById("City").innerHTML="city:"+city;
- }
-
- function handle_error(err) {
- switch (err.code) {
- case 1:
- alert("permission denied");
- break;
- case 2:
- alert("the network is down or the position satellites can't be contacted");
- break;
- case 3:
- alert("time out");
- break;
- default:
- alert("unknown error");
- break;
- }
- }
其中position对象包含很多数据 error代码及选项 可以查看文档
● 构建HTML5离线应用
需要提供一个cache manifest文件,理出所有需要在离线状态下使用的资源
例如
- CACHE MANIFEST
- #这是注释
- images/sound-icon.png
- images/background.png
- clock.html
- clock.css
- clock.js
-
- NETWORK:
- test.cgi
-
- CACHE:
- style/default.css
-
- FALLBACK:
- /files/projects /projects
在html标签中声明 <html manifest="clock.manifest">
HTML5离线应用更新缓存机制
分为手动更新和自动更新2种
自动更新:
在cache manifest文件本身发生变化时更新缓存 资源文件发生变化不会触发更新
手动更新:
使用window.applicationCache
- if (window.applicationCache.status == window.applicationCache.UPDATEREADY) {
- window.applicationCache.update();
- }
在线状态检测
HTML5 提供了两种检测是否在线的方式:navigator.online(true/false) 和 online/offline事件。
在Android中构建离线应用
-
- webSettingssetAppCacheEnabled(true);
- String dir = this.getApplicationContext().getDir("cache", Context.MODE_PRIVATE).getPath();
-
- webSettings.setAppCachePath(dir);
-
- webSettings.setCacheMode(WebSettings.LOAD_DEFAULT);
-
- webSettings.setAppCacheMaxSize(1024*1024*8);
-
-
- public void onReachedMaxAppCacheSize(long spaceNeeded,
- long totalUsedQuota, WebStorage.QuotaUpdater quotaUpdater) {
- quotaUpdater.updateQuota(spaceNeeded * 2);
- }
(完)还有一个尾巴关于canvas绘图的 不如之前记录的来的详细 就不做介绍了