Android - downloading image from web, saving to internal memory in location private to app, displaying for list item
Solution 1
Looks like simply referring to the image file name when trying to read it was not enough, and I had to call getFilesDir() to get the path of the file storage. Below is the code I used:
String path = context.getFilesDir().toString();
String fileName = cursor.getString(cursor.getColumnIndex(DbAdapter.KEY_PRODUCT_ID));
if (fileName != null && !fileName.equals("")) {
Bitmap bMap = BitmapFactory.decodeFile(path + "/" + fileName);
if (bMap != null) {
thumbnail.setImageBitmap(bMap);
}
}
Solution 2
it seems that some code is left out, I re-wrote it like this:
ProductUtils.java
public static String productLookup(String productID, Context c) throws IOException {
URL url = new URL("http://www.samplewebsite.com/" + productID + ".jpg");
InputStream input = null;
FileOutputStream output = null;
try {
String outputName = productID + "-thumbnail.jpg";
input = url.openConnection().getInputStream();
output = c.openFileOutput(outputName, Context.MODE_PRIVATE);
int read;
byte[] data = new byte[1024];
while ((read = input.read(data)) != -1)
output.write(data, 0, read);
return outputName;
} finally {
if (output != null)
output.close();
if (input != null)
input.close();
}
}
Keeb13r
Updated on August 18, 2020Comments
-
Keeb13r almost 4 years
What I'm trying to do is this: I want my application to download an image from the Internet and save it to the phone's internal memory in a location that is private to the application. If there is no image available for the list item (i.e. it can't be found on the Internet), I want a default placeholder image to display. This is the image that I have defined in my list_item_row.xml file as the default.
In my ListActivity file, I am calling an instance of a CustomCursorAdapter class I have written. It is in CustomCursorAdapter where I am iterating through all the list items and defining what content needs to be mapped to the views, including the image file by trying to read it from internal memory.
I've seen several questions on this subject, but the examples either are specific to external phone memory (e.g. SDCard), involve saving strings instead of images, or involve using Bitmap.CompressFormat to reduce the resolution of the file (which is unnecessary in my case, as these images will be small thumbnails of already-small resolution). Trying to piece together code from each example has been difficult, hence my asking about my specific example.
At the moment, I believe I've written valid code, but no image is displaying for my list items, including the default placeholder image. I don't know if the problem is being caused by invalid download/save code, or invalid read code - it doesn't help that I don't know how to check internal memory to see if the image exists.
Anyways, here's my code. Any help would be greatly appreciated.
ProductUtils.java
public static String productLookup(String productID, Context c) throws IOException { URL url = new URL("http://www.samplewebsite.com/" + productID + ".jpg"); URLConnection connection = url.openConnection(); InputStream input = connection.getInputStream(); FileOutputStream output = c.openFileOutput(productID + "-thumbnail.jpg", Context.MODE_PRIVATE); byte[] data = new byte[1024]; output.write(data); output.flush(); output.close(); input.close(); }
CustomCursorAdapter.java
public class CustomCursorAdapter extends CursorAdapter { public CustomCursorAdapter(Context context, Cursor c) { super(context, c); } @Override public void bindView(View view, Context context, Cursor cursor) { ImageView thumbnail = (ImageView) view.findViewById(R.id.thumbnail); String fileName = cursor.getString(cursor.getColumnIndex(DbAdapter.KEY_IMAGE_FILE_PATH)); Bitmap bMap = BitmapFactory.decodeFile(fileName); thumbnail.setImageBitmap(bMap); } @Override public View newView(Context context, Cursor cursor, ViewGroup parent) { LayoutInflater inflater = LayoutInflater.from(context); View v = inflater.inflate(R.layout.list_item_row, parent, false); bindView(v, context, cursor); return v; } }
-
Keeb13r over 13 yearsThe application won't compile with that code. It says that the input and output variables need to be initialized. I corrected to problematic lines to say "InputStream input = null" and "FileOutputStream output = null", but I'm still having the same problem with no image displaying.
-
Keeb13r over 13 yearsLooks like the error I'm getting is this: "java.io.IOException: Is a directory". I'm not sure what to think, since I thought that merely specifying the filename without introducing any intervening folders would result in the write and read path being exactly the same.
-
dacwe over 13 yearsHum, does productID contain slashes (
/
)? -
Keeb13r over 13 yearsNope, it can only contain numbers and sometimes, an X to represent a 10. Is it possible I'm not reading the file from the proper location, i.e. when I call decodeFile(), I need to tell it the path where that file will be?
-
dacwe over 13 yearsWrite to the log so you are sure that you have write and read the same file?
-
dacwe over 13 yearsAlso, instead of writing the file to internal storage and storing the filename in a database, just download the file and show it directly in the view (just to be sure that you are downloading the correct file). Maybe the productID + "-thumbnail.jpg" does not exist on the server and you end up writing garbage to the internal storage!
-
Keeb13r over 13 yearsHow would this be any different from what I'm currently doing? If I'm downloading the image to the phone's internal memory and then displaying it directly in the view, my app will still be reading the image from the exact same location it would if it was looking up the path from my DB.
-
dacwe over 13 yearsThen my question was valid: "Write to the log so you are sure that you have write and read the same file?".
-
Keeb13r over 13 yearsOriginally, I wasn't aware that anything more than the filename was needed and I thought that the application was self-aware of the specific path where the file would be.
-
Keeb13r over 13 yearsOne thing I forgot to ask - are there any catch statements I need in the downloading image block of code? What if the URL can't have a connection opened to it? What if there is no input stream to retrieve? Don't catch statements need to
-
dacwe over 13 yearsWell, if
productLookup
throws an exception you need to work out what should happen.. use a default image perhaps? -
Keeb13r over 13 yearsWhat types of exceptions should I be throwing, though? Instantiating both the "input" and "output" variables can fail, can't they? Same goes for the reading/writing portion of that code block.
-
IcedDante about 7 yearsThis code is not really relevant to the question and does not even compile. I do think there's value in outlining the algorithm to persist the bitmap for future use, however.