2

The user select a image, the path of the image is then stored in my SQLite database. I then populate the text/images from SQLite in a GridView using a CursorAdapter:

public class MyNiftyAdapter extends CursorAdapter{
private LayoutInflater mInflater;
private Cursor cur;

public MyNiftyAdapter(Context context, Cursor c) {
    super(context,c);
    this.mInflater = LayoutInflater.from(context);
    this.cur = c;
}
public MyNiftyAdapter(Context context, Cursor c, boolean autoRequery)
{
    super(context, c, autoRequery);
    this.mInflater = LayoutInflater.from(context);
    this.cur = c;
}
@Override
public View getView(int position, View convertView, ViewGroup parent)
{
    ViewHolder viewHolder;
    if(convertView == null)
    {
        convertView = this.mInflater.inflate(R.layout.single_item, null);
        viewHolder = new ViewHolder();
        viewHolder.name = (TextView)convertView.findViewById(R.id.txtName);
        viewHolder.Age = (TextView)convertView.findViewById(R.id.studentage);
        viewHolder.Id = (TextView)convertView.findViewById(R.id.rowid);
        viewHolder.Image = (CircularImageView)convertView.findViewById(R.id.imgFood);
        convertView.setTag(viewHolder);
    }else
    {
        viewHolder = (ViewHolder)convertView.getTag();
    }
    this.cur.moveToPosition(position);

    viewHolder.name.setText(this.cur.getString(this.cur.getColumnIndex(SQLiteHelper.NAME)));
    viewHolder.Age.setText(this.cur.getString(this.cur.getColumnIndex(SQLiteHelper.AGE)));
    viewHolder.Id.setText(this.cur.getString(this.cur.getColumnIndex(SQLiteHelper._ID)));
    Uri jg = Uri.parse(this.cur.getString(this.cur.getColumnIndex("imagepath")));
    viewHolder.Image.setImageURI(jg);

    return convertView;
}

@Override
public void bindView(View view, Context context, Cursor cursor) {

}

@Override
public View newView(Context context, Cursor cursor, ViewGroup parent) {
    // Dont need to do anything here
    return null;
}

static class ViewHolder
{
    TextView name;
    TextView Age;
    TextView Id;
    CircularImageView Image;
}
}

When I select large images I get a out of memory error:

java.lang.OutOfMemoryError: Failed to allocate a 21566748 byte allocation with 8448604 free bytes and 8MB until OOM

I have seen that the bitmap should be scaled down, but I'm just using the Uri of the file and displaying it. Is there anyway to avoid this issue as I don't want to save another(compressed) file to the device?

I have tried android:hardwareAccelerated="false" in manifest.


This is what worked for me:

I ended up using picasso as the answers suggested, but something important to note is that when loading a URI from device is to load the URI like this:

Picasso.with(mContext)
            .load(new File(String.valueOf(Uri)))
            .placeholder(R.drawable.profile)
            .resize(800, 800)
            .centerCrop()
            .into(viewHolder.Image);

note that I used .load(new File(String.valueOf(Uri))) instead of .load(uri). If you load the URI directly the view will return empty.

If you load a image from a url, it should be loaded like this:

Picasso.with(mContext)
            .load(URL)
            .placeholder(R.drawable.profile)
            .resize(800, 800)
            .centerCrop()
            .into(viewHolder.Image);

So my adapter ended up looking like this:

public class MyNiftyAdapter extends CursorAdapter{
private LayoutInflater mInflater;
private Cursor cur;
private Context mContext;

public MyNiftyAdapter(Context context, Cursor c) {
    super(context,c);
    this.mInflater = LayoutInflater.from(context);
    this.mContext = context;
    this.cur = c;
}
public MyNiftyAdapter(Context context, Cursor c, boolean autoRequery)
{
    super(context, c, autoRequery);
    this.mInflater = LayoutInflater.from(context);
    this.cur = c;
    this.mContext = context;
}
@Override
public View getView(int position, View convertView, ViewGroup parent)
{
    ViewHolder viewHolder;
    if(convertView == null)
    {
        convertView = this.mInflater.inflate(R.layout.single_item, null);
        viewHolder = new ViewHolder();
        viewHolder.name = (TextView)convertView.findViewById(R.id.txtName);
        viewHolder.Age = (TextView)convertView.findViewById(R.id.studentage);
        viewHolder.Id = (TextView)convertView.findViewById(R.id.rowid);
        viewHolder.Image = (CircularImageView)convertView.findViewById(R.id.imgFood);
        convertView.setTag(viewHolder);
    }else
    {
        viewHolder = (ViewHolder)convertView.getTag();
    }
    this.cur.moveToPosition(position);

    viewHolder.name.setText(this.cur.getString(this.cur.getColumnIndex(SQLiteHelper.NAME)));
    viewHolder.Age.setText(this.cur.getString(this.cur.getColumnIndex(SQLiteHelper.AGE)));
    viewHolder.Id.setText(this.cur.getString(this.cur.getColumnIndex(SQLiteHelper._ID)));
    Uri jg = Uri.parse(this.cur.getString(this.cur.getColumnIndex("imagepath")));

    Picasso.with(mContext)
            .load(new File(String.valueOf(jg)))
            .placeholder(R.drawable.profile)
            .resize(800, 800)
            .centerCrop()
            .into(viewHolder.Image);

    return convertView;
}

@Override
public void bindView(View view, Context context, Cursor cursor) {

}

@Override
public View newView(Context context, Cursor cursor, ViewGroup parent) {
    // Dont need to do anything here
    return null;
}

static class ViewHolder
{
    TextView name;
    TextView Age;
    TextView Id;
    CircularImageView Image;
}
}

Thank you all for the help.

ClassA
  • 2,480
  • 1
  • 26
  • 57
  • Possible duplicate of [How to solve java.lang.OutOfMemoryError trouble in Android](https://stackoverflow.com/questions/25719620/how-to-solve-java-lang-outofmemoryerror-trouble-in-android) – Dima Kozhevin Sep 29 '17 at 09:13
  • https://stackoverflow.com/questions/37776939/android-how-to-avoid-this-out-of-memory-error – Dima Kozhevin Sep 29 '17 at 09:14
  • @DimaKozhevin that question uses a image stored in drawable resources, I'm asking about Image uri/path stored in phone memory. – ClassA Sep 29 '17 at 09:15
  • you can use image loading library as Picasso or Glide to avoid out of memory error – steevoo Sep 29 '17 at 09:16
  • @DimaKozhevin the second example as well. – ClassA Sep 29 '17 at 09:16
  • Try to use 'leakcanary' library(https://github.com/square/leakcanary) because problem may be in another places in your app – Dima Kozhevin Sep 29 '17 at 09:24
  • @DimaKozhevin The problem is definitely to do with the setting of the `Uri` of large images specifically. When I select small images only then everything works perfectly. The problem only occurs when I use large images. – ClassA Sep 29 '17 at 09:28

2 Answers2

2

You can use Picasso library to display images.

compile 'com.squareup.picasso:picasso:2.5.2'

And in your adapter something like this :

Uri jg = Uri.parse(this.cur.getString(this.cur.getColumnIndex("imagepath")));
Picasso.with(context).load(jg).into(viewHolder.Image);
Maroof
  • 891
  • 6
  • 7
  • use mContext in place of context. – Maroof Sep 29 '17 at 09:30
  • No image is displayed – ClassA Sep 29 '17 at 09:34
  • can you check Uri jg is null or not. – Maroof Sep 29 '17 at 09:35
  • Also try more something like Picasso.with(mContext).load(jg).fit().into(viewHolder.Image); – Maroof Sep 29 '17 at 09:36
  • Uri jg is not null – ClassA Sep 29 '17 at 09:40
  • try { Uri jg = Uri.parse(this.cur.getString(this.cur.getColumnIndex("imagepath"))); Picasso.with(context).load(jg).into(viewHolder.Image); } catch (OutOfMemoryError error) { error.printStackTrace(); } Debug and let me know that this comes in catch block or not. – Maroof Sep 29 '17 at 09:42
  • Also share your R.layout.single_item. – Maroof Sep 29 '17 at 09:48
  • 1
    okay so you set hardcoded 80dp dimens for height and width. Edit something like this :: Uri jg = Uri.parse(this.cur.getString(this.cur.getColumnIndex("imagepath"))); Picasso.with(mContext).load(jg).centerInside().resize(80,80).into(viewHolder.Image); – Maroof Sep 29 '17 at 10:01
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/155579/discussion-between-maroof-and-classa). – Maroof Sep 29 '17 at 10:03
1

For Context

public class MyNiftyAdapter extends CursorAdapter{
private LayoutInflater mInflater;
private Cursor cur;
private Context mContext;

public MyNiftyAdapter(Context context, Cursor c) {
    super(context,c);
    this.mInflater = LayoutInflater.from(context);
this.mContext= context;
    this.cur = c;
}
public MyNiftyAdapter(Context context, Cursor c, boolean autoRequery)
{
    super(context, c, autoRequery);
    this.mInflater = LayoutInflater.from(context);
    this.cur = c;
    this.mContext= context;

}

an then use :

Uri jg = Uri.parse(this.cur.getString(this.cur.getColumnIndex("imagepath")));
Picasso.with(mContext).load(jg).into(viewHolder.Image);
yogesh lokhande
  • 1,245
  • 1
  • 11
  • 20