Recyclerview is not recycling views properly - java

I am loading images from URL into horizontal recyclerview using Picasso as:
public class pIndicatorAdaptor extends
RecyclerView.Adapter<pIndicatorAdaptor.IndicatorViewHolder> {
//constructor and other stuff
#Override
public IndicatorViewHolder onCreateViewHolder(ViewGroup parent, int vType) {
View view = layoutInflater.inflate(R.layout.i_item, parent, false);
return new IndicatorViewHolder(view);
}
#Override
public void onBindViewHolder(IndicatorViewHolder holder, int position) {
picasso.load(images.get(position).getSrc()).fit().centerCrop()
.into(holder.imageView, null);
}
class IndicatorViewHolder extends RecyclerView.ViewHolder {
ImageView imageView;
IndicatorViewHolder(#NonNull View itemView) {
super(itemView);
imageView = itemView.findViewById(R.id.imageView);
}
}
}
But I get the result like this,The bottom horizontal recyclerview is where I am loading images:

when you keep scroll the recycler view like that,it's load the image every time and ofcourse it took alot of time to load the image.i think you should use glide on this because glide is really good on load the image from cache ( if exist) ;)

Related

How to add dynamic views to android layout in recyclerview adapter

enter image description here
I have a list of parents that each has zero or many children
I use recyclerview to show the parents.
I want to show parents as header of each recyclerview item and below show all the children
what is the best way to show the children?
is it suitable to show children in a listview or add dynamic views for each child if so how to do that?
I have attach the image of layout, please check what I mean
thanks
enter image description here
I think, may this helpful bcz, in every position there are dynamicly generate item view respectably.
LinearLayoutManager linearLayoutManager = new LinearLayoutManager(getContext());
linearLayoutManager.setOrientation(RecyclerView.HORIZONTAL);
IAFTbind.rcvFilters.setLayoutManager(linearLayoutManager);
IAFTbind.rcvFilters.setAdapter(new RecyclerView.Adapter() {
public int checkedPosition = 0;
#NonNull
#Override
public RecyclerView.ViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
ImageView imageView = new ImageView(getContext());
imageView.setScaleX(.9f);
imageView.setScaleY(.9f);
imageView.setLayoutParams(new ViewGroup.LayoutParams(size, size));
return new RecyclerView.ViewHolder(imageView) {
#Override
public String toString() {
return super.toString();
}
};
}
#Override
public void onBindViewHolder(#NonNull RecyclerView.ViewHolder holder, int position) {
int p = holder.getAdapterPosition();
((ImageView) holder.itemView).setBackground(new BitmapDrawable(getResources(), Bitmap.createScaledBitmap(fBits.get(p), size, size, false)));
// ((ImageView) holder.itemView).setBackground(new BitmapDrawable(getResources(), bitmaps.get(position)));
int cp = this.checkedPosition;
if (cp == -1) {
((ImageView) holder.itemView).setImageResource(0);
} else if (cp == p) {
((ImageView) holder.itemView).setImageResource(R.drawable.draw_tool_selecter_strock);
} else {
((ImageView) holder.itemView).setImageResource(0);
}
holder.itemView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
((ImageView) holder.itemView).setImageResource(R.drawable.draw_tool_selecter_strock);
checkedPosition = p;
notifyDataSetChanged();
changeBitmapEffect(p);
}
});
}
#Override
public int getItemCount() {
return fBits.size();
}
});
Problem statement
You want to add childs dynamically as per the screenshot you shared.
Solution
So here I can see 2 recycler views, one inside another. The first recycler view is for parents which have 2 items
Parents name
Another recycler view for children
What you need to do is, you need to pass the updated list of item to the parent's recyclerview adapter, which will send the updated list of item to childs recyclerview adapter and the childs recyclerview adapter will check using the diffUtil about any changes and it will reflect the changes in the recyclerview.

Glide isn't loading images from URL despite both placeholder image and URL in logs working

