I'm currently developing an Android application that fetches images using http requests. It would be quite swell if I could cache those images in order to improve to performance and bandwidth use.
I came across the CacheManager class in the Android reference, but I don't really know how to use it, or what it really does.
I already scoped through this example, but I need some help understanding it:
/core/java/android/webkit/gears/ApacheHttpRequestAndroid.java
Also, the reference states:
"Network requests are provided to this component and if they can not be resolved by the cache, the HTTP headers are attached, as appropriate, to the request for revalidation of content."
I'm not sure what this means or how it would work for me, since CacheManager's getCacheFile accepts only a String URL and a Map containing the headers. Not sure what the attachment mentioned means.
An explanation or a simple code example would really do my day. Thanks!
Update
Here's what I have right now. I am clearly doing it wrong, just don't know where.
public static Bitmap getRemoteImage(String imageUrl) {
URL aURL = null;
URLConnection conn = null;
Bitmap bmp = null;
CacheResult cache_result = CacheManager.getCacheFile(imageUrl, new HashMap());
if (cache_result == null) {
try {
aURL = new URL(imageUrl);
conn = aURL.openConnection();
conn.connect();
InputStream is = conn.getInputStream();
cache_result = new CacheManager.CacheResult();
copyStream(is, cache_result.getOutputStream());
CacheManager.saveCacheFile(imageUrl, cache_result);
} catch (Exception e) {
return null;
}
}
bmp = BitmapFactory.decodeStream(cache_result.getInputStream());
return bmp;
}
I don't think the CacheManger can be used outside of a WebView as noted in this bug report
http://code.google.com/p/android/issues/detail?id=7222
I came across this issue awhile ago as well. The cache manager is only for the webview and not really useful outside of that. For my application I needed to cache xml responses and images so I ended up writing my own cache manager to accomplish that. Nothing too terrible but certainly not as easy as using a would-be built-in one.
If you have any questions about the specifics, add a comment to my post, I check back frequently.
Related
I am trying to test downloading and storing an image (any image) using Robolectric but I keep getting a 403. The URL is properly accessible and work with Android's VM, also works when I open in the browser.
Here is what I am trying to test.
try{
URLConnection urlConnection = new URL("http://<any image url>").openConnection();
InputStream inputStream = urlConnection.getInputStream();
// call a method to write to disk
} catch(Exception ex){
ex.printStackTrace();
}
My Roboelectric method fails when I try to get the inputStream. It always returns a 403. I looked at the FalseHTTP thing as well but it only seems to work with apache's connection.
Is this a Roboelectric problem or what am I doing incorrectly ? Robolectric is properly configured. RUnnables work. It fails over here.
Thanks!
Try Robolectric.getFakeHttpLayer().interceptHttpRequests(false) to allow the requests to actually go through instead of being intercepted.
I'm trying to download an object from S3 using the AWS Android SDK 1.0.4 or 1.0.3.
This is my code:
AmazonS3Client client = getConnection(userCredentials);
S3Object obj = client.getObject(workspaceName, objectName);
ObjectMetadata meta = obj.getObjectMetadata();
long size = meta.getContentLength();
logger.info("S3 object length: "+size);
InputStream is = new BufferedInputStream(obj.getObjectContent());
byte[] fragmentBytes = IOUtils.toByteArray(is);
logger.info("Read bytes: "+ fragmentBytes.length);
This sometimes, rarely, works. Most of the time either an "java.net.SocketException: Socket is closed" is thrown or no error is reported but only part of the object is read.
Note, that the BufferedInputStream should not be necessary for IOUtils.toByteArray(...) and it makes no difference if it is there or not.
The problem does not seem to occur when stepping through the code line by line in a debugger.
This happens on my Android 2.3.3 device and 3.2 device. It happens over WiFi and 3G.
Any ideas?
ps> The objects are about 250k big
The issue is that the client is being Garbage Collected. To fix it, you need to keep an explicit reference to the S3Client.
The flow of the bug is as follows:
The program gets an S3 client
The program gets a S3 object from the client.
The program gets an inputStream from the s3Object, which gets it through the client.
Garbage collection runs, and since there is no reference to the client, it gets Garbage Collected, randomly closing your inputStream.
IMO, this is a very bad bug by Amazon. Why the S3 object input stream does not have a reference back to the client is a mystery to me.
Here's the thread on the AWS forums: https://forums.aws.amazon.com/thread.jspa?threadID=83326
You probably already solved this but I could not find the correct answer and ended up figuring it out by myself, so here goes the solution:
The getObjectContent methods documentation is very clear about closing the InputStream:
S3ObjectInputStream com.amazonaws.services.s3.model.S3Object.getObjectContent()
Gets an input stream containing the contents of this object. Callers should close this input stream as soon as possible, because the object contents aren't buffered in memory and stream directly from Amazon S3.
You are making the same mistake as I was of using the InputStream (S3Object) as if closure was transparent.
I am guessing you need to get an image from S3 to be used on Android, so here goes an example method that returns a Bitmap. It really applies to any kind of input.
private Bitmap getFromStore(String fileName) {
AmazonS3Client client = new AmazonS3Client(new BasicAWSCredentials(ACCESS_KEY, SECRET_KEY));
S3Object o = client.getObject(BUCKET, fileName);
InputStream is = o.getObjectContent();
Bitmap image = null;
try {
// Use the inputStream and close it after.
image = BitmapFactory.decodeStream(is);
} finally {
try {
is.close();
} catch (IOException e) {
Log.w(TAG, "Error trying to close image stream. ", e);
}
}
return image;
}
Just in case, dont forget to execute this on a different thread then the UI.
Good luck,
Well, it seems you are not alone. The accepted in the post answer talks of your problem.
How to write an S3 object to a file?
I would try looping the content like the answer in the question above. Buffered is good, but....
You could also try not using the IOUtil, after all there are other options in java.
no need to keep re-initializing s3.
In your onCreate, make the call to initialize s3Object and s3Client.
Then use the call in your asynctask. This way, your s3Client will keep the same data and never close the socket connection with s3 when doing the while read.
S3Client s3Client;
S3Object s3Object;
onCreate() {
s3Client = new AmazonS3Client(new BasicSessionCredentials(
Constants.ACCESS_KEY_ID, Constants.SECRET_KEY, Constants.TOKEN
));
object = new S3Object();
}
doinbackground() {
object = s3Client.getObject(new GetObjectRequest(Constants.getBucket(), id +".png"));
}
/****** add this in your onCreate ******/
AmazonS3Client client = getConnection(userCredentials);
I have the following code to read a website. The code is searches on google. I want to open automatically the first result and read it again. For the keywords i want the "I am feeling lucky is not working". Please somebody help me find a solution
I have the following code.
URL url = new URL("http://www.google.com/search?q=sample");
URLConnection urlConnection = url.openConnection();
InputStream in = new BufferedInputStream(urlConnection.getInputStream());
try {
readStream(in);
finally {
in.close();
}
}
The query sample is just a sample....
Its already discussed in SO QA :
How to search in google by using java code?
Your approach is also a solution. But it will be complex as it requires parsing of returned HTML.
I think there are some APIS for doing this.
http://code.google.com/p/google-api-java-client/
This is deprecated but might still work -->
http://code.google.com/apis/websearch/docs/
I would like to use Android's system cache when downloading images as per these previous instructions: android system cache. I was able to get the following code working but the log statements are telling me that the images are never being read from the cache.
try {
//url = new URL("http://some.url.com/retrieve_image.php?user=" + username);
URL url = new URL("http://some.url.com/prof_pics/b4fe7bdfa174ff372c9f26ce6f78f19c.png");
URLConnection connection = url.openConnection();
connection.setUseCaches(true);
Object response = connection.getContent();
if (response instanceof Bitmap) {
Log.i("CHAT", "this is a bitmap");
current_image.setImageBitmap((Bitmap) response);
}
else {
Log.i("CHAT", "this is not a bitmap");
Log.i("CHAT", response.toString());
InputStream is = connection.getInputStream();
BufferedInputStream bis = new BufferedInputStream(is);
current_image.setImageBitmap(BitmapFactory.decodeStream(bis));
}
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
I have tried two different types of requests, one is to go through a PHP script that returns the image and another that is directly accessing the image file. I refresh the same image multiple times in a row and it never seems to get cached. For the direct image access, I get:
05-31 23:45:12.177 I/CHAT ( 2995): this is not a bitmap
05-31 23:45:12.177 I/CHAT ( 2995): org.apache.harmony.luni.internal.net.www.protocol.http.FixedLengthInputStream#40c1c660`
For the indirect image access, I consistently get:
05-31 23:45:14.550 I/CHAT ( 2995): this is not a bitmap
05-31 23:45:14.550 I/CHAT ( 2995): org.apache.harmony.luni.internal.net.www.protocol.http.ChunkedInputStream#40c02448
I found a better way to do it. If anyone else is having trouble after following the link android system cache, use this Google developer's blog post instead. The source code in that blog post is designed for a ListView but I am using it for all image retrievals. It downloads the image in an AsyncTask, puts a temporary image while downloading, and has an image cache. This last part is listed as a "Future Item" in the blog post, but if you download the source code, the cache is implemented. I had to modify the code slightly because the AndroidHttpClient isn't supported in 2.1. I switched it to a URL connection. So far, this looks to be a great image downloader class. Let's just hope it doesn't impact our already struggling memory management issues.
I would like to make an ImageView display an image on a website. So I create a new ImageView and execute imgView.setImageURI(uri);
When I launch the app the image does not appear and I get the error, "resolveUri failed on bad Bitmap Uri (uri)".
Any ideas on how to solve this?
If it's not a content URI, this link may help. It seems to indicate that imgView.setImageURI() should not be used for regular URIs. Copying in the relevant bit:
Yes, ImageView.setImageURI(ContentURI uri) works, but it is for content URIs particular to the Android platform, not URIs specifying Internet resources. The convention is applied to binary objects (images, for example) which cannot be exposed directly through a ContentProvider's Cursor methods. Instead, a String reference is used to reference a distinct content URI, which can be resolved by a separate query against the content provider. The setImageURI method is simply a wrapper to perform those steps for you.
I have tested this usage of setImageView, and it does work as expected. For your usage, though, I'd look at BitmapFactory.decodeStream() and URL.openStream().
Also to make this answer self-contained, the sample code from another post at that link, showing how to do it:
private Bitmap getImageBitmap(String url) {
Bitmap bm = null;
try {
URL aURL = new URL(url);
URLConnection conn = aURL.openConnection();
conn.connect();
InputStream is = conn.getInputStream();
BufferedInputStream bis = new BufferedInputStream(is);
bm = BitmapFactory.decodeStream(bis);
bis.close();
is.close();
} catch (IOException e) {
Log.e(TAG, "Error getting bitmap", e);
}
return bm;
}
I haven't tested this code, I'm just paranoid and like to ensure SO answers are useful even if every other site on the net disappears :-)
Glide is an awesome library for displaying images!
Glide.with(context)
.load(uri)
.into(imageView);
You need to download the image and then set it as bitmap.
Here is one of the many examples:
http://android-developers.blogspot.com/2010/07/multithreading-for-performance.html
Use library Picasso
Manifest
uses-permission android:name="android.permission.INTERNET"
build gradle
implementation 'com.squareup.picasso:picasso:2.71828'
Activity:
Picasso.get().load(photoUrl).into(imageView);
First, you should download the image and save it in your device(sdcard or memory).
Then, get its file path, using Uri.parse(filePath) to convert path to uri
finally, call ImageView's setImageURI(Uri) to fullfill.
-- I use this way to achieve my purpose and there is a bug:if the image is to large(maybe exceed 1Mb or so, it may report outOfMemeroy Exception!!!)