Android webView 缓存 Cache + HTML5离线功能 解决_hllofflinewebview-程序员宅基地

技术标签: android  

WebView的缓存可以分为页面缓存和数据缓存。

           页面缓存是指加载一个网页时的html、JS、CSS等页面或者资源数据。这些缓存资源是由于浏览器的行为而产生,开发者只能通过配置HTTP响应头影响浏览器的行为才能间接地影响到这些缓存数据。

         他们的索引存放在/data/data/package_name/databases下。他们的文件存放在/data/data/package_name/cache/xxxwebviewcachexxx下。文件夹的名字在2.x和4.x上有所不同,但都文件夹名字中都包含webviewcache。



            数据缓存分为两种:AppCache和DOM Storage(Web Storage)。他们是因为页面开发者的直接行为而产生。所有的缓存数据都由开发者直接完全地掌控。
AppCache使我们能够有选择的缓冲web浏览器中所有的东西,从页面、图片到脚本、css等等。尤其在涉及到应用于网站的多个页面上的CSS和JavaScript文件的时候非常有用。其大小目前通常是5M。
            在Android上需要手动开启(setAppCacheEnabled),并设置路径(setAppCachePath)和容量(setAppCacheMaxSize)

Android中Webkit使用一个db文件来保存AppCache数据(my_path/ApplicationCache.db)


          如果需要存储一些简单的用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中的缓存数据同样存在。需要杀死程序运行的当前进程再重新启动才可以。

           

---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

HTML5的离线应用功能可以使得WebApp即使在网络断开的情况下仍能正常使用,这是个非常有用的功能。近来工作中也要用到HTML5离线应用功能,由于是在Android平台上做,所以自然而然的选择Webview来解析网页。但如何使Webivew支持HTML5离线应用功能呢,经过反复摸索和上网查找资料,反复做试验终于成功了。

首先需配置webview的的一些属性,假设activity中已经有了一个Webview的实例对象,名为m_webview,然后增加以下代码:

[html]  view plain copy
  1. WebSettings webseting = m_webview.getSettings();  
  2.     webseting.setDomStorageEnabled(true);             
  3.         webseting.setAppCacheMaxSize(1024*1024*8);//设置缓冲大小,我设的是8M  
  4.     String appCacheDir = this.getApplicationContext().getDir("cache", Context.MODE_PRIVATE).getPath();      
  5.         webseting.setAppCachePath(appCacheDir);  
  6.         webseting.setAllowFileAccess(true);  
  7.         webseting.setAppCacheEnabled(true);  
  8.         webseting.setCacheMode(WebSettings.LOAD_DEFAULT);   
webview可以设置一个WebChromeClient对象,在其onReachedMaxAppCacheSize函数对扩充缓冲做出响应。代码如下:
[html]  view plain copy
  1. m_webview.setWebChromeClient(m_chromeClient);  
  2.     private WebChromeClient m_chromeClient = new WebChromeClient(){  
  3.         //扩充缓存的容量    
  4.     @Override  
  5.     public void onReachedMaxAppCacheSize(long spaceNeeded,    
  6.                 long totalUsedQuota, WebStorage.QuotaUpdater quotaUpdater) {    
  7.             quotaUpdater.updateQuota(spaceNeeded * 2);    
  8.         }         
  9.     };  

 

其次要修改http服务器中的配置,使其支持text/cache-manifest,我使用的是apache服务器,是windows版本的,在apache的conf文件夹中找到mime.types文件,打开后在文件的最后加上
“text/cache-manifest              mf  manifest”,重启服务器即可。这一步很重要,我就是因为服务器端没有配置这个,所以失败了好多次,最后是在附录链接1的回复中找到的线索。


经过以上设置Webview就可以支持HTML5的离线应用了。

附录链接1中说缓冲目录应该是getApplicationContext().getCacheDir().getAbsolutePath();但我经过试验后发现设置那个目录不起作用,可能是Android版本不同吧,我的是Android4.0.3,而他的可能是以前的Android版本吧。

缓冲目录使用getApplicationContext().getDir("cache", Context.MODE_PRIVATE).getPath()是从附录链接2中找到的线索。

附录链接:
1.http://alex.tapmania.org/2010/11/html5-cache-android-webview.html
2.http://johncookie.iteye.com/blog/1182459
3.HTML5 Offline官方文档:http://www.w3.org/TR/html5/offline.html#manifests

原因:
webview加载 服务端的网页,为了减少访问压力,用html5缓存技术,本地建了数据库,在手机浏览器里  可以显示页面,换成webView就不行了。


