gpt4 book ai didi

java - 如何在黑莓浏览器字段中缓存

转载 作者:IT老高 更新时间:2023-10-28 20:35:30 26 4
gpt4 key购买 nike

我正在创建一个 Blackberry 应用程序来显示某个站点的全屏 Web View 。我有一个可以正常显示的工作浏览器字段,但是从页面到页面的导航比 native 浏览器的导航要慢。浏览器字段似乎没有内置缓存,导致加载时间很慢。当我添加以下代码来管理缓存时,网站不再正确显示。

BrowserFieldScreen.java:

import net.rim.device.api.browser.field2.*;
import net.rim.device.api.script.ScriptEngine;
import net.rim.device.api.system.*;
import net.rim.device.api.ui.*;
import net.rim.device.api.ui.component.*;
import net.rim.device.api.ui.container.*;
import org.w3c.dom.Document;

class BrowserFieldScreen extends MainScreen
{
BrowserField browserField;
LoadingScreen load = new LoadingScreen();;

public BrowserFieldScreen()
{
browserField = new BrowserField();
browserField.getConfig().setProperty(
BrowserFieldConfig.JAVASCRIPT_ENABLED,
Boolean.TRUE);
browserField.getConfig().setProperty(
BrowserFieldConfig.NAVIGATION_MODE,
BrowserFieldConfig.NAVIGATION_MODE_POINTER);
browserField.getConfig().setProperty(
BrowserFieldConfig.CONTROLLER,
new CacheProtocolController(browserField));

browserField.requestContent("http://www.stackoverflow.com");
add(browserField);
}
}

CacheProtocolController.java:

import javax.microedition.io.HttpConnection;
import javax.microedition.io.InputConnection;

import net.rim.device.api.browser.field2.BrowserField;
import net.rim.device.api.browser.field2.BrowserFieldRequest;
import net.rim.device.api.browser.field2.ProtocolController;

public class CacheProtocolController extends ProtocolController{

// The BrowserField instance
private BrowserField browserField;

// CacheManager will take care of cached resources
private CacheManager cacheManager;

public CacheProtocolController(BrowserField browserField) {
super(browserField);
this.browserField = browserField;
}

private CacheManager getCacheManager() {
if ( cacheManager == null ) {
cacheManager = new CacheManagerImpl();
}
return cacheManager;
}

/**
* Handle navigation requests (e.g., link clicks)
*/
public void handleNavigationRequest(BrowserFieldRequest request)
throws Exception
{
InputConnection ic = handleResourceRequest(request);
browserField.displayContent(ic, request.getURL());
}

/**
* Handle resource request
* (e.g., images, external css/javascript resources)
*/
public InputConnection handleResourceRequest(BrowserFieldRequest request)
throws Exception
{
// if requested resource is cacheable (e.g., an "http" resource),
// use the cache
if (getCacheManager() != null
&& getCacheManager().isRequestCacheable(request))
{
InputConnection ic = null;
// if requested resource is cached, retrieve it from cache
if (getCacheManager().hasCache(request.getURL())
&& !getCacheManager().hasCacheExpired(request.getURL()))
{
ic = getCacheManager().getCache(request.getURL());
}
// if requested resource is not cached yet, cache it
else
{
ic = super.handleResourceRequest(request);
if (ic instanceof HttpConnection)
{
HttpConnection response = (HttpConnection) ic;
if (getCacheManager().isResponseCacheable(response))
{
ic = getCacheManager().createCache(request.getURL(),
response);
}
}
}
return ic;
}
// if requested resource is not cacheable, load it as usual
return super.handleResourceRequest(request);
}

}

CacheManager.java:

import javax.microedition.io.HttpConnection;
import javax.microedition.io.InputConnection;

import net.rim.device.api.browser.field2.BrowserFieldRequest;

public interface CacheManager {
public boolean isRequestCacheable(BrowserFieldRequest request);
public boolean isResponseCacheable(HttpConnection response);
public boolean hasCache(String url);
public boolean hasCacheExpired(String url);
public InputConnection getCache(String url);
public InputConnection createCache(String url, HttpConnection response);
public void clearCache(String url);
}

CacheManagerImpl.java:

import java.io.IOException;
import java.io.InputStream;
import java.util.Date;
import java.util.Hashtable;

import javax.microedition.io.HttpConnection;
import javax.microedition.io.InputConnection;

import net.rim.device.api.browser.field2.BrowserFieldRequest;
import net.rim.device.api.browser.field2.BrowserFieldResponse;
import net.rim.device.api.io.http.HttpHeaders;


