OutOfMemoryError при установке Uri с помощью setImageURI

Пользователь выбирает изображение, путь к нему затем сохраняется в моей базе данных SQLite. Затем я заполняю текст / изображения из SQLite в GridView используя 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;
}
}

Когда я выбираю большие изображения, я получаю сообщение об ошибке:

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

Я видел, что растровое изображение должно быть уменьшено, но я просто использую Uri файла и его отображение. Есть ли способ избежать этой проблемы, поскольку я не хочу сохранять другой (сжатый) файл на устройстве?

я пытался android:hardwareAccelerated="false" в манифесте.


Вот что сработало для меня:

В конечном итоге я использовал Picasso в ответах, но важно отметить, что при загрузке URIот устройства, чтобы загрузить URI как это:

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

обратите внимание, что я использовал .load(new File(String.valueOf(Uri))) вместо .load(uri), Если вы загрузите URI непосредственно представление вернется пустым.

Если вы загружаете изображение из URL, оно должно быть загружено так:

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

В итоге мой адаптер выглядел так:

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;
}
}

Спасибо всем за помощь.

2 ответа

Решение

Вы можете использовать библиотеку Picasso для отображения изображений.

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

И в вашем адаптере что-то вроде этого:

Uri jg = Uri.parse(this.cur.getString(this.cur.getColumnIndex("imagepath")));
Picasso.with(context).load(jg).into(viewHolder.Image);

Для контекста

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;

}

затем используйте:

Uri jg = Uri.parse(this.cur.getString(this.cur.getColumnIndex("imagepath")));
Picasso.with(mContext).load(jg).into(viewHolder.Image);
Другие вопросы по тегам