解决范例:
Activity code:

?
代码片段,双击复制
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
public  class  efan_NewsReader  extends Activity {
         /** Called when the activity is first created. */
         @Override
         public void onCreate(Bundle savedInstanceState)
         {   
                 super .onCreate(savedInstanceState);   
                 setContentView(R.layout.main);            
                 WebView myWebView=(WebView)findViewById(R.id.my_webview);   
                 myWebView.setWebViewClient( new WebViewClient());   
                 WebSettings settings = myWebView.getSettings();
                // 开启javascript设置
                settings.setJavaScriptEnabled( true );  
                // 设置可以使用localStorage
                settings.setDomStorageEnabled( true );
                // 应用可以有数据库
                settings.setDatabaseEnabled( true );   
                String dbPath = this .getApplicationContest().getDir( "database" , Context.MODE_PRIVATE).getPath();
                settings.setDatabasePath(dbPath);
                // 应用可以有缓存
                settings.setAppCacheEnabled( true );            
                String appCaceDir = this .getApplicationContext().getDir( "cache" , Context.MODE_PRIVATE).getPath();
                settings.setAppCachePath(appCaceDir);
                
                myWebView.loadUrl( "http://10.10.35.47:8080/html5test/test.htm" );
         }
}

HTML5 page source code:  
?
代码片段,双击复制
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
     < html manifest = "mymanifest.manifest" >
     < head >
< meta http-equiv = "Content-Type" content = "text/html; content=" no-cache" charset = utf -8" />
< script type = "text/javascript" src = "js/jquery-1.6.1.min.js" ></ script >
 
< script >
$(document).ready(function(){      
 
     databaseTest();
});
 
function databaseTest(){
 
 
     //open database
      var db = openDatabase('mydb', '1.0', 'Test DB', 2 * 1024 * 1024);  
 
       db.transaction(function (tx) {            
       tx.executeSql('CREATE TABLE IF NOT EXISTS testHtml (id unique, contentText)');
       tx.executeSql('INSERT INTO testHtml (contentText) VALUES ("insert data test!")');  
        });  
 
      db.transaction(function(tx){           
      tx.executeSql('SELECT * FROM testHtml',[],function(tx,result){
             var len=result.rows.length;
             var msg = "< p >Found rows: " + len + "</ p >";  
              $("#testinfo").append(msg);
         },null);
      });   
 
 
}
 
</ script >
 
 
</ head >
< body >
     < div >here is test info:</ div >
     < div id = "testinfo" ></ div >
</ body >




其他设置还有:
settings.setCacheMode(WebSettings.LOAD_DEFAULT);   // 默认使用缓存
settings.setAppCacheMaxSize(8*1024*1024);   //缓存最多可以有8M
settings.setAllowFileAccess(true);   // 可以读取文件缓存(manifest生效)