public class CacheManagerImpl implements CacheManager {

private static final int MAX_STANDARD_CACHE_AGE = 2592000;
private Hashtable cacheTable;

public CacheManagerImpl() {
cacheTable = new Hashtable();
}

public boolean isRequestCacheable(BrowserFieldRequest request) {
// Only HTTP requests are cacheable
if (!request.getProtocol().equals("http")) {
return false;
}

// Don't cache the request whose method is not "GET".
if (request instanceof HttpConnection) {
if (!((HttpConnection) request).getRequestMethod().equals("GET"))
{
return false;
}
}

// Don't cache the request with post data.
if (request.getPostData() != null) {
return false;
}

// Don't cache authentication request.
if (request.getHeaders().getPropertyValue("Authorization") != null) {
return false;
}

return true;
}

public boolean isResponseCacheable(HttpConnection response) {
try {
if (response.getResponseCode() != 200) {
return false;
}
} catch (IOException ioe) {
return false;
}

if (!response.getRequestMethod().equals("GET")) {
return false;
}

if (containsPragmaNoCache(response)) {
return false;
}

if (isExpired(response)) {
return false;
}

if (containsCacheControlNoCache(response)) {
return false;
}

if ( response.getLength() <= 0 ) {
return false;
}

// additional checks can be implemented here to inspect
// the HTTP cache-related headers of the response object

return true;
}

private boolean isExpired(HttpConnection response) {
try
{
// getExpiration() returns 0 if not known
long expires = response.getExpiration();
if (expires > 0 && expires <= (new Date()).getTime()) {
return true;
}
return false;
} catch (IOException ioe) {
return true;
}
}

private boolean containsPragmaNoCache(HttpConnection response) {
try
{
if (response.getHeaderField("pragma") != null
&& response.getHeaderField("pragma")
.toLowerCase()
.indexOf("no-cache") >= 0)
{
return true;
}

return false;
} catch (IOException ioe) {
return true;
}
}

private boolean containsCacheControlNoCache(HttpConnection response) {
try {
String cacheControl = response.getHeaderField("cache-control");
if (cacheControl != null) {
cacheControl = removeSpace(cacheControl.toLowerCase());
if (cacheControl.indexOf("no-cache") >= 0
|| cacheControl.indexOf("no-store") >= 0
|| cacheControl.indexOf("private") >= 0
|| cacheControl.indexOf("max-age=0") >= 0) {
return true;
}

long maxAge = parseMaxAge(cacheControl);
if (maxAge > 0 && response.getDate() > 0) {
long date = response.getDate();
long now = (new Date()).getTime();
if (now > date + maxAge) {
// Already expired
return true;
}
}
}

return false;
} catch (IOException ioe) {
return true;
}
}

public InputConnection createCache(String url, HttpConnection response) {

byte[] data = null;
InputStream is = null;
try {
// Read data
int len = (int) response.getLength();
if (len > 0) {
is = response.openInputStream();
int actual = 0;
int bytesread = 0 ;
data = new byte[len];
while ((bytesread != len) && (actual != -1)) {
actual = is.read(data, bytesread, len - bytesread);
bytesread += actual;
}
}
} catch (IOException ioe) {
data = null;
} finally {
if (is != null) {
try {
is.close();
} catch (IOException ioe) {
}
}
if (response != null) {
try {
response.close();
} catch (IOException ioe) {
}
}
}

if (data == null) {
return null;
}

// Calculate expires
long expires = calculateCacheExpires(response);

// Copy headers
HttpHeaders headers = copyResponseHeaders(response);

// add item to cache
cacheTable.put(url, new CacheItem(url, expires, data, headers));

return new BrowserFieldResponse(url, data, headers);
}

private long calculateCacheExpires(HttpConnection response) {
long date = 0;
try {
date = response.getDate();
} catch (IOException ioe) {
}

if (date == 0) {
date = (new Date()).getTime();
}

long expires = getResponseExpires(response);

// If an expire date has not been specified assumes the maximum time
if ( expires == 0 ) {
return date + (MAX_STANDARD_CACHE_AGE * 1000L);
}

return expires;
}

private long getResponseExpires(HttpConnection response) {
try {
// Calculate expires from "expires"
long expires = response.getExpiration();
if (expires > 0) {
return expires;
}

// Calculate expires from "max-age" and "date"
if (response.getHeaderField("cache-control") != null) {
String cacheControl = removeSpace(response
.getHeaderField("cache-control")
.toLowerCase());
long maxAge = parseMaxAge(cacheControl);
long date = response.getDate();

if (maxAge > 0 && date > 0) {
return (date + maxAge);
}
}
} catch (IOException ioe) {
}

return 0;
}

private long parseMaxAge(String cacheControl) {
if (cacheControl == null) {
return 0;
}

long maxAge = 0;
if (cacheControl.indexOf("max-age=") >= 0) {
int maxAgeStart = cacheControl.indexOf("max-age=") + 8;
int maxAgeEnd = cacheControl.indexOf(',', maxAgeStart);
if (maxAgeEnd < 0) {
maxAgeEnd = cacheControl.length();
}

try {
maxAge = Long.parseLong(cacheControl.substring(maxAgeStart,
maxAgeEnd));
} catch (NumberFormatException nfe) {
}
}

// Multiply maxAge by 1000 to convert seconds to milliseconds
maxAge *= 1000L;
return maxAge;
}

private static String removeSpace(String s) {
StringBuffer result= new StringBuffer();
int count = s.length();
for (int i = 0; i < count; i++) {
char c = s.charAt(i);
if (c != ' ') {
result.append(c);
}
}

return result.toString();
}

private HttpHeaders copyResponseHeaders(HttpConnection response) {
HttpHeaders headers = new HttpHeaders();
try {
int index = 0;
while (response.getHeaderFieldKey(index) != null) {
headers.addProperty(response.getHeaderFieldKey(index),
response.getHeaderField(index));
index++;
}
} catch (IOException ioe) {
}

return headers;
}

public boolean hasCache(String url) {
return cacheTable.containsKey(url);
}

public boolean hasCacheExpired(String url) {
Object o = cacheTable.get(url);

if (o instanceof CacheItem) {
CacheItem ci = (CacheItem) o;
long date = (new Date()).getTime();
if (ci.getExpires() > date) {
return false;
} else {
// Remove the expired cache item
clearCache(url);
}
}

return true;
}

public void clearCache(String url) {
cacheTable.remove(url);
}

public InputConnection getCache(String url) {
Object o = cacheTable.get(url);
if (o instanceof CacheItem) {
CacheItem ci = (CacheItem) o;
return new BrowserFieldResponse(url,
ci.getData(),
ci.getHttpHeaders());
}
return null;
}
}

