Firestore Recycler loads in one page (instance) but not another - android

I have a restaurant app with a food page that is populated by 2 Firestore recycler views. The weird this is one restaurant loads everything normal but the others fail. I have gone over the database and everything seems fine there but it just won't work. here are some images showing the differences:
PS how do i resize uploaded images?
As you can see there is no size option in the first pic but the 2nd pic has them.
here is my code:
the page:
private void setUpSizes() {
if (getIntent() != null)
foodId = getIntent().getStringExtra("foodid");
Log.d("TAG", "setUpSizes: "+foodId);
if (!foodId.isEmpty() && foodId != null) {
Log.d("TAG", "setUpSizes: "+foodId);
Query foodSizes = db.collectionGroup("sizes").whereEqualTo("id", foodId);
FirestoreRecyclerOptions<SizeOptionsModel> options = new FirestoreRecyclerOptions.Builder<SizeOptionsModel>()
.setQuery(foodSizes, SizeOptionsModel.class)
.build();
mSelectedFoodSizeAdapter = new SizeOptionsAdapter(options);
RecyclerView recyclerView = findViewById(R.id.size_recycler);
recyclerView.setHasFixedSize(true);
recyclerView.setLayoutManager(new LinearLayoutManager(this));
recyclerView.setAdapter(mSelectedFoodSizeAdapter);
}
}
}
#Override
protected void onStart() {
super.onStart();
mSelectedFoodExtrasAdapter.startListening();
mSelectedFoodSizeAdapter.startListening();
}
#Override
protected void onStop() {
super.onStop();
mSelectedFoodExtrasAdapter.stopListening();
mSelectedFoodSizeAdapter.stopListening();
}
}
the adapter:
private FoodSizesHolder holder;
private int mSelectedItem = -1;
private Context context;
public String getPriceFromAdapter() {
return priceFromAdapter;
}
private String priceFromAdapter;
public SizeOptionsAdapter(#NonNull FirestoreRecyclerOptions<SizeOptionsModel> options) {
super(options);
}
#Override
protected void onBindViewHolder(#NonNull FoodSizesHolder holder, int position, #NonNull SizeOptionsModel model) {
holder.food_size.setText(model.getName());
holder.food_size_price.setText(model.getPrice());
//Allow only one radio button to be checked
holder.food_size.setChecked(position == mSelectedItem);
//Auto select the first item
}
#Override
public int getItemCount() {
return super.getItemCount();
}
#NonNull
#Override
public FoodSizesHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.sizes_item, parent, false);
return new FoodSizesHolder(v);
}
class FoodSizesHolder extends RecyclerView.ViewHolder {
RadioButton food_size;
TextView food_size_price;
public FoodSizesHolder(#NonNull final View itemView) {
super(itemView);
food_size = itemView.findViewById(R.id.sizes_checkbox);
food_size_price = itemView.findViewById(R.id.sizes_prices);
if (food_size.isChecked()){
priceFromAdapter = String.valueOf(food_size_price.getText());
}
}
});
}
}
}

Related

Update RecyclerView with Firebase Values not working