in WebChromeClient :
?
代码片段,双击复制
01
02
03
04
05
06
07
08
09
10
myWebView.setWebChromeClient( new WebChromeClient()
{   
         @Override   
         public void onExceededDatabaseQuota(String url, String databaseIdentifier,
                        long currentQuota, long estimatedSize, long totalUsedQuota,
                        WebStorage.QuotaUpdater quotaUpdater)   
         {        
                 quotaUpdater.updateQuota(estimatedSize *  2 );   
         }
}


or:
?
代码片段,双击复制
01
02
03
04
05
06
07
08
09
10
myWebView.setWebChromeClient( new WebChromeClient()
{
     // 扩充缓存的容量   
         @Override   
         public void onReachedMaxAppCacheSize( long spaceNeeded, long totalUsedQuota,
                        WebStorage.QuotaUpdater quotaUpdater)   
         {        
                 quotaUpdater.updateQuota(spaceNeeded *  2 );
     }
}




按照范例,我成功的解决了我的问题,而且之前弹出框所出现的找不到数据(提示:underfine)也解决了,这个应该是当初数据库没设所引起的。


WebView中存在着两种缓存:网页数据缓存(存储打开过的页面及资源)、H5缓存(即appcache)。

一、网页缓存

1、缓存构成
/data/data/package_name/cache/
/data/data/package_name/database/webview.db
/data/data/package_name/database/webviewCache.db

2、缓存模式
较难理解的是以下两个模式:
LOAD_DEFAULT,根据cache-control决定是否从网络上取数据。
LOAD_CACHE_ELSE_NETWORK,只要本地有,无论是否过期,或者no-cache,都使用缓存中的数据。
如:m.taobao.com的cache-control为no-cache,在模式LOAD_DEFAULT下,无论如何都会从网络上取数据,如果没有网络,就会出现错误页面;在LOAD_CACHE_ELSE_NETWORK模式下,无论是否有网络,只要本地有缓存,都使用缓存。本地没有缓存时才从网络上获取。
m.sina.com.cn的cache-control为max-age=60,在两种模式下都使用本地缓存数据。


总结:根据以上两种模式,建议缓存策略为,判断是否有网络,有的话,使用LOAD_DEFAULT,无网络时,使用LOAD_CACHE_ELSE_NETWORK。


3、清除缓存
clearCache(boolean)。
CacheManager.clear。高版本中需要调用隐藏API。

4、控制大小
无系统API支持。
可选方式:定时统计缓存大小、按时间顺序删除缓存。

二、H5缓存

1、缓存构成
根据setAppCachePath(String appCachePath)提供的路径,在H5使用缓存过程中生成的缓存文件。

2、缓存模式
无模式选择,通过setAppCacheEnabled(boolean flag)设置是否打开。默认关闭,即,H5的缓存无法使用。

3、清除缓存
找到调用setAppCachePath(String appCachePath)设置缓存的路径,把它下面的文件全部删除就OK了。

4、控制大小
通过setAppCacheMaxSize(long appCacheMaxSize)设置缓存最大容量,默认为Max Integer。
同时,可能通过覆盖WebChromeClient.onReachedMaxAppCacheSize(long requiredStorage, long quota, WebStorage.QuotaUpdater quotaUpdater)来设置缓存超过先前设置的最大容量时的策略。

三、参考网址

以下地址有关于H5缓存的一些内幕,如每个Application只调用一次WebSettings.setAppCachePath(),WebSettings.setAppCacheMaxSize()被忽略等一系列问题,需要仔细阅读和实验。
http://code.google.com/p/android/issues/detail?id=24180
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/fishmai/article/details/52398504

智能推荐

jbpm4.4集成mysql_JBPM4.4安装(Tomcat-MySQL)-程序员宅基地

文章浏览阅读77次。一、下载相关的工具软件JBPM4.4下载(http://sourceforge.net/projects/jbpm)Apache-tomcat-6.0.35下载(http://tomcat.apache.org/download-60.cgi)MySQL下载(http://www.mysql.com/downloads/)Eclipse-java-galileo-SR2-win32下载(http:..._jbpm-4.4/install/src/db/create/jbpm.mysql.create.sql在哪儿

linux能在pc上运行吗,技术|在Windows 8 PC上安装Linux的四种方法-程序员宅基地

文章浏览阅读156次。之前有消息称Windows 8的安全机制将会阻碍其他操作系统的启动。现在,很多想在Mac上运行Linux的人使用兼容支持模块CSM,提供Mac上BIOS的仿真。这种方式很麻烦,运行得不好,在Secure Boot Windows 8 PC上可能会更糟糕。同时随着微软Windows 8 发布的日子越来越近,Windows 8 中的 UEFI 功能和效应也会慢慢显示出来,所以在 PC 上安装 Linu..._linux能运行在pc机上吗

Git使用心得_echo "# oneupyenova" >> readme.md git init git add-程序员宅基地

文章浏览阅读170次。Github使用记录最近对github的一些使用心得清除git工程的git信息rm -rf .git本地创建git项目并push到远程echo "# Readme" >> README.mdgit initgit add README.mdgit commit -m "first commit"git remote add origin [email protected]:addressgit push -u origin masterpush一个已经存在的库git rem_echo "# oneupyenova" >> readme.md git init git add readme.md git commit -m

java代码动态注入与class文件热加载实现_java 运行时 注入新类-程序员宅基地

文章浏览阅读5.8k次,点赞3次,收藏18次。一、java代码动态注入在本文中,我们将研究如何将Java代码动态加载到正在运行的jvm中。 该代码可能是全新的,或者我们可能想更改程序中某些现有代码的功能。(在开始之前,您可能想知道为什么到底有人会这样做。显而易见的示例是规则引擎之类的东西。规则引擎希望为用户提供添加或更改规则的能力,而不必重新启动规则。您可以通过将DSL脚本作为规则注入规则库来执行此操作,这种方法的真正问题在于,必须对DSL脚本进行解释,使其运行起来极其缓慢。然后可以像程序中的任何其他代码一样编译和运行该程序,效率将提高几个数量级。_java 运行时 注入新类

用pip安装pymongo模块报错:Could not find a version that satisfies the requirement pymongo(from version:)-程序员宅基地

文章浏览阅读10w+次,点赞28次,收藏40次。安装VN.PY时,进行到安装pymongo步骤出现错误Could not find a version that satisfies the requirement pymongo(from version:)_could not find a version that satisfies the requirement pymongo (from versio

YV12,I420,YUV420P的区别-程序员宅基地

文章浏览阅读43次。2019独角兽企业重金招聘Python工程师标准>>> ..._yv12和iyuv的区别

随便推点

关于HashMap的加载因子相关理解_hashmap加载因子-程序员宅基地

文章浏览阅读399次。HashMap在JDK1.7是以数组加链表的形式组成,JDK1.8后新增了红黑树结构,当链表大于8并且容量大于64时,链表结构会转成红黑树结构。JDK1.8 之所以会加入红黑树是因为当链表过长是会严重影响HashMap的性能,而红黑树具有快速增删改查的特点。关于加载因子加载因子也叫作扩容因子,用来判断什么时候进行扩容,假设加载因子为0.75,HashMap的初始容量为16,当HashMap中有16 * 0.75 = 12个容量时,HashMap就会进行扩容。如果加载因子越大,扩容发生的频率就会比较低_hashmap加载因子

python一二三【warning模块使用】_import warnings-程序员宅基地

文章浏览阅读1.3w次,点赞2次,收藏10次。warning模块使用目的和exception异常要求用户立刻进行处理不同,warning通常用于提示用户一些错误或者过时的用法。casescrapy源码中用到了继承了Warning类创建了一个提醒对象ScrapyDeprecationWarning,用于提醒过时的用户操作,在新版本可能会直接去除支持。用户感知warningspython参数控制warning输出 ..._import warnings

ssm常用的注解_ssm框架注解-程序员宅基地

文章浏览阅读2.3k次。@RestController此注解有两个目的。首先他是一个类似于@controller和@Service的构造型注解,能够让类被组件扫描功能发现。但是,与REST最相关在于@RestController会告诉Spring,控制器中所有的处理器方法的返回值都要直接写入响应体中,而不是将值放到模型中并传递给一个视图以便于渲染。作为替代方案就是@Controller加上@Response。@RestControllerpublic class Controller { }@ApiVersi_ssm框架注解

opengl菜单出现乱码_opengl文字显示(二) | 学步园-程序员宅基地

文章浏览阅读355次。Windows系统中,可以使用wglUseFontBitmaps函数来批量的产生显示字符用的显示列表。函数有四个参数:第一个参数是HDC,学过WindowsGDI的朋友应该会熟悉这个。如果没有学过,那也没关系,只要知道调用wglGetCurrentDC函数,就可以得到一个HDC了。具体的情况可以看下面的代码。第二个参数表示第一个要产生的字符,因为我们要产生0到127的字符的显示列表,所以这里填0..._c++上运行opengl,glutcreatewindow汉字报错

MySQL 团队开发规范_group by后面的字段最好是索引列-程序员宅基地

文章浏览阅读83次。数据库对象命名规范数据库对象数据库对象是数据库的组成部分,常见的有以下几种:表(Table )、索引(Index)、视图(View)、图表(Diagram)、缺省值(Default)、规则(Rule)、触发器(Trigger)、存储过程(Stored Procedure)、 用户(User)等。命名规范是指数据库对象如数据库(SCHEMA)、表(TABLE)、索引(INDEX)、约束(CONSTRAINTS)等的命名约定。数据库对象全局命名规范1、命名使用具有意义的英文词汇,词汇中间以下划线_group by后面的字段最好是索引列

Java入门到精通——第十五单元 多态(没有十四哦)_多态技能目标-程序员宅基地

文章浏览阅读67次。第十五单元 多态昨日知识点回顾本单元知识点概述本单元教学目标(Ⅰ)重点知识目标(Ⅱ)能力目标本单元知识详讲15.1 多态15.1.1 概念引入★★★15.1.2 多态的定义★★★15.1.3 多态体的体现★★★★15.1.4 多态的好处★★★★★15.1.5 向上转型★★★★★15.1.6 向下转型★★★★★15.1.7 转型的使用场景★★★★★15.1.8 转型的异常★★★15.2 接口多态的综合案例15.2.1 案例分析★★★15.2.2 案例实现★★★本单元知识总结昨日知识点回顾接口的概念?接_多态技能目标