I'm trying to load images into a RecyclerView object via the Glide library but no matter what I change I can't get the image to successfully load.
'holder.image' (shown in the code snippet below) directly inserts the image into the RecyclerView ViewHolder and it successfully displays placeholder images if I include them.
In addition the log snippet displays the URL link I am passing in, and when clicked the image is successfully displayed.
I have tried multiple different versions of Glide: 4.9, 4.4 and 3.7 (the most recent, the version in the tutorial I'm following and one recommended on a previous stack exchange answer).
I have included both the following permissions in the manifest:
As well as just including one and including neither.
I have tried both HTTPS and HTTP links as well as links from different sites. (Including copying links directly from the tutorial I followed).
The below is my RecyclerViewAdapter class with all non-image variables removed. As far as I know the only key section is in the onBindViewHolder function as the placeholder is correctly working, but I have included the full (reduced) class just in case.
public class RecyclerViewAdapter extends RecyclerView.Adapter<RecyclerViewAdapter.ViewHolder> {
private ArrayList<String> mImageAddresses = new ArrayList<>();
public RecyclerViewAdapter(Context mContext, ArrayList<String> mImageAddresses) {
this.mImageAddresses = mImageAddresses;
}
#NonNull
#Override
public ViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.recycler_entry, parent, false);
ViewHolder holder = new ViewHolder(view);
return holder;
}
#Override
public void onBindViewHolder(#NonNull ViewHolder holder, final int position) {
Log.d(TAG, "onBindViewHolder: called. Address name: " + mImageAddresses.get(position));
Glide.with(mContext)
.load(mImageAddresses.get(position))
.placeholder(R.drawable.ic_launcher_foreground)
.into(holder.image);
holder.parentLayout.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Log.d(TAG, "onClick: clicked on: " + mTitles.get(position));
Toast.makeText(mContext, "PLACEHOLDER", Toast.LENGTH_SHORT).show();
}
}
}
#Override
public int getItemCount() {
return mTitles.size(); //I have removed mTitles elsewhere for a more concise code snippet but it is successfully implemented
}
public class ViewHolder extends RecyclerView.ViewHolder {
ImageView image;
public ViewHolder(#NonNull View itemView) {
super(itemView);
image = itemView.findViewById(R.id.Icon);
}
}
}
2019-08-16 20:18:46.515 19359-19359/com.example.myapplication D/RecyclerViewAdapter: onBindViewHolder: called. Address name: http://c1.staticflickr.com/5/4636/25316407448_de5fbf183d_o.jpg
2019-08-16 20:18:46.745 19359-19359/com.example.myapplication D/RecyclerViewAdapter: onBindViewHolder: called. Address name: https://i.redd.it/obx4zydshg601.jpg
2019-08-16 20:18:46.764 19359-19359/com.example.myapplication D/RecyclerViewAdapter: onBindViewHolder: called. Address name: https://i.imgur.com/ZcLLrkY.jpg
The above are some sample log outputs using images from the tutorial I followed. All links are clickable. No errors seem to be appearing in the logs.
A common problem is the position been final
#Override
public void onBindViewHolder(#NonNull ViewHolder holder, int position) {
Glide.with(mContext)
.load(mImageAddresses.get(holder.getAdapterPosition()))
.placeholder(R.drawable.ic_launcher_foreground)
.into(holder.image);
}

Unable to load an image from an URL in a RecyclerView