I am working on a Bus app and visualized the seats of a bus in an activity using Recyclerview as follows
I am taking the no of available and booked seats from Firebase. What I want to do is
update the color of the seat according to the count of available
and booked seats.
For example, if booked seats: 2 then there should be 2 green-colored seats in the recycler view. Here is my code
SeatsFragment.java:
public class SeatsFragment extends Fragment {
public static int mCountSeat, mTotal;
public static StringBuffer mSb;
private int mSeatNo = 0;
private RecyclerView mRvViewSeats;
private ImageView mIvAvailable, mIvBooked;
private LinearLayout mLinear, mLlDack, mLlDynamic;
private List<AbstractItem> mAbstractItemsList;
private List<SeatModel> mSeatModelsItemsList;
private TextView tvAvailabe, tvBooked;
SeatAdapter adapter;
// Firebase
FirebaseDatabase database;
DatabaseReference seatsRef;
public SeatsFragment() {
// Required empty public constructor
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
View view = inflater.inflate(R.layout.fragment_seats, container, false);
tvAvailabe = view.findViewById(R.id.tvAvailableSeats);
tvBooked = view.findViewById(R.id.tvBookedSeats);
database = FirebaseDatabase.getInstance();
seatsRef = database.getReference(Common.SEATS_REFERENCE).child("2").child(Common.AVAILABLE_SEATS);
// Toast.makeText(getActivity(), seatsRef.toString(), Toast.LENGTH_SHORT).show();
seatsRef.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot snapshot) {
tvBooked.setText(snapshot.getValue().toString());
tvAvailabe.setText(String.valueOf(40 - (Long.parseLong(snapshot.getValue().toString()))));
mSeatModelsItemsList.add(new SeatModel(SeatType.AVAILABLE.BOOKED));
initializeSeats();
}
#Override
public void onCancelled(#NonNull DatabaseError error) {
}
});
return view;
}
#Override
public void onViewCreated(#NonNull View view, #Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
initLayouts(view);
initializeSeats();
}
/* initialize seats */
private void initializeSeats() {
mIvAvailable.setColorFilter(ContextCompat.getColor(getActivity(), R.color.view_color));
mIvBooked.setColorFilter(ContextCompat.getColor(getActivity(), R.color.colorPrimary));
for (int i = 0; i < 40; i++) {
mSeatModelsItemsList.add(new SeatModel(SeatType.BOOKED));
mSeatModelsItemsList.add(new SeatModel(SeatType.AVAILABLE));
int mCOLUMNS = 5;
if (i % mCOLUMNS == 0 || i % mCOLUMNS == 4) {
mSeatNo++;
mAbstractItemsList.add(new EdgeItem(String.valueOf(mSeatNo)));
} else if (i % mCOLUMNS == 1 || i % mCOLUMNS == 3) {
mSeatNo++;
mAbstractItemsList.add(new CenterItem(String.valueOf(mSeatNo)));
} else {
mAbstractItemsList.add(new EmptyItem(mSeatModelsItemsList));
}
GridLayoutManager mManager = new GridLayoutManager(getActivity(), mCOLUMNS);
mRvViewSeats.setLayoutManager(mManager);
adapter = new SeatAdapter(mSeatModelsItemsList, mAbstractItemsList, getActivity());
mRvViewSeats.setAdapter(adapter);
}
mSeatNo = 0;
}
private void initLayouts(View view) {
mLinear = view.findViewById(R.id.llOffer);
mIvAvailable = view.findViewById(R.id.ivAvailable);
mIvBooked = view.findViewById(R.id.ivSeatFragmentBooked);
mAbstractItemsList = new ArrayList<>();
mSeatModelsItemsList = new ArrayList<>();
mSb = new StringBuffer();
mRvViewSeats = view.findViewById(R.id.rvSeat);
mLlDack = view.findViewById(R.id.lvDack);
mLlDynamic = view.findViewById(R.id.llDynamicContent);
}
}
Look at the initializeSeats() method above. I've added two items(available and booked) to the list that is passed to the adapter. These items should be added according to the no of available and booked seats
e.g
if booked seats are 38, then 38 booked items should be added to the list
When I try to call initializeSeats() in the onDataChange() it adds the correct no of seats to list but
since seats are added through loop every time seats get doubled, 1st time 40,80 and so on.
SeatsAdapter.java:
public class SeatAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
private List<SeatModel> mSeatItem;
private List<AbstractItem> mItems;
private LayoutInflater mLayoutInflater;
private Context mCtx;
public SeatAdapter(List<SeatModel> mSeatItem, List<AbstractItem> mItems, Context mCtx) {
this.mSeatItem = mSeatItem;
this.mItems = mItems;
this.mCtx = mCtx;
mLayoutInflater = LayoutInflater.from(mCtx);
}
#NonNull
#Override
public RecyclerView.ViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
if (viewType == AbstractItem.TYPE_CENTER) {
View itemView = mLayoutInflater.inflate(R.layout.list_item_seat, parent, false);
return new CenterViewHolder(itemView);
} else if (viewType == AbstractItem.TYPE_EDGE) {
View itemView = mLayoutInflater.inflate(R.layout.list_item_seat, parent, false);
return new EdgeViewHolder(itemView);
} else {
View itemView = new View(mCtx);
return new EmptyViewHolder(itemView);
}
}
#Override
public void onBindViewHolder(#NonNull RecyclerView.ViewHolder holder, int position) {
int type = mItems.get(position).getType();
final SeatModel seatModel = mSeatItem.get(position);
if (type == AbstractItem.TYPE_CENTER) {
final CenterViewHolder centerViewHolder = (CenterViewHolder)holder;
if (seatModel.getSeatType().equals(SeatType.AVAILABLE)){
centerViewHolder.mIvSeat.setVisibility(View.VISIBLE);
} else {
centerViewHolder.mIvSeatBooked.setVisibility(View.VISIBLE);
}
} else if (type == AbstractItem.TYPE_EDGE) {
final EdgeViewHolder edgeViewHolder = (EdgeViewHolder) holder;
if (seatModel.getSeatType().equals(SeatType.AVAILABLE)){
edgeViewHolder.mIvSeat.setVisibility(View.VISIBLE);
} else {
edgeViewHolder.mIvSeatBooked.setVisibility(View.VISIBLE);
}
}
}
#Override
public int getItemCount() {
return mItems.size();
}
#Override
public int getItemViewType(int position) {
return mItems.get(position).getType();
}
/*view holder*/
private static class CenterViewHolder extends RecyclerView.ViewHolder {
private ImageView mIvSeat, mIvSeatBooked;
CenterViewHolder(View itemView) {
super(itemView);
mIvSeat = itemView.findViewById(R.id.ivSeat);
mIvSeatBooked = itemView.findViewById(R.id.ivSeatBooked);
}
}
/*view holder*/
private static class EdgeViewHolder extends RecyclerView.ViewHolder {
private ImageView mIvSeat, mIvSeatBooked;
EdgeViewHolder(View itemView) {
super(itemView);
mIvSeat = itemView.findViewById(R.id.ivSeat);
mIvSeatBooked = itemView.findViewById(R.id.ivSeatBooked);
}
}
/*view holder*/
private static class EmptyViewHolder extends RecyclerView.ViewHolder {
EmptyViewHolder(View itemView) {
super(itemView);
}
}
}
Any help or guidance would be appreciable.
Thank you.
You just keep on adding new data in your onDataChange callback, you should clear the data when you have a new data change.
There is no need to create new adapter each time, you create your adapter once and then you just notify about changes, you should add a method in your adapter that will take a new list so you can update it in other way not only though the constructor only.
I would strongly recommend taking a look at Diff Utils It is the best way to update data inside RecyclerView and the most performant.
There are many resources on it so you can find a lot about it.
Example: https://iammert.medium.com/using-diffutil-in-android-recyclerview-bdca8e4fbb00
Inside your value eventListener you need to clear the list every time, and because you are not doing this so every time the new data gets added to the older ones that's why you are facing this issue. Add this line mSeatModelsItemsList.clear();
Solution is here
seatsRef.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot snapshot) {
mSeatModelsItemsList.clear();// add this line
tvBooked.setText(snapshot.getValue().toString());
tvAvailabe.setText(String.valueOf(40 - (Long.parseLong(snapshot.getValue().toString()))));
mSeatModelsItemsList.add(new SeatModel(SeatType.AVAILABLE.BOOKED));
initializeSeats();
}
#Override
public void onCancelled(#NonNull DatabaseError error) {
}
});

