hello im loading lots of little images (ex: 180x180 10.21kb) from a LOCAL database into lots of different recycler views in fragments in viewpagers in tab layouts (nested fragments.) for instance each tab has a new fragment with a recycler view with these little cards and images everything works fine but eventually it all seems to get a bit much for the system and my app is force closed with an out of memory error the error points to my adapters onBindViewHolder, which looks like this
@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);
}
specifically its pointing at this line
BitmapDrawable(Utility.getPhoto(cardmaker.getCardIcon()));
this is getting a byte array from the database and converting it into a bitmap here is the method from my Utility class
public static Bitmap getPhoto(byte[] image) {
return BitmapFactory.decodeByteArray(image, 0, image.length);
}
can anyone see something that i cant, or that i could be doing to avoid this here im quite new to all this, or is there a different workaround any suggestions welcome
EDIT
Thought id try and be clever and have all the images load from an async task, I dont actually know if this would resolve my issue or not but i get this error
07-10 14:18:28.594 18486-18832/ss.sealstudios.com.socialstories D/skia: --- SkImageDecoder::Factory returned null
i understand it i just dont know what i need to be passing the method to fix it heres what ive tried
MY ENTIRE VIEW HOLDER TRYING TO IMPLEMENT ASYNC TASK
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();
}
}
Try using Picasso
Dependency :
compile 'com.squareup.picasso:picasso:2.5.2
Apparently the huge number of images causes your app to crash with
OutOfMemoryError
, and unfortunately you can do nothing if your app got this error, it will forced to be closed.So, all you can do is to avoid the
OutOfMemoryError
, and this can be done by a lot of ways:1. assign a
largeHeap
for your application:you can do that by adding
android:largeHeap="true"
to the<application>
tag inside your manifest.xml file.2. override the onLowMemory method of your activity, which will enable you to take an action if the system feels like the memory is very low at some point:
3. you can use any of the Image Libraries to changing the settings of your retrieved images, like reducing its resolution, reducing its size, and even reducing its color set, and the most common ones that are being used in this manner will be Universal-Image-Loader and Picasso, for example in Universal-Image-Loader you can use it in any process of downloading and displaying your Bitmap:
In your case, you have the Bitmap already loaded and all you want is to use an Image library to edit its options(here we will use UniversalImageLoader), in this case you can save the image as mentioned is this answer and after that load it from the memory with the options you gave to it: