I'm working on a school android project.
I need to have a download button which downloads a picture(when we have class)
And after display it in another activity(even in offline mode, and after quiting)
I've tried picasso, but I can't get it to save and use it in offline mode.
For you to support offline mode, You need to Save the image on your disk because when your cache is cleared, The image is cleared as well.
You can easily use Glide to Solve this, also storing on device and retrieving
You can Learn more about Glide here http://inthecheesefactory.com/blog/get-to-know-glide-recommended-by-google/en
/** Download the image using Glide **/
Bitmap theBitmap = null;
theBitmap = Glide.
with(YourActivity.this).
load("Url of your image").
asBitmap().
into(-1, -1).
get();
saveToInternalStorage(theBitmap, getApplicationContext(), "your preferred image name");
/** Save it on your device **/
public String saveToInternalStorage(Bitmap bitmapImage, Context context, String name){
ContextWrapper cw = new ContextWrapper(context);
// path to /data/data/yourapp/app_data/imageDir
String name_="foldername"; //Folder name in device android/data/
File directory = cw.getDir(name_, Context.MODE_PRIVATE);
// Create imageDir
File mypath=new File(directory,name);
FileOutputStream fos = null;
try {
fos = new FileOutputStream(mypath);
// Use the compress method on the BitMap object to write image to the OutputStream
bitmapImage.compress(Bitmap.CompressFormat.PNG, 100, fos);
fos.close();
} catch (Exception e) {
e.printStackTrace();
}
Log.e("absolutepath ", directory.getAbsolutePath());
return directory.getAbsolutePath();
}
/** Method to retrieve image from your device **/
public Bitmap loadImageFromStorage(String path, String name)
{
Bitmap b;
String name_="foldername";
try {
File f=new File(path, name_);
b = BitmapFactory.decodeStream(new FileInputStream(f));
return b;
}
catch (FileNotFoundException e)
{
e.printStackTrace();
}
return null;
}
/** Retrieve your image from device and set to imageview **/
//Provide your image path and name of the image your previously used.
Bitmap b= loadImageFromStorage(String path, String name)
ImageView img=(ImageView)findViewById(R.id.your_image_id);
img.setImageBitmap(b);
Thanks to #Droidman :
How to download and save an image in Android
Of course you can perform downloading and managing images by yourself,
but if your project is quite complex already, there are a lot of
libraries around and you do not need to reinvent the wheel. I won't
post code this time since there are a lot of examples, but I'm going
to tell you about 2 most useful libraries (IMO) related to image
downloading.
1) Android Volley. A powerful networking library created by Google and
covered by official documentation. POST'ing or GET'ing data, images,
JSON - volley will manage it for you. Using volley just for image
downloading is a bit of an overkill in my opinion.
2) Picasso
Image downloading and caching, perfect for
ListView/GridView/RecyclerView. Apache 2.0 license.
3) Fresco
Quite a new image loading library created by Facebook. Progressive
JPEG streaming, gifs and more. Apache 2.0
You could use Android Library called Universal Image Loader:
https://github.com/nostra13/Android-Universal-Image-Loader
Related
Is it possible to show previously downloaded image in Glide as placeholder while downloading new image.
Like I have an image loaded in imageview using glide. Now the imageurl is changed, so while loading this new image is it possible to keep displaying the old image (might be from cache).
What I want is while the new image is being loaded from the URL, is it possible to keep the current image as placeholder.
I found the answer to this in the discussion here - https://github.com/bumptech/glide/issues/527#issuecomment-148840717.
Intuitively I also thought of using placeholder(), but the problem is that as soon as you load the second image, you loose the reference to the first one. You can still reference it but it is not safe as it may be reused by Glide or recycled.
The proposed solution from the discussion is to use thumbnail() and load the first image again. The load will return the first image immediately from the memory cache and it will look as if the image did not change until the second image is loaded:
String currentImageUrl = ...;
String newImageUrl = ...;
Glide.with(this)
.load(newImageUrl)
.thumbnail(Glide.with(this)
.load(currentImageUrl)
.fitCenter()
)
.fitCenter()
.into(imageView);
Glide have a capability of getting the bitmap of the image from that url, so just get it and then save it to a desired storage into your phone, and after that in your .placeholder() just use that bitmap when you are trying to get another image , take a look at this snippet
/** Download the image using Glide **/
Bitmap theBitmap = null;
theBitmap = Glide.
with(YourActivity.this).
asBitmap().
load("Url of your image").
into(-1, -1).
get(); //with this we get the bitmap of that url
saveToInternalStorage(theBitmap, getApplicationContext(), "your preferred image name");
/** Save it on your device **/
public String saveToInternalStorage(Bitmap bitmapImage, Context context, String name){
ContextWrapper cw = new ContextWrapper(context);
// path to /data/data/yourapp/app_data/imageDir
String name_="foldername"; //Folder name in device android/data/
File directory = cw.getDir(name, Context.MODE_PRIVATE);
// Create imageDir
File mypath=new File(directory,name_);
FileOutputStream fos = null;
try {
fos = new FileOutputStream(mypath);
// Use the compress method on the BitMap object to write image to the OutputStream
bitmapImage.compress(Bitmap.CompressFormat.PNG, 100, fos);
fos.close();
} catch (Exception e) {
e.printStackTrace();
}
Log.e("absolutepath ", directory.getAbsolutePath());
return directory.getAbsolutePath();
}
/** Method to retrieve image from your device **/
public Bitmap loadImageFromStorage(String path, String name)
{
Bitmap b;
String name_= name; //your folderName
try {
File f=new File(path, name_);
b = BitmapFactory.decodeStream(new FileInputStream(f));
return b;
}
catch (FileNotFoundException e)
{
e.printStackTrace();
}
return null;
}
/** Retrieve your image from device and set to imageview **/
//Provide your image path and name of the image your previously used.
Bitmap b= loadImageFromStorage(String path, String name)
ImageView img=(ImageView)findViewById(R.id.your_image_id);
img.setImageBitmap(b);
I'm workin with Volley API in my WebServices, and then I'll write the data in with SQLITE.
Webservices that comes with a JSON with many itens, each of then has data and a image, and I need to keep this image in my cache to display offline in a ListView and later on a detail screen. In the future the user will clean these itens and clear the imagens of them too.
Well, how can I save these images in my local DB and link with each Item that I have from the JSON?
I will be, in 90% of the time, offline. I will only stay online for synchronizing and download the updated server items.
For dealing with images in Android the benchmark is to use Picasso library. It takes care of:
Handling ImageView recycling and download cancelation in an adapter;
Complex image transformations with minimal memory use;
Automatic memory and disk caching.
Besides that, if you're going to display images in lists and need animation to enhance your UI, I strongly recommend changing from ListView to RecyclerView. It is not recommended to store the images in the DB, you would lose time converting this from/to blobs (check here and here). Said that, what I suggest is:
Use Picasso to load the images from the URL provided in the JSON;
Implement a Custom target to handle the image file downloaded by Picasso;
Save the image in a folder inside your app directory;
Use RecyclerView to display the images; (optional)
If you need a project example where those things are done, you can check this. In this project I follow the approache I've described above. You can download the app from the store and see how it will download the images.
Quicky-guide:
To use Picasso add this to you module's gradle file: compile 'com.squareup.picasso:picasso:2.5.2'
Create a class that implements import com.squareup.picasso.Callback;:
public class ImageWarehouse implements Callback {
private static final String TAG = "ImageWarehouse";
private String mDirectory;
private String mFileName;
private ImageView mContainer;
#Inject
App mApplication;
public ImageWarehouse(String fileName, ImageView container, String directory) {
this.mFileName = fileName;
this.mContainer = container;
this.mDirectory = directory;
this.getStorageDir();
}
#Override
public void onSuccess() {
if (this.isExternalStorageWritable()) {
final Bitmap bitmap = ((BitmapDrawable) this.mContainer.getDrawable()).getBitmap();
new AsyncTask<Void, Void, File>() {
#Override
protected File doInBackground(Void... params) {
File file = null;
try {
file = new File(ImageWarehouse.this.getStorageDir().getPath().concat("/").concat(ImageWarehouse.this.mFileName.concat(Constants.MEDIA_EXTENSION)));
file.createNewFile();
FileOutputStream ostream = new FileOutputStream(file);
bitmap.compress(Bitmap.CompressFormat.JPEG, 100, ostream);
ostream.close();
} catch (Exception e) {
Log.e(TAG, "External Storage is not available");
}
return file;
}
}.execute();
} else {
Log.e(TAG, "External Storage is not available");
}
}
#Override
public void onError() {
}
public boolean isExternalStorageWritable() {
String state = Environment.getExternalStorageState();
if (Environment.MEDIA_MOUNTED.equals(state)) {
return true;
}
return false;
}
public File getStorageDir() {
File file = new File(Environment.getExternalStorageDirectory(), Constants.MEDIA_DIRECTORY.concat(this.mDirectory));
if (!file.mkdirs()) {
}
return file;
}
}
Call Picasso in order to display the image in the layout and save it to the specified path:
Picasso
.load(URL)
.fit()
.centerCrop()
.into(viewHolder.cover,
new ImageWarehouse(
name,
viewHolder.cover,
Constants.MEDIA_CHARACTER
)
);
You can user Android-Universal-Image-Loader it is also cache image in memory. it is show from cache when next time same url used in imageloader for get image
see below link for complete source code of Universal Image Loader Example.
Android - Universal Image Loader
You can save your images in Sqlite as blob and can retrieve it when required. Create table as
create table sometable(id integer primary key autoincrement,photo BLOB);
And save the image as
//convert image into byte[]
ByteArrayOutputStream baos = new ByteArrayOutputStream();
Bitmap bitmap = ((BitmapDrawable)getResources().getDrawable(R.drawable.common)).getBitmap();
bitmap.compress(Bitmap.CompressFormat.PNG, 100, baos);
byte[] photo = baos.toByteArray();
//And now store this image
ContentValues initialValues = new ContentValues();
initialValues.put("photo",photo);
return db.insert("sometable", null, initialValues);
And retrieve image as
Cursor cur=your query;
while(cur.moveToNext())
{
byte[] photo=cur.getBlob(index of blob cloumn);
}
Im new to android development and trying to get metadata of image using ExifInterface. I stored the image under drawable and trying to get the metadata but getting null values for all fields(date, imagelength, imagewidth). I tried to access image path as this :
String path = "drawable://" + R.drawable.testimage;
and provided this path to ExifInterface.
ExifInterface exif = new ExifInterface(path);
I dont know if storing image under drawable is correct or not because when I run the app in emulator I get something like this :
E/JHEAD﹕ can't open 'drawable://2130837561'
So if this is wrong then please tell me where should I store the image and how to provide image path to ExifInterface.
Thank you in advance.
To get a drawable, you can you this snippet:
Drawable drawable = getResources().getDrawable(android.R.drawable.your_drawable);
I'm not sure if your way is correct, as I've never seen it like that. Do you really need the path to your image to use it on that ExifInterface class?
Ok, I did some digging and found this question, which led me to this one. As it seems, you can not get an absolute path from a resource inside your apk. A good solution would be for you to save it as a file on the external memory, and then you can get the path you want.
First of all, add this to your AndroidManifest.xml, so your app can write to the cellphone memory:
<uses-permission
android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
Ok, to save it you can try this, first create a bitmap from your drawable resource:
Bitmap bitmap = BitmapFactory.decodeResource(getResources(),R.drawable.your_drawable);
After that get the path you want to save your images, and put it on a String. More info on that here.
The Android docs have a good example on how to get the path. You can see it here.
To keep it simple, I'll copy and paste the snippet from the docs.
void createExternalStoragePrivateFile() {
// Create a path where we will place our private file on external
// storage.
File file = new File(getExternalFilesDir(null), "DemoFile.jpg");
try {
// Very simple code to copy a picture from the application's
// resource into the external file. Note that this code does
// no error checking, and assumes the picture is small (does not
// try to copy it in chunks). Note that if external storage is
// not currently mounted this will silently fail.
InputStream is = getResources().openRawResource(R.drawable.balloons);
OutputStream os = new FileOutputStream(file);
byte[] data = new byte[is.available()];
is.read(data);
os.write(data);
is.close();
os.close();
} catch (IOException e) {
// Unable to create file, likely because external storage is
// not currently mounted.
Log.w("ExternalStorage", "Error writing " + file, e);
}
}
void deleteExternalStoragePrivateFile() {
// Get path for the file on external storage. If external
// storage is not currently mounted this will fail.
File file = new File(getExternalFilesDir(null), "DemoFile.jpg");
if (file != null) {
file.delete();
}
}
boolean hasExternalStoragePrivateFile() {
// Get path for the file on external storage. If external
// storage is not currently mounted this will fail.
File file = new File(getExternalFilesDir(null), "DemoFile.jpg");
if (file != null) {
return file.exists();
}
return false;
}
After that, get the path of the file you saved on the external memory, and do as you wish.
I'll keep the old example as well. You can use the method getExternalStorageDirectory() to get the path, or getExternalCacheDir(). After that, you can use File method called getAbsolutePath() to get your String.
String path = (...) // (you can choose where to save here.)
File file = new File(path, "your_drawable.png");
FileOutputStream out = new FileOutputStream(file);
bitmap.compress(Bitmap.CompressFormat.PNG, 100, out); // You can change the quality from 0 to 100 here, and the format of the file. It can be PNG, JPEG or WEBP.
out.flush();
out.close();
For more info on the Bitmap class, check the docs.
If you need more info, let me know and I'll try to show more samples.
EDIT: I saw your link, and there was this snippet there:
//change with the filename & location of your photo file
String filename = "/sdcard/DSC_3509.JPG";
try {
ExifInterface exif = new ExifInterface(filename);
ShowExif(exif);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
Toast.makeText(this, "Error!",
Toast.LENGTH_LONG).show();
}
As you can see, if you really want to see the exif data of a internal image resource, you'll have to save it somewhere else, and then you can try to get the absolute path for that File, then, call the method to show the exif.
I am currently work on a magazine like apps. Since there is an option to zoom in(150%, 200%, 250% of original source) , I would prefer not to scale down the image. However , the app will force restart when I try to decode the image because of the out of memory. Are there any suggestion to fix that?
The image are local (SD card) , can be retrieve in any approach, but eventually need to be a bitmap as I use something like cavans.drawbitmap to display it. I tried, input stream-> bytes , input stream->bitmap etc... but are there any most efficient way or at least
I can sure the app does not force restart / close? Thanks
try {
InputStream is = (InputStream) new URL(url).getContent();
try {
return BitmapFactory.decodeStream(is);
} finally {
is.close();
}
} catch (Exception e) {
return BitmapFactory.decodeResource(context.getResources(), defaultDrawable);
}
You should consider using nostra's image loader, it deals with memory quite efficiently, you can specify lots of config stuffs, im using it and its working pretty well for large images aswell
This is what smartImageView(by loopj - you can find him on http://loopj.com/) uses to retrieve files from the drive/sd.
private Bitmap getBitmapFromDisk(String imgID) {
Bitmap bitmap = null;
if(diskCacheEnabled){
String filePath = getFilePath(imgID);
File file = new File(filePath);
if(file.exists()) {
bitmap = BitmapFactory.decodeFile(filePath);
}
}
return bitmap;
}
My application is some kind of "mini paint" and I would like to save my current view to the device memory... I would like to do the the opposite process too (Load an image from the device memory and set it as my currentview)
MiniPaint
yeah that's suppose to be a flamingo, I'm an artist!
Haven't tried it myself, but this answer shows taking a screenshot programmatically by getting the root view and saving off its drawing cache. That may be all you need to save your painting.
EDIT: Fixed link
First off I am assuming you are performing this drawing by overriding the onDraw() method on a View object, which passes in a Canvas object that you then perform some drawing operations on.
Here's a very basic way to approach this problem. There are probably lots of additional considerations to take into account, such as the file format(s) you read from and write to, and some extra error handling in the I/O code. But this should get you going.
To save what drawing you currently have, write out your View's drawingCache to a Picture object, then use the Picture's writeToStream method.
To load a pre-existing picture, you can use the Picture.readFromStream method, then in your onDraw call, draw the loaded picture to your Canvas.
To Wit:
/**
* Saves the current drawing cache of this View object to external storage.
* #param filename a file to be created in the device's Picture directory on the SD card
*/
public void SaveImage(String filename) {
// Grab a bitmap of what you've drawn to this View object so far
Bitmap b = this.getDrawingCache();
// It's easy to save a Picture object to disk, so we copy the contents
// of the Bitmap into a Picture
Picture pictureToSave = new Picture();
// To copy the Bitmap into the Picture, we have to use a Canvas
Canvas c = pictureToSave.beginRecording(b.getWidth(), b.getHeight());
c.drawBitmap(b, 0, 0, new Paint());
pictureToSave.endRecording();
// Create a File object where we are going to write the Picture to
File file = new File(this.getContext().getExternalFilesDir(Environment.DIRECTORY_PICTURES), filename);
try {
file.createNewFile();
}
catch (IOException ioe) {
ioe.printStackTrace();
}
// Write the contents of the Picture object to disk
try {
OutputStream os = new FileOutputStream(file);
pictureToSave.writeToStream(os);
os.close();
}
catch (FileNotFoundException fnfe) {
fnfe.printStackTrace();
}
}
/**
* Returns a Picture object loaded from external storage
* #param filename the name of the file in the Pictures directory on the SD card
* #return null if the file is not found, or a Picture object.
*/
public Picture LoadImage(String filename) {
// Load a File object where we are going to read the Picture from
File file = new File(this.getContext().getExternalFilesDir(Environment.DIRECTORY_PICTURES), filename);
Picture pictureToLoad = null;
try {
InputStream is = new FileInputStream(file);
pictureToLoad = Picture.createFromStream(is);
is.close();
}
catch (FileNotFoundException fnfe) {
fnfe.printStackTrace();
}
// Return the picture we just loaded. Draw the picture to canvas using the
// Canvas.draw(Picture) method in your View.onDraw(Canvas) method
return pictureToLoad;
}
Useful links I read to figure this out:
Reference on generating file paths in the device's external storage
Picture
Canvas
Bitmap