Notifydatasetchanged() is causing blinking within child recyclerview

I am having an extremely hard time trying to disable animations for a nested recyclerview whenever the parent recyclerview calls ondatasetchanged(). So some context a recyclerview that holds tinder-like swap cards and a nested recyclerview within each card to scroll through user images. After every swipe ondatasetchanged is called and causing a bad flickering within the nested recyclerview. I have tried to disabled the animations from both parent and child recyclerviews and pretty much anything I can think of at this point. The code below is my view holder for each card.
public class CardStackHolder extends RecyclerView.ViewHolder implements OnItemSwipePercentageListener {
ImageButton profileInfoBtn;
RecyclerView images_recyclerView;
PagerSnapHelper snapHelper;
ProfileImagesAdapter imagesAdapter;
String profileName;
TextView nameBox;
TextView ageBox;
TextView workBox;
List<String> list;
public CardStackHolder(final View itemView) {
super(itemView);
profileInfoBtn = (ImageButton) itemView.findViewById(R.id.ID_datingRecyclerView_profileInfoBtn);
profileInfoBtn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
//show profile info dialog
User_Info_Dialog dialog = User_Info_Dialog.getDialog(mHostId, mCurrentProfile.getGender(), mCurrentProfile.getOrientation(), mCurrentProfile.getInterestedIn(), mCurrentProfile.getIntro(), mCurrentProfile.getStatus());
dialog.show(getChildFragmentManager(), "");
}
});
nameBox = (TextView) itemView.findViewById(R.id.ID_datingRecyclerView_profile_name);
ageBox = (TextView) itemView.findViewById(R.id.ID_datingRecyclerView_profile_age);
images_recyclerView = (RecyclerView) itemView.findViewById(R.id.ID_datingRecyclerView_profileImagesRecyclerView);
RecyclerView.ItemAnimator animator = images_recyclerView.getItemAnimator();
((SimpleItemAnimator) animator).setSupportsChangeAnimations(false);
animator.setChangeDuration(0);
animator.setRemoveDuration(0);
images_recyclerView.setLayoutManager(new LinearLayoutManager(mContext));
snapHelper = new PagerSnapHelper();
snapHelper.attachToRecyclerView(images_recyclerView);
workBox = (TextView) itemView.findViewById(R.id.ID_datingRecyclerView_profile_work);
}
public void onBind(Context context, User_Profile profile) {
getImages(profile.getProfileId());
profileName = profile.getFirst_name();
profileName = profileName.substring(0, 1).toUpperCase() + profileName.substring(1);
nameBox.setText(profileName);
ageBox.setText(profile.getAge());
String workStr = profile.getWork();
workStr = workStr.substring(0, 1).toUpperCase() + workStr.substring(1);
workBox.setText(workStr);
mCurrentProfile = profile;
}
public void getImages(String id) {
mFirebaseDatabase.getReference().child("profile_pictures").child(id).addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
if (dataSnapshot.exists()) {
list = new ArrayList<>();
for (DataSnapshot snapshot : dataSnapshot.getChildren()) {
if (snapshot.hasChild("dating_card_imagePath")) {
list.add(snapshot.child("dating_card_imagePath").getValue().toString());
}
}
imagesAdapter = new ProfileImagesAdapter(list);
imagesAdapter.setHasStableIds(true);
images_recyclerView.setAdapter(imagesAdapter);
} else {
// no images found for profile
imagesAdapter = new ProfileImagesAdapter();
imagesAdapter.setHasStableIds(true);
images_recyclerView.setAdapter(imagesAdapter);
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
}
#Override
public void onItemSwipePercentage(double percentage) {
//log percentage moved
//Log.d("Enchanted", Double.toString(percentage));
if (percentage > -0.20 && percentage < 0.20) {
swipeResultImageView.setVisibility(View.GONE);
} else if (percentage < 0.20) {
swipeResultImageView.setImageResource(R.drawable.ic_swipe_no_like);
swipeResultImageView.setVisibility(View.VISIBLE);
} else if (percentage > -0.20) {
swipeResultImageView.setImageResource(R.drawable.ic_swipe_like);
swipeResultImageView.setVisibility(View.VISIBLE);
}
}
}
code below is my adapter
//CardStack Adapter
class CardStackAdapter extends RecyclerView.Adapter<CardStackHolder> {
LayoutInflater mInflater;
List<User_Profile> profileList;
RecyclerView.RecycledViewPool ImagePool;
public CardStackAdapter(Context context, List<User_Profile> list) {
mInflater = LayoutInflater.from(context);
profileList = new ArrayList<>(list);
ImagePool = new RecyclerView.RecycledViewPool();
}
#Override
public CardStackHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = mInflater.inflate(R.layout.recyclerview_item_dating_profile_card, parent, false);
return new CardStackHolder(view);
}
#Override
public void onBindViewHolder(final CardStackHolder holder, int position) {
holder.images_recyclerView.setRecycledViewPool(ImagePool);
profileList.get(position).setItemId(holder.getItemId());
holder.onBind(mContext, profileList.get(position));
}
public void removeTopItem() {
profileList.remove(0);
notifyDataSetChanged();
}
public void addItemToTop() {
profileList.add(0, mPreviousProfile);
notifyItemInserted(0);
}
public void updateProfileList(List<User_Profile> p) {
ImagePool.clear();
profileList.clear();
profileList.addAll(p);
notifyDataSetChanged();
}
#Override
public int getItemViewType(int position) {
return super.getItemViewType(position);
}
#Override
public int getItemCount() {
return profileList.size();
}
#Override
public long getItemId(int position) {
return profileList.get(position).getItemId();
}
}
Why are you calling notifyDataSetChanged() inside removeTopItem()?
Using notifyDataSetChanged() recreate all views again. You can notify recyclerview in which position item removed.
public void removeTopItem() {
profileList.remove(0);
notifyItemRemoved(0);
}

