I'm trying to fetch images from Parse.com in the array of ImageViews. However, the app is crashing with nullpointerException in ImageLoader class. I have 5 images in parse.com and 6 ImageViews. one ImageView has an image set in drawable folder. So 5 images get loaded dynamically from parse in array of Imageviews 1-6. HomeActivity is :
ImageView ad1,ad2,ad3,ad4,ad5,ad6;
List<ParseObject> ob;
private ImageView[] imgs = new ImageView[5];
int k=0;
public ImageLoader imgl;
in onCreate():
imgl=new ImageLoader(getApplicationContext());
ad1=(ImageView) findViewById(R.id.ad1);
ad2=(ImageView) findViewById(R.id.ad2);
ad3=(ImageView) findViewById(R.id.ad3);
ad4=(ImageView) findViewById(R.id.ad4);
ad5=(ImageView) findViewById(R.id.ad5);
ad6=(ImageView) findViewById(R.id.ad6);
imgs[0] = ad2;
imgs[1] = ad3;
imgs[2] = ad4;
imgs[3] = ad5;
imgs[4] = ad6;
try {
// Locate the class table named "Footer" in Parse.com
ParseQuery<ParseObject> query = new ParseQuery<ParseObject>("Adverts");
query.orderByDescending("updatedAt");
query.whereEqualTo("Status", true);
ob = query.find();
for (ParseObject country : ob) {
ParseFile image = (ParseFile) country.get("imageFile");
imgl.DisplayImage(image.getUrl(), imgs[k]);
k=k+1;
System.out.println("the urls are"+image.getUrl());
}
} catch (ParseException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
In ImageLoader class:
public ImageLoader(Context context) {
fileCache = new FileCache(context);
executorService = Executors.newFixedThreadPool(5);
}
final int stub_id = R.drawable.ic_launcher;
public void DisplayImage(String url, ImageView imageView) {
imageViews.put(imageView, url);
Bitmap bitmap = memoryCache.get(url);
if (bitmap != null)
imageView.setImageBitmap(bitmap);
else {
queuePhoto(url, imageView);
imageView.setImageResource(stub_id);
}
}
I'm getting nullpointer at imageView.setImageResource(stub_id);
Please help.
only reason a null pointer can appear for a placeholder is ur imageview is null...May be
you have to double check whether view is passed properly
Related
When I display album art directly in my music app, it hangs. In stackoverflow, someone suggested me to implemented AsyncTask. So, I implemented AsyncTask to make my app faster. Right now, my app is not hanging but it is not displaying correct album art. And album arts are random means changing frequently when I scroll my listview.
Please help me.
Here is AsyncTask class :
class BitmapWorkerTask extends AsyncTask<Integer, Void, Bitmap> {
private final WeakReference<ImageView> imageViewReference;
private int data = 0;
private long l;
public BitmapWorkerTask(ImageView imageView) {
// Use a WeakReference to ensure the ImageView can be garbage collected
imageViewReference = new WeakReference<ImageView>(imageView);
}
public BitmapWorkerTask(ImageView imageView, long l) {
// Use a WeakReference to ensure the ImageView can be garbage collected
imageViewReference = new WeakReference<ImageView>(imageView);
this.l = l;
}
// Decode image in background.
#Override
protected Bitmap doInBackground(Integer... params) {
//Bitmap art = getAlbumart(songlist.this, l);
Context context = songlist.this;
Bitmap bm = null;
BitmapFactory.Options options = new BitmapFactory.Options();
try {
final Uri sArtworkUri = Uri.parse("content://media/external/audio/albumart");
Uri uri = ContentUris.withAppendedId(sArtworkUri, l);
ParcelFileDescriptor pfd = context.getContentResolver().openFileDescriptor(uri, "r");
if (pfd != null) {
FileDescriptor fd = pfd.getFileDescriptor();
bm = BitmapFactory.decodeFileDescriptor(fd, null, options);
pfd = null;
fd = null;
}
} catch (Error ee) {
} catch (Exception e) {
}
return bm;
}
// Once complete, see if ImageView is still around and set bitmap.
#Override
protected void onPostExecute(Bitmap bitmap) {
if (imageViewReference != null && bitmap != null) {
final ImageView imageView = imageViewReference.get();
if (bitmap != null) {
iv_art.setImageBitmap(bitmap);
} else {
iv_art.setImageResource(R.mipmap.app_splash_screen_icon);
}
}
}
}
My class which displays song in the listview :
public class MediaCursorAdapter extends SimpleCursorAdapter {
String backgroundColor = "white";
String someOtherBackgroundColor = "#FAFAFA";
public MediaCursorAdapter(Context context, int layout, Cursor c) {
super(context, layout, c,
new String[]{MediaStore.MediaColumns.DISPLAY_NAME, MediaStore.MediaColumns.TITLE, MediaStore.Audio.AudioColumns.DURATION, MediaStore.Audio.Media.ALBUM_ID},
new int[]{R.id.displayname, R.id.title, R.id.duration, R.id.iv_art});
}
#Override
public void bindView(View view, Context context, Cursor cursor) {
if (cursor.getPosition() % 2 == 0) {
view.setBackgroundColor(
Color.parseColor(backgroundColor));
} else {
view.setBackgroundColor(
Color.parseColor(someOtherBackgroundColor));
}
TextView title = (TextView) view.findViewById(R.id.title);
TextView name = (TextView) view.findViewById(R.id.displayname);
TextView duration = (TextView) view.findViewById(R.id.duration);
iv_art = (ImageView) view.findViewById(R.id.iv_art);
String a = cursor.getString(cursor.getColumnIndex(MediaStore.Audio.Media.ALBUM_ID));
l = Long.parseLong(a);
bwc = new BitmapWorkerTask(iv_art,l);
bwc.execute();
long durationInMs = Long.parseLong(cursor.getString(
cursor.getColumnIndex(MediaStore.Audio.AudioColumns.DURATION)));
name.setText(cursor.getString(
cursor.getColumnIndex(MediaStore.MediaColumns.DISPLAY_NAME)));
title.setText(cursor.getString(
cursor.getColumnIndex(MediaStore.MediaColumns.TITLE)));
Utility d = new Utility();
String durationInMin = d.convertDuration(durationInMs);
duration.setText("" + durationInMin);
view.setTag(cursor.getString(cursor.getColumnIndex(MediaStore.MediaColumns.DATA)));
}
#Override
public View newView(Context context, Cursor cursor, ViewGroup parent) {
LayoutInflater inflater = LayoutInflater.from(context);
View v = inflater.inflate(R.layout.songlist_listitem, parent, false);
bindView(v, context, cursor);
return v;
}
}
Its because of row reordering. The image view you want to load it into when you start a fetch is not necessarily where you want to load it at the end. The weak reference isn't helping because the view isn't being destroyed, its just not the right one anymore.
Instead of loading the data directly into the view, store it in a cache, then call notifyDataSetChanged. When you bind the row, check and see if the image is int he cache. If so, use it. If not, send the request. That will fix the majority of the issues you see, and prevent OOM errors (you can put a max memory usage on the cache).
Or use a library that does all this for you, like Volley.
how do i display image using the imagepath fetched from mysql database into gridview. i tried lot but unable to do.
this is my asynctask code:
public class sampling_info extends AsyncTask<String, String, JSONObject> {
#Override
protected void onPreExecute() {
super.onPreExecute();
pDialog = new ProgressDialog(SamplingActivity.this);
pDialog.setMessage("Product..");
pDialog.setIndeterminate(false);
pDialog.setCancelable(true);
pDialog.show();
}
#Override
protected JSONObject doInBackground(String... params) {
// TODO Auto-generated method stub
String doc = dcname.toString();
ArrayList<NameValuePair> namevaluepair = new ArrayList<NameValuePair>();
namevaluepair.add(new BasicNameValuePair("docname", doc));
JSONObject json = jParser.makeHttpRequest(URL_SAMPLING, "POST",
namevaluepair);
return json;
}
protected void onPostExecute(JSONObject json) {
// dismiss the dialog once done
pDialog.dismiss();
if (json != null) {
try {
JSONArray jarray = json.getJSONArray("product_entered");
Log.d("jarray in sampling : ", "" + jarray.toString());
for (int i = 0; i < jarray.length(); i++) {
JSONObject jobj = jarray.getJSONObject(i);
String docname = jobj.getString("docname");
String imagep= jobj.getString("image_path");
GridItem gItem= new GridItem();
gItem.setTitle("sagar");
gItem.setImage(imagep);
mgrid.add(gItem);
Log.d("jobj : ", "" + jobj);
Log.d("jobj docname", "" + docname);
}
} catch (Exception e) {
e.printStackTrace();
}
gridAdapter = new GridViewAdapter(SamplingActivity.this, R.layout.grid_item_layout,mgrid);
gridview.setAdapter(gridAdapter);
}
}
i this asynctask am fetching imagepath from database and storing it in imagep variable and passing it to GridItem class
This is my griditem class :
public class GridItem {
private Bitmap image;
private String title,image1;
public GridItem(Bitmap image) {
this.image=image;
}
public Bitmap getImage() {
return image;
}
public Bitmap setImage(String image) { // this is where am trying to set my image but can't do.
try {
} catch (Exception e) {
}
return null;
}
And this is my adapter class :
public GridViewAdapter(Context mContext, int layoutResourceId,
ArrayList<GridItem> mGridData) {
super(mContext, layoutResourceId, mGridData);
this.layoutResourceId = layoutResourceId;
this.mContext = mContext;
this.mGridData = mGridData;
}
/**
* Updates grid data and refresh grid items.
*
* #param mGridData
*/
public void setGridData(ArrayList<GridItem> mGridData) {
this.mGridData = mGridData;
notifyDataSetChanged();
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
View row = convertView;
//ViewHolder holder;
ImageView imageView = (ImageView) row
.findViewById(R.id.grid_item_image);
if (row == null) {
LayoutInflater inflater = ((Activity) mContext).getLayoutInflater();
row = inflater.inflate(layoutResourceId, parent, false);
// holder = new ViewHolder();
//imageView = (ImageView) convertView;
TextView titleTextView = (TextView) row
.findViewById(R.id.grid_item_title);
imageView.setScaleType(ImageView.ScaleType.CENTER_CROP);
} else {
}
GridItem item = mGridData.get(position);
imageView.setImageBitmap(item.getImage());
return row;
}
I suggest you to use Universal Image Loader
First of all, include last version of jar file from 'lib' directory to your project
in Adapter :
ImageLoader imageLoader = null;
DisplayImageOptions options;
in Adapter's Contractor :
imageLoader = ImageLoader.getInstance();
options = new DisplayImageOptions.Builder()
/*.displayer(new RoundedBitmapDisplayer((int) 27.5f))*/
.showImageOnLoading(R.drawable.thumb_square)
.showImageForEmptyUri(R.drawable.thumb_square)
.showImageOnFail(R.drawable.thumb_square)
.cacheInMemory(true)
.cacheOnDisc(true)
.considerExifParams(true)
.imageScaleType(ImageScaleType.NONE)
.bitmapConfig(Bitmap.Config.RGB_565)
/*.postProcessor(new BitmapProcessor() {
#Override
public Bitmap process(Bitmap bitmap) {
int w = bitmap.getWidth();
int h = bitmap.getHeight();
float r = ((float)h / (float)w);
ExceptionHelpers.dLog("POST_PROCESSOR", "width : " + w + " , height : " + h + " , R1 : " + r + " , W : " + UIHelpers.width + " , Percent W : " + UIHelpers.setPercentW(r));
return Bitmap.createScaledBitmap(bitmap, UIHelpers.width, UIHelpers.setPercentW(r), false);
}
})*/
.build();
and getView :
String imgURL = "http://www.website.com/images/image_path.png";
imageLoader.init(ImageLoaderConfiguration.createDefault(mContext));
imageLoader.displayImage(imgURL, holder.img_view, options);
First of all dont store the bitmap in modelClass, Alternatively you can add sd card path or live url of an image(http://...)
Loading the image:
-- I suggest you to use Glide library
Code sample:
Glide.with(context)
.load(url) // pass your image url
.centerCrop()
.placeholder(R.drawable.loading_spinner)
.crossFade() //animate the image
.into(myImageView);
How to implement downloading images from server and showing them on a listview with Cursor adapter. I am able to download the images from url by executing AsyncTask from the bindView method of the CursorAdapter Class by passing the image url and ImageView in the constructor of the AsyncTask. But the problem is all the rows are getting populated with the same image and when the list is scrolled , the AsyncTask gets executed again for the rows that appear again after scrolling. I know this is a very common issue when downloading and showing images asynchronously in listview from getview (of ArrayAdapter) method as the Imageview reference in not provided to the Asynctask thread properly , all the solutions i found on web for this is provided for ArrayAdapter (using viewHolders or Weakreferences hashmaps etc) but i am not able to find any same work around with bindView method of CursorAdapter. Any help would be greatful.
My code goes here...
#Override
public View newView(Context context, Cursor cursor, ViewGroup parent) {
View v = mLayoutInflater.inflate(R.layout.friend_row, parent, false);
ViewHolder holder = new ViewHolder();
holder.group_name = (TextView) v.findViewById(R.id.textView1);
holder.tvSteps = (TextView) v.findViewById(R.id.textView3);
holder.tvMobile = (TextView) v.findViewById(R.id.textView2);
holder.pic = (ImageView) v.findViewById(R.id.imageViewF1);
holder.mobtv = (TextView) v.findViewById(R.id.textView22);
holder.pbar = (ProgressBar) v.findViewById(R.id.prbar);
v.setTag(holder);
return v;
}
#Override
public void bindView(View v, Context context, Cursor c) {
//String mob = c.getString(c.getColumnIndexOrThrow(FriendsDataProvider.COL_ADMIN_MOB));
String group_name = c.getString(c.getColumnIndexOrThrow(FriendsDataProvider.COL_GROUP_NAME));
String admin_name = c.getString(c.getColumnIndexOrThrow(FriendsDataProvider.COL_ADMIN_NAME));
String image = c.getString(c.getColumnIndexOrThrow(FriendsDataProvider.COL_GROUP_IMAGE));
//int self_admin = c.getInt(c.getColumnIndexOrThrow(FriendsDataProvider.COL_SELF_ADMIN));
//int steps = c.getInt(c.getColumnIndexOrThrow(FriendsDataProvider.COL_STEPS));
//int group_id = c.getInt(c.getColumnIndexOrThrow(FriendsDataProvider.COL_GROUP_ID));
long date = c.getLong(c.getColumnIndexOrThrow(FriendsDataProvider.COL_CREATE_DATE));
/**
* Next set the title of the entry.
*/
holder = (ViewHolder) v.getTag();
/*TextView tvgroup_name = (TextView) v.findViewById(R.id.textView1);
TextView tvsteps_ = (TextView) v.findViewById(R.id.textView3);
TextView tvMobile = (TextView) v.findViewById(R.id.textView2);
ImageView grp_iv = (ImageView) v.findViewById(R.id.imageViewF1);
TextView mobtv = (TextView) v.findViewById(R.id.textView22);
ProgressBar pbar = (ProgressBar) v.findViewById(R.id.prbar);*/
holder.pbar.setVisibility(View.GONE);
holder.mobtv.setText("");
holder.group_name
.setText(Html
.fromHtml("<font color = '#442E5B'></font><font>"
+ group_name+ "</font>"));
SimpleDateFormat dateFormat = new SimpleDateFormat("d/MM/yy");
dateFormat.setTimeZone(Database.tz);
holder.tvSteps.setText("Created On : "+dateFormat.format(date));
holder.tvMobile.setText("Admin : "+admin_name+"\n " );
if(image!=null&&image.length()>0){
new GetImage(context, image, holder.pic, holder.pbar).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
}else
holder.pic
.setBackgroundResource(R.drawable.user_add);
}
and the GetImage class as ...
public class GetImage extends AsyncTask<Void, Void, Void> {
private Bitmap bitmap ;
Context ctx;
private final WeakReference<ImageView> viewReference;
String photo_path;
ProgressBar pbar;
public GetImage(Context ctx,String image_path,ImageView iv,ProgressBar pbar) {
super();
this.ctx = ctx;
this.photo_path = image_path;
this.pbar = pbar;
viewReference = new WeakReference<ImageView>(iv);
}
#Override
protected void onPreExecute() {
// TODO Auto-generated method stub
pbar.setVisibility(View.VISIBLE);
super.onPreExecute();
}
#Override
protected Void doInBackground(Void... objects) {
try
{
File file1 = new File(photo_path);
String path1 = file1.getAbsolutePath();
Bitmap bitmap1 = null;
if (path1 != null) {
bitmap1 = Profile.decodeFile(file1, 2);
}
if (bitmap1 != null) {
this.bitmap = bitmap1;
} else
{
Log.i("Profile", "photo text : "+photo_path);
String[] path = photo_path.split("/");
String urll = ctx.getResources().getString(R.string.url);
String image_url = urll+"/uploads/"+path[path.length-1];
Log.i("Profile", "image url : "+image_url);
URL url = new URL(image_url);
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setDoInput(true);
connection.connect();
InputStream input = connection.getInputStream();
Bitmap myBitmap = BitmapFactory.decodeStream(input);
// String data1 = String.valueOf(String.format(u.photo));
File miDirs = new File(
Environment.getExternalStorageDirectory() + "/FITGEN/Images");
if (!miDirs.exists())
miDirs.mkdirs();
String imageFilePath = String.format(
Environment.getExternalStorageDirectory() + "/FITGEN/Images/"
+ path[path.length-1]);
File file = new File(imageFilePath);
try {
file.createNewFile();
Log.i("Profile", "File created name : "+file.getAbsolutePath());
} catch (IOException e) {
e.printStackTrace();
}
FileOutputStream stream = new FileOutputStream(file);
ByteArrayOutputStream outstream = new ByteArrayOutputStream();
myBitmap.compress(Bitmap.CompressFormat.JPEG, 100, outstream);
byte[] byteArray = outstream.toByteArray();
stream.write(byteArray);
stream.close();
ImageView iv = viewReference.get();
iv.setDrawingCacheEnabled(true);
Bitmap screenshot = Bitmap.createBitmap(iv.getDrawingCache());
iv.setDrawingCacheEnabled(false);
Bitmap scaledPicture = Bitmap.createScaledBitmap(myBitmap, screenshot.getWidth(), screenshot.getHeight(), true);
bitmap = scaledPicture;
}
}
catch (Exception e)
{
Log.i("Profile", "error in getimage : "+e.getMessage());//e.printStackTrace();
}
return null;
}
#Override
protected void onPostExecute(Void o) {
pbar.setVisibility(View.INVISIBLE);
if(bitmap!=null)
{
ImageView iv = viewReference.get();
bitmap = Statics.getRoundedCornerBitmap(bitmap, 10);
iv.setImageBitmap(bitmap);
}
}
}
I want to display full screen image on another activity after clicking an imageview. I have 6 ImageViews in my layout and each ImageView is getting image from Parse backend. How can I display image on fetching the imagepath ?
public ImageLoader imgl;
ImageView ad1,ad2,ad3,ad4,ad5,ad6;
List<ParseObject> ob;
private ImageView[] imgs = new ImageView[5];
int k=0;
ad1=(ImageView) findViewById(R.id.ad1);
ad2=(ImageView) findViewById(R.id.ad2);
ad3=(ImageView) findViewById(R.id.ad3);
ad4=(ImageView) findViewById(R.id.ad4);
ad5=(ImageView) findViewById(R.id.ad5);
ad6=(ImageView) findViewById(R.id.ad6);
imgs[0] = ad2;
imgs[1] = ad3;
imgs[2] = ad4;
imgs[3] = ad5;
imgs[4] = ad6;
ParseQuery<ParseObject> query = new ParseQuery<ParseObject>("Adverts");
query.orderByDescending("updatedAt");
query.whereEqualTo("Status", true);
try {
ob = query.find();
System.out.println("the urls areeee "+ob);
for (ParseObject country : ob) {
ParseFile image = (ParseFile) country.get("imageFile");
imgl.DisplayImage(image.getUrl(), imgs[k]);
k=k+1;
System.out.println("the urls are"+image.getUrl());
pd.dismiss();
}
} catch (com.parse.ParseException e) {
// TODO Auto-generated catch block
pd.dismiss();
e.printStackTrace();
}
ad1.setOnClickListener(new View.OnClickListener() {
public void onClick(View view) {
Intent ent= new Intent(HomeActivity.this,AdvertsActivity.class);
startActivity(ent);
}
});
}
Set click listener on your ImageView and pass your image url in argument and call method
private void viewImage(String url)
{
final Dialog nagDialog = new Dialog(ProjectDetailActivity.this,android.R.style.Theme_Translucent_NoTitleBar_Fullscreen);
nagDialog.requestWindowFeature(Window.FEATURE_NO_TITLE);
nagDialog.setCancelable(false);
nagDialog.setContentView(R.layout.dialog_full_image);
ivPreview = (ImageView)nagDialog.findViewById(R.id.imageView1);
BitmapDrawable bmd = (BitmapDrawable)getDrawableFromUrl(url)
Bitmap bitmap = bmd.getBitmap();
ivPreview.setImageBitmap(bitmap);
nagDialog.show();
}
public Drawable getDrawableFromUrl(String imgUrl)
{
if(imgUrl == null || imgUrl.equals(""))
return null;
try
{
URL url = new URL(imgUrl);
InputStream in = url.openStream();
Drawable d = Drawable.createFromStream(in, imgUrl);
return d;
}
catch (Exception e)
{
e.printStackTrace();
}
return null;
}
use xml file
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:background="#android:color/white"
android:layout_gravity="center" >
<ImageView
android:id="#+id/imageView1"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_centerHorizontal="true"
android:layout_centerVertical="true"
android:contentDescription="#string/hello_world"
android:src="#android:color/white"
android:layout_margin="5dp"
android:scaleType="centerInside"/>
</RelativeLayout>
I need help understanding androids LruCache. I want to use to load images into my gridview in order make the loading/scrolling better. Can someone post an example code using LruCache please. Thanks in advance.
Below is a class I made for using LruCache, this is based on the presentation Doing More With Less: Being a Good Android Citizen given at Google I/O 2012.
Check out the movie for more information about what I'm doing in the TCImageLoader class:
public class TCImageLoader implements ComponentCallbacks2 {
private TCLruCache cache;
public TCImageLoader(Context context) {
ActivityManager am = (ActivityManager) context.getSystemService(
Context.ACTIVITY_SERVICE);
int maxKb = am.getMemoryClass() * 1024;
int limitKb = maxKb / 8; // 1/8th of total ram
cache = new TCLruCache(limitKb);
}
public void display(String url, ImageView imageview, int defaultresource) {
imageview.setImageResource(defaultresource);
Bitmap image = cache.get(url);
if (image != null) {
imageview.setImageBitmap(image);
}
else {
new SetImageTask(imageview).execute(url);
}
}
private class TCLruCache extends LruCache<String, Bitmap> {
public TCLruCache(int maxSize) {
super(maxSize);
}
#Override
protected int sizeOf(ImagePoolKey key, Bitmap value) {
int kbOfBitmap = value.getByteCount() / 1024;
return kbOfBitmap;
}
}
private class SetImageTask extends AsyncTask<String, Void, Integer> {
private ImageView imageview;
private Bitmap bmp;
public SetImageTask(ImageView imageview) {
this.imageview = imageview;
}
#Override
protected Integer doInBackground(String... params) {
String url = params[0];
try {
bmp = getBitmapFromURL(url);
if (bmp != null) {
cache.put(url, bmp);
}
else {
return 0;
}
} catch (Exception e) {
e.printStackTrace();
return 0;
}
return 1;
}
#Override
protected void onPostExecute(Integer result) {
if (result == 1) {
imageview.setImageBitmap(bmp);
}
super.onPostExecute(result);
}
private Bitmap getBitmapFromURL(String src) {
try {
URL url = new URL(src);
HttpURLConnection connection
= (HttpURLConnection) url.openConnection();
connection.setDoInput(true);
connection.connect();
InputStream input = connection.getInputStream();
Bitmap myBitmap = BitmapFactory.decodeStream(input);
return myBitmap;
} catch (IOException e) {
e.printStackTrace();
return null;
}
}
}
#Override
public void onConfigurationChanged(Configuration newConfig) {
}
#Override
public void onLowMemory() {
}
#Override
public void onTrimMemory(int level) {
if (level >= TRIM_MEMORY_MODERATE) {
cache.evictAll();
}
else if (level >= TRIM_MEMORY_BACKGROUND) {
cache.trimToSize(cache.size() / 2);
}
}
}
I've found a really easy way that work perfectly for me...
This is the Cache.java class. In this class, the static getInstance() method enables us to create only one cache instance in the whole application. getLru() method is used to retrieve the cached object, it will be shown later how to use it. This cache is generic, meaning you can save any Object type into it. The cache memory size here is set to 1024. It can be changed if it is too small:
import android.support.v4.util.LruCache;
public class Cache {
private static Cache instance;
private LruCache<Object, Object> lru;
private Cache() {
lru = new LruCache<Object, Object>(1024);
}
public static Cache getInstance() {
if (instance == null) {
instance = new Cache();
}
return instance;
}
public LruCache<Object, Object> getLru() {
return lru;
}
}
This is the code in your activity where you save the bitmap to the cache:
public void saveBitmapToCahche(){
//The imageView that you want to save it's bitmap image resourse
ImageView imageView = (ImageView) findViewById(R.id.imageViewID);
//To get the bitmap from the imageView
Bitmap bitmap = ((BitmapDrawable)imageview.getDrawable()).getBitmap();
//Saving bitmap to cache. it will later be retrieved using the bitmap_image key
Cache.getInstance().getLru().put("bitmap_image", bitmap);
}
This is the code where you retrieve the bitmap from the cache, then set an imageView to this bitmap:
public void retrieveBitmapFromCache(){
//The imageView that you want to set to the retrieved bitmap
ImageView imageView = (ImageView) findViewById(R.id.imageViewID);
//To get bitmap from cache using the key. Must cast retrieved cache Object to Bitmap
Bitmap bitmap = (Bitmap)Cache.getInstance().getLru().get("bitmap_image");
//Setting imageView to retrieved bitmap from cache
imageView.setImageBitmap(bitmap));
}
THAT'S ALL! As you can see this is rather easy and simple.
EXAMPLE:
In my application, All the views are saved in class variables so they can be seen by all the methods in the class. In my first activity, I save the image bitmap to the cache in an onClickButton() method, right before I start a new activity using intent. I also save a string value in my cache:
public void onClickButton(View v){
Bitmap bitmap = ((BitmapDrawable)imageView.getDrawable()).getBitmap();
String name = textEdit.getText().toString();
Cache.getInstance().getLru().put("bitmap_image", bitmap);
Cache.getInstance().getLru().put("name", name);
Intent i = new Intent(FirstActivity.this, SecondActivity.class);
startActivity(i);
}
Then I navigate from the second activity to a third activity also using intents. In the last activity I save other objects into my cache, then go back to the first activity using an intent. Once I'm back in the first activity, the onCreate() method will start. In that method, I check if my cache has any bitmap value or any String value separately (based on my application business):
public ImageView imageView;
public EditText editText;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_first);
//...Other code...
//The imageView that you want to save it's bitmap image resourse
imageView = (ImageView) findViewById(R.id.imageViewID);
//The editText that I want to save it's text into cache
editText = (EditText)findViewById(R.id.editTextID);
if(Cache.getInstance().getLru().get("name")!=null){
editText.setText(Cache.getInstance().getLru().get("name").toString());
}
if(Cache.getInstance().getLru().get("bitmap_image")!=null){
imageView.setImageBitmap((Bitmap)Cache.getInstance().getLru().get("bitmap_image"));
}
//...Other code...
}
Take a look at Caching Bitmaps where the use of LruCache is demonstrated.
The relevant portion of the code from the page is as follows:-
private LruCache mMemoryCache;
#Override
protected void onCreate(Bundle savedInstanceState) {
...
// Get memory class of this device, exceeding this amount will throw an
// OutOfMemory exception.
final int memClass = ((ActivityManager) context.getSystemService(
Context.ACTIVITY_SERVICE)).getMemoryClass();
// Use 1/8th of the available memory for this memory cache.
final int cacheSize = 1024 * 1024 * memClass / 8;
mMemoryCache = new LruCache(cacheSize) {
#Override
protected int sizeOf(String key, Bitmap bitmap) {
// The cache size will be measured in bytes rather than number of items.
return bitmap.getByteCount();
}
};
...
}
public void addBitmapToMemoryCache(String key, Bitmap bitmap) {
if (getBitmapFromMemCache(key) == null) {
mMemoryCache.put(key, bitmap);
}
}
public Bitmap getBitmapFromMemCache(String key) {
return mMemoryCache.get(key);
}
https://techienotes.info/2015/08/28/caching-bitmaps-in-android-using-lrucache/
This link has a full project having sample application to load images into Gridview using LruCache.
This class is using LruCache and taken from the code given in the link
public class ImageAdapter extends BaseAdapter{
private String TAG = getClass().getSimpleName();
Context mContext;
ArrayList<Uri> imageList;
private LruCache<String, Bitmap> mLruCache;
public ImageAdapter (Context context){
mContext = context;
//Find out maximum memory available to application
//1024 is used because LruCache constructor takes int in kilobytes
final int maxMemory = (int) (Runtime.getRuntime().maxMemory() / 1024);
// Use 1/4th of the available memory for this memory cache.
final int cacheSize = maxMemory / 4;
Log.d(TAG, "max memory " + maxMemory + " cache size " + cacheSize);
// LruCache takes key-value pair in constructor
// key is the string to refer bitmap
// value is the stored bitmap
mLruCache = new LruCache<String, Bitmap>(cacheSize) {
#Override
protected int sizeOf(String key, Bitmap bitmap) {
// The cache size will be measured in kilobytes
return bitmap.getByteCount() / 1024;
}
};
imageList = new ArrayList<Uri>();
//Change this directory to where the images are stored
String imagesFolderPath = Environment.getExternalStorageDirectory().getPath()+"/backups/";
File imageSrcDir = new File (imagesFolderPath);
// if directory not present, build it
if (!imageSrcDir.exists()){
imageSrcDir.mkdirs();
}
ArrayList<File> imagesInDir = getImagesFromDirectory(imageSrcDir);
for (File file: imagesInDir){
// imageList will hold Uri of all images
imageList.add(Uri.fromFile(file));
}
}
#Override
public int getCount() {
return imageList.size();
}
#Override
public Object getItem(int position) {
return null;
}
#Override
public long getItemId(int position) {
return 0;
}
/**
*
* #param position The position of the item within the
* adapter's data set of the item whose view we want.
* #param convertView it is the view to be reused
* #param parent The parent that this view will eventually be attached to
* #return a View corresponding to the data at the specified position.
*/
#Override
public View getView(int position, View convertView, ViewGroup parent) {
ImageView imageView;
Bitmap thumbnailImage = null;
if (convertView == null){
imageView = new ImageView(mContext);
imageView.setLayoutParams(
//150,150 is size of imageview to display image
new GridView.LayoutParams(150, 150));
imageView.setScaleType(ImageView.ScaleType.CENTER_CROP);
}
else {
imageView = (ImageView)convertView;
}
// Use the path as the key to LruCache
final String imageKey = imageList.get(position).toString();
//thumbnailImage is fetched from LRU cache
thumbnailImage = getBitmapFromMemCache(imageKey);
if (thumbnailImage == null){
// if asked thumbnail is not present it will be put into cache
BitmapWorkerTask task = new BitmapWorkerTask(imageView);
task.execute(imageKey);
}
imageView.setImageBitmap(thumbnailImage);
return imageView;
}
/**
* This function returns the files from a directory
* #param parentDirPath source directory in which images are located
* #return list of Files
*/
private ArrayList<File> getImagesFromDirectory (File parentDirPath){
ArrayList <File> listOfImages = new ArrayList<File>();
File [] fileArray = null;
if ( parentDirPath.isDirectory() ){//parentDirPath.exists() &&
// &&
// parentDirPath.canRead()){
fileArray = parentDirPath.listFiles();
}
if (fileArray == null){
return listOfImages; // return empty list
}
for (File file: fileArray){
if (file.isDirectory()){
listOfImages.addAll(getImagesFromDirectory(file));
}
else {
// Only JPEG and PNG formats are included
// for sake of simplicity
if (file.getName().endsWith("png") ||
file.getName().endsWith("jpg")){
listOfImages.add(file);
}
}
}
return listOfImages;
}
/**
* This function will return the scaled version of original image.
* Loading original images into thumbnail is wastage of computation
* and hence we will take put scaled version.
*/
private Bitmap getScaledImage (String imagePath){
Bitmap bitmap = null;
Uri imageUri = Uri.parse (imagePath);
try{
BitmapFactory.Options options = new BitmapFactory.Options();
/**
* inSampleSize flag if set to a value > 1,
* requests the decoder to sub-sample the original image,
* returning a smaller image to save memory.
* This is a much faster operation as decoder just reads
* every n-th pixel from given image, and thus
* providing a smaller scaled image.
* 'n' is the value set in inSampleSize
* which would be a power of 2 which is downside
* of this technique.
*/
options.inSampleSize = 4;
options.inScaled = true;
InputStream inputStream = mContext.getContentResolver().openInputStream(imageUri);
bitmap = BitmapFactory.decodeStream(inputStream, null, options);
} catch (FileNotFoundException e) {
e.printStackTrace();
}
return bitmap;
}
public void addBitmapToMemoryCache(String key, Bitmap bitmap) {
if (getBitmapFromMemCache(key) == null) {
mLruCache.put(key, bitmap);
}
}
public Bitmap getBitmapFromMemCache(String key) {
return mLruCache.get(key);
}
class BitmapWorkerTask extends AsyncTask<String, Void, Bitmap> {
private final WeakReference<ImageView> imageViewReference;
public BitmapWorkerTask(ImageView imageView) {
// Use a WeakReference to ensure the ImageView can be garbage collected
imageViewReference = new WeakReference<ImageView>(imageView);
}
#Override
protected Bitmap doInBackground(String... params) {
final Bitmap bitmap = getScaledImage(params[0]);
addBitmapToMemoryCache(String.valueOf(params[0]), bitmap);
return bitmap;
}
// onPostExecute() sets the bitmap fetched by doInBackground();
#Override
protected void onPostExecute(Bitmap bitmap) {
if (imageViewReference != null && bitmap != null) {
final ImageView imageView = (ImageView)imageViewReference.get();
if (imageView != null) {
imageView.setImageBitmap(bitmap);
}
}
}
}
}
Utility Class to save and retrieve Bitmap from own Cache.
package com.roomco.android.utils;
import android.graphics.Bitmap;
import android.support.v4.util.LruCache;
public class MyCache {
private static MyCache instance;
private LruCache<Object, Object> lru;
private MyCache() {
lru = new LruCache<Object, Object>(1024);
}
public static MyCache getInstance() {
if (instance == null) {
instance = new MyCache();
}
return instance;
}
public LruCache<Object, Object> getLru() {
return lru;
}
public void saveBitmapToCahche(String key, Bitmap bitmap){
MyCache.getInstance().getLru().put(key, bitmap);
}
public Bitmap retrieveBitmapFromCache(String key){
Bitmap bitmap = (Bitmap)MyCache.getInstance().getLru().get(key);
return bitmap;
}
}
Usage:
//Save bitmap in cache
MyCache.getInstance().saveBitmapToCahche("your_key",bitmap);
// Get bitmap from cache
MyCache.getInstance().retrieveBitmapFromCache("your_key");