How to Load many images in Recycle View without Problem in android - android

im using Glide library to load my images from storage to imageView using RecyclerView
all thing good
but when number of images be alot app crashed or should be wait so much to activity load completely
this is my code
public static File DIR_IMG = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM), "MyHairSamples");
private void readExistingImages(){
File[] images;
try {
images= DIR_IMG.listFiles();
for (int i = 0; i < images.length; i++) {
if (images[i].isFile() && images[i].length() > 50L) {
Bitmap b = BitmapFactory.decodeFile(images[i].getAbsolutePath());
addImage(b, "5", images[i].getName());
}
else{
images[i].delete();
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
and i using this method in onCreate method
and this is my Adapter Code
#Override
public void onBindViewHolder(#NonNull MyViewHolder viewHolder, int i) {
viewHolder.title.setText(arrayList.get(i).getImageTitle());
viewHolder.thumbnail.setLabelFor(i);
Glide.with(context)
.load(arrayList.get(i).getImage())
.into(viewHolder.thumbnail);
}

When the images resolution is big, loading will be slow and even your application will crash.
So you can resize your image set like this
Glide.with(context)
.load(arrayList.get(i).getImage())
.apply(new RequestOptions().override(400, 400))
.into(viewHolder.thumbnail);
EDIT
RequestOptions reqOpt = RequestOptions
.fitCenterTransform()
.diskCacheStrategy(DiskCacheStrategy.ALL)
.override(300,300)

Load images inside the uithread, it is not interrupt the main thread.
Use below code.
context.runOnUiThread(new Runnable() {
#Override
public void run() {
Glide.with(context)
.load(arrayList.get(i).getImage())
.into(viewHolder.thumbnail);
}
});

Related

Checking if imageView is empty with Picasso

I have database table, there is a column "image_link", so when I open activity, class Picasso get this image_link and show me image. But now I also may have path to image in my column instead of imageLink, but I need show image in any case, I think that it will work if I will do something like that:
#Override
public void onBindViewHolder(#NonNull ViewHolder holder, int position) {
Picasso.get().load(favouriteTemplates.get(position).getImageLink()).into(holder.icon);
if(holder.icon.getDrawable() == null){
Picasso.get().load(new File(favouriteTemplates.get(position).getImageLink())).into(holder.icon);
}
}
But I know, that it takes some time to download image into imageview with Picasso, so my "if" always is true. How can I solve it?
Picasso.get()
.load(favouriteTemplates.get(position).getImageLink())
.into(holder.icon),
new Callback() {
#Override
public void onSuccess() {
//Do Nothing
}
#Override
public void onError(Exception e) {
Picasso
.get()
.load(newmFile(favouriteTemplates.get(position).getImageLink()))
.into(holder.icon);
}
}
);

Picasso Not Loading Images From Server

My problem statement is to load the images from the server.
Now I have used picasso inside the custom adapter.
The image which I am downloading its size is approximately 100kb
not more than that.But instead of displaying the image white background is
been displayed.
To check error I have used callback but somehow the callback is not working
I mean the callback is never getting called.
Below is my code
#Override
public void onBindViewHolder(FolderListAdapter.Viewholder holder, int position) {
userDetails=userList.get(position);
//Context context=);
if(userDetails.getLogo()!=null && !userDetails.getLogo().isEmpty()) {
Context context=holder.cardProfilePic.getContext();
Picasso.with(context)
.load(userDetails.getLogo())
.fit()
.into(holder.cardProfilePic, new Callback() {
#Override
public void onSuccess() {
Log.d("succes","success");
}
#Override
public void onError() {
Log.d("failure","failure");
}
});
}
if(userDetails.getBanner()!=null && !userDetails.getBanner().isEmpty()) {
Picasso.with(context)
.load(userDetails.getBanner())
.resize(300,300)
.into(holder.cardBackgroundPic);
}
if(userDetails.getPersonName()!=null && !userDetails.getPersonName().isEmpty()) {
holder.username.setText(userDetails.getPersonName());
}
if(userDetails.getDesignation()!=null && !userDetails.getDesignation().isEmpty()) {
holder.userRole.setText(userDetails.getDesignation());
}
}

How to check that all the files uploaded by Picasso lib?

I want before render MainActivity check what all pictures is loaded:
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
...
getBitmapsByURLs(urls);
}
public void getBitmapsByURLs(List<String> urls) {
final List<Target> targets = new ArrayList<>();
for (int i = 0; i < urls.size(); i++) {
final int k = i;
Target target = new Target() {
#Override
public void onBitmapLoaded(Bitmap bitmap, Picasso.LoadedFrom from) {
Log.i("TEMP", "Loaded: " + k);
targets.remove(this);
}
#Override
public void onBitmapFailed(Drawable errorDrawable) {
targets.remove(this);
}
#Override
public void onPrepareLoad(Drawable placeHolderDrawable) {
Log.i("TEMP", "Preparing: " + k);
}
};
targets.add(target);
Picasso.with(this)
.load(urls.get(i))
.memoryPolicy(NO_CACHE, NO_STORE)
.into(target);
}
}
How I can check inside onCreate what all pictures is loaded?
If I write while on method onCreate (after call getBitmapsByURLs) then it will be called before all pictures are loaded.
You must be known that when you use
Picasso.with(this)
.load(urls.get(i))
.memoryPolicy(NO_CACHE, NO_STORE)
.into(target);
to load a picture,it is a asynchronized task.First picasso download the picture from internet.After downloading is finished,the picture will be loaded into target.Of course,when downloading,the main thread will never be waiting.Picasso use something like Observer-Subcriber or interface Future to make the main thread informed that downing is over.Above all,no matter what you write after getBitmapsByURLs(urls),it will be called before picasso finishes loading pictures.(Because it usually costs some more time to download pictures and load them into targets).
What's more.This is not a recommended way to do such a time-costing work in onCreate().Because onCreate() is called in main thread.If you do something costs much time here,then you will get an Application Not Responding error.

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

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();
}
}
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:
#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. 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:
// 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);
Try using Picasso Dependency : 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);

Slideshow with Picasso

I'm displaying multiple images from our server as a slideshow with a ImageSwitcher. Before the ImageSwitcher gets initialized I want to preload the images with Picasso library.
I want to say that I use Picasso with an interceptor, because our server requires Basic Authentication for the images.
My current preloading:
final int[] downloadedCounter = {0};
for (int i = 0; i < images.size(); i++) {
final SlideshowImage image = images.get(i);
PicassoUtils.getPicassoWithBasicAuthorizationFrom(user, getContext())
.load(image.getImageUrl())
.fetch(new Callback() {
#Override
public void onSuccess() {
downloadedCounter[0]++;
if (downloadedCounter[0] == images.size()) {
callback.downloadFinished();
}
}
#Override
public void onError() {
}
});
}
And that is my ImageSwitcher:
ImageView image = (ImageView) this.getNextView();
PicassoUtils.getPicassoWithBasicAuthorizationFrom(user, getContext())
.load(imageUrl)
.noFade()
.into(image, new Callback() {
#Override
public void onSuccess() {
showNext();
}
#Override
public void onError() {
}
});
But the problem is, that it won't get cached, because when I use .networkPolicy(NetworkPolicy.OFFLINE) on Picasso in my ImageSwitcher nothing gets loaded.
And everytime i call showNext() in my ViewSwitcher the used memory of the device rises a bit.

Categories

Resources