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);
你好,我正在从 LOCAL 数据库中将大量小图像(例如:180x180 10.21kb)加载到选项卡布局(嵌套片段)中的 viewpager 中的片段中的许多不同的回收器视图中。例如
@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);