I am using Picasso to download and display images in views all accros my application. Those images are changing very rarely (they are considered valid for a few months).
Is there a simple way to ask Picasso (or the underlying okHttp) to keep those images on disc for this much time?
Disk caching happens "below" Picasso inside the HTTP client. In fact, this process is completely transparent. We never explicitly ask for a cached-version or an internet-version, the HTTP client will make the decision internally and do the right thing.
Because we opted to leverage the HTTP client for caching, we're offered very little control over how the caching actually happens. To answer your question, no, there is no way to tell Picasso (or OkHttp) to cache an image for longer than its headers allow.
I solved it with a Home-made cache, the trick is to add a parameter to the URL that is not used, but making each URL different every X minutes
Calendar cal2 = Calendar.getInstance();
long d = cal2.getTimeInMillis();
int extra = (int) Math.ceil(d/ (10*60*1000)); // 10 minutes cache
Picasso.with(getBaseContext())
.load("http://www.myurl.cat/myimage.png&extra=" + extra)
.placeholder(R.drawable.graphicLoading)
.error(R.drawable.graphicLoadingError)
.into(bottomGraphic);
Before thinking about HTTP behavior, make sure you set a large max size for the disk cache:
cache = Cache(File(application.filesDir, "photos"), Long.MAX_VALUE)
(MAX_VALUE is not recommended for production.) Don't store the cache in application.cacheDir, because android can clear that whenever it wants.
Add an interceptor to set max-stale, which tells the disk cache to use all old files:
val httpClient = OkHttpClient.Builder().cache(cache).addInterceptor { chain ->
// When offline, we always want to show old photos.
val neverExpireCacheControl = CacheControl.Builder().maxStale(Int.MAX_VALUE, TimeUnit.SECONDS).build()
val origRequest = chain.request()
val neverExpireRequest = origRequest.newBuilder().cacheControl(neverExpireCacheControl).build()
chain.proceed(neverExpireRequest)
}.build()
return Picasso.Builder(application).downloader(OkHttp3Downloader(httpClient)).loggingEnabled(true).build()
I discovered this solution by debugging CacheStrategy.getCandidate(). Take a look there if this doesn't solve your problem.
Related
I need to know how long a cached version of URI would be on the disk in fresco cache?
As it is written at http://frescolib.org/docs/caching.html#trimming-the-caches:
When configuring the image pipeline, you can set the maximum size of
each of the caches. But there are times when you might want to go
lower than that. For instance, your application might have caches for
other kinds of data that might need more space and crowd out Fresco's.
Or you might be checking to see if the device as a whole is running
out of storage space.
Fresco's caches implement the DiskTrimmable or MemoryTrimmable
interfaces. These are hooks into which your app can tell them to do
emergency evictions.
Your application can then configure the pipeline with objects
implementing the DiskTrimmableRegistry and MemoryTrimmableRegistry
interfaces.
These objects must keep a list of trimmables. They must use
app-specific logic to determine when memory or disk space must be
preserved. They then notify the trimmable objects to carry out their
trims.
So, if you don't specify DiskTrimmable or MemoryTrimmable while configuration your ImagePipeline will be using default DiskTrimmable, MemoryTrimmable. So, after looking for default values in sources i found this:
private static DiskCacheConfig getDefaultMainDiskCacheConfig(final Context context) {
return DiskCacheConfig.newBuilder()
.setBaseDirectoryPathSupplier(
new Supplier<File>() {
#Override
public File get() {
return context.getApplicationContext().getCacheDir();
}
})
.setBaseDirectoryName("image_cache")
.setMaxCacheSize(40 * ByteConstants.MB)
.setMaxCacheSizeOnLowDiskSpace(10 * ByteConstants.MB)
.setMaxCacheSizeOnVeryLowDiskSpace(2 * ByteConstants.MB)
.build();
}
So conclusion is next: when the memory is full (40 ByteConstants.MB or 10 ByteConstants.MB or 2 ByteConstants.MB) - Fresco will delete old records and write new records(images).
Maybe Fresco use this method.
As the tile, i'm using Here-map.
I'm trying to custom raster tiles from S3 server instead. Folow the documentation, there are two class that support me to do that: UrlMapRasterTileSourceBase and MapRasterTileSource.
In my case, i tried to new an instance of MapRasterTileSource then override getTileWithError(int x, int y, int zoomLevel) function to load my tile image from S3 server.
The problem is the time to load an image is too long, and the UI seem be lagged.
In the document, here is part:
Note: Ensure that getTileWithError() returns within a reasonable
amount of time. If your operation takes a longer period of time,
launch an asynchronous operation and return the
TileResult.Error.NOT_READY error code while the operation is in
progress.
But, i don't have any idea how to apply that. I have tried to load image with a callback, but don't know what to do after having result.
Could you give me a hand on this please!?
How are you loading raster tiles from S3? Is it a synchronous HTTP request that you call from getTileWithError?
The proper flow should be:
-getTileWithError() // for a particular x, y, z
-Execute the tile fetch from your S3 layer asynchronously via a thread or AsyncTask.
-Meanwhile, getTileWithError() will be called continously, and you can return "TileResult.NOT_READY"
-When the image is fully downloaded, then return the image back to the runtime.
If the amount of time spent in the getTileWithError takes too long, the tile source will be disabled automatically.
I am using Picasso to download and display images in views all accros my application. Those images are changing very rarely (they are considered valid for a few months).
Is there a simple way to ask Picasso (or the underlying okHttp) to keep those images on disc for this much time?
Disk caching happens "below" Picasso inside the HTTP client. In fact, this process is completely transparent. We never explicitly ask for a cached-version or an internet-version, the HTTP client will make the decision internally and do the right thing.
Because we opted to leverage the HTTP client for caching, we're offered very little control over how the caching actually happens. To answer your question, no, there is no way to tell Picasso (or OkHttp) to cache an image for longer than its headers allow.
I solved it with a Home-made cache, the trick is to add a parameter to the URL that is not used, but making each URL different every X minutes
Calendar cal2 = Calendar.getInstance();
long d = cal2.getTimeInMillis();
int extra = (int) Math.ceil(d/ (10*60*1000)); // 10 minutes cache
Picasso.with(getBaseContext())
.load("http://www.myurl.cat/myimage.png&extra=" + extra)
.placeholder(R.drawable.graphicLoading)
.error(R.drawable.graphicLoadingError)
.into(bottomGraphic);
Before thinking about HTTP behavior, make sure you set a large max size for the disk cache:
cache = Cache(File(application.filesDir, "photos"), Long.MAX_VALUE)
(MAX_VALUE is not recommended for production.) Don't store the cache in application.cacheDir, because android can clear that whenever it wants.
Add an interceptor to set max-stale, which tells the disk cache to use all old files:
val httpClient = OkHttpClient.Builder().cache(cache).addInterceptor { chain ->
// When offline, we always want to show old photos.
val neverExpireCacheControl = CacheControl.Builder().maxStale(Int.MAX_VALUE, TimeUnit.SECONDS).build()
val origRequest = chain.request()
val neverExpireRequest = origRequest.newBuilder().cacheControl(neverExpireCacheControl).build()
chain.proceed(neverExpireRequest)
}.build()
return Picasso.Builder(application).downloader(OkHttp3Downloader(httpClient)).loggingEnabled(true).build()
I discovered this solution by debugging CacheStrategy.getCandidate(). Take a look there if this doesn't solve your problem.
In a normal Android web app the maximum size for a WebSQL database is normally around 8MB. In a hybrid web app I am making I would like to increase this limit. How would I go about doing that?
It seems that WebStorage might have something to do with it, but the only method I can see there that seems to set the size, setQuotaForOrigin, is marked deprecated.
Sample code (that is not deprecated) is welcome :)
The quota for a web app seems to differ from that of a hybrid app (as in something running within a view). Regardless, by implementing the following in your android.app.Activity subclass you will double the quota until it finally stops at approximately 48MB.
#Override
public void onExceededDatabaseQuota(String url, String databaseIdentifier, long currentQuota, long estimatedSize, long totalUsedQuota, WebStorage.QuotaUpdater quotaUpdater) {
quotaUpdater.updateQuota(estimatedSize * 2);
}
The user will not be asked to interact when this happens.
You may want to look at this other question on how to increase quota limit.
Looks like changing the size is only a problem for users that already have a local DB created, this is because there is no way to change the size of the DB when running upgrade scripts for versioning. That said, you just only need to change the size in the initialization script (code in JavaScript):
var size = 10 * 1024 * 1024; // changed from 5 to 10MB
var db = openDatabase("oversized_db", "v1.1", "Ten MB DB", size);
Take into account that this will only affect new users. All users that have previously created a DB with a different size need to clear their cache (you have controll of the cache on a webView so its not that bad) but all previous data would be lost (unless you manually migrate it to the new DB with native code).
In my case I have to do the same but decreasing the size. That would take care of the issue.
Hope this helps.
So I am using the Android camera to take pictures within an Android app. About 90% of my users have no issues, but the other 10% get a picture that returns pure black or a weird jumbling of pixels.
Has anyone else seen this behavior? or have any ideas why it happens?
Examples:
Black:
Jumbled:
I've had similar problems like this.
The problem in short is: Missing data.
It occurs to a Bitmap/Stream if the datastream was interrupted for too long or it is accidentally no more available.
Another example where it may occur: Downloading and uploading images.
If the user disables all of a sudden Wifi/mobile network no more data can be transmitted.
You end up in a splattered image.
The image will appear/view okay(where okay means black/splattered, it's still viewable!) but is invalid internally (missing or corrupted information).
If it's not too critical you can try to move all the data into a Bitmap object (BitmapFactory.decode*) and test if the returned Bitmap is null. If yes the data possibly is corrupted.
This is just solving the consequences of the problem, as you can guess.
The better way would be to take the problem on the foot:
Ensure a good connection to your data source (Large enough, stout buffer).
Try to avoid unneccesary casts (e.g. from char to int)
Use the correct type of buffers (Either Reader/Writer for character streams or InputStream/OutputStream for byte streams).
From android 4.0 they put hardwareAcceleration set to true as default in the manifest. Hardwareaccelerated canvas does not support Pictures and you will get a black screen...
Please also check that whether you use BitmapFactory.Options object for generating the bitmap or not. Because few methods of this object also makes the bitmap corrupted.