This question already has an answer here:
Deleting row from recycler view and firebase
(1 answer)
Closed 3 years ago.
I want to remove an item from my recyclerview using an if condition
Here is my code for my adapter class. What I want to do is remove from displaying if its status is equal to unlive I'm retrieving the data from firebase
ArrayList<Adapter_Hotels> hotelsList;
Context context;
public Hotels_Adapter(ArrayList<Adapter_Hotels> list, Context context) {
this.hotelsList = list;
this.context = context;
}
#NonNull
#Override
public MyHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(context).inflate(R.layout.listview_layout, parent, false);
return new MyHolder(view);
}
#Override
public void onBindViewHolder(#NonNull MyHolder holder, int i) {
holder.hName.setText(hotelsList.get(i).getTitle());
holder.hAddress.setText(hotelsList.get(i).getProvince() + ", " + hotelsList.get(i).getCountry());
Picasso.get().load(hotelsList.get(i).getUrl_path()).fit().into(holder.hImage);
String status = hotelsList.get(i).getStatus();
if (status.equals("unlive")) {
removeItem(holder.getAdapterPosition());
}
}
#Override
public int getItemCount() {
return hotelsList.size();
}
public void removeItem(int position){
hotelsList.remove(position);
this.notifyItemRemoved(position);
}
My activity code
mRef.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
for (DataSnapshot hotelsSnapshot : dataSnapshot.getChildren()) {
Adapter_Hotels hotels = hotelsSnapshot.getValue(Adapter_Hotels.class);
String hotel_status = hotels.getStatus();
String hotel_name = hotels.getTitle();
String hotel_image = hotels.getUrl_path();
String hotel_province = hotels.getProvince();
String hotel_country = hotels.getCountry();
String hn = hotels.setTitle(hotel_name);
String hi = hotels.setUrl_path(hotel_image);
String hp = hotels.setProvince(hotel_province);
String hc = hotels.setCountry(hotel_country);
String hs = hotels.setStatus(hotel_status);
hotelList.add(new Adapter_Hotels(hn, hi, hc, hp, hs));
Log.v("DSDS", String.valueOf(hotelList.size()));
dialog.dismiss();
getActivity().getWindow().clearFlags(WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE);
}
hotelsAdapter.notifyDataSetChanged();
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
throw databaseError.toException();
}
});
hotelsAdapter = new Hotels_Adapter(hotelList, getContext());
mListview.setLayoutManager(new LinearLayoutManager(getContext()));
mListview.setAdapter(hotelsAdapter);
To remove, you can add this line
hotelList.remove(getAdapterPosition());
Perform the above code inside onLongClick() method in the ViewHolder class.
#Override
public boolean onLongClick(View view) {
//You can generate one list from which user can choose to delete.
hotelList.remove(getAdapterPosition());
return true;
}
Hi there ! why don't you remove the line of your list before pass that to the adapter ?
You can define function in your Activity to do this , and then pass the final list to your adapter
Related
how are you? I am trying to add Google AdMob native ads to a recyclerview feed. I followed the instructions provided by the Google Developer Codelabs here. https://codelabs.developers.google.com/codelabs/admob-native-advanced-feed-android/#0. It mostly worked. I have the ads inserted and posts being displayed. But the problem is, I think, the number of total items to be displayed, my app's posts plus the ads. I'm testing it, so there are only four posts to be displayed plus one native ad. But the feed is only returning three posts plus the one ad. Here is the Home Activity:
private PostAdapter postAdapter;
private List<Post> postList;
private List<String> followingList;
List<Object> mRecyclerViewItems = new ArrayList<>();
public static final int NUMBER_OF_ADS = 1;
// The AdLoader used to load ads.
private AdLoader adLoader;
// List of native ads that have been successfully loaded.
private List<UnifiedNativeAd> mNativeAds = new ArrayList<>();
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_home);
mContext = HomeActivity.this;
setupRecyclerView();
loadNativeAds();
}
private void insertAdsInMenuItems() {
if (mNativeAds.size() <= 0) {
return;
}
int offset = (mRecyclerViewItems.size() / mNativeAds.size()) + 1;
Log.d(TAG, "insertAdsInMenuItems: m native ads value: " + mNativeAds);
Log.d(TAG, "insertAdsInMenuItems: post list value: " + postList);
Log.d(TAG, "insertAdsInMenuItems: offset value: " + offset);
int index = 0;
for (UnifiedNativeAd ad: mNativeAds) {
mRecyclerViewItems.add(index, ad);
index = index + offset;
Log.d(TAG, "insertAdsInMenuItems: index value: " + index);
}
}
private void loadNativeAds() {
AdLoader.Builder builder = new AdLoader.Builder(this, getString(R.string.ad_mob_native_ad_id));
adLoader = builder.forUnifiedNativeAd(
new UnifiedNativeAd.OnUnifiedNativeAdLoadedListener() {
#Override
public void onUnifiedNativeAdLoaded(UnifiedNativeAd unifiedNativeAd) {
// A native ad loaded successfully, check if the ad loader has finished loading
// and if so, insert the ads into the list.
mNativeAds.add(unifiedNativeAd);
if (!adLoader.isLoading()) {
insertAdsInMenuItems();
}
}
}).withAdListener(
new AdListener() {
#Override
public void onAdFailedToLoad(int errorCode) {
// A native ad failed to load, check if the ad loader has finished loading
// and if so, insert the ads into the list.
Log.e("MainActivity", "The previous native ad failed to load. Attempting to"
+ " load another.");
if (!adLoader.isLoading()) {
insertAdsInMenuItems();
}
}
}).build();
// Load the Native Express ad.
adLoader.loadAds(new AdRequest.Builder().build(), NUMBER_OF_ADS);
}
private void setupRecyclerView(){
recyclerView = findViewById(R.id.recycler_view_posts);
recyclerView.setHasFixedSize(true);
LinearLayoutManager linearLayoutManager = new LinearLayoutManager(mContext);
linearLayoutManager.setReverseLayout(true);
linearLayoutManager.setStackFromEnd(true);
recyclerView.setLayoutManager(linearLayoutManager);
postList = new ArrayList<>();
postAdapter = new PostAdapter(getApplicationContext(), postList, mRecyclerViewItems);
recyclerView.setAdapter(postAdapter);
checkFollowing();
}
private void checkFollowing(){
Log.d(TAG, "checkFollowing: compile following list...");
followingList = new ArrayList<>();
DatabaseReference reference = FirebaseDatabase.getInstance().getReference().child("following").child(currentUserID);
reference.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
followingList.clear();
for (DataSnapshot snapshot : dataSnapshot.getChildren()){
followingList.add(snapshot.getKey());
Log.d(TAG, "checkFollowing: following list array" + followingList);
}
displayPosts();
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
}
});
}
private void displayPosts(){
Log.d(TAG, "displayPosts: running....");
allPostsReference.orderByKey().addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
postList.clear();
for (DataSnapshot snapshot : dataSnapshot.getChildren()){
try{
Post post = snapshot.getValue(Post.class);
for (String id : followingList){
if (post.getUser_id().equals(id)){
postList.add(post);
}
}try{
if (post.getUser_id().equals(currentUserID)){
postList.add(post);
}
}catch (NullPointerException e){
e.getMessage();
}
int postCount = (int)dataSnapshot.getChildrenCount();
Log.d(TAG, "displayPosts: post count of my timeline: " + postCount);
}catch (NullPointerException e){
e.getMessage();
}catch (DatabaseException e){
e.getMessage();
}
}
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
}
});
}
That's how I am adding the native ads to mRecyclerViewItems and all of the posts to postList. The checkFollowing method is displaying only posts of those I am following, which at this point, is all of the posts in the Firebase Realtime Database. And this is the relevant portions of the Post Adapter class:
public class PostAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
private static final String TAG = "PostAdapter";
// A menu item view type.
private static final int MENU_ITEM_VIEW_TYPE = 0;
// The unified native ad view type.
private static final int UNIFIED_NATIVE_AD_VIEW_TYPE = 1;
public Context mContext;
public List<Post> mPost;
public List<Object> mRecyclerViewItems;
public PostAdapter(Context mContext, List<Post> mPost, List<Object> mRecyclerViewItems) {
this.mContext = mContext;
this.mPost = mPost;
this.mRecyclerViewItems = mRecyclerViewItems;
}
#NonNull
#Override
public RecyclerView.ViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
switch (viewType){
case UNIFIED_NATIVE_AD_VIEW_TYPE:
View unifiedNativeLayoutView = LayoutInflater.from(
parent.getContext()).inflate(R.layout.layout_native_express_ad_container, parent, false);
return new UnifiedNativeAdViewHolder(unifiedNativeLayoutView);
case MENU_ITEM_VIEW_TYPE:
//fall through
default:
View view = LayoutInflater.from(mContext).inflate(R.layout.layout_post_item, parent, false);
return new PostViewHolder(view);
}
}
#Override
public void onBindViewHolder(#NonNull final RecyclerView.ViewHolder holder, int position) {
int viewType = getItemViewType(position);
switch (viewType){
case UNIFIED_NATIVE_AD_VIEW_TYPE:
UnifiedNativeAd nativeAd = (UnifiedNativeAd) mRecyclerViewItems.get(position);
populateNativeAdView(nativeAd, ((UnifiedNativeAdViewHolder) holder).getAdView());
break;
case MENU_ITEM_VIEW_TYPE:
//follow through
default:
final PostViewHolder postViewHolder = (PostViewHolder) holder;
Post post = (Post) mPost.get(position);
final String postKey = post.getPost_key();
mAuth = FirebaseAuth.getInstance();
currentUserID = mAuth.getCurrentUser().getUid();
publicUserReference = FirebaseDatabase.getInstance().getReference().child("public_user");
allPostsReference = FirebaseDatabase.getInstance().getReference().child("all_posts");
//some sample methods
postViewHolder.setInitialLayouts(postKey);
mVotes.setTextForVoteButtons(postKey, postViewHolder.voteOne, postViewHolder.voteTwo, postViewHolder.voteThree, postViewHolder.voteFour);
postViewHolder.getProfilephotoFullnameUsername(postKey);
postViewHolder.getVoteText(postKey);
postViewHolder.getDate(postKey);
postViewHolder.displayPhoto(postKey);
}
#Override
public int getItemCount() {
return mPost.size() + mRecyclerViewItems.size();
}
#Override
public int getItemViewType(int position) {
try{
Object recyclerViewItem = mRecyclerViewItems.get(position);
if (recyclerViewItem instanceof UnifiedNativeAd) {
return UNIFIED_NATIVE_AD_VIEW_TYPE;
}
}catch (IndexOutOfBoundsException e){
e.printStackTrace();
}
return MENU_ITEM_VIEW_TYPE;
}
Sorry if that's a lot of code, I am just kind of confused. Like I said, only three of my four posts in the database are being returned. It's as if the native ad is taking its place instead of being added into the feed along with the post items. Is there something I am missing? Should I be sending something different from Home Activity to the Post Adapter? Any help would be appreciated. Thank you.
So you have List<Post> and Ads two types of Data need to present into a single RecyclerView .So now you need to merge both data into 1 single data source to be used in the RecyclerView.
Here is the example:
First: Create a data class that combine Post and Ads named PostAdsData:
public class PostAdsData {
public int getType() {
return type;
}
public UnifiedNativeAd getAds() {
return ads;
}
public Post getPost() {
return post;
}
public int type; // 1 is ads and 2 is post
public UnifiedNativeAd ads;
public Post post;
}
Second: Your adapter should look like this:
public class YourAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
// A menu item view type.
private static final int MENU_ITEM_VIEW_TYPE = 0;
// The unified native ad view type.
private static final int UNIFIED_NATIVE_AD_VIEW_TYPE = 1;
public List<PostAdsData> postAdsDataList;
public PostAdapter(Context mContext) {
this.context = mContext;
}
public void setPostAdsDataList(List<PostAdsData> postAdsData){ // we set the data for the recyclerView here
this.postAdsDataList = postAdsData;
notifyDataSetChanged();
}
#NonNull
#Override
public RecyclerView.ViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
switch (viewType) {
// here do your thing as usual
}
}
#Override
public void onBindViewHolder(#NonNull RecyclerView.ViewHolder viewHolder, final int position) {
int viewType = getItemViewType(position);
switch (viewType){
// here switch viewType as usual,but refer the data from postAdsDataList
}
}
#Override
public int getItemViewType(int position) {
if(postAdsDataList.get(position).getType() == 1){
return UNIFIED_NATIVE_AD_VIEW_TYPE;
}else{
return MENU_ITEM_VIEW_TYPE;
}
}
#Override
public int getItemCount() {
if (postAdsDataList != null) {
return postAdsDataList.size();
} else {
return 0;
}
}
}
Third: In your HomeActivity, so here is the place you need to set the data(Post) into the RecyclerView,you need to "transform" the data inside List<Post> to List<PostAdsData> like this:
private void displayContent(List<Post> posts){
List<PostAdsData> postAdsDataList = new ArrayList<>();
for(Post item : posts) {
PostAdsData data = new PostAdsData();
data.ads = null;
data.post = item;
data.type = 2; // here 1 for ads, 2 will be post
postAdsDataList.add(data);
}
yourAdapter.setPostAdsDataList(postAdsDataList); // here set in the Posts data into the recyclerView
}
displayContent() function above should be called after you get the data from Firebase I assumed.So it will look like this:
private void displayPosts(){
//ALL OTHER STUFF
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
for(....){
// after your for loop
// then all the Post will added inside the List<Post>
}
// then we called here
displayContent(postList) // your postList
}
}
So now we done insert the posts. Therefore, when you get the UnifiedNativeAd from Google Admob,we also need to "transform" UnifiedNativeAd to postAdsData object,like this:
// add this to YourAdapter class
public void insertAdsToRecyclerView(UnifiedNativeAd ad){ // if more than 1 ads,then here should be a list,and use for loop at the code below
PostAdsData adsData = new PostAdsData();
adsData.post = null;
adsData.ads = ad;
adsData.type = 1;
postAdsDataList.add(0,adsData); // here will add the ads to the 1st item of the list
notifyItemInserted(0);
}
Then in your insertAdsInMenuItems() will become like this:
private void insertAdsInMenuItems() {
postAdapter.insertAdsToRecyclerView(mNativeAds.get(0))// cause i seen you request for 1 ad only
}
Hope you get the idea.Now we successfully merge both Post and Ad into 1 data source.So it will easier for us to present in RecylerView.
This is not a duplicate.
I am trying to access a child within a child in firebase and then putting that child into a recycler adapter. It won't show in the recycler adapter. There is a similar question on here to this but when implementing it, it still doesn't work.
Currently using an adapter, a messages object and a fragment.
Fragment Activity
private ArrayList<Messages> results = new ArrayList<>();
private void listenForChat() {
final DatabaseReference userDb = FirebaseDatabase.getInstance().getReference().child("users").child(currentUid)
.child("receivedMessages");
messageUrlDb = userDb.child("messageUrl");
messageUrlDb.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
String message = "";
if (dataSnapshot.child("messageUrl").getValue() != null)
message = dataSnapshot.child("messageUrl").getValue().toString();
Messages obj = new Messages(message, name, image);
if (!results.contains(obj)) {
results.add(obj);
messagesList.setAdapter(mAdapter);
mAdapter.notifyDataSetChanged();
initializeDisplay();
}
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) { }
});
}
public class ChatAdapter extends RecyclerView.Adapter<ChatAdapter.ChatViewHolders> {
private List<Messages> mMessageList;
private List<UserObject> usersList;
private Context context;
private DisplayTextFragment displayTextFragment;
private String message;
public ChatAdapter(List<Messages> mMessageList, Context context) {
this.mMessageList = mMessageList;
this.context = context;
}
#Override
public ChatViewHolders onCreateViewHolder(ViewGroup parent, int viewType) {
View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.message_layout, null);
ChatViewHolders rcv = new ChatViewHolders(v);
return rcv;
}
#Override
public void onBindViewHolder(final ChatViewHolders holder, int position) {
holder.messageText.setText(mMessageList.get(position).getMessage());
}
#Override
public int getItemCount() {
return mMessageList.size();
}
public class ChatViewHolders extends RecyclerView.ViewHolder {
public TextView messageText, timeSent, mName;
ImageView mProfile;
LinearLayout mLayout;
public ChatViewHolders(View view) {
super(view);
messageText = (TextView) view.findViewById(R.id.message_text);
mLayout = itemView.findViewById(R.id.layout);
}
}
}
I am trying access (messageUrl) users -> receivedMessages -> messageUrl. However as there is a key they I assume it doesn't as far as messagesUrl. For the recycler adapter it needs take in messagesUrl as a string and update accordingly but I just can't do it.
If any more code is needed I can post. Thank you.
This is how you're attaching your ValueEventListener:
final DatabaseReference userDb = FirebaseDatabase.getInstance().getReference().child("users").child(currentUid)
.child("receivedMessages");
messageUrlDb = userDb.child("messageUrl");
messageUrlDb.addValueEventListener(new ValueEventListener() {
If we take the path from this code, you're attaching the listener to /users/$uid/receivedMessages/messageUrl. This path doesn't exist in the data you showed, so your onDataChanged will get called with an empty snapshot.
If you want to read all messages for the user, you should attach your listener to /users/$uid/receivedMessages and parse the snapshot inside onDataChanged:
final DatabaseReference userDb = FirebaseDatabase.getInstance().getReference().child("users").child(currentUid)
.child("receivedMessages");
userDb.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
for (DataSnapshot userMessages: dataSnapshot.getChildren()) {
for (DataSnapshot messageSnapshot: userMessages.getChildren()) {
System.out.println(messageSnapshot.getKey()+": "+messageSnapshot.getChild("messageUrl").getValue(String.class));
}
}
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
throw databaseError.toException(); // don't ignore errors
}
});
This loops over the two level of child nodes you have under the user's receivedMessages node.
I have an array of data which I am retrieving from firebase. I am using a recyclerview to display the data but my adapter is not working correctly.I tried adding the arraylist in the adapter but this is not working.
It is saying the adapter is not attached and I am having a blank activity.
Any help on this ?
Here are my details.
Modal Class
public class Order {
private String ProductId;
private String ProductName;
private String Quantity;
public Order() {
}
public String getProductId() {
return ProductId;
}
public void setProductId(String productId) {
ProductId = productId;
}
public String getProductName() {
return ProductName;
}
public void setProductName(String productName) {
ProductName = productName;
}
public String getQuantity() {
return Quantity;
}
public void setQuantity(String quantity) {
Quantity = quantity;
}
public Order(String productId, String productName, String quantity) {
ProductId = productId;
ProductName = productName;
Quantity = quantity;
}
}
Adapter
public class AllOrdersAdapter extends RecyclerView.Adapter<AllOrdersViewHolder> {
List<Order> myfoods;
public AllOrdersAdapter(List<Order> myfoods) {
this.myfoods = myfoods;
}
#NonNull
#Override
public AllOrdersViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View itemView = LayoutInflater.from(parent.getContext())
.inflate(R.layout.allorders_layout,parent,false);
return new AllOrdersViewHolder(itemView);
}
#Override
public void onBindViewHolder(#NonNull AllOrdersViewHolder holder, int position) {
holder.foodname.setText(myfoods.get(position).getProductName());
holder.foodquantity.setText(myfoods.get(position).getQuantity());
holder.foodId.setText(myfoods.get(position).getProductId());
}
#Override
public int getItemCount() {
return myfoods.size();
}
}
Test Class
public class Test extends AppCompatActivity {
FirebaseDatabase db;
DatabaseReference requests;
RecyclerView lstFoods;
RecyclerView.LayoutManager layoutManager;
TextView food_id,food_quan,food_name;
// List foods = new ArrayList<>();
// RecyclerView.Adapter<AllOrder> adapter;
// List<String> myOrders = new ArrayList<String>();
// ArrayList<String> foods=new ArrayList<>();
List<String> myfoods = new ArrayList<String>();
AllOrdersAdapter adapter;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_test);
//firebase
db = FirebaseDatabase.getInstance();
requests= db.getReference().child("Requests");
lstFoods = (RecyclerView)findViewById(R.id.lstAllFoods);
lstFoods.setHasFixedSize(true);
layoutManager = new LinearLayoutManager(this);
lstFoods.setLayoutManager(layoutManager);
loadOrderss();
}
private void loadOrderss() {
requests.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
for (DataSnapshot postSnapshot : dataSnapshot.getChildren()) {
if (postSnapshot.getValue() != null) {
// List ingredients = new ArrayList<>();
for (DataSnapshot ing : postSnapshot.child("foods").getChildren()) {
// String data = String.valueOf(postSnapshot.getValue(Order.class));
myfoods.add(ing.child("quantity").getValue(String.class));
myfoods.add(ing.child("productName").getValue(String.class));
myfoods.add(ing.child("productId").getValue(String.class));
// myfoods.add(String.valueOf(Order.class));
System.out.println("Gained data: " + ing.child("productName").getValue(String.class));
}
}
}
adapter = new AllOrdersAdapter((ArrayList<String>) myfoods);
lstFoods.setAdapter(adapter);
adapter.notifyDataSetChanged();
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
}
});
}
There seems to be a couple things wrong with the code. As it is posted I would be surprised if it compiles.
In your Adapter you have:
List<Order> myfoods;
and
public AllOrdersAdapter(List<Order> myfoods) {
this.myfoods = myfoods;
}
but in your activity code you pass:
adapter = new AllOrdersAdapter((ArrayList<String>) myfoods);
one is a ArrayList of String the other of Order !
You also need to change your adapter class to something like:
public class AllOrdersAdapter extends RecyclerView.Adapter<AllOrdersAdapter.AllOrdersViewHolder> {
private static final String TAG = AllOrdersAdapter.class.getSimpleName();
private ArrayList<Order> mData;
public class AllOrdersViewHolder extends RecyclerView.ViewHolder {
public TextView mTvFoodname;
public TextView mTvFoodQuantity;
public TextView mTvFoodId;
public AllOrdersViewHolder(View v){
super(v);
// TODO: You need to assign the appropriate View Id's instead of the placeholders ????
mTvFoodQuantity = v.findViewById(R.id.????);
mTvFoodname = v.findViewById(R.id.????);
mTvFoodId = v.findViewById(R.id.????);
}
}
public AllOrdersAdapter(ArrayList<Order> data){
this.mData = data;
}
#Override
public AllOrdersViewHolder onCreateViewHolder(ViewGroup parent, int viewType){
View itemView = LayoutInflater.from(parent.getContext()).inflate(R.layout.business_list_card_view, parent, false);
return new AllOrdersViewHolder(itemView);
}
#Override
public void onBindViewHolder(final AllOrdersViewHolder holder, final int position){
//TODO: You need to decide whether you want to pass a string or order object
Order data = mData.get(position);
final String name = data.getProductName();
final String quantity = data.getQuantity();
final String id = data.getProductId();
holder.mTvFoodname.setText(name);
holder.mTvFoodQuantity.setText(quantity );
holder.mTvFoodId.setText(id)
}
#Override
public int getItemCount(){
return mData.size();
}
}
Note: That since I can not know, whether an ArrayList of String or of Order should be used the parameters in either the Activity or Adapter will need to be changed. Also how you assign the data to the RecyclerView will be affected in the onBindViewHolder method.
You should also follow the advice given by Frank.
EDIT
Change your onDataChange() method to this:
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
for (DataSnapshot postSnapshot : dataSnapshot.getChildren()) {
if (postSnapshot.getValue() != null) {
List ingredients = new ArrayList<>();
for (DataSnapshot ing : postSnapshot.child("foods").getChildren()) {
String name = ing.child("productName").getValue(String.class);
String quantity = ing.child("quantity").getValue(String.class);
String productId = ing.child("productId").getValue(String.class);
// Using your overloaded class constructor to populate the Order data
Order order = new Order(productId, name, quantity);
// here we are adding the order to the ArrayList
myfoods.add(order);
Log.e(TAG, "Gained data: " + name)
}
}
}
adapter.notifyDataSetChanged();
}
In your Activity you will need to change the ArrayList class variable "myfoods" to this:
ArrayList(Order) myfoods = new ArrayList<>();
and in your onCreate() method you can now change:
adapter = new AllOrdersAdapter((ArrayList<String>) myfoods);
to simply this:
adapter = new AllOrdersAdapter(myfoods);
Also notice that I have made some changes in my original code above.
You'll want to create the adapter, and attach it to the view, straight in onCreate:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_test);
//firebase
db = FirebaseDatabase.getInstance();
requests= db.getReference().child("Requests");
lstFoods = (RecyclerView)findViewById(R.id.lstAllFoods);
lstFoods.setHasFixedSize(true);
layoutManager = new LinearLayoutManager(this);
lstFoods.setLayoutManager(layoutManager);
adapter = new AllOrdersAdapter((ArrayList<String>) myfoods);
lstFoods.setAdapter(adapter);
loadOrders();
}
This also means you should declare myfoods as a ArrayList<String>, which saves you from having to downcast it. Something like:
ArrayList<String> myfoods = new ArrayList<String>();
Now in loadOrders you simple add the items to the list, and then notify the adapter that its data has changed (so that it repaints the view):
private void loadOrders() {
requests.child("foods").addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
for (DataSnapshot postSnapshot : dataSnapshot.getChildren()) {
for (DataSnapshot ing: postSnapshot.getChildren()) {
myfoods.add(ing.child("quantity").getValue(String.class));
myfoods.add(ing.child("productName").getValue(String.class));
myfoods.add(ing.child("productId").getValue(String.class));
}
}
adapter.notifyDataSetChanged();
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
throw databaseError.toException(); // don't ignore errors
}
});
}
I'm trying to build a simple chat activity in side my app where all the requirements needed are in one place, the adapter, the attributes class, the viewholder class and the main activity are all to gather, at this point the activity sends one string line to firebase with no problem at all, but the code for data fetching is not working , I'm using the ChildEeventListiner to receive one single string line in the listview, ((((( my guess the DataSnapShot is not receiving any data )))))
PS: I've used the same code in the same app but holding more complex data and works fine, I'm not sure what is missing here, hope somebody can figure out what wrong here, ask me if there is any additional data u need.
public class MainActivity extends Activity {
//---------------------attributes Class ==> 1 string input-------------------
public class classChat {
String messageInPut;
public classChat(String messageInPut) {
this.messageInPut = messageInPut;
}
public String getMessageInPut() {
return messageInPut;
}
}
//---------------------------------------------------------------------------
FirebaseUser user;
DatabaseReference databaseChatView;
String msg;
classChat chats;
public static chatAdapter adapter;
ArrayList<classChat> bidChatdata;
ListView chatinstnc;
ImageView sendButton;
EditText messageArea;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//user = FirebaseAuth.getInstance().getCurrentUser();
databaseChatView = FirebaseDatabase.getInstance().getReference("Chat");
chatinstnc = (ListView) findViewById(R.id.chatinstnc);
sendButton = (ImageView)findViewById(R.id.sendButton);
messageArea = (EditText)findViewById(R.id.messageArea);
bidChatdata = new ArrayList<>();
//------------------sending to firebase------------------------------------
sendButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
String messageId = databaseChatView.push().getKey();
String msg = messageArea.getText().toString().trim();
databaseChatView.child(messageId).setValue(msg);
Toast.makeText(MainActivity.this, "chat: "+ chats, Toast.LENGTH_SHORT).show();
}
});
//--------------------List Item Click-------------------------------------
/* chatinstnc.setOnItemClickListener(new AdapterView.OnItemClickListener(){
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long messageId) {classChat dataModel = bidChatdata.get(position);}
});*/
//-------------Receiving Data From Firebase------------------------------
ChildEventListener childEventListener = new ChildEventListener() {
#Override
public void onChildAdded(DataSnapshot dataSnapshot, String s) {
bidChatdata.clear();
for (DataSnapshot chatSnapshot : dataSnapshot.getChildren()) {
chats = chatSnapshot.getValue(classChat.class);
bidChatdata.add(chats);
}
adapter = new chatAdapter(MainActivity.this, bidChatdata);
chatinstnc.setAdapter(adapter);
adapter.notifyDataSetChanged();
}
#Override
public void onChildChanged(DataSnapshot dataSnapshot, String s) {
bidChatdata.clear();
for (DataSnapshot chatSnapshot : dataSnapshot.getChildren()) {
chats = chatSnapshot.getValue(classChat.class);
bidChatdata.add(chats);
}
adapter = new chatAdapter(MainActivity.this, bidChatdata);
chatinstnc.setAdapter(adapter);
adapter.notifyDataSetChanged();
}
#Override
public void onChildRemoved(DataSnapshot dataSnapshot) {
}
#Override
public void onChildMoved(DataSnapshot dataSnapshot, String s) {
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
};
databaseChatView.addChildEventListener(childEventListener);
}
//---------------adapter class--------------------------------------------
public class chatAdapter extends ArrayAdapter<classChat>{
ArrayList<classChat> chat;
Context Context;
public class ViewHolder {
TextView msg1;
}
public chatAdapter(Context context, ArrayList<classChat> chat) {
super(context, R.layout.list_view_items, chat);
this.chat = chat;
this.Context = context;
}
#NonNull
#Override
public View getView(int position, #Nullable View convertView, #NonNull ViewGroup parent) {
final classChat chatdata = getItem(position);
ViewHolder viewHolder;
final View result;
if (convertView == null) {
viewHolder = new ViewHolder();
LayoutInflater inflater = LayoutInflater.from(getContext());
convertView = inflater.inflate(R.layout.list_view_items, parent, false);
viewHolder.msg1 = (TextView)convertView.findViewById(R.id.msg1);
result = convertView;
convertView.setTag(viewHolder);
}else{
viewHolder = (ViewHolder) convertView.getTag();
result = convertView;
}
viewHolder.msg1.setText(chatdata.getMessageInPut());
return convertView;
}
}
}
I am developing an android app that displays the ranks of students based on their marks retrieved from the firebase database. Everything is working fine but, when I update the marks in the db, it keeps the old data and adds the new data in the recyclerView. I can restart the app to refresh the data. But while it is still running, it shows the old data too.
Below is my firebase data:
Student1: {
c: 70,
cPlus: 90,
java: 70,
name: "Samson",
regno: "16sksb7034",
unix: 60
}
Student2: {
c: 20,
cPlus: 85,
java: 68,
name: "Samson",
regno: "16sksb7034",
unix: 86
}
Student3: {
c: 70,
cPlus: 70,
java: 80,
name: "Samson",
regno: "16sksb7034",
unix: 90
}
Here is my dataModel class:
public class Marks {
private String name;
private String regno;
private int c;
private int cPlus;
private int java;
private int unix;
private int percentage;
public Marks() {}
public Marks(int c, int cPlus, int java, int unix) {
this.c = c;
this.cPlus = cPlus;
this.java = java;
this.unix = unix;
}
public int getPercentage() {
return percentage;
}
public void setPercentage(int percentage) {
this.percentage = percentage;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getRegno() {
return regno;
}
public void setRegno(String regno) {
this.regno = regno;
}
public int getC() {
return c;
}
public void setC(int c) {
this.c = c;
}
public int getcPlus() {
return cPlus;
}
public void setcPlus(int cPlus) {
this.cPlus = cPlus;
}
public int getJava() {
return java;
}
public void setJava(int java) {
this.java = java;
}
public int getUnix() {
return unix;
}
public void setUnix(int unix) {
this.unix = unix;
}
}
class MarksComparator implements Comparator<Marks> {
#Override
public int compare(Marks marks1, Marks marks2) {
int Marks1Total = marks1.getPercentage();
int Marks2Total = marks2.getPercentage();
if (Marks2Total < Marks1Total) {
return -1;
} else if (Marks2Total > Marks1Total) {
return 1;
} else {
return 0;
}
}
}
Here's my activity class:
public class MarksFragment extends Fragment{
private List<Marks> mMarksList = new ArrayList<>();
private RecyclerView mRecyclerView;
private MyAdapter mAdapter;
private RecyclerView.LayoutManager mLayoutManager;
private FirebaseDatabase mDatabase;
private DatabaseReference mReference;
private int total=0;
public MarksFragment() {
// 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_marks, container, false);
mRecyclerView = (RecyclerView) view.findViewById(R.id.recycler_view);
// use this setting to improve performance if you know that changes
// in content do not change the layout size of the RecyclerView
mRecyclerView.setHasFixedSize(true);
// use a linear layout manager
mLayoutManager = new LinearLayoutManager(getActivity());
mRecyclerView.setLayoutManager(mLayoutManager);
mRecyclerView.setItemAnimator(new DefaultItemAnimator());
// specify an adapter (see also next example)
/*mAdapter = new MyAdapter(getContext(),mMarksList);
mAdapter.notifyDataSetChanged();
mRecyclerView.setAdapter(mAdapter);*/
//get Firebase Reference
FirebaseDatabase.getInstance().setPersistenceEnabled(true);
mDatabase = FirebaseDatabase.getInstance();
mReference = mDatabase.getReference();
mReference.addChildEventListener(new ChildEventListener() {
#Override
public void onChildAdded(DataSnapshot dataSnapshot, String s) {
fetchData(dataSnapshot);
}
#Override
public void onChildChanged(DataSnapshot dataSnapshot, String s) {
fetchData(dataSnapshot);
}
#Override
public void onChildRemoved(DataSnapshot dataSnapshot) {
}
#Override
public void onChildMoved(DataSnapshot dataSnapshot, String s) {
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
return view;
}
public void findPercentage(Marks value) {
total =value.getC() + value.getcPlus() + value.getJava() + value.getUnix();
value.setPercentage(total);
}
private void fetchData(DataSnapshot dataSnapshot) {
Marks value = dataSnapshot.getValue(Marks.class);
Log.v("Marks Fragment", "" +value);
findPercentage(value);
mMarksList.add(value);
Collections.sort(mMarksList, new MarksComparator());
// specify an adapter (see also next example)
mAdapter = new MyAdapter(getContext(),mMarksList);
mAdapter.notifyDataSetChanged();
mRecyclerView.setAdapter(mAdapter);
Here is my adapter class:
public class MyAdapter extends RecyclerView.Adapter<MyAdapter.MyViewHolder>{
private Context mContext;
private List<Marks> marksList;
public MyAdapter(Context mContext, List<Marks> marksList) {
this.mContext = mContext;
this.marksList = marksList;
}
public class MyViewHolder extends RecyclerView.ViewHolder {
public TextView mItemName, mItemRegNo, mItemNo, mTotal;
CircleImageView mImageView;
public MyViewHolder(View view) {
super(view);
mItemName = (TextView) view.findViewById(R.id.card_name);
mItemRegNo = (TextView) view.findViewById(R.id.card_regno);
mItemNo = (TextView) view.findViewById(R.id.item_id);
mImageView = (CircleImageView) view.findViewById(R.id.item_photo);
mTotal = view.findViewById(R.id.card_total);
}
}
#Override
public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View itemView = LayoutInflater.from(parent.getContext())
.inflate(R.layout.card_item, parent, false);
return new MyViewHolder(itemView);
}
#Override
public void onBindViewHolder(final MyViewHolder holder, int position) {
Marks marks = marksList.get(position);
int count = position + 1;
holder.mItemName.setText("" + marks.getName());
holder.mItemRegNo.setText("" + marks.getRegno());
holder.mItemNo.setText("" + count);
holder.mImageView.setImageResource(R.drawable.after_cookie);
holder.mTotal.setText(""+ marks.getPercentage());
}
#Override
public int getItemCount() {
return marksList.size();
}
}
So the code does what its intended to do it retrieves the data and calculates the total and ranks the students. but when I update the data in firebase console the views in recyclerView duplicates temporarily. Like for example if I update Student1 unix value as 10 then two views will be shown in the recyclerView: 1 for previous value and 2 for updated value and again if I update the values it will yet show another views representing the new data without removing the old views. But if I restart recyclerView gets refreshed and its all ok but while I am running the app during the update it shows temporary duplicate views too.
I am new here and this is my first question so I can't even upload picture as you need 10 points to upload photo. I really hope someone help me out on this. I thank you in advance.
UPDATE
Here is link to the image:
When I start the app, the image is:
first Image
when I update the unix value of Student3, the image in recyclerView becomes like this:
After updating the data in firebase console
So, you see it adds new data as well as keeps the old data untill I restart.
Your problem is that you're never checking if the student already exists in your mMarksList so you're simply duplicating him by adding him again with new grades.
What I would do in you case is to add an unique id in firebase to each student.
Then you can check in your fetchData whether the student with that id is already in the array, delete him and add the new one.
private void fetchData(DataSnapshot dataSnapshot) {
Marks value = dataSnapshot.getValue(Marks.class);
Log.v("Marks Fragment", "" +value);
findPercentage(value);
// Get an iterator.
Iterator<Marks> ite = mMarksList.iterator();
while(ite.hasNext()) {
Marks iteValue = ite.next();
if(iteValue.getId().equals(value.getId())) ite.remove();
}
mMarksList.add(value);
....
}
Optionally To make that even cleaner, you can override the equals and hashcode methods in your Marks data model, so that a Marks object is considered the same if the id is equal. More
//ASSUMING THAT ID IS int
#Override
public int hashCode() {
return id;
}
#Override
public boolean equals(Object obj) {
if (this == obj) return true;
if (obj == null) return false;
if (this.getClass() != obj.getClass()) return false;
Marks other = (Marks) obj;
if (this.getId != other.getId) {
return false;
}
return true;
}
Then it's possible to either use a hashmap, which will override the old student automatically or a arraylist as is and iterate through it before and check if a student equals your new student, like this:
private void fetchData(DataSnapshot dataSnapshot) {
Marks value = dataSnapshot.getValue(Marks.class);
Log.v("Marks Fragment", "" +value);
findPercentage(value);
// Use an iterator.
Iterator<Marks> ite = mMarksList.iterator();
while(ite.hasNext()) {
Marks iteValue = ite.next();
if(iteValue.equals(value)) ite.remove();
}
mMarksList.add(value);
....
}