android 回收器视图适配器、viewpager、数据库、位图和内存不足错误

android recycler view adapters, viewpagers, databases, bitmaps and out of memory errors

你好,我正在从 LOCAL 数据库中将大量小图像(例如:180x180 10.21kb)加载到选项卡布局(嵌套片段)中的 viewpager 中的片段中的许多不同的回收器视图中。例如 每个选项卡有一个带有这些小卡片和图像的回收器视图的新片段,一切正常,但最终它似乎对系统来说有点多,我的应用程序因内存不足错误而被强制关闭错误指向我的适配器 onBindViewHolder,看起来像这样

@Override
public void onBindViewHolder(MyViewHolder holder, int position){
    addNewCard cardmaker = cardMakerListDB.get(position);
    holder.cardText.setText(cardmaker.getCardName());
    holder.speechText.setText(cardmaker.getCardSpeech());
    Drawable drawable = new    
    BitmapDrawable(Utility.getPhoto(cardmaker.getCardIcon()));
    holder.cardImage.setImageDrawable(drawable);
}

特别是它指向这条线

BitmapDrawable(Utility.getPhoto(cardmaker.getCardIcon()));

这是从数据库中获取字节数组并将其转换为位图,这是我的实用程序中的方法class

 public static Bitmap getPhoto(byte[] image) {
    return BitmapFactory.decodeByteArray(image, 0, image.length);
}

谁能看到我看不到的东西,或者我可以做些什么来避免这种情况,我对这一切都很陌生,或者是否有不同的解决方法欢迎任何建议

编辑

我想聪明一点,让所有图像都从异步任务加载,我实际上不知道这是否能解决我的问题,但我得到了这个错误

07-10 14:18:28.594 18486-18832/ss.sealstudios.com.socialstories D/skia: --- SkImageDecoder::Factory 返回 null

我明白了,我只是不知道我需要传递什么方法来修复它,这是我尝试过的方法

我的整个视图持有者正在尝试执行异步任务

public class CardAdapterDB extends    
RecyclerView.Adapter<CardAdapterDB.MyViewHolder> {
private List<addNewCard> cardMakerListDB;

public class MyViewHolder extends RecyclerView.ViewHolder{

    public TextView cardText, speechText;
    public ImageView cardImage;
    public ProgressBar progress;


    public MyViewHolder(View view){
        super(view);
        cardText = (TextView) view.findViewById(R.id.cardText);
        speechText = (TextView) view.findViewById(R.id.speechText);
        cardImage = (ImageView) view.findViewById(R.id.cardimage);
        progress = (ProgressBar) view.findViewById(R.id.progressBarFetch);

    }

}
public CardAdapterDB(List<addNewCard> cardMakerListDB){
    this.cardMakerListDB = cardMakerListDB;
}
@Override
public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType){
    View itemView = LayoutInflater.from(parent.getContext())
            .inflate(R.layout.card, parent, false);
    return new MyViewHolder(itemView);
}
@Override
public void onBindViewHolder(MyViewHolder holder, int position){
    addNewCard cardmaker = cardMakerListDB.get(position);
    holder.cardText.setText(cardmaker.getCardName());
    holder.speechText.setText(cardmaker.getCardSpeech());
    holder.progress.setVisibility(View.VISIBLE);
    startNewAsyncTask(cardmaker.getCardIcon(),holder.progress,holder);

}

private class MyAsyncTask extends AsyncTask<Bitmap, Void, Bitmap> {

    private byte[] data;
    private ProgressBar progress;
    private MyViewHolder holder;

    public MyAsyncTask(byte[] data,ProgressBar progress,MyViewHolder holder)   
    {
        this.data = data;
        this.progress = progress;
        this.holder = holder;
    }

    @Override
    protected void onPreExecute() {
        super.onPreExecute();
        progress.setVisibility(View.VISIBLE);
        progress.setIndeterminate(true);
    }

    @Override
    protected Bitmap doInBackground(Bitmap... data) {

        return BitmapFactory.decodeByteArray(this.data, 0, data.length);
    }
    @Override
    protected void onPostExecute(Bitmap response) {
        super.onPostExecute(response);
        {
        Drawable drawable = new BitmapDrawable(response);
        holder.cardImage.setImageDrawable(drawable);
           // progress.setVisibility(View.GONE);
        }
    }
}
public void startNewAsyncTask(byte[] image,ProgressBar progress,MyViewHolder 
holder) {
    MyAsyncTask asyncTask = new MyAsyncTask(image,progress,holder);
    asyncTask.execute();
}

@Override
public int getItemCount(){
    return cardMakerListDB.size();
}
}

尝试使用 Picasso
依赖关系:compile 'com.squareup.picasso:picasso:2.5.2

Picasso
  .with(context)
  .load(your_image)
  .fit()
  // call .centerInside() or .centerCrop() to avoid a stretched image
  .into(your_imageview);

显然,大量图片会导致您的应用程序崩溃 OutOfMemoryError,不幸的是,如果您的应用程序出现此错误,您将无能为力,它将被强制关闭。

所以,你所能做的就是避免OutOfMemoryError,这可以通过很多方法来实现:

1. 为您的申请分配一个 largeHeap

您可以通过将 android:largeHeap="true" 添加到 manifest.xml 文件中的 <application> 标签来做到这一点。

2.覆盖你的activity的onLowMemory方法,这将使你能够在系统感觉内存不足时采取行动在某个时候很低:

@Override
    public void onLowMemory() {
        // you can here remove the Bitmaps or stopping the process of generating images or do whatever you want to survive being trapped into 'OutOfMemoryError'.
    };

3.您可以使用任何图像库来更改检索到的图像的设置,例如降低其分辨率减小它的大小,甚至减小它的颜色集,以这种方式使用的最常见的是Universal-Image-Loader and Picasso,例如在 Universal-Image-Loader 中,您可以在任何下载和显示位图的过程中使用它:


在你的情况下,你已经加载了位图,你想要的只是使用图像库来编辑它的选项(这里我们将使用 UniversalImageLoader),在这种情况下您可以按照提到的方式保存图像 this answer,然后使用您提供的选项从内存中加载它:

// Saving image to disk
String filename = "some_name.jpg";
File sd = Environment.getExternalStorageDirectory();
File dest = new File(sd, filename);

Bitmap bitmap = (Bitmap)data.getExtras().get("data");
try {
     FileOutputStream out = new FileOutputStream(dest);
     bitmap.compress(Bitmap.CompressFormat.PNG, 90, out);
     out.flush();
     out.close();
} catch (Exception e) {
     e.printStackTrace();
}

// this is an example of the used options
BitmapFactory.Options options = new BitmapFactory.Options();
options.inSampleSize = 2;
options.inJustDecodeBounds = true;
options.inDither = false;
options.inPurgeable = true;
options.inInputShareable = true;

// create ImageLoader instance
ImageLoader loader = ImageLoader.getInstance();
loader.loadImageSync(dest.getAbsolutePath(), options);