I can't seem to figure out why I haven't been able to load any sort of image (I've tried multiple URLs). I've tried using an AsyncTask class, and the issue still hasn't been resolved. My adapter class is listed below, any sort of help would be greatly appreciated.
I'm trying to load an image (in this test case, the same image) for each RecyclerView entry. The default view (an orange square) appears when I don't attempt to set an image derived from URL, but if I do attempt it, the ImageView is simply left blank.
EntryAdapter
public class EntryAdapter extends RecyclerView.Adapter<EntryAdapter.EntryViewHolder> {
private Entry[] mDataset;
// Provide a reference to the views for each data item
// Complex data items may need more than one view per item, and
// you provide access to all the views for a data item in a view holder
public static class EntryViewHolder extends RecyclerView.ViewHolder {
// each data item is just a string in this case
public String source;
public TextView textContent, title, label, author;
public ImageView thumbnail;
public CardView topCard, mainCard;
public EntryViewHolder(View v) {
super(v);
title = v.findViewById(R.id.title);
textContent = v.findViewById(R.id.textContent);
topCard = v.findViewById(R.id.top_card);
mainCard = v.findViewById(R.id.main_card);
thumbnail = mainCard.findViewById(R.id.thumbnail);
author = mainCard.findViewById(R.id.author);
label = topCard.findViewById(R.id.label);
}
}
// Provide a suitable constructor (depends on the kind of dataset)
public EntryAdapter(Entry[] myDataset) {
mDataset = myDataset;
}
// Create new views (invoked by the layout manager)
#Override
public EntryAdapter.EntryViewHolder onCreateViewHolder(ViewGroup parent,
int viewType) {
// create a new view
View v = LayoutInflater.from(parent.getContext())
.inflate(R.layout.entry_item_constraints, parent, false);
EntryViewHolder vh = new EntryViewHolder(v);
return vh;
}
// Replace the contents of a view (invoked by the layout manager)
#Override
public void onBindViewHolder(EntryViewHolder holder, int position) {
// - get element from your dataset at this position
// - replace the contents of the view with that element
holder.title.setText(mDataset[position].getTitle());
holder.label.setText(mDataset[position].getLabel());
holder.textContent.setText(mDataset[position].getTextContent());
holder.thumbnail.setImageDrawable(LoadImageFromWebOperations(mDataset[position].getThumbnail()));
holder.author.setText(mDataset[position].getAuthor());
//new DownloadImageTask(holder.thumbnail).execute(mDataset[position].getThumbnail());
}
// Return the size of your dataset (invoked by the layout manager)
#Override
public int getItemCount() {
return mDataset.length;
}
public static Drawable LoadImageFromWebOperations(String url) {
try {
InputStream is = (InputStream) new URL(url).getContent();
Drawable d = Drawable.createFromStream(is, "reddit_thumbnail");
return d;
} catch (Exception e) {
return null;
}
}
}
Try to use Glide to show images in RecyclerView which handles lazy loading for scrolling the list smoother. Also it cancels loading operation when the list is scrolled to make the performance and resource consumption better.
Glide.with(holder.thumbnail.getContext())
.load(mDataset[position].getThumbnail())
.into(holder.thumbnail);
In app level build.gradle:
repositories {
mavenCentral()
google()
}
dependencies {
implementation 'com.github.bumptech.glide:glide:4.8.0'
annotationProcessor 'com.github.bumptech.glide:compiler:4.8.0'
}
You can also use placeholder() method to specify an image (it may point to a drawable using resource id for example) to show it when the target image is not downloaded or unavailable.

Android Realm RecyclerView animations not working?

I have a RecyclerView which gets populated by a RealmRecyclerViewAdapter but somehow there are no animations playing when the data changes.
The adapter class uses multiple ViewHolders for different layouts but that should not affect animations right?
public class DiaryPageEntryAdapter extends RealmRecyclerViewAdapter<Entry, RecyclerView.ViewHolder> {
static class MealEntryViewHolder extends RecyclerView.ViewHolder {
#BindView(R.id.item_diary_entry_drink_title) TextView tvMealEntryTitle;
#BindView(R.id.item_diary_entry_meal_time) TextView tvMealEntryTime;
BindView(R.id.item_diary_entry_meal_bullet_list) RecyclerView rvBulletList;
MealEntryBulletAdapter bulletAdapter;
public MealEntryViewHolder(View itemView) {
super(itemView);
ButterKnife.bind(this, itemView);
this.bulletAdapter = new MealEntryBulletAdapter();
rvBulletList.setLayoutManager(new LinearLayoutManager(itemView.getContext()));
rvBulletList.setAdapter(this.bulletAdapter);
}
void bindData(MealEntry mealEntry) {
tvMealEntryTitle.setText(mealEntry.getTitle());
tvMealEntryTime.setText(DateTimeUtils.timeValueToText(itemView.getContext(), mealEntry.getTime()));
this.bulletAdapter.updateData(mealEntry.getConsumedMeals() ,mealEntry.getConsumedDrinks());
}
}
// Other ViewHolders
public DiaryPageEntryAdapter(#Nullable OrderedRealmCollection<Entry> data, boolean autoUpdate) {
super(data, autoUpdate, true);
}
#Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
switch (viewType) {
case MEAL_ENTRY:
// Inflate meal entry layout and then create a new meal view holder with it
View rowMeal = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_diary_entry_meal, parent, false);
return new MealEntryViewHolder(rowMeal);
// Other case options.
}
#Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
Entry entry = getItem(position);
if(Entry.isMealEntry(entry)) {
MealEntryViewHolder mealHolder = (MealEntryViewHolder) holder;
mealHolder.bindData(Entry.getMealEntryFromEntry(entry));
}
// Other if branches.
}
#Override
public int getItemViewType(int position) {
Entry entry = getItem(position);
if(Entry.isMealEntry(entry)) return MEAL_ENTRY;
// Other if branches.
}
The code for setting up the RecyclerView and adapter looks as following:
RecyclerView recyclerView = (RecyclerView) view.findViewById(R.id.frag_diary_page_rv_entries);
recyclerView.setLayoutManager(new LinearLayoutManager(getActivity()));
entryAdapter = new DiaryPageEntryAdapter(null, true);
recyclerView.setAdapter(entryAdapter);
The code that binds the data to the adapter is stated below:
RealmResults<Entry> sortedEntries = diaryEntry.getEntries()
.where()
.findAllSortedAsync("time");
entryAdapter.updateData(sortedEntries);
The auto-updates work fine but somehow no there is no animation when the data changes. A new entry simply appears but without animations. Furthermore I want a short animation to play once the RecyclerView is populated for the first time - an entrance animation similar to [http://anthony-skr.com/article/recyclerview-items-animation-with-rebound-effect][1].
Note: In my appĀ“s build.gradle file
dependencies {
// Other dependencies
compile 'io.realm:android-adapters:2.1.0'
}
In the Project build.gradle file:
dependencies {
classpath 'com.android.tools.build:gradle:2.3.2'
classpath "io.realm:realm-gradle-plugin:3.1.4"
}
From your code sample, it isn't easy to see where you call entryAdapter.updateDate() from, but calling this method continuously on every update will disable all animations as it just calls notifyDataSetChanged().
A more standard pattern would look like this:
RealmResults<Entry> sortedEntries = diaryEntry.getEntries()
.where()
.findAllSortedAsync("time");
entryAdapter = new DiaryPageEntryAdapter(sortedEntries, true);
recyclerView.setAdapter(entryAdapter);
Animations should work if you do the above.

Android: How to scroll a parentView when child containing recyclerView is scrolled

I have created an app that contains a viewPager inside the mainActivity, this viewPager contains 5 fragments, of which 4 are recyclerViews and one is a normal linearLayout containing some text...
Here is a screenshot of the app, not all tabs in the tablayout are visible:
Now, as you might have seen already, there isn't much space in the viewPager for the user to see anything, so they have to scroll too much to view things in the recylerView. I want to modify my app so that when the user tries to scroll inside the recyclerView, the visible part of the mainActivity is scrolled down till the recyclerView occupies the entire page and then the recyclerView begins to scroll normally.
Can someone please help me implement this type of scroll feature into my app. You can just check out this app for a reference to what I'm saying. Just open up any movie or tvSeries and then try scrolling, the mainActivity gets scrolled first and then the rest of the layout.... Can someone please help. I've already tried the solutions on stackOverflow and many of them don't work, I also tried to google for a solution, but didn't get anything useful....
Here is the code for my adapter:
public class cardViewAdapterCreditsCast extends RecyclerView.Adapter<cardViewAdapterCreditsCast.ViewHolder> {
private Context context;
private List<creditsModel> creditsModels;
public cardViewAdapterCreditsCast(Context context, List<creditsModel> creditsModels) {
this.context = context;
this.creditsModels = creditsModels;
}
#Override
public cardViewAdapterCreditsCast.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.new_cast_row, parent, false);
return new cardViewAdapterCreditsCast.ViewHolder(view);
}
#Override
public void onBindViewHolder(cardViewAdapterCreditsCast.ViewHolder holder, int position) {
final creditsModel creditsModel = creditsModels.get(position);
int tempNumber = holder.celebImage.getWidth();
holder.celebImage.setMinimumHeight(tempNumber);
holder.celebImage.setMaxHeight(tempNumber + 1);
String imagePath = "https://image.tmdb.org/t/p/w500" + creditsModel.getProfilePath();
holder.starringAs.setText(creditsModel.getCharacter());
holder.celebName.setText(creditsModel.getActorName());
if (creditsModel.getProfilePath() != null) {
Picasso.with(context).load(imagePath).transform(new CircleTransform()).into(holder.celebImage);
} else
holder.celebImage.setBackgroundResource(R.drawable.not_found);
}
#Override
public int getItemCount() {
return creditsModels.size();
}
public class ViewHolder extends RecyclerView.ViewHolder {
public ImageView celebImage;
public TextView celebName;
public TextView starringAs;
private LinearLayout linearLayout;
public ViewHolder(View itemView) {
super(itemView);
linearLayout = (LinearLayout) itemView.findViewById(R.id.castRowMainLinearLayout);
celebImage = (ImageView) itemView.findViewById(R.id.castRowImage);
celebName = (TextView) itemView.findViewById(R.id.castRowName);
starringAs = (TextView) itemView.findViewById(R.id.castRowAppearance);
}
}
}
Use nested Scrollview if there are more than one scrollview or recyclerview.
You can use a CoordinatorLayout to implement this easily.
Example, http://saulmm.github.io/mastering-coordinator
Documentation, https://developer.android.com/reference/android/support/design/widget/CoordinatorLayout.html

Categories