问题
I'm trying to use apache httpclient to load images with caching. After request the file is saved but after repeating same request it begins to download again and new file saved as cache. So cached images not reused. And not deleting.
File names differ only by hash
1389449846612.0000000000000001-3f1e8b88.localhost.-images-goods-212250-7841874.jpg
1389449952782.0000000000000001-5720e341.localhost.-images-goods-212250-7841874.jpg
I want, that image will be loaded once and be able to show cached image even when there is no connection to internet.
Here my code
RequestConfig config = RequestConfig.custom()
.setConnectTimeout(30000)
.setSocketTimeout(30000)
.setProxy(getProxy())
.build();
CacheConfig cacheConfig = CacheConfig.custom()
.build();
CloseableHttpClient client = CachingHttpClientBuilder.create()
.setCacheDir(new File("/sdcard/Android/data/com.myapp/cache/"))
.setCacheConfig(cacheConfig)
.setDefaultRequestConfig(config)
.build();
HttpGet request = new HttpGet(imageUri);
HttpCacheContext context = HttpCacheContext.create();
CloseableHttpResponse response = client.execute(request, context);
This is image response headers
Cache-Control:max-age=604800
Connection:keep-alive
Content-Length:449512
Content-Type:image/jpeg
Date:Sat, 11 Jan 2014 15:03:21 GMT
Expires:Sat, 18 Jan 2014 15:03:21 GMT
Last-Modified:Tue, 12 Jul 2011 19:40:44 GMT
回答1:
First problem is that i'm created new httpclient every time before download, so every time was created new instance of HttpCacheStorage, this is why files had different names.
Second, default HttpCacheStorage stores info of downloaded data just in LinkedHashMap so after every new launch of app cacheStorage don't know anything about cached data in previous launch.
Solutions was to create own HttpCacheStorage, wich will save cached data to file system and will get data from files when response can be got from cache.
I just added one line to CachingHttpClientBuilder - setHttpCacheStorage
CachingHttpClientBuilder.create()
.setCacheConfig(cacheConfig)
.setHttpCacheStorage(new ImagesCacheStorage(cacheConfig, cacheDir))
.setDefaultRequestConfig(config)
.build();
and created new class FileCacheStorage
import myapp.org.apache.http.client.cache.HttpCacheEntry;
import myapp.org.apache.http.client.cache.HttpCacheUpdateCallback;
import myapp.org.apache.http.impl.client.cache.CacheConfig;
import myapp.org.apache.http.impl.client.cache.ManagedHttpCacheStorage;
public class FileCacheStorage extends ManagedHttpCacheStorage {
private File mCacheDir;
public FileCacheStorage(final CacheConfig config, File cacheDir) {
super(config);
mCacheDir = cacheDir;
}
@Override
public HttpCacheEntry getEntry(final String url) throws IOException {
HttpCacheEntry entry = super.getEntry(url);
if (entry == null) {
entry = loadCacheEnrty(url);
}
return entry;
}
@Override
public void putEntry(final String url, final HttpCacheEntry entry) throws IOException {
super.putEntry(url, entry);
saveCacheEntry(url, entry);
}
@Override
public void removeEntry(final String url) throws IOException {
super.removeEntry(url);
File cache = getCacheFile(url);
if (cache != null && cache.exists()) {
cache.delete();
}
}
@Override
public void updateEntry(
final String url,
final HttpCacheUpdateCallback callback) throws IOException {
super.updateEntry(url, callback);
HttpCacheEntry entry = loadCacheEnrty(url);
if (entry != null) {
callback.update(entry);
}
}
private void saveCacheEntry(String url, HttpCacheEntry entry) {
ObjectOutputStream stream = null;
try {
File cache = getCacheFile(url);
stream = new ObjectOutputStream(new FileOutputStream(cache));
stream.writeObject(entry);
stream.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
private HttpCacheEntry loadCacheEnrty(String url) {
HttpCacheEntry entry = null;
File cache = getCacheFile(url);
if (cache != null && cache.exists()) {
synchronized (this) {
ObjectInputStream stream = null;
try {
stream = new ObjectInputStream(new FileInputStream(cache));
entry = (HttpCacheEntry) stream.readObject();
stream.close();
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (StreamCorruptedException e) {
e.printStackTrace();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
return entry;
}
private File getCacheFile(String url) {
return new File(mCacheDir, MD5.getHash(url));
}
}
As you can see Apache classes have package name with prefix myapp. I got errors when tryed to use origin jar files, I think it's because many classes are already present in Android. So I combined few jar files from apache and made from them one jar with that prefix. If someone have a better solution let me know. Hope it help someone.
来源:https://stackoverflow.com/questions/21064180/httpclient-doesnt-correctly-caches-responses