java.lang.OutOfMemory在sqlite db中存储图像的错误

2022-09-04 01:48:18

我想将图像存储在我的数据库中。另外,我想检查图像和标题是否已经在数据库中。如果是这样,它不会将它们添加到数据库中。这是我的班级。

景点

public class Attractions extends ListActivity {
DataBaseHandler db = new DataBaseHandler(this);
ArrayList<Contact> imageArry = new ArrayList<Contact>();
List<Contact> contacts;
ContactImageAdapter adapter;
int ctr, loaded; 
int [] landmarkImages={R.drawable.oblation,R.drawable.eastwood,R.drawable.ecopark,R.drawable.circle};
String []landmarkDetails = { "Oblation", "Eastwood", "Ecopark", "QC Circle"};

/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_attractions);
    ctr  = db.checkContact(landmarkDetails[loaded]);



    // get image from drawable

    /**
     * CRUD Operations
     * */
    // Inserting Contacts
    Log.d("Insert: ", "Inserting ..");


    for(loaded=0; loaded <landmarkDetails.length;loaded++){

        Bitmap image = BitmapFactory.decodeResource(getResources(),
                landmarkImages[loaded]);


        // convert bitmap to byte
        ByteArrayOutputStream stream = new ByteArrayOutputStream();
        image.compress(Bitmap.CompressFormat.JPEG, 100, stream);
        byte imageInByte[] = stream.toByteArray();
        Log.d("Going to load images", "Image "+ loaded);

        Log.d("Goind to load objects", "loading");

        if(ctr == 0){
            Log.d("Nothing Loaded", "Loading Now");
            db.addContact(new Contact(landmarkDetails[loaded], imageInByte));}
            Log.d(landmarkDetails[loaded], "Loaded!");
            image.recycle();
    }
    loadFromDb();


}

@Override
public boolean onCreateOptionsMenu(Menu menu) {
    // Inflate the menu; this adds items to the action bar if it is present.
    getMenuInflater().inflate(R.menu.attractions, menu);


    return true;
}

public void loadFromDb(){
    // Reading all contacts from database
            contacts = db.getAllContacts();
            for (Contact cn : contacts) {
                String log = "ID:" + cn.getID() + " Name: " + cn.getName()
                        + " ,Image: " + cn.getImage();

                // Writing Contacts to log
                Log.d("Result: ", log);
                //add contacts data in arrayList
                imageArry.add(cn);

            }
            adapter = new ContactImageAdapter(this, R.layout.screen_list,
                    imageArry);
            ListView dataList = (ListView) findViewById(android.R.id.list);
            dataList.setAdapter(adapter);

}

public void onPause(){
    super.onPause();
}

public void onResume(){
    super.onResume();

}


}

它在模拟器上工作正常,但我尝试在S4上进行测试,然后在3次尝试进入这个类后,它强制停止。我尝试了USB调试,日志显示.logcat指出了我的接触图像适配器中的错误。java.lang.outofmemoryerror

联系人图像适配器

public class ContactImageAdapter extends ArrayAdapter<Contact>{
 Context context;
    int layoutResourceId;   
   // BcardImage data[] = null;
    ArrayList<Contact> data=new ArrayList<Contact>();
    public ContactImageAdapter(Context context, int layoutResourceId, ArrayList<Contact> data) {
        super(context, layoutResourceId, data);
        this.layoutResourceId = layoutResourceId;
        this.context = context;
        this.data = data;
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        View row = convertView;
        ImageHolder holder = null;

        if(row == null)
        {
            LayoutInflater inflater = ((Activity)context).getLayoutInflater();
            row = inflater.inflate(layoutResourceId, parent, false);

            holder = new ImageHolder();
            holder.txtTitle = (TextView)row.findViewById(R.id.txtTitle);
            holder.imgIcon = (ImageView)row.findViewById(R.id.imgIcon);
            row.setTag(holder);
        }
        else
        {
            holder = (ImageHolder)row.getTag();
        }

        Contact picture = data.get(position);
        holder.txtTitle.setText(picture._name);
        //convert byte to bitmap take from contact class

        byte[] outImage=picture._image;
        ByteArrayInputStream imageStream = new ByteArrayInputStream(outImage);
        Bitmap theImage = BitmapFactory.decodeStream(imageStream);
        holder.imgIcon.setImageBitmap(theImage);
       return row;

    }

    static class ImageHolder
    {
        ImageView imgIcon;
        TextView txtTitle;
    }
}

并指向这条线Bitmap theImage = BitmapFactory.decodeStream(imageStream);

我对管理和存储图像知之甚少(几乎没有)。我也启用,但仍然强制关闭多次尝试。我希望有人能帮助我解决这个问题,或者至少向我展示一种将文本和图像存储到sqlite db的不同方法。非常感谢!android:largeHeap


答案 1

您有多个位置,其中整个图像(假设它很大)保留在内存中:

  1. 联系人对象有它。所有加载的图像都在 imageArry 中,这是实例级变量。

    public class Attractions extends ListActivity {
        DataBaseHandler db = new DataBaseHandler(this);
        ArrayList<Contact> imageArry = new ArrayList<Contact>();
    
  2. 在方法中,您在持有者对象中创建图像的另一个副本作为 BMP 并将其传递出方法。因此,在某些时候,您没有足够的内存来保留所有这些内存。我也确定需要更多的内存来执行。ContactImageAdapter.getViewdecodeStream

毕竟,当GC清理中创建的每个新持有者时,这是不可预测的。通常,对于这种情况,当在某个方法中创建对象为新对象,然后传递回调用方法时,该对象将仅由Full GC收集。getView

因此,正如“软件Sainath”所说,不要将图像存储在数据库中......也不要将它们保存在内存中。

附言:然后向视图提供指向外部图像文件的链接。这也将节省加载视图的时间。图像将在缓存中,如果用户至少获得一次,它将不会再次通过网络。

我猜那里的图像不会经常改变它们自己。联系人的另一个图像将是另一个文件...


答案 2

不久前,我写了一个类似问题的答案,这是您可以检查的链接。问题在于将图像保存到数据库中的方法,您不应该这样做。相反,将图像作为文件写入手机内存并进一步使用它。


推荐