How to save images downloaded via UrlImageViewHelper to SD card on Android? - android

I'm using UrlImageViewHelper library and it works fine.
It caches the images on internal storage and it's bad for me because I've about lots of images and if I want to cache them it's horrible.
How can I save these downloaded files and store them in SD card instead of internal storage?

Please check your whether your URL is valid or not by putting into browser. If image size is large then please use placeholder image which still displays your URL, not load image available, like this:
UrlImageViewHelper.setUrlDrawable(imageView, "http://example.com/image.png", R.drawable.placeholder);

Use this class
public class DemoHelper {
private static final String TAG = DemoMainActivity.TAG;
public static class RemoteImageTask extends AsyncTask<Void, Void, Bitmap> {
ImageView _image;
String _imageSource;
TaskCallback _callback;
public RemoteImageTask(ImageView image, String imageSource) {
this(image, imageSource, null);
}
public RemoteImageTask(ImageView image, String imageSource, TaskCallback callback) {
_image = image;
_imageSource = imageSource;
_callback = callback;
}
protected Bitmap doInBackground(Void... params) {
URL url;
Bitmap bmp = null;
try {
url = new URL(_imageSource);
bmp = BitmapFactory.decodeStream(url.openConnection().getInputStream());
} catch (Exception ignored) {
Log.e(TAG, "Exception", ignored);
}
return bmp;
}
protected void onPostExecute(Bitmap bmp) {
_image.setImageBitmap(bmp);
if (_callback != null)
_callback.onTaskFinished(bmp);
}
}
public interface TaskCallback {
public void onTaskFinished(final Bitmap bmp);
}
}

Related

Provide Only bitmap to Glide Not url

i have list of video Urls. i create thumbnails from them. These thumbnails are in form of bitmap.so what i tried
Glide.with(mContext)
.load(bitmap)
.into(mVideoThumbnail)
What i found from Here.We can do something like this.
Glide.with(mContext)
.load(url).asBitmap()
.into(mVideoThumbnail)
But above function is used for loading URL as bitmap. It doesn't take bitmap as parameter.
i also know that i can set directly bitmap into image as below mentioned
mVideoThumbnail.setImageBitmap(bitmap);
Above method works fine if i have to set thumbnail for single video but in case of multiple videos, it cause some performance issue.
i am sharing my code for fetching thumbnail as a bitmap and set into my ImageView. Is There any way to pass directly bitmap to Glide or any other options are available for reducing performance issue. Please Help
public class TopicInstructionViewHolder implements View.OnClickListener {
#BindView(R.id.iv_thumbnail)
ImageView mVideoThumbnail;
#BindView(R.id.iv_play_video)
ImageView mVideoPlayIcon;
#BindView(R.id.tv_instruction_name)
TextView mInstructionName;
private ITopicVideoPlayListener mTopicVideoPlayListener;
private Context mContext;
private String videoPath;
private int instructionId;
private boolean mHasVideoSeenBL;
public TopicInstructionViewHolder(View itemView,
ITopicVideoPlayListener mTopicVideoPlayListener,
Context mContext) {
ButterKnife.bind(this, itemView);
this.mTopicVideoPlayListener = mTopicVideoPlayListener;
this.mContext = mContext;
}
public void setData(TopicInstructionDetail topicInstructionDetail) {
String thumbnailPath = null;
TopicInstructionTranslationDetail topicInstructionTranslationDetails = findTopicInstructionAsPerLang(topicInstructionDetail.getmTopicInstructionTranslationDetails());
mVideoPlayIcon.setOnClickListener(this);
videoPath = topicInstructionTranslationDetails.getmInstructionPath();
mHasVideoSeenBL = topicInstructionDetail.isCompleteSeen();
instructionId = topicInstructionTranslationDetails.getmInstructionId();
mInstructionName.setText(topicInstructionTranslationDetails.getmInstructionName());
thumbnailPath = (NetworkConstants.VIDEO_URL + topicInstructionTranslationDetails.getmThumbnailPath());
new SampleAsyncTask().execute(NetworkConstants.VIDEO_URL+videoPath);
if (topicInstructionDetail.isCompleteSeen()) {
mVideoPlayIcon.setImageResource(R.drawable.check);
} else {
mVideoPlayIcon.setImageResource(R.drawable.ic_play);
}
}
private TopicInstructionTranslationDetail findTopicInstructionAsPerLang(List<TopicInstructionTranslationDetail> topicInstructionTranslationDetails) {
TopicInstructionTranslationDetail topicInstructionTranslationDetail = null;
for (TopicInstructionTranslationDetail topicTranslation : topicInstructionTranslationDetails) {
if (topicTranslation.getmLanguage().equals(AppPreferencesHelper.getInstance(mContext).getCurrentUserLanguage())) {
topicInstructionTranslationDetail = topicTranslation;
}
}
if (topicInstructionTranslationDetail == null) {
topicInstructionTranslationDetail = findDefaultTopicInstruction(topicInstructionTranslationDetails);
}
return topicInstructionTranslationDetail;
}
private TopicInstructionTranslationDetail findDefaultTopicInstruction(List<TopicInstructionTranslationDetail> topicInstructionTranslationDetails) {
TopicInstructionTranslationDetail topicInstructionDetail = null;
for (TopicInstructionTranslationDetail topicTranslation : topicInstructionTranslationDetails) {
if (topicTranslation.getmLanguage().equals(LanguageCode.getLanguageCode(LanguageCode.LANGUAGE_FIRST))) {
topicInstructionDetail = topicTranslation;
}
}
return topicInstructionDetail;
}
#Override
public void onClick(View view) {
mTopicVideoPlayListener.playVideo(videoPath, instructionId, mHasVideoSeenBL);
}
//fetching bitmap from video url
private class SampleAsyncTask extends AsyncTask {
#Override
protected Bitmap doInBackground(String... strings) {
Bitmap bitmap = null;
MediaMetadataRetriever mediaMetadataRetriever = null;
try {
mediaMetadataRetriever = new MediaMetadataRetriever();
if (Build.VERSION.SDK_INT >= 14) {
mediaMetadataRetriever.setDataSource(strings[0], new HashMap<String, String>());
} else {
mediaMetadataRetriever.setDataSource(strings[0]);
}
bitmap = mediaMetadataRetriever.getFrameAtTime(1, MediaMetadataRetriever.OPTION_CLOSEST);
} catch (Exception e) {
e.printStackTrace();
} finally {
if (mediaMetadataRetriever != null) {
mediaMetadataRetriever.release();
}
}
return bitmap;
}
#Override
protected void onPostExecute(Bitmap s) {
super.onPostExecute(s);
try {
mVideoThumbnail.setImageBitmap(s);
/* Glide.with(mContext)
.load(s).asBitmap()
.into(mVideoThumbnail);*/
}
catch (Exception e){
e.printStackTrace();
}
}
}
}
You are using Glide v3. Glide v4 did add an option for loading Bitmap as Drawable. Docs here
Update to v4 require some more configuration, check here
Use Fresco Library instead of Glide.
You can use facebook fresco library instead of glide for smooth and efficient loading in list. Fresco library have pipeline techniques for loading the image thumbnail in list. Use Asynctask and fresco pipeline to get the Thumbnail from video and load it.
Check this answer, implemented solution for your problem.

Saving image from URL using Picasso without change in size (using bitmap.compress() changes size)

I am using Picasso for my image handling and use it to download images from a backend server and save to the local device. I use Target to save the image
Picasso.with(context)
.load(url)
.into(target);
Since the target code gets a bitmap, I have to use bitmap.compress() to write the image to local disk and I use JPEF format with quality of 100 assuming this will preserve the original quality.
Reading this it seems like this might not be what I want. In one case, the image on the backend was 90kb and the image that was written was 370kb. The original image can be generated using an arbitrary quality value. What is the easiest way to save the image using Picasso without the size/quality changing?
Target target = new Target() {
#Override
public void onPrepareLoad(Drawable arg0) {
}
#Override
public void onBitmapLoaded(final Bitmap bitmap, Picasso.LoadedFrom arg1) {
new AsyncTask<Void, Void, Void>() {
#Override
protected Void doInBackground(Void... params) {
FileOutputStream out = null;
try {
out = new FileOutputStream(imagePath);
bitmap.compress(Bitmap.CompressFormat.JPEG, 100, out);
out.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
#Override
protected void onPostExecute(Void info) {
}
}.execute();
}
#Override
public void onBitmapFailed(Drawable arg0) {
}
};
UPDATE: more elegant solution here: https://github.com/square/picasso/issues/1025#issuecomment-102661647
Solved the problem using this solution.
In my PagerAdapter's instantiateItem() method, I run an AsyncTask that will download the image, save it to a file and then call Picasso with that image file.
PagerAdapter instantiateItem():
RemoteImageToImageViewAsyncTask remoteImageToImageViewAsyncTask =
new RemoteImageToImageViewAsyncTask(imageView, url, imagePath);
remoteImageToImageViewAsyncTask.execute();
RemoteImageToImageViewAsyncTask
public class RemoteImageToImageViewAsyncTask extends AsyncTask<Void, Void, Void> {
ImageView imageView;
String url;
File output;
public RemoteImageToImageViewAsyncTask(ImageView imageView, String url, File output) {
this.imageView = imageView;
this.url = url;
this.output = output;
}
#Override
protected Void doInBackground(Void... params) {
// Downloads the image from url to output
ImageDownloader.download(url, output);
return null;
}
#Override
protected void onPostExecute(Void params) {
Picasso.with(context)
.load(output)
.into(imageView);
}
}

How to retrieve profile picture of linkedin user android

I have tried to fetch the profile picture of linkedin user by the following url
http://api.linkedin.com/v1/people/"+userID+"/picture-url
But i'm getting file not found exception.
Try this, hopefully it should work for you or at least give you an idea how to go about it.
//picUrl is your linkedin contact image url
BitmapWorkerTask task = new BitmapWorkerTask(picUrl,mContactPic);
task.execute();
/* Async task to download the image from URL and display it in imageView*/
class BitmapWorkerTask extends AsyncTask<String, Void, Bitmap>{
/*contact bitmap url */
private final String mUrl;
/*contact image view*/
ImageView mView;
public BitmapWorkerTask(String aUrl, ImageView aView) {
mUrl = aUrl;
mView = aView;
}
#Override
protected Bitmap doInBackground(String... params) {
if(mBgTaskCancel) {
/*cancel the execution of this task if the mBgTaskCancel flag is true */
this.cancel(false);
} else {
/*else get the contact bitmap from the url */
final Bitmap bitmap = Utils.getBitmapFromURL(this.mUrl);
return bitmap;
}
return null;
}
#Override
protected void onPostExecute(Bitmap aBitmap) {
if (aBitmap != null) {
/*set the image bitmap if it is not null */
mView.setImageBitmap(aBitmap);
}
}
}
/**
* function to download the image from url
*/
public static Bitmap getBitmapFromURL(String aURL) {
URL lBitmapURL;
Bitmap lBitmap = null;
try {
lBitmapURL = new URL(aURL);
InputStream lInStream = lBitmapURL.openStream();
lBitmap = BitmapFactory.decodeStream(lInStream);
} catch (IOException e) {
e.printStackTrace();
return null;
}
return lBitmap;
}

How to efficiently store bitmaps in Android?

I'm building a relatively basic news-reader app that involves displaying news in a custom listview (Image + Title + Short Description per list element).
My question is How can I store the images I download from the server and then attach them to the listview? The images will be relatively small, 200 X 200 usually, in .jpeg format.
It's not so much a question of how as much as "how to do it efficiently", as I'm already noticing lag in lower-end phones when using the default "ic_launcher" icon instead of bitmaps.
Would it be faster to store them as files or into the news database along with other news data when the app starts and syncs up the news or cache them...?
How should I go about this?
better you can do it's use SoftReference via an ImageManager class.
In you ListAdpater getView() method call the displayImage() method of ImageManager.
ImageManager Coding Exemple :
public class ImageManagerExemple {
private static final String LOG_TAG = "ImageManager";
private static ImageManagerExemple instance = null;
public static ImageManagerExemple getInstance(Context context) {
if (instance == null) {
instance = new ImageManagerExemple(context);
}
return instance;
}
private HashMap<String, SoftReference<Bitmap>> imageMap = new HashMap<String, SoftReference<Bitmap>>();
private Context context;
private File cacheDir;
private ImageManagerExemple(Context context) {
this.context = context;
// Find the dir to save cached images
String sdState = android.os.Environment.getExternalStorageState();
if (sdState.equals(android.os.Environment.MEDIA_MOUNTED)) {
File sdDir = android.os.Environment.getExternalStorageDirectory();
cacheDir = new File(sdDir,"data/yourappname");
} else {
cacheDir = context.getCacheDir();
}
if(!cacheDir.exists()) {
cacheDir.mkdirs();
}
}
/**
* Display web Image loading thread
* #param imageUrl picture web url
* #param imageView target
* #param imageWaitRef picture during loading
*/
public void displayImage(String imageUrl, ImageView imageView, Integer imageWaitRef) {
String imageKey = imageUrl;
imageView.setTag(imageKey);
if(imageMap.containsKey(imageKey) && imageMap.get(imageKey).get() != null) {
Bitmap bmp = imageMap.get(imageKey).get();
imageView.setImageBitmap(bmp);
} else {
queueImage(imageUrl, imageView);
if(imageWaitRef != null)
imageView.setImageResource(imageWaitRef);
}
}
private void queueImage(String url, ImageView imageView) {
ImageRef imgRef=new ImageRef(url, imageView);
// Start thread
Thread imageLoaderThread = new Thread(new ImageQueueManager(imgRef));
// Make background thread low priority, to avoid affecting UI performance
imageLoaderThread.setPriority(Thread.NORM_PRIORITY-1);
imageLoaderThread.start();
}
private Bitmap getBitmap(String url) {
String filename = String.valueOf(url.hashCode());
File f = new File(cacheDir, filename);
try {
// Is the bitmap in our cache?
Bitmap bitmap = BitmapFactory.decodeFile(f.getPath());
if(bitmap != null) return bitmap;
// Nope, have to download it
bitmap = ImageServerUtils.pictureUrlToBitmap(url);
// save bitmap to cache for later
writeFile(bitmap, f);
return bitmap;
} catch (Exception ex) {
ex.printStackTrace();
Log.e(LOG_TAG, ""+ex.getLocalizedMessage());
return null;
} catch (OutOfMemoryError e) {
Log.e(LOG_TAG, "OutOfMemoryError : "+e.getLocalizedMessage());
e.printStackTrace();
return null;
}
}
private void writeFile(Bitmap bmp, File f) {
if (bmp != null && f != null) {
FileOutputStream out = null;
try {
out = new FileOutputStream(f);
//bmp.compress(Bitmap.CompressFormat.PNG, 80, out);
bmp.compress(Bitmap.CompressFormat.JPEG, 80, out);
} catch (Exception e) {
e.printStackTrace();
}
finally {
try { if (out != null ) out.close(); }
catch(Exception ex) {}
}
}
}
private class ImageRef {
public String imageUrl;
public ImageView imageView;
public ImageRef(String imageUrl, ImageView i) {
this.imageUrl=imageUrl;
this.imageView=i;
}
}
private class ImageQueueManager implements Runnable {
private ImageRef imageRef;
public ImageQueueManager(ImageRef imageRef) {
super();
this.imageRef = imageRef;
}
#Override
public void run() {
ImageRef imageToLoad = this.imageRef;
if (imageToLoad != null) {
Bitmap bmp = getBitmap(imageToLoad.imageUrl);
String imageKey = imageToLoad.imageUrl;
imageMap.put(imageKey, new SoftReference<Bitmap>(bmp));
Object tag = imageToLoad.imageView.getTag();
// Make sure we have the right view - thread safety defender
if (tag != null && ((String)tag).equals(imageKey)) {
BitmapDisplayer bmpDisplayer = new BitmapDisplayer(bmp, imageToLoad.imageView);
Activity a = (Activity)imageToLoad.imageView.getContext();
a.runOnUiThread(bmpDisplayer);
}
}
}
}
//Used to display bitmap in the UI thread
private class BitmapDisplayer implements Runnable {
Bitmap bitmap;
ImageView imageView;
public BitmapDisplayer(Bitmap b, ImageView i) {
bitmap=b;
imageView=i;
}
#Override
public void run() {
if(bitmap != null) {
imageView.setImageBitmap(bitmap);
}
}
}
The trick to getting smooth ListView scrolling without stutter is to not update it in any way, shape or form while the user is scrolling it. Afaik, this is essentially how iOS manages to get its ListViews that smooth: it disallows any changes to it (and the UI in general) while the user has his finger on it.
Just comment out any code that changes your ListView while leaving all the bitmap loading code intact, and you'll see that the actual loading of the bitmaps in the background doesn't really impact performance at all. The problem is that the UI thread can't keep up with view updates and scrolling at the same time.
You can achieve the same thing by using a OnScrollListener that blocks all updates to the ListView while the User is scrolling it. As soon as the user stops, you can sneak in all pending updates.
For added performance, try not to use notifyDataSetChanged but iterate over the views of the ListView and only update the views that have actually changed.

Asynchronous image loading on Android

Hello fellow developers :)
I've made a very basic image fetcher for Android to download and display bitmaps from the web on my application the code for it is:
public class BitmapFetcher {
private static HashMap<String, SoftReference<Bitmap>> bitmapCache = new HashMap<String, SoftReference<Bitmap>>();
public static Bitmap fetchBitmap(String urlString) {
SoftReference<Bitmap> cachedBitmap = bitmapCache.get(urlString);
if (cachedBitmap != null && cachedBitmap.get() != null) {
return cachedBitmap.get();
}
try {
InputStream is = fetch(urlString);
Bitmap bitmap = BitmapFactory.decodeStream(is);
SoftReference<Bitmap> softReferencedBitmap = new SoftReference<Bitmap>(bitmap);
bitmapCache.put(urlString, softReferencedBitmap);
return bitmap;
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
public static void fetchBitmapAsync(final String urlString, final ImageView view) {
final Handler handler = new Handler() {
public void handleMessage(Message message) {
AsyncImageContainer imageContainer = (AsyncImageContainer) message.obj;
imageContainer.applyImageToView();
}
};
BitmapTaskRunnable asyncImageFetcherTask = new BitmapTaskRunnable(view, urlString, handler);
new Thread(asyncImageFetcherTask).start();
}
public static InputStream fetch(String urlString) throws MalformedURLException, IOException {
Log.d("BitmapFetcher", "fetch: " + urlString);
DefaultHttpClient httpClient = new DefaultHttpClient();
HttpGet request = new HttpGet(urlString);
HttpResponse response = httpClient.execute(request);
return response.getEntity().getContent();
}
}
BitmapTaskRunnable.java:
public class BitmapTaskRunnable implements Runnable {
private ImageView imageView;
private String imageUrl;
private Handler handler;
public BitmapTaskRunnable() {
}
public BitmapTaskRunnable(ImageView imageView, String imageUrl, Handler handler) {
setImageView(imageView);
setImageUrl(imageUrl);
setHandler(handler);
}
public void run() {
Bitmap bitmap = BitmapFetcher.fetchBitmap(getImageUrl());
AsyncImageContainer imageContainer = new AsyncImageContainer(getImageView(), bitmap);
handler.sendMessage(handler.obtainMessage(0, imageContainer));
}
public ImageView getImageView() {
return imageView;
}
public void setImageView(ImageView imageView) {
this.imageView = imageView;
}
public String getImageUrl() {
return imageUrl;
}
public void setImageUrl(String imageUrl) {
this.imageUrl = imageUrl;
}
public Handler getHandler() {
return handler;
}
public void setHandler(Handler handler) {
this.handler = handler;
}
}
AsyncImageContainer.java:
public class AsyncImageContainer {
private ImageView imageView;
private Bitmap bitmap;
public AsyncImageContainer() {
}
public AsyncImageContainer(ImageView imageView, Bitmap bitmap) {
setImageView(imageView);
setBitmap(bitmap);
}
public void applyImageToView() {
getImageView().setImageBitmap(getBitmap());
}
public ImageView getImageView() {
return imageView;
}
public void setImageView(ImageView imageView) {
this.imageView = imageView;
}
public Bitmap getBitmap() {
return bitmap;
}
public void setBitmap(Bitmap bitmap) {
this.bitmap = bitmap;
}
}
As I said, it's very basic, with a very basic caching and no throttling on threads being created (this is already planned to be done soon).
Well, I'm currently experiencing a weird behavior from this when I need to load images in a ListView, what I did is: I have some classes that extend ArrayAdapter and overrides getView to display my layout, whenever I need an image on it, I will do the following:
BitmapFetcher.fetchBitmapAsync(news.getChannelAvatar(), holder.channelAvatarView);
And this should start make BitmapFetcher start a new thread which will download the bitmap and send a message to the handler to it apply the image to the view (as only the thread which created a view hierarchy can modify it).
Everything is fine for the 2nd to n-th ImageViews in the list, but the 1st result ALWAYS goes crazy, changing to images which have been downloaded until all the images are loaded and it settles to it. Then if I drag the list a little until the 1st result disappears and goes back to the top, it displays the correct image.
This is really bugging me, as I had done a much simpler version of the code (one which the handler handled directly placing the Bitmap in the ImageView, the Runnable did not exist, it was a simple anonymous Thread object with run() overriden, etc) and tried this version thinking that somehow fetchBitmapAsync was losing reference to the correct ImageView or something like that.
Does this happen for some thing that Android does to recycle Views inside a ListView? If not, what could be the reason? Am I being silly somewhere and after a couple days working on this code I've gone blind? :(
Thanks for all the help :D
For all of my lazy image loading I use Prime. It even has an example of how to use it within a ListView.

Categories

Resources