CacheItem.java:

import net.rim.device.api.io.http.HttpHeaders;

public class CacheItem {

private String url;
private long expires;
private byte[] data;
private HttpHeaders httpHeaders;

public CacheItem(String url,
long expires,
byte[] data,
HttpHeaders httpHeaders)
{
this.url = url;
this.expires = expires;
this.data = data;
this.httpHeaders = httpHeaders;
}

public String getUrl() {
return url;
}

public long getExpires() {
return expires;
}

public byte[] getData() {
return data;
}

public HttpHeaders getHttpHeaders() {
return httpHeaders;
}
}

我们将不胜感激任何可以为此提供的帮助。这真的让我很难过。谢谢。

更新:看起来缓存只在一定级别的 Blackberry 库中有效。我添加了逻辑来检查当前的软件级别,如果设备的当前软件级别支持缓存,则打开缓存。这为我提供了一个很好的解决方法,但我仍然想知道是否有更好的方法让缓存适用于所有设备。

更新 2 基于评论:该网站不再正确显示与未显示正确布局、图像和文本的网站有关。它基本上是白色背景,链接和文本显示为项目符号列表,所有格式都已删除。

最佳答案

我一直在查看您的代码,唯一发现它有问题的是您完全忽略了 response.getLength(); 返回小于零的可能性(在 CacheManagerImpl.createCache() 中)。虽然我在 stackoverflow.com 页面上没有发生这种情况,但有些页面使用 Transfer-Encoding: chunked,这意味着 Content-Length 不存在。但是,这已得到很好的处理,并且不会导致缓存失败(它只会降低效率)。

我建议在较小的问题上测试您的代码,一次一步。首先,创建只包含一些文本(如“hello”)而没有任何 HTML 标记的可缓存页面。这应该工作得很好,如果没有,应该不难确定数据丢失的位置。或者尝试手动创建不会过期且包含没有(外部)样式表或图像的网页的缓存项,并查看是否可以按照您的方式将其传递给 BrowserField。然后构建,添加图像,添加样式表,以便解决问题。

代码写得很好,但是在这一点上,无法帮助你,因为代码中没有明显的缺陷,而且你没有很好地解释自己,不清楚错误是如何表现出来的,如果是每次或随机,...如果我有一个黑莓设备,我可能会尝试为自己运行代码,但我没有。

关于java - 如何在黑莓浏览器字段中缓存,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7687200/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com