FirebaseRecyclerAdapter duplicating the objects in recycle view

My Structure:
I am developing a chat app by using firebase realtime database. I am using FirebaseRecyclerAdapter to display messages. But the thing is on scrolling, messages get duplicated and out of order.
Here is my implementation:
public class FirebaseChatActivity extends AppCompatActivity {
private String messageSenderId;
private String messageReceiverId;
private FirebaseRecyclerAdapter<ChatMessage, MessageViewHolder> firebaseRecyclerAdapter;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_firebase_chat);
RecyclerView recyclerView = findViewById(R.id.rv_firebase_chat_activity);
recyclerView.setLayoutManager(new LinearLayoutManager(this));
messageSenderId = "eoSU5m7PyucyC9h30JfHhV6S8Av2";
messageReceiverId = "ZOqofCid0XN5ovIAj1mXhRYxdnO2";
DatabaseReference rootRef = FirebaseDatabase.getInstance().getReference();
Query query = rootRef.child("messages").child(messageSenderId).child(messageReceiverId);
FirebaseRecyclerOptions<ChatMessage> firebaseRecyclerOptions = new FirebaseRecyclerOptions.Builder<ChatMessage>()
.setQuery(query, ChatMessage.class)
.build();
firebaseRecyclerAdapter = new FirebaseRecyclerAdapter<ChatMessage, MessageViewHolder>(firebaseRecyclerOptions) {
#Override
protected void onBindViewHolder(#NonNull MessageViewHolder messageViewHolder, int position, #NonNull ChatMessage message) {
if (message.getMessageType().equals("text")) {
messageViewHolder.showMessage.setText(message.getMessageText());
} else if (message.getMessageType().equals("image")) {
try {
Glide.with(getApplicationContext())
.load(message.getPhotoUrl())
.placeholder(R.drawable.no_image2)
.error(R.drawable.image_1)
.into(messageViewHolder.photoImageView);
} catch (Exception e) {
Log.d("MessageAdapterLog", e.toString());
}
}
}
#Override
public MessageViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
android.view.View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.chat_item_right, parent, false);
return new MessageViewHolder(view);
}
};
recyclerView.setAdapter(firebaseRecyclerAdapter);
}
private class MessageViewHolder extends RecyclerView.ViewHolder {
public TextView showMessage;
public ImageView photoImageView;
public MessageViewHolder(#NonNull android.view.View itemView) {
super(itemView);
showMessage = itemView.findViewById(R.id.show_message);
photoImageView = itemView.findViewById(R.id.photo_image_view);
}
}
#Override
protected void onStart() {
super.onStart();
firebaseRecyclerAdapter.startListening();
}
#Override
protected void onStop() {
super.onStop();
if (firebaseRecyclerAdapter!= null) {
firebaseRecyclerAdapter.stopListening();
}
}
}
I have tried many different solutions e.g set as mentioned here as well as .addChildEventListener (completely different implementation) but unable to solve the issue.
Full Activity code as well as database structure is attached. Kindly let me know what I am doing wrong.
Thanks
The problem is that everytime you scroll, to make a new item visible again it will run the code inside your onBindViewHolder to inflate that view and rebind it.
if (message.getMessageType().equals("text")) {
messageViewHolder.showMessage.setText(message.getMessageText());
} else if (message.getMessageType().equals("image")) {
try {
Glide.with(getApplicationContext())
.load(message.getPhotoUrl())
.placeholder(R.drawable.no_image2)
.error(R.drawable.image_1)
.into(messageViewHolder.photoImageView);
} catch (Exception e) {
Log.d("MessageAdapterLog", e.toString());
}
}
}
to solve this problem you will need to override two methods inside your adapter
#Override
public long getItemId(int position) {
return position;
}
#Override
public int getItemViewType(int position) {
return position;
}

