I am trying to remove some Items from my Json Response in my recyclerview but when I do that an empty item spaces is being created in place of the removed item. This is happening only when I use gridlayout manager with recyclerview , if I use Linearlayout manager there are no empty spaces.
Below is my code:
activityRecylerviewBinding.recyclerview1.setHasFixedSize(true);
//activityRecylerviewBinding.recyclerview1.setLayoutManager(new LinearLayoutManager(getActivity()));
RecyclerView.LayoutManager mLayoutManager = new GridLayoutManager(getActivity(), 2);
activityRecylerviewBinding.recyclerview1.setLayoutManager(mLayoutManager);
activityRecylerviewBinding.recyclerview1.addItemDecoration(new GridSpacingItemDecoration(2, dpToPx(5), true));
activityRecylerviewBinding.recyclerview1.setItemAnimator(new DefaultItemAnimator());
And for Removing items:
if (!user.emailId.equals(clickedemail)){
viewHolder.setIsRecyclable(false);
viewHolder.mAdapterItemChatsBinding.gooot.removeAllViews();
viewHolder.mAdapterItemChatsBinding.gooot.setPadding(0, 0, 0, 0);
//viewHolder.mAdapterItemChatsBinding.gooot.getLayoutParams().height = 0;
}else {
viewHolder.bindUser(user, RecycFragment.this);
}
When I use the blow code it's works fine.
activityRecylerviewBinding.recyclerview1.setLayoutManager(new LinearLayoutManager(getActivity()));
JsonParsing code:
private void initializeFirebase() {
final Query refUsers = FirebaseDatabase.getInstance()
.getReference(ConstantsFirebase.FIREBASE_LOCATION_GARMENTS);
refUsers.keepSynced(true);
final List<UploadImage> uploadImageList = new ArrayList<>();
refUsers.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
for (DataSnapshot messageSnapshot : dataSnapshot.getChildren()) {
UploadImage uploadImage = messageSnapshot.getValue(UploadImage.class);
uploadImageList.add(uploadImage);
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
mAdapter = new FirebaseRecyclerAdapter<UploadImage, ChatsItemHolder>(UploadImage.class, R.layout.recycitemfirebase,
ChatsItemHolder.class, refUsers) {
#Override
public ChatsItemHolder onCreateViewHolder(ViewGroup parent, int viewType) {
adapterItemChatsBinding = DataBindingUtil.inflate(LayoutInflater
.from(parent.getContext()), viewType, parent, false);
//adapterItemChatsBinding.tvUserName.setTypeface(Typefaces.get(getActivity(), Constants.FONT_ROBOT_REGULAR));
return new ChatsItemHolder(adapterItemChatsBinding);
}
#Override
protected void populateViewHolder(ChatsItemHolder viewHolder, final UploadImage user, int position) {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getActivity());
clickedemail = prefs.getString(Constants.KEY_CLICKED_EMAIL, "");
if (!user.emailId.equals(clickedemail)){
viewHolder.setIsRecyclable(false);
viewHolder.mAdapterItemChatsBinding.gooot.removeAllViews();
viewHolder.mAdapterItemChatsBinding.gooot.setPadding(0, 0, 0, 0);
//viewHolder.mAdapterItemChatsBinding.gooot.getLayoutParams().height = 0;
}else {
viewHolder.bindUser(user, RecycFragment.this);
}
viewHolder.mAdapterItemChatsBinding.title.setText(user.getGarment_name());
viewHolder.mAdapterItemChatsBinding.count.setText(user.getGarment_color());
Glide.with(viewHolder.mAdapterItemChatsBinding.thumbnail.getContext())
.load(user.getImage())
.placeholder(R.drawable.ic_person)
.fitCenter()
.dontAnimate()
.into(viewHolder.mAdapterItemChatsBinding.thumbnail);
}
};
activityRecylerviewBinding.recyclerview1.setAdapter(mAdapter);
}
Can someone tell me what am I doing wrong?
Where are you removing your item from the dataset?
The action to remove the item should have the items index in the dataset should it not? If so something like this should work:
public void removeItem(final int index) {
list.remove(index);
adapter.notifyItemRemoved(index);
}
Seems, that adapter for recyclerview is built with the the firebase query as the source of the items.
You need to change your firebase query to only fetch the items you want to have in your list.
Related
this is my first question on Stackoverflow. I have very recently started Android Development.
What I want to do:
I have a list of people and I want to filter/Search the RecyclerView (using Custom Adapter) list (Initial List) based on user input in the search box, in my toolbar(not ActionBar).
My Problem:
Initially, nothing was happening. The list was not changing at all. Now, the list changes, but only one fixed list item (Current Search output) gets displayed no matter what the input. My recycler adapter is not refreshing to the new filtered list. And I am not getting any errors in the bulid or the logcat.
What I have tried:
After debugging for a whole day, and fixing some "NullPointerExceptions" in my Layout Manager and the RecycleView adapter and having tried 2 different method for filtering. Even though I am able to generate a filtered array (List values in Logcat) I am not able to get the results. I tried using , the "notifyDataSetChanged()", "notifyItemRangeChanged()" and "*notifyAll();, but all in vain....
Please help.....
public class MainActivity extends AppCompatActivity {
ArrayList<Consultant> consultants= new ArrayList<>();
ArrayList<Consultant> allConsultants = new ArrayList<>();
int rating=5;
int price = 10000;
String categoryFilter;
String ratingFilter;
RecyclerView recyclerView;
Consultant_RecyclerAdapter.RecyclerViewClickListener listener;
Consultant_RecyclerAdapter adapter= new Consultant_RecyclerAdapter(consultants,listener);
Spinner s_categories;
Spinner s_rating;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Toolbar toolbar = findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
recyclerView= findViewById(R.id.RecycleView);
s_categories=findViewById(R.id.Spinner_Category);
s_rating=findViewById(R.id.Spinner_Rating);
addToList();
setUpAdapter();
}
private void setUpAdapter() {
Log.i("Adapter","Started");
setOnClickListener();
Consultant_RecyclerAdapter adapter = new Consultant_RecyclerAdapter(consultants,listener);
recyclerView.setLayoutManager(new LinearLayoutManager(this));
recyclerView.setItemAnimator(new DefaultItemAnimator());
recyclerView.setAdapter(adapter);
Log.i("Adapter","Ended");
}
private void addToList(){
consultants.add(new Consultant("Dr Kapoor", "consultant_id", "profilePic_src", new String[]{"Dentist","Dermatology"}, 1000, 5));
consultants.add(new Consultant("Dr Pankaj Kumar", "consultant_id", "profilePic_src", new String[]{"Psychology","Respiratory"}, 3000, 1));
consultants.add(new Consultant("Dr Harsh Jha", "consultant_id", "profilePic_src", new String[]{"Internal Medicine"}, 1500, 5));
consultants.add(new Consultant("Dr Gaurav Singh", "consultant_id", "profilePic_src", new String[]{"Dentist","Cardiologist"}, 3500, 4));
consultants.add(new Consultant("Dr Aman", "consultant_id", "profilePic_src", new String[]{"Lungs","Neuro"}, 1000, 2));
consultants.add(new Consultant("Dr Jatin Chabra", "consultant_id", "profilePic_src", new String[]{"Psychology"}, 5000, 3));
Log.i("List","Done");
allConsultants=new ArrayList<>(consultants);
}
private void setOnClickListener() {
listener = new Consultant_RecyclerAdapter.RecyclerViewClickListener() {
#Override
public void onClick(View v, int position) {
Intent intent = new Intent(getApplicationContext(), ConsultantProfileActivity.class);
intent.putExtra("consultant_name", consultants.get(position).getName());
intent.putExtra("pic_src", consultants.get(position).getProfilePic_src());
intent.putExtra("about", consultants.get(position).getAbout());
intent.putExtra("consultant_id",consultants.get(position).getConsultant_id());
intent.putExtra("categories",consultants.get(position).getCategories());
startActivity(intent);
}
};
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.search, menu);
MenuItem menuItem = menu.findItem(R.id.action_search);
SearchView searchView = (SearchView) menuItem.getActionView();
searchView.setQueryHint("Search....");
searchView.setImeOptions(EditorInfo.IME_ACTION_DONE);
searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
#Override
public boolean onQueryTextSubmit(String query) {
return false;
}
#Override
public boolean onQueryTextChange(String newText) {
Log.i("Search","QueryChanged");
//adapter.getFilter().filter(newText);
filter(newText);
return false ;
}
});
return true;
}
private void filter(String text) {
// creating a new array list to filter our data.
ArrayList<Consultant> filteredlist = new ArrayList<>();
// running a for loop to compare elements.
for (Consultant item : allConsultants) {
Log.i("Filter: ",item.getName()+"...."+text);
// checking if the entered string matched with any item of our recycler view.
if (item.getName().toLowerCase().contains(text.toLowerCase())) {
Log.i("Match","Found");
// if the item is matched we are
// adding it to our filtered list.
filteredlist.add(item);
}
}
Log.i("Filter: ",(filteredlist.toString()));
if (filteredlist.isEmpty()) {
// if no item is added in filtered list we are
// displaying a toast message as no data found.
Toast.makeText(this, "No Data Found..", Toast.LENGTH_SHORT).show();
} else {
// at last we are passing that filtered
// list to our adapter class.
adapter.filterList(filteredlist);
}
}
}
Please, ignore the search method in the following Recycler Adapter, I am currently using the search method in the mainActivity
public class Consultant_RecyclerAdapter extends RecyclerView.Adapter<Consultant_RecyclerAdapter.MyViewHolder>{
ArrayList consultants;
ArrayList AllConsultants,preFilteredList;
private RecyclerViewClickListener listener;
public Consultant_RecyclerAdapter(ArrayList<Consultant> consultants, RecyclerViewClickListener listener) {
this.consultants = consultants;
this.listener = listener;
//AllConsultants = new ArrayList<>(consultants);
//preFilteredList = new ArrayList<>(consultants);
}
//NOTIFYING THE ADAPTER ABOUT UPDATE
public void filterList(ArrayList<Consultant> filteredlist) {
consultants.clear();
consultants.addAll(filteredlist);
notifyDataSetChanged();
}
public class MyViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
private TextView name, rating, price, category;
private ImageView profile;
public MyViewHolder(#NonNull View view) {
super(view);
name = view.findViewById(R.id.textView_Name);
profile = view.findViewById(R.id.imageView_ProfilePic);
category = view.findViewById(R.id.textView_Category);
rating = view.findViewById(R.id.textView_Rating);
price = view.findViewById(R.id.textView_Price);
view.setOnClickListener(this);
}
#Override
public void onClick(View view) {listener.onClick(view, getAdapterPosition()); }
}
#NonNull
#Override
public Consultant_RecyclerAdapter.MyViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View itemView = LayoutInflater.from(parent.getContext()).inflate(R.layout.consultant_list_item, parent, false);
return new MyViewHolder(itemView);
}
#Override
public void onBindViewHolder(#NonNull MyViewHolder holder, int position) {
String name = consultants.get(position).getName();
String profilePic_src = consultants.get(position).getProfilePic_src();
float rating = consultants.get(position).getRating();
String categories = "";
//Converting Array to string
for (String i : consultants.get(position).getCategories()) {
categories = i + ", " + categories;
}
int price = consultants.get(position).getPrice();
holder.name.setText(name);
holder.category.setText(categories);
holder.price.setText(String.valueOf(price));
holder.rating.setText(String.valueOf(rating));
holder.profile.setImageResource(R.drawable.consultant);}
#Override
public int getItemCount() {
return consultants.size();
}
public interface RecyclerViewClickListener {
void onClick(View v, int position);
}
public void listUpdate(String categoryFilter, String ratingFilter) {
preFilteredList = new ArrayList<>();
if (categoryFilter != null || ratingFilter != null) {
for (Consultant item : AllConsultants) {
if (String.valueOf(item.getRating()).toLowerCase(Locale.ROOT).contains(ratingFilter) && item.getCategories().toString().toLowerCase(Locale.ROOT).contains(categoryFilter)) {
preFilteredList.add(item);
}
}
}else{
preFilteredList= new ArrayList<Consultant>(AllConsultants);
}
consultants.clear();
consultants.addAll(preFilteredList);
getFilter();
}
#Override
public Filter getFilter() {
return theFilter;
}
public Filter theFilter = new Filter() {
#Override
protected FilterResults performFiltering(CharSequence constraint) {
List<Consultant> filteredList = new ArrayList<>();
if (constraint == null || constraint.length() == 0) {
filteredList.addAll(AllConsultants);
} else {
String filterPattern = constraint.toString().toLowerCase().trim();
for (Consultant item : AllConsultants) {
Log.i("Filter: ",item.getName()+"...."+filterPattern);
if (item.getName().toLowerCase().contains(filterPattern)) {
Log.i("Match","Found");
filteredList.add(item);
}
}
}
FilterResults results = new FilterResults();
results.values = filteredList;
return results;
}
#Override
protected void publishResults(CharSequence constraint, FilterResults results) {
Log.i("Filter ","Published");
consultants.clear();
consultants.addAll((List) results.values);
notifyDataSetChanged();
}
};
}
Do not Use Activity To filter the Results this kinda degrade the performance . use Filterable interface in Adapter it performs filtering on a background thread and post the result on Main thread. Which you already implemented i see .
By looking at your code of adapter i think it should work because you are maintaining different references for Both list complete and filtered .
The main culprit i thing is You have initialized Adapter as Global variable but the adapter you are setting to RecyclerView is a another one which you have created locally . Fix this and it should work .
private Consultant_RecyclerAdapter adapter ; // Global variable
private void setUpAdapter() {
Log.i("Adapter","Started");
setOnClickListener();
adapter = new Consultant_RecyclerAdapter(consultants,listener);
recyclerView.setLayoutManager(new LinearLayoutManager(this));
recyclerView.setItemAnimator(new DefaultItemAnimator());
recyclerView.setAdapter(adapter);
Log.i("Adapter","Ended");
}
I had tried to retrieve data from firebase database and show in recyclerview.
Everything is going perfect. Now in my firebase database has lots of node for recyclerview and each node has image link and now i just seen that recyclerview only show when all images are loaded from firebase database first.
Database has a string and long both types of values.
But No any text values display until all images are not loaded. Here i shows what am i tried.
So the question is how to show recyclerview step by step.
if Text("string") is loaded than why it waiting for images loading?
mAdapter = new PostAdapter(MainActivity.this);
query = PostRef
.orderByChild("timestamp")
.limitToLast(mPostsPerPage);
query.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
List<Post> userModels = new ArrayList<>();
for (DataSnapshot userSnapshot : dataSnapshot.getChildren()) {
String o=userSnapshot.getKey();
userModels.add(userSnapshot.getValue(Post.class));
}
mAdapter.addAll(userModels);
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
this is my adapter
public class PostAdapter extends RecyclerView.Adapter<PostHolder>
{
List<Post> mPost;
Context mContext;
Boolean likecheck=false;
public PostAdapter(Context c) {
this.mPost = new ArrayList<>();
mContext=c;
}
#NonNull
#Override
public PostHolder onCreateViewHolder(#NonNull ViewGroup viewGroup, int i) {
return new PostHolder(LayoutInflater.from(viewGroup.getContext())
.inflate(R.layout.all_post_layout, viewGroup, false));
}
#Override
public void onBindViewHolder(#NonNull final PostHolder postHolder, final int i) {
postHolder.setData(mPost.get(i));
final String PostKey=mPost.get(i).getPostid();
FirebaseAuth mAuth=FirebaseAuth.getInstance();
final String currentUserID=mAuth.getCurrentUser().getUid();
final DatabaseReference post=FirebaseDatabase.getInstance().getReference().child("Posts");
post.child(PostKey).child("postimg").addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot)
{
if (dataSnapshot.exists())
{
for (DataSnapshot dataSnapshot1:dataSnapshot.getChildren())
{
String postimagelink =dataSnapshot1.getValue().toString();
postimagelist.add(postimagelink);
}
String[] urls =postimagelist.toArray(new String[postimagelist.size()]);
postHolder.mPager.setAdapter(new SlidingImage_Adapter(mContext,urls));
postHolder.indicator.setViewPager(postHolder.mPager);
final float density = mContext.getResources().getDisplayMetrics().density;
postHolder.indicator.setRadius(5 * density);
postHolder.NUM_PAGES = urls.length;
postHolder.indicator.setOnPageChangeListener(new ViewPager.OnPageChangeListener()
{
#Override
public void onPageSelected(int position) {
postHolder.currentPage = position;
}
#Override
public void onPageScrolled(int pos, float arg1, int arg2) {
}
#Override
public void onPageScrollStateChanged(int pos) {
}
});
}
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
}
});
#Override
public int getItemCount() {
return mPost.size();
}
public void addAll(List<Post> newPost) {
int initialSize = mPost.size();
mPost.addAll(newPost);
notifyItemRangeInserted(initialSize, newPost.size());
}
public String getLastItemId() {
return mPost.get(mPost.size() - 1).getPostid();
}
}
viewholder
public class PostHolder extends RecyclerView.ViewHolder
{
AutoLinkTextView description;
TextView postfullname;
ViewPager mPager;
int currentPage = 0;
int NUM_PAGES = 0;
CirclePageIndicator indicator;
Context context;
public PostHolder(#NonNull View itemView) {
super(itemView);
postfullname = itemView.findViewById(R.id.user_post_full_name);
description = itemView.findViewById(R.id.user_post_description);
mPager = (ViewPager) itemView.findViewById(R.id.pager);
indicator = (CirclePageIndicator)itemView.findViewById(R.id.indicator);
}
public void setData(Post post)
{
description.setText(post.getDescription());
postfullname.setText(post.getFirstname()+" "+post.getLastname());
}
}
Ok, I see a couple of problems with your adapter.
First
public void addAll(List<Post> newPost) {
int initialSize = mPost.size();
mPost.addAll(newPost);
notifyItemRangeInserted(initialSize, newPost.size());
}
Here, you are passing a list of Post as a parameter, you are using mPost.size() wich will not do anything there, the addAll method can be replaced with just add and the newPost.size() could be empty as well as the mPost.size()
Second
#Override
public int getItemCount() {
return mPost.size();
}
You should also handle if the list is empty
#Override
public int getItemCount() {
if(mPost.size() > 0){
return mPost.size();
}else{
return 0;
}
}
Third
All your firebase code inside your onBindViewHolder is wrong because while you are binding the data into each row, you are also trying to get each time the values with firebase. Doing this will lend to multiple firebase calls to get the data for just 1 row instead of getting all the data that you want to show.
The solution of this is to do all your firebase logic in your main activity and pass the data to the adapter to set the values.
To solve this with a more cleaner approach, pass your Array as a parameter in your Adapter Constructor, delete the addAll method and do this.
public PostAdapter(Context c, List<Post> mPost) {
this.mPost = mPost
mContext=c;
}
Then as I said, delete all the firebase code from your onBindViewHolder and place it in your MainActivity
With the constructor changed of your Adapter, you should now use your data fetched from firebase like this to work with your adapter.
query = PostRef
.orderByChild("timestamp")
.limitToLast(mPostsPerPage);
query.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
List<Post> userModels = new ArrayList<>();
for (DataSnapshot userSnapshot : dataSnapshot.getChildren()) {
String o=userSnapshot.getKey();
userModels.add(userSnapshot.getValue(Post.class));
}
mAdapter = new PostAdapter(MainActivity.this,userModels)
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
If you want to notify your adapter about any change. Just make a global declaration of the adapter like
private PostAdapter adapter;
and then just use
adapter.notifySetDataChanged();
Make sure the instance has been executed at least once.
mAdapter = new PostAdapter(MainActivity.this,userModels);
Firebase has released firebaseRecyclerViewAdapter class. This will do a lot of the work for you.
the adapter takes 4 input arguments:
Object class
List item layout resource
Viewholder Class
Query/firebase reference
the populateViewHolder method is all that will be required
FirebaseRecyclerViewAdapter<Object, ObjectViewHolder> adapter = new FirebaseRecyclerViewAdapter<Object, ObjectViewHolder>
(Object.class, android.R.layout.*list_item_layout*, ObjectViewHolder.class, objectQuery) {
public void populateViewHolder(ObjectViewHolder ObjectViewHolder, Object Object) {
//populate your views, example:
ObjectViewHolder.textview.setText(object.getTextOne());
}
};
Then set the adapter:
recycler.setAdapter(mAdapter);
More info on this Firebase RecyclerView Adapter
messageList = (RecyclerView) findViewById(R.id.message_list);
mRefreshLayout = (SwipeRefreshLayout) findViewById(R.id.swipe_refresh_layout);
linearLayoutManager = new LinearLayoutManager(getApplicationContext());
messageList.setLayoutManager(linearLayoutManager);
mAdapter = new MessagesAdapter(messages);
messageList.setAdapter(mAdapter);
final MainData mHelper = new MainData(this);
final Cursor csr = mHelper.getAllQuestions3();
sqlite = mDatabaseReference.child("Messages").child(MessageSenderId).child(MessageRecieverId);
valueEventListener = new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
for (DataSnapshot ds : dataSnapshot.getChildren()) {
//I add the data from firebase to SQLITE here
while (csr.moveToNext()) {
String mSender = csr.getString(csr.getColumnIndex(KEY_SENDER));
String mMessage = csr.getString(csr.getColumnIndex(KEY_MESSAGE));
long mTime = csr.getLong(csr.getColumnIndex(KEY_TIME));
String mSeen = csr.getString(csr.getColumnIndex(KEY_SEEN));
String mTimer = csr.getString(csr.getColumnIndex(KEY_TIMER));
String mType = csr.getString(csr.getColumnIndex(KEY_TYPE));
messages.add(new SQLiteHelper(mSender, mMessage, mType, mSeen, mTimer, mTime));
mAdapter.notifyDataSetChanged();
}
mDatabaseReference.child("Messages").child(MessageSenderId).child(MessageRecieverId).setValue(null);
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
};
sqlite.addListenerForSingleValueEvent(valueEventListener);
Adapter
public class MessagesAdapter extends RecyclerView.Adapter<MessagesAdapter.MessageViewHolder>{
ChatData mHelper;
Cursor csr;
private List<SQLiteHelper> mMessagesHelperList;
private FirebaseAuth mAuth;
public MessagesAdapter(List<SQLiteHelper> MessagesHelperList) {
this.mMessagesHelperList = MessagesHelperList;
}
public class MessageViewHolder extends RecyclerView.ViewHolder{
public TextView messageText;
public MessageViewHolder(View view) {
super(view);
SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(view.getContext());
mHelper = new ChatData(view.getContext(),"MessagePlus",null,1);
csr = mHelper.getAllQuestions3();
messageText = (TextView)view.findViewById(R.id.message_text_layout);
}
}
#Override
public MessageViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View V = LayoutInflater.from(parent.getContext()).inflate(R.layout.custom_activity_chat,parent,false);
mAuth = FirebaseAuth.getInstance();
return new MessageViewHolder(V);
}
#Override
public void onBindViewHolder(final MessageViewHolder holder, int position) {
SQLiteHelper messagesHelper = mMessagesHelperList.get(position);
holder.messageText.setText(messagesHelper.getMessage());
}
#Override
public int getItemCount() {
return mMessagesHelperList.size();
}
I have another activity where i fetch sqlite data and show it in recyclerview and it works and i had achieved that the same way as this. Here too it used to work but then i added some features and moved around some code and now its not working and i have checked the whole code numerous times but still not finding why its not working...
The table and rows exists with data and the size of list too isnt null
Just discovered that the Adapter isnt getting called when i added Logs inside it. Thats where the problem is but idk why
Your problem is that you are adding the extra messages to the list that you first created your adapter so
instead of
messages.add(new SQLiteHelper(mSender, mMessage, mType, mSeen, mTimer, mTime));
mAdapter.notifyDataSetChanged();
do
mAdapter.add(new SQLiteHelper(mSender, mMessage, mType, mSeen, mTimer, mTime));
and in your adapter you have to add the add function like that
public void add(SQLiteHelper item){
if(mMessagesHelperList!=null){
mMessagesHelperList.add(item);
notifyDataSetChanged();
}
}
also
you have too much "trash" on your code, on your ValueEventListener you are trying to read the values of a cursor and not the ds (DataSnapshot). so probably your cursor there is empty. If the cursor is empty you don't add any item to the adapter, so the adapter don't have items to show, so onBindViewHolder correctly don't get called
recyclerView = findViewById(R.id.recyclerView);
database = FirebaseDatabase.getInstance();
reference_root = database.getReference("/image");
reference_grocery_and_staples = database.getReference("image/Grocery & Staples");
reference_beverages = database.getReference("image/Beverages");
reference_home_and_kitchen = database.getReference("image/Home & Kitchen");
reference_furnishing_and_home_needs = database.getReference("image/Furnishing & Home Needs");
reference_household_needs = database.getReference("image/Household Needs");
reference_personal_care = database.getReference("image/Personal Care");
reference_breakfast_and_dairy = database.getReference("image/Breakfast & Dairy");
reference_biscuits_snacks_and_chocolates = database.getReference("image/Biscuits, Snacks & Chocolates");
reference_noodles_sauces_and_instant_food = database.getReference("image/Noodles, Sauces & Instant Food");
reference_baby_and_kids = database.getReference("image/Baby & Kids");
reference_pet_care = database.getReference("image/Pet Care");
reference_frozen_food = database.getReference("image/Frozen Food");
reference_vegetables = database.getReference("image/Vegetables");
layoutManager = new GridLayoutManager(this, 2);
recyclerView.setLayoutManager(layoutManager);
final ArrayList<DatabaseReference> reference = new ArrayList<>();
reference.add(reference_grocery_and_staples);
reference.add(reference_beverages);
reference.add(reference_home_and_kitchen);
reference.add(reference_furnishing_and_home_needs);
reference.add(reference_household_needs);
reference.add(reference_personal_care);
reference.add(reference_breakfast_and_dairy);
reference.add(reference_biscuits_snacks_and_chocolates);
reference.add(reference_noodles_sauces_and_instant_food);
reference.add(reference_baby_and_kids);
reference.add(reference_pet_care);
reference.add(reference_frozen_food);
reference.add(reference_vegetables);
for(int i = 0; i < 13; i++) {
FirebaseRecyclerOptions<ImageModel> options = new FirebaseRecyclerOptions
.Builder<ImageModel>()
.setQuery(reference.get(i), ImageModel.class)
.build();
adapter = new FirebaseRecyclerAdapter<ImageModel, HomePage.ImageHolder>(options) {
#NonNull
#Override
public HomePage.ImageHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater
.from(HomePage.this)
.inflate(R.layout.row_layout, parent, false);
HomePage.ImageHolder holder = new HomePage.ImageHolder(view);
return holder;
}
#Override
protected void onBindViewHolder(#NonNull HomePage.ImageHolder holder, int position, #NonNull final e.shweta.authenticationdemo.ImageModel model) {
String url = model.getProductURL();
String name = model.getProductName();
String price = model.getProductPrice();
String descritpion = model.getProductDescription();
holder.textView1.setText(name);
holder.textView2.setText("Price: Rs. " + price);
Picasso.get()
.load(url)
.into(holder.imageView);
holder.linearLayoutRowLayout.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Intent intent = new Intent(HomePage.this, e.shweta.authenticationdemo.ProductInfo.class);
intent.putExtra("productImage", model.getProductURL());
intent.putExtra("productName", model.getProductName());
intent.putExtra("productPrice", model.getProductPrice());
intent.putExtra("productDescription", model.getProductDescription());
startActivity(intent);
}
});
}
#Override
public void onDataChanged() {
super.onDataChanged();
adapter.notifyDataSetChanged();
}
};
}
recyclerView.setAdapter(adapter);
I want to show the data of all the children in my home page. I have tried to loop the references to the children. But what it is doing is putting the data of only the final loop to the page. I guess it is doing it because it is updating the view every time.
It is only showing me the data of the final loop, i.e the vegetables i want the data on my homepage of every child.
You need to structure your data differently. Add another field like productType which can be beverages, biscuits etc. If you are ready to do this then just create a class Product.java:
public class Product {
private String productName, productPrice;//etc
//add setters and getters
}
To get data and update recycler view
private List<Product> productList;
productList = new ArrayList<>();
mRef = database.getReference().child(); //path
mRef.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
Iterable<DataSnapshot> productData = dataSnapshot.getChildren();
for(DataSnapshot d : productData){
Product product = d.getValue(Product.class);
if(product.getProductType() == "Beverages"){ //getProductType() is the getter from Product.java
productList.add(product);
recyclerAdapter.notifyDataSetChanged();
}
//Now only beverages are added to recycler view
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
Pass the List item to the adapter
recyclerAdapter = new mRecyclerAdapter(getContext(), productList);
modify your adapter constructor to accept these values
I am trying to create a RecyclerView that populates CardViews based on data in Firebase. I am receiving an IndexOutOfBoundsException when there is no data in Firebase, however I would like for the RecyclerView to display (without any data) when there is no data in Firebase:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Firebase.setAndroidContext(this);
setContentView(R.layout.activity_discussion);
toolbar = (Toolbar) findViewById(R.id.tool_bar);
setSupportActionBar(toolbar);
setTitle(R.string.discussion_title_text);
mDateFormat = new SimpleDateFormat("MM-dd-yyyy");
mDate = new Date();
mCurrentDateString = mDateFormat.format(mDate);
mBaseRef = new Firebase(FIREBASE_URL);
mPollsRef = mBaseRef.child(POLLS_LABEL);
mUpdateRef = mPollsRef.child(mCurrentDateString).child(String.valueOf(mPollIndex + 1));
mCommentsRef = mUpdateRef.child(COMMENTS_LABEL);
mPollImage = (ImageView) findViewById(R.id.comments_image);
mPollCommentQuestion = (TextView) findViewById(R.id.poll_comment_question);
mUserComment = (EditText) findViewById(R.id.user_comment);
mUserAvatar = (ImageView) findViewById(R.id.profile_image_avatar);
mCommentArrayList = new ArrayList<Comments>();
mCommentIDArrayList = new ArrayList<String>();
mPollCommentsList = (RecyclerView) findViewById(R.id.poll_comments_list);
LinearLayoutManager llm = new LinearLayoutManager(this);
llm.setOrientation(LinearLayoutManager.VERTICAL);
mPollCommentsList.setLayoutManager(llm);
mPollCommentsList.setHasFixedSize(true);
getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_HIDDEN);
mUpdateRef.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
setImage(dataSnapshot);
setQuestion(dataSnapshot);
createInitialCommentIDArray(dataSnapshot);
mNumberOfCommentsAtPoll = (int) dataSnapshot.child(COMMENTS_LABEL).getChildrenCount();
for (int i = 0; i < mNumberOfCommentsAtPoll; i++) {
String commentID = (String) dataSnapshot.child(COMMENTS_LABEL).child(mCommentIDArrayList.get(i)).child("COMMENT").getValue();
Log.v("COMMENT_ID", "The comment ID is " + commentID);
String userID = (String) dataSnapshot.child(COMMENTS_LABEL).child(mCommentIDArrayList.get(i)).child("USER_ID").getValue();
Log.v("USER_ID", "The user ID is " + userID);
mCommentArrayList.add(0, new Comments(mUserAvatar, userID, commentID));
mCommentAdapter.notifyDataSetChanged();
}
}
#Override
public void onCancelled(FirebaseError firebaseError) {
}
});
mCommentAdapter = new MyAdapter(mCommentArrayList);
mPollCommentsList.setAdapter(mCommentAdapter);
Intent intent = getIntent();
String pollID = intent.getStringExtra("POLL_ID");
mPollIndex = intent.getIntExtra("POLL_INDEX", 0);
//TODO: Store unique comment ID's in an array
//TODO: Figure out how to programmatically add images to AWS and then store URL in Firebase
ImageView fab = (ImageView) findViewById(R.id.add_comment);
fab.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
HashMap<String, Object> commentMap = new HashMap<String, Object>();
commentMap.put("USER_ID", mBaseRef.getAuth().getUid());
commentMap.put("COMMENT", mUserComment.getText().toString());
mUpdateRef.child(COMMENTS_LABEL).push().updateChildren(commentMap);
hideKeyboard(view);
mUserComment.setText("");
Toast.makeText(getApplicationContext(), R.string.comment_added, Toast.LENGTH_LONG).show();
}
});
}
My Array Adapter, I note where the error is occurring:
public class MyAdapter extends RecyclerView.Adapter<MyAdapter.ViewHolder> {
private ArrayList<Comments> 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 class ViewHolder extends RecyclerView.ViewHolder {
// each data item is just a string in this case
protected ImageView userAvatar;
protected TextView userID;
protected TextView userComment;
public ViewHolder(View v) {
super(v);
userAvatar = (ImageView) findViewById(R.id.profile_image_avatar);
userID = (TextView) findViewById(R.id.user_ID);
userComment = (TextView) findViewById(R.id.user_comment);
}
}
// Provide a suitable constructor (depends on the kind of dataset)
public MyAdapter(ArrayList<Comments> myDataset) {
mDataSet = myDataset;
}
// Create new views (invoked by the layout manager)
#Override
public MyAdapter.ViewHolder onCreateViewHolder(ViewGroup parent,
int viewType) {
// create a new view
View v = LayoutInflater.from(parent.getContext())
.inflate(R.layout.individual_comment, parent, false);
// set the view's size, margins, paddings and layout parameters
ViewHolder x = new ViewHolder(v);
return x;
}
// Replace the contents of a view (invoked by the layout manager)
//The OutOfBoundsException is pointing here
#Override
public void onBindViewHolder(ViewHolder holder, int position) {
holder.userComment.setText(mCommentArrayList.get(position).getUserComment());
String x = mCommentArrayList.get(position).getUserComment();
Log.v("ON_BIND_VIEW", "THE STRING IS " + x);
}
// Return the size of your dataset (invoked by the layout manager)
#Override
public int getItemCount() {
return mNumberOfCommentsAtPoll;
}
}
Result:
You should try to return mDataset.size() in the getItemCount() method instead of mNumberOfCommentsAtPoll.
#Override
public int getItemCount() {
return mDataSet.size();
}