Admob banner ads making my recyclerview lag

I am showing banner ads within my android app. I followed official doc for implementing admob banner contentView ads and I successfully loaded ads but now my recyclerview starts lagging like hell. If i remove ads from my code scroll becomes smooth. Please help me with this problem.
Here's my fragment class
public class WallpaperFragment extends Fragment {
private RecyclerView recyclerView;
private DatabaseReference wallRef;
private String category;
private FirebaseAuth mAuth;
private final String CATEGORY = "Category";
private Context context;
private ArrayList<Object> modelList = new ArrayList<>();
private GridLayoutManager manager;
// The number of native ads to load and display.
public int NUMBER_OF_ADS = 5;
// List of native ads that have been successfully loaded.
private List<NativeAd> mNativeAds = new ArrayList<>();
private WallpaperAdapter adapter;
#Nullable
#Override
public View onCreateView(#NonNull LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fg_wallpaper, container, false);
category = "Recent";
init(view);
Util.showDialog(context, "Loading wallpapers...");
manager.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() {
#Override
public int getSpanSize(int position) {
return (position % (SPACE_BETWEEN_ADS + 1) == SPACE_BETWEEN_ADS) ? 2 : 1;
}
});
setScrollListener();
initializeFirebaseDatabase();
return view;
}
private void init(View view) {
context = getContext();
MobileAds.initialize(context, getString(R.string.admob_app_id));
wallRef = FirebaseDatabase.getInstance().getReference().child(WALL).child(CATEGORY).child(category).getRef();
mAuth = FirebaseAuth.getInstance();
recyclerView = view.findViewById(R.id.recyclerView);
manager = new GridLayoutManager(context, 2, GridLayoutManager.VERTICAL, false);
recyclerView.setLayoutManager(manager);
recyclerView.addItemDecoration(new GridItemDecor(0));
recyclerView.setHasFixedSize(true);
recyclerView.setItemAnimator(null);
}
private void setScrollListener() {
recyclerView.addOnScrollListener(new HidingScrollListener() {
#Override
public void onHide() {
if (context instanceof ToolbarShowHideListener) {
((ToolbarShowHideListener) context).hideBottomNavigation();
}
}
#Override
public void onShow() {
if (context instanceof ToolbarShowHideListener) {
((ToolbarShowHideListener) context).showBottomNavigation();
}
}
});
}
private void initializeFirebaseDatabase() {
mNativeAds.clear();
wallRef.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
modelList.clear();
for (DataSnapshot childDataSnapshot : dataSnapshot.getChildren()) {
WallpaperModel model = childDataSnapshot.getValue(WallpaperModel.class);
modelList.add(model);
}
NUMBER_OF_ADS = modelList.size() / 2;
loadNativeAd();
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
}
});
}
private void loadNativeAd() {
loadNativeAd(0);
}
private void insertAdsInMenuItems() {
if (mNativeAds.size() <= 0) {
return;
}
int offset = (modelList.size() / mNativeAds.size()) + 1;
int index = 2;
for (NativeAd ad : mNativeAds) {
modelList.add(index, ad);
index = index + offset;
}
if (adapter == null) {
adapter = new WallpaperAdapter(context, modelList, Objects.requireNonNull(mAuth.getCurrentUser()).getUid(), true, WALLPAPER_FRAGMENT);
recyclerView.setAdapter(adapter);
} else {
adapter.updateList(modelList);
}
}
private void loadNativeAd(final int adLoadCount) {
if (adLoadCount >= NUMBER_OF_ADS) {
insertAdsInMenuItems();
return;
}
AdLoader.Builder builder = new AdLoader.Builder(context, /*getString(R.string.ad_unit_id)*/"ca-app-pub-3940256099942544/2247696110");
AdLoader adLoader = builder.forContentAd(new NativeContentAd.OnContentAdLoadedListener() {
#Override
public void onContentAdLoaded(NativeContentAd ad) {
// A content ad loaded successfully, call this method again to
// load the next ad in the items list.
mNativeAds.add(ad);
loadNativeAd(adLoadCount + 1);
}
}).withAdListener(new AdListener() {
#Override
public void onAdFailedToLoad(int errorCode) {
// A native ad failed to load. Call this method again to load
// the next ad in the items list.
Log.e("MainActivity", "The previous native ad failed to load. Attempting to" +
" load another.");
loadNativeAd(adLoadCount + 1);
}
}).build();
// Load the Native Express ad.
adLoader.loadAd(new AdRequest.Builder().addTestDevice("9F50A23B86C21B90330202FAECE3C331").build());
}
}
and here's my adapter class,
public class WallpaperAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
private Context context;
private int height, fragment_id;
private String uId;
private Animation fadeout, fadein;
private DatabaseReference favCheckRef;
private final String CATEGORY = "Category";
private ArrayList<Object> modelList;
private boolean showLikeBtn;
public WallpaperAdapter(Context context, ArrayList<Object> modelList, String uId, boolean showLikeBtn, int fragment_id) {
this.context = context;
this.modelList = modelList;
this.uId = uId;
this.showLikeBtn = showLikeBtn;
height = context.getResources().getDisplayMetrics().heightPixels;
fadeout = AnimationUtils.loadAnimation(context, R.anim.anim_fade_out);
fadein = AnimationUtils.loadAnimation(context, R.anim.anim_fade_in);
favCheckRef = FirebaseDatabase.getInstance().getReference().child(WALL).child(USER)
.child(uId).child(FAVOURITES).getRef();
this.fragment_id = fragment_id;
}
#NonNull
#Override
public RecyclerView.ViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
switch (viewType) {
case NATIVE_CONTENT_AD_VIEW_TYPE:
View nativeContentLayoutView = LayoutInflater.from(
parent.getContext()).inflate(R.layout.ad_content,
parent, false);
return new NativeContentAdViewHolder(nativeContentLayoutView);
case MENU_ITEM_VIEW_TYPE:
// Fall through.
default:
View dataView = LayoutInflater.from(context).inflate(R.layout.single_wallpaper_unit, parent, false);
return new ViewHolder(dataView);
}
}
#Override
public void onBindViewHolder(#NonNull RecyclerView.ViewHolder holder, int position) {
int viewType = getItemViewType(position);
Util.dismissDialog();
switch (viewType) {
case NATIVE_CONTENT_AD_VIEW_TYPE:
NativeContentAd contentAd = (NativeContentAd) modelList.get(position);
populateAdView(contentAd, (NativeContentAdView) holder.itemView);
break;
case MENU_ITEM_VIEW_TYPE:
// fall through
default:
final ViewHolder wallHolder = (ViewHolder) holder;
WallpaperModel model = (WallpaperModel) modelList.get(position);
wallHolder.wallpaper.getLayoutParams().height = (int) (height / 2.5);
wallHolder.name.setText(model.getName());
favCheck(wallHolder, model);
Glide.with(wallHolder.wallpaper.getContext())
.load(model.getThumbnail())
.into(wallHolder.wallpaper);
break;
}
}
#Override
public int getItemViewType(int position) {
Object recyclerViewItem = modelList.get(position);
if (recyclerViewItem instanceof NativeContentAd) {
return NATIVE_CONTENT_AD_VIEW_TYPE;
}
return MENU_ITEM_VIEW_TYPE;
}
#Override
public int getItemCount() {
return modelList.size();
}
private void populateAdView(NativeContentAd ad,NativeContentAdView adView){
((TextView) adView.getHeadlineView()).setText(ad.getHeadline());
List<NativeAd.Image> images = ad.getImages();
if (images.size() > 0) {
((ImageView) adView.getImageView()).setImageDrawable(images.get(0).getDrawable());
}
adView.setNativeAd(ad);
}
public class ViewHolder extends RecyclerView.ViewHolder {
TextView name;
ImageView wallpaper, favouriteIcon;
private ViewHolder(View itemView) {
super(itemView);
wallpaper = itemView.findViewById(R.id.wallpaper);
name = itemView.findViewById(R.id.name);
favouriteIcon = itemView.findViewById(R.id.favouriteIcon);
}
}
public class NativeContentAdViewHolder extends RecyclerView.ViewHolder {
NativeContentAdViewHolder(View view) {
super(view);
NativeContentAdView adView = (NativeContentAdView) view;
adView.setHeadlineView(adView.findViewById(R.id.contentad_headline));
adView.setImageView(adView.findViewById(R.id.contentad_image));
}
}
}
You are loading native express, not banner.
The problem is the ads have images, just like a normal viewholder, you have to handel the caching of the images, I see you already use glide...
Also, it's not a good idea showing your ad ID.
Last thing, NONE of this matters because native express ads are deprecated and will anyway not work.
Another option is to use Native Ads Advance, but unless you have a few million downloads you will not be able to use it - look here:
Note: Native Ads Advanced is currently released to a limited set of publishers. If you're interested in participating, reach out to your account manager to discuss the possibility.
What I would suggest is using some ad provider like Appodeal which supports native ads.

Android Button Click Event is fired multiple times in implemeting a recycler view with search filter?

I am working in Xamarin Android. I have implemented a recycler view with list of patients. I have also implemented a search view to filter the list of patients searched. I have a button click event inside the OnBindViewHolder which becomes called multiple times, whenever I implement a search as the list gets updated. If I dont filter patients, the button is initialized only once so, I have no problem in that. But if I perform a search filter the button becomes initialized again and again so whenever I click a button I go into another activity "NewActivity" multiple times. How can I solve this? The "populateRecyclerView" will be called after running a query which I have not mentioned here.
My RecylerAdapter.cs
public class PatientRecyclerAdapter : RecyclerView.Adapter
{
private Context context;
private List<Patient> patientList, filteredPatientList;
public event EventHandler<CheckInClickArgs> CheckInClicked;
MyHolder myholder;
public class CheckInClickArgs : EventArgs
{
public Patient selectedPatient { get; set; }
}
public PatientRecyclerAdapter(Context context, List<Patient> patientList)
{
this.context = context;
this.patientList = patientList;
this.filteredPatientList = patientList;
}
public override int ItemCount
{
get { return filteredPatientList.Count; }
}
public override void OnBindViewHolder(RecyclerView.ViewHolder holder, int position)
{
myholder = (MyHolder)holder;
Patient patient = filteredPatientList[position];
myholder.tvPatientName.Text = patient.Fullname;
myholder.btnCheckIn.Click += (sender, e) =>
{
if (CheckInClicked != null)
{
CheckInClicked(this, new CheckInClickArgs { selectedPatient = patient });
}
}
public override RecyclerView.ViewHolder OnCreateViewHolder(ViewGroup parent, int viewType)
{
View view = LayoutInflater.From(parent.Context).Inflate(Resource.Layout.layout_patientCardViewRecyler, parent, false);
MyHolder holder = new MyHolder(view);
return holder;
}
public void filter(string searchText)
{
searchText = searchText.ToLower();
this.filteredPatientList = patientList.Where(x => x.Fullname.ToLower().Contains(searchText)).ToList();
}
}
class MyHolder : RecyclerView.ViewHolder
{
public TextView tvPatientName;
public Button btnCheckIn;
public MyHolder(View itemView) : base(itemView)
{
tvPatientName = itemView.FindViewById<TextView>(Resource.Id.textViewPatientName);
btnCheckIn = itemView.FindViewById<Button>(Resource.Id.btnCheckIn);
}
}
PatientsTabFragment.cs
public class PatientsTabFragment : Android.Support.V4.App.Fragment, ITextWatcher, TextView.IOnEditorActionListener
{
private Android.Views.View view;
private RecyclerView recyclerView;
private RecyclerView.LayoutManager recyclerview_layoutmanager;
private PatientRecyclerAdapter recyclerview_adapter;
private EditText etSearchView;
public override Android.Views.View OnCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
view = inflater.Inflate(Resource.Layout.fragment_patients_tab, container, false);
etSearchView = view.FindViewById<EditText>(Resource.Id.etSearchView);
return view;
}
void populateRecyclerView(List<Patient> patient)
{
recyclerView = view.FindViewById<RecyclerView>(Resource.Id.recyclerViewPatient);
recyclerview_layoutmanager = new LinearLayoutManager(this.Activity, LinearLayoutManager.Vertical, false);
recyclerView.SetLayoutManager(recyclerview_layoutmanager);
recyclerview_adapter = new PatientRecyclerAdapter(this.Activity, patient);
recyclerView.SetAdapter(recyclerview_adapter);
etSearchView.AddTextChangedListener(this);
recyclerview_adapter.CheckInClicked += (sender, e) =>
{
AppController.SelectedPatient = e.selectedPatient;
Activity.StartActivity(typeof(NewActivity));
};
}
public void OnTextChanged(ICharSequence s, int start, int before, int count)
{
recyclerview_adapter.filter(s.ToString());
recyclerview_adapter.NotifyDataSetChanged();
}
On your Bind you have set your click this way. this is set only click
so change you this code
myholder.btnCheckIn.Click += (sender, e) =>
{
if (CheckInClicked != null)
{
CheckInClicked(this, new CheckInClickArgs { selectedPatient = patient });
}
to this
if(!myholder.btnCheckIn.HasOnClickListeners)
{
myholder.btnCheckIn.Click += (sender, e) =>
{
if (CheckInClicked != null)
{
CheckInClicked(this, new CheckInClickArgs { selectedPatient = patient });
}
}
}
EDIT :
change your this code because the problem is in your position. you have to set Adapter Position which will give the correct position of Button Click see below code.
myholder = (MyHolder)holder;
Patient patient = filteredPatientList[myholder.AdapterPosition];
myholder.tvPatientName.Text = patient.Fullname;

Categories

Resources