RecycerView always reset back to first position after inserting new Firebase data - android

My recyclerview always reset to first position after new data is inserted to firebase. In my TestAdapter class, I have an onClickListener which increments like on a post when clicked. Whenever I click on this "like" button, view is reset to first position. I believe this issue is related to setAdapter() being called on data changed. Please help!
MainActivity fetches "post" data from Firebase and populates it in TestAdapter class.
public class MainActivity extends AppCompatActivity {
private RecyclerView recyclerView;
private TestAdapter testAdapter;
private ArrayList<Post> postList;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
recyclerView = findViewById(R.id.recyclerView);
recyclerView.setLayoutManager(new LinearLayoutManager(this));
fetchPostFromDB();
}
private void fetchPostFromDB() {
DatabaseReference databaseRef = FirebaseDatabase.getInstance().getReference("Post");
databaseRef.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot snapshot) {
postList = new ArrayList<>();
for (DataSnapshot snap : snapshot.getChildren()) {
String post = snap.child("post").getValue().toString();
Post post = new Post(post);
postList.add(post);
}
testAdapter = new TestAdapter(getApplicationContext(), postList);
recyclerView.setAdapter(testAdapter);
}
#Override
public void onCancelled(#NonNull DatabaseError error) {
}
});
}
TestAdapter binds the data (postList) and has an onClickListener.
public class TestAdapter extends RecyclerView.Adapter<TestAdapter.TestHolder> {
private List<Post> postList;
private Context context;
private DatabaseReference databaseReference;
public TestAdapter(Context ct, ArrayList<Post> postList) {
context = ct;
this.postList = postList;
}
#NonNull
#Override
public TestHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
LayoutInflater layoutInflater = LayoutInflater.from(context);
View view = layoutInflater.inflate(R.layout.post_item, parent, false);
final TestHolder holder = new TestHolder(view);
holder.ibLike.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
String postID = postList.get(holder.getAdapterPosition()).getPostID();
databaseReference = FirebaseDatabase.getInstance().getReference("Posts").child(postID).child("likes");
int incrementLike = postList.get(holder.getAdapterPosition()).getLikes() + 1;
databaseReference.setValue(incrementLike);
}
});
return holder;
}
#Override
public void onBindViewHolder(#NonNull final TestHolder holder, final int position) {
holder.tvPost.setText(postList.get(position).getPost());
holder.tvVotes.setText(Integer.toString(postList.get(position).getLikes()));
}
#Override
public int getItemCount() {
return postList.size();
}
public static class TestHolder extends RecyclerView.ViewHolder {
TextView tvPost, tvLikes;
ImageButton ibLike;
public TestHolder(#NonNull View itemView) {
super(itemView);
tvPost = itemView.findViewById(R.id.tvPost);
tvLikes = itemView.findViewById(R.id.tvLikes);
ibLike = itemView.findViewById(R.id.ibLike);
}
}

Here need to initialize your adapter class from main activity. and then when data received just call adapter.notifiyDatasetChanged like:
onCreate():
postList = new ArrayList<>();
recyclerView = findViewById(R.id.recyclerView);
recyclerView.setLayoutManager(new LinearLayoutManager(this));
testAdapter = new TestAdapter(getApplicationContext(), postList);
recyclerView.setAdapter(testAdapter);
and from your fetchPostFromDB delete adapter initialization insted of this just put this line testAdapter.notifiyDataSetChanged()
And when click on text button you can update/handle like this:
holder.ibLike.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
String postID = postList.get(holder.getAdapterPosition()).getPostID();
databaseReference = FirebaseDatabase.getInstance().getReference("Posts").child(postID).child("likes");
int incrementLike = postList.get(holder.getAdapterPosition()).getLikes() + 1;
postList.get(holder.getAdapterPosition()).setLikes(incrementLike);
databaseReference.setValue(incrementLike);
notifyDataSetChanged();
}
});

Related

Child recyclerView showing same items for all parent recyclerView (using Firebase Realtime Database)

Basically I want to create a parent recyclerView which shows the categories and the child recyclerView shows the books of that specific category. But the result of my code is giving me the same books for all categories. Below is the necessary code attached.
Java Source Code for home fragment adapter call
private void loadCategories() {
//init arrayList
categoryArrayList = new ArrayList<>();
//get all categories from firebase
DatabaseReference ref = FirebaseDatabase.getInstance().getReference("Categories");
ref.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot snapshot) {
//clear arrayList before adding data to it
categoryArrayList.clear();
for (DataSnapshot ds : snapshot.getChildren()) {
//get data
ModelCategory model = ds.getValue(ModelCategory.class);
//add category to arrayList
categoryArrayList.add(model);
}
//setup adapter
adapterCategoryHome = new AdapterCategoryHome(categoryArrayList);
//set adapter to recyclerView
binding.categoryRv.setAdapter(adapterCategoryHome);
adapterCategoryHome.notifyDataSetChanged();
}
#Override
public void onCancelled(#NonNull DatabaseError error) {
}
});
}
Parent Adapter
public class AdapterCategoryHome extends RecyclerView.Adapter<AdapterCategoryHome.HolderCategory> {
private Context context;
public ArrayList<ModelCategory> categoryArrayList;
public static final String TAG = "CATEGORY_HOME_TAG";
//arrayList to hold data of type ModelPdf
private ArrayList<ModelPdf> pdfArrayList;
private AdapterPdfHome adapterPdfHome;
public AdapterCategoryHome(ArrayList<ModelCategory> categoryArrayList) {
this.categoryArrayList = categoryArrayList;
}
#NonNull
#Override
public HolderCategory onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
//bind view of row_category_home.xml
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.row_category_home, parent, false);
this.context = parent.getContext();
return new HolderCategory(view);
}
#Override
public void onBindViewHolder(#NonNull AdapterCategoryHome.HolderCategory holder, int position) {
//get data
ModelCategory model = categoryArrayList.get(position);
String id = model.getId();
String category = model.getCategory();
String uid = model.getUid();
long timestamp = model.getTimestamp();
Log.d(TAG, "onBindViewHolder: "+category);
//set data
holder.categoryTv.setText(category);
loadPdfList(model, holder);
}
private void loadPdfList(ModelCategory model, HolderCategory holder) {
//init list before adding data
pdfArrayList = new ArrayList<>();
DatabaseReference ref = FirebaseDatabase.getInstance().getReference("Books");
ref.orderByChild("categoryId").equalTo(model.getId())
.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot snapshot) {
pdfArrayList.clear();
for (DataSnapshot ds : snapshot.getChildren()) {
//get data
ModelPdf model = ds.getValue(ModelPdf.class);
//add to list
pdfArrayList.add(model);
}
RecyclerView.LayoutManager layoutManager = new LinearLayoutManager(context,LinearLayoutManager.HORIZONTAL,false);
holder.bookRv.setHasFixedSize(true);
Log.d(TAG, "pdf size: " + pdfArrayList.size() + model.getCategory() + holder.categoryTv.getText()+ holder.categoryTv.getContext());
//setup adapter
adapterPdfHome = new AdapterPdfHome(holder.bookRv.getContext(), pdfArrayList);
holder.bookRv.setLayoutManager(layoutManager);
holder.bookRv.setAdapter(adapterPdfHome);
adapterPdfHome.notifyDataSetChanged();
}
#Override
public void onCancelled(#NonNull DatabaseError error) {
}
});
}
#Override
public int getItemCount() {
return categoryArrayList.size();
}
/*View Holder class to hold UI views for row_category.xml*/
class HolderCategory extends RecyclerView.ViewHolder {
//ui views of row_category.xml
TextView categoryTv;
RecyclerView bookRv;
public HolderCategory(#NonNull View itemView) {
super(itemView);
//init ui views
categoryTv = itemView.findViewById(R.id.categoryTv);
bookRv = itemView.findViewById(R.id.bookRv);
}
}
}
Child Adapter
public class AdapterPdfHome extends RecyclerView.Adapter<AdapterPdfHome.HolderPdfAdmin> {
//context
private Context context;
//arrayList to hold list of data of type modelPdf
public ArrayList<ModelPdf> pdfArrayList;
private FilterPdfAdmin filter;
private static final String TAG = "PDF_ADAPTER_TAG";
//progress dialog
private ProgressDialog progressDialog;
//constructor of above
public AdapterPdfHome(Context context, ArrayList<ModelPdf> pdfArrayList) {
this.context = context;
this.pdfArrayList = pdfArrayList;
Log.d(TAG, "AdapterPdfHome: "+pdfArrayList.size());
//init progress dialog
progressDialog = new ProgressDialog(context);
progressDialog.setTitle("Please Wait");
progressDialog.setCanceledOnTouchOutside(false);
}
#NonNull
#Override
public HolderPdfAdmin onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
//bind view of row_pdf_admin.xml
View view = LayoutInflater.from(context).inflate(R.layout.row_pdf_home,parent,false);
return new HolderPdfAdmin(view);
}
#Override
public void onBindViewHolder(#NonNull AdapterPdfHome.HolderPdfAdmin holder, int position) {
/*Get data, Set Data, handle clicks, etc.*/
//get data
ModelPdf model = pdfArrayList.get(position);
String title = model.getTitle();
String author = model.getAuthor();
Log.d(TAG, "onBindViewHolder: "+title);
//set data
holder.titleTv.setText(title);
holder.authorTv.setText(author);
Glide.with(context)
.load(model.getCoverPageUrl())
.placeholder(R.drawable.back01)
.into(holder.pdfIv);
}
#Override
public int getItemCount() {
//return size of arrayList
return pdfArrayList.size();
}
/*view holder class for row_pdf_user.xml*/
class HolderPdfAdmin extends RecyclerView.ViewHolder {
//UI views of row_pdf_admin.xml
TextView titleTv, authorTv;
ImageView pdfIv;
public HolderPdfAdmin(#NonNull View itemView) {
super(itemView);
//init ui views
titleTv = itemView.findViewById(R.id.titleTv);
authorTv = itemView.findViewById(R.id.authorTv);
pdfIv = itemView.findViewById(R.id.pdfIv);
}
}
}
move "private AdapterPdfHome adapterPdfHome;" to "onBindViewHolder"

About opening a new activity in respond to a click on a RecyclerView item which is inside of a fragment

I'm loading some data into a RecyclerView from Firebase Realtime Database. This RecyclerView is in a fragment and I want to open a new activity when an item is clicked. But when i add the onClickListener to an item from the adapter, my click doesn't even recognized by the app. I'm not sure what I'm doing wrong here because this method worked fine for a RecyclerView when it is inside of a normal activity.
This is a project for my university and I should submit it tomorrow. So I can really use some help.
This is the my data Adapter class,
public class Adapter_NoLimit extends RecyclerView.Adapter<Adapter_NoLimit.LViewHolder> {
Context context;
ArrayList<Helper> list_nl;
public Adapter_NoLimit(Context context, ArrayList<Helper> list_nl) {
this.context = context;
this.list_nl = list_nl;
}
#NonNull
#Override
public Adapter_NoLimit.LViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View v = LayoutInflater.from(context).inflate(R.layout.itemlist, parent, false);
return new LViewHolder(v);
}
#Override
public void onBindViewHolder(#NonNull Adapter_NoLimit.LViewHolder holder, int position) {
//final Helper temp = list_nl.get(position);
String fname_txt = list_nl.get(position).getFname();
String catg_txt = list_nl.get(position).getSpin();
String prof_img = list_nl.get(position).getProfile_url();
holder.setUsers(fname_txt, catg_txt, prof_img);
holder.f_name.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
AppCompatActivity activity = (AppCompatActivity) v.getContext();
Intent i = new Intent(activity, UserProfile_VV.class);
i.putExtra("full name", fname_txt);
activity.startActivity(i);
}
});
}
#Override
public int getItemCount() {
return list_nl.size();
}
public class LViewHolder extends RecyclerView.ViewHolder{
private TextView f_name, catG;
private ImageView profile_pic;
public LViewHolder(#NonNull View itemView) {
super(itemView);
f_name = itemView.findViewById(R.id.username_view);
catG = itemView.findViewById(R.id.category_view);
profile_pic = itemView.findViewById(R.id.userimage);
}
public void setUsers(String fname_txt, String catg_txt, String prof_img) {
f_name.setText(fname_txt);
catG.setText(catg_txt);
Picasso.get().load(prof_img).fit().into(profile_pic);
}
}
}
This is one of fragments,
public class Beauty_Frag extends Fragment {
RecyclerView recyclerView;
DatabaseReference reference, user_ref;
ArrayList<Helper> list;
Adapter adapter;
FirebaseAuth auth;
String uid;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
View v = inflater.inflate(R.layout.fragment_beauty, container, false);
recyclerView = v.findViewById(R.id.beauty_recycler_frag);
reference = FirebaseDatabase.getInstance().getReference();
user_ref = reference.child("users");
auth = FirebaseAuth.getInstance();
recyclerView.setHasFixedSize(true);
recyclerView.setLayoutManager(new LinearLayoutManager(getContext()));
//searchField = findViewById(R.id.search_field);
list = new ArrayList<>();
adapter = new Adapter(getContext(), list);
recyclerView.setAdapter(adapter);
user_ref.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull /*#org.jetbrains.annotations.NotNull*/ DataSnapshot snapshot) {
for (DataSnapshot key : snapshot.getChildren()) {
if( key.child("spin").getValue().toString().equals("Beauty")) {
Helper helper = key.getValue(Helper.class);
list.add(helper);
adapter.notifyDataSetChanged();
}
}
}
#Override
public void onCancelled(#NonNull /*#org.jetbrains.annotations.NotNull*/ DatabaseError error) {
}
});
return v;
}
}
You are very welcome if you have any solution.
Use below code for onClicklistner:
holder.f_name.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Intent i = new Intent(context, UserProfile_VV.class);
i.putExtra("full name", fname_txt);
context.startActivity(i);
}
});

How do I show info from two different models / adapters in one recyclerview

I have two Models (ModelChat and ModelUsers) and their class adapters (PostsAdapter and AllUsersAdapter).
I want to get and set user info such as name and email from the ModelUser and get and set post information from the ModelPost from Firebase database into the same recyclerview in my HomeActivity.
The codes are as shown below:
PostsAdapter.java
public class PostsAdapter extends RecyclerView.Adapter<PostsAdapter.MyHolder>{
Context context;
List<ModelPost> postList;
public PostsAdapter(Context context, List<ModelPost> postList) {
this.context = context;
this.postList = postList;
}
#NonNull
#Override
public MyHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
//inflate layout row_post.xml
View view = LayoutInflater.from(context).inflate(R.layout.row_posts, parent, false);
return new MyHolder(view);
}
#Override
public void onBindViewHolder(#NonNull MyHolder holder, int position) {
//get data
String userUID = postList.get(position).getUserUID();
String userEmail = postList.get(position).getUserEmail();
String userProfilePic = postList.get(position).getUserProfilePic();
String firstName = postList.get(position).getUserFirstName();
String lastName = postList.get(position).getUserLastName();
String userNickName = postList.get(position).getUserNickName();
String postTimeStamp = postList.get(position).getPostTime();
String userPost = postList.get(position).getUserPost();
//set data
//set data
Glide
.with(context)
.load(userProfilePic)
.apply(RequestOptions.circleCropTransform())
.into(holder.avatarTv);
holder.firstnameTv.setText(firstName);
holder.lastnameTv.setText(lastName);
holder.nicknameTv.setText(userNickName);
}
#Override
public int getItemCount() {
return postList.size();
}
//view holder class
class MyHolder extends RecyclerView.ViewHolder {
//views from row_posts layout
public MyHolder(#NonNull View itemView) {
super(itemView);
//init view
//my views here
}
}
}
AllUsersAdapter.java
public class AllUsersAdapter extends RecyclerView.Adapter<AllUsersAdapter.MyHolder>{
Context context;
List<ModelUser> userList;
//Constructor > Generate
public AllUsersAdapter(Context context, List<ModelUser> userList) {
this.context = context;
this.userList = userList;
}
#NonNull
#Override
public MyHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
//Inflate layout (row_user)
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.row_all_users, parent, false);
return new MyHolder(view);
}
#Override
public void onBindViewHolder(#NonNull MyHolder holder, int position) {
//get data
String userUID = userList.get(position).getUid();
String userProfilePic = userList.get(position).getProfilepic();
String userName = userList.get(position).getFirstname() + " " + userList.get(position).getLastname();
String userNickname = userList.get(position).getNickname();
String userStatus = userList.get(position).getStatus();
//set data
Glide
.with(context)
.load(userProfilePic)
.apply(RequestOptions.circleCropTransform())
.into(holder.mAvatarIv);
holder.mNameTv.setText(userName);
holder.mNicknameTv.setText(userNickname);
holder.mStatusTv.setText(userStatus);
//Handle item click
holder.itemView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
/*Click user from user list to start conversation
*Start Activity by putting UID of receiver
*we will use that UID to identify the user we are gonna chat */
Intent intent = new Intent(context, MessageActivity.class);
intent.putExtra("userUid", userUID);
context.startActivity(intent);
}
});
}
#Override
public int getItemCount() {
return userList.size();
}
class MyHolder extends RecyclerView.ViewHolder {
public MyHolder(#NonNull View itemView) {
super(itemView);
//init my views here
}
}
}
HomeActivity.java
public class HomeActivity extends AppCompatActivity {
FirebaseAuth firebaseAuth;
RecyclerView recyclerView;
List<ModelPost> postList;
PostsAdapter postsAdapter;
String mUID;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_home);
firebaseAuth = FirebaseAuth.getInstance();
//recyclerview and its properties
recyclerView = findViewById(R.id.posts_recyclerview);
//init post list
postList = new ArrayList<>();
loadPosts();
}
private void loadPosts() {
//path of all posts
DatabaseReference reference = FirebaseDatabase.getInstance().getReference("Posts");
//get all data from this reference
reference.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot snapshot) {
postList.clear();
for (DataSnapshot ds: snapshot.getChildren()) {
ModelPost modelPost = ds.getValue(ModelPost.class);
postList.add(modelPost);
//adapter
postsAdapter = new PostsAdapter(HomeActivity.this, postList);
//set adapter to recyclerview
recyclerView.setAdapter(postsAdapter);
}
}
#Override
public void onCancelled(#NonNull DatabaseError error) {
//in case of errors
//Toast.makeText(HomeActivity.this, ""+error.getMessage(), Toast.LENGTH_SHORT).show();
}
});
}
}
Try using ConcatAdapter.
An RecyclerView.Adapter implementation that presents the contents of multiple adapters in sequence. More info
Concatenate adapters sequentially with ConcatAdapter:
https://medium.com/androiddevelopers/merge-adapters-sequentially-with-mergeadapter-294d2942127a
I think this will help
MyAdapter adapter1 = ...;
AnotherAdapter adapter2 = ...;
ConcatAdapter concatenated = new ConcatAdapter(adapter1, adapter2);
recyclerView.setAdapter(concatenated);

getting last item from list - onclicking add button on Recyclerview

I have added cart image in my Adapter class but whenever I click on the button always get the last element from the list. Here is my adapter class and activity class.
Details are perfectly fetched from firebase and Log file showing list of menu.
Here is my MenuAdapter.java class.
public class MenuAdapter extends RecyclerView.Adapter<MenuAdapter.MenuViewHolder> {
private Context mCtx;
private List<Menu> menuList;
private ItemClickEvent itemclick;
public MenuAdapter(Context mCtx, List<Menu> menuList, ItemClickEvent itemclick) {
this.mCtx = mCtx;
this.menuList = menuList;
this.itemclick = itemclick;
}
#NonNull
#Override
public MenuViewHolder onCreateViewHolder(#NonNull ViewGroup viewGroup, int i)
{
View view = LayoutInflater.from(mCtx).inflate(R.layout.menu_list, viewGroup, false);
return new MenuViewHolder(view);
}
#Override
public void onBindViewHolder(#NonNull final MenuViewHolder menuViewHolder, final int i) {
final Menu menu = menuList.get(i);
menuViewHolder.itemName.setText(menu.itemName);
menuViewHolder.itemPrice.setText(menu.itemPrice);
menuViewHolder.addCart.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
itemclick.imageClicked(menu);
}
});
}
#Override
public int getItemCount() {
return menuList.size();
}
public class MenuViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
TextView itemName, itemPrice;
#SuppressLint("StaticFieldLeak")
ImageView addCart;
MenuViewHolder(#NonNull View itemView) {
super(itemView);
itemName = itemView.findViewById(R.id.itemName);
itemPrice = itemView.findViewById(R.id.itemPrice);
addCart = itemView.findViewById(R.id.menuAddCart);
//addCart.setOnClickListener(this);
itemView.setOnClickListener(this);
}
#Override
public void onClick(View v) {
}
}
}
and this MenuActivity.java class
public class MenuActivity extends AppCompatActivity implements ItemClickEvent
{
private ActionBar toolbar;
List<Menu> menuList;
RecyclerView recyclerView;
MenuAdapter adapter;
DatabaseReference databaseReference;
ProgressBar progressBar;
Menu menu;
int foodId = 1;
int cat;
String id,itemName, itemPrice;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_menu);
Intent intent = getIntent();
final String category = intent.getStringExtra("cat_id");
final String catName = intent.getStringExtra("cat_name");
toolbar = getSupportActionBar();
toolbar.setTitle(catName);
cat = Integer.parseInt(category) - 1;
menuList = new ArrayList<>();
recyclerView = findViewById(R.id.menu_recycler);
recyclerView.setHasFixedSize(true);
recyclerView.setLayoutManager(new LinearLayoutManager(this));
adapter = new MenuAdapter(this, menuList,this);
recyclerView.setAdapter(adapter);
ImageView addTCart = findViewById(R.id.menuAddCart);
progressBar = findViewById(R.id.progressBarLoading);
databaseReference = FirebaseDatabase.getInstance().getReference("foods/" + cat + "/menu-items");
// fetchMenu(category);
progressBar.setVisibility(View.VISIBLE);
databaseReference.addListenerForSingleValueEvent(new ValueEventListener()
{
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
progressBar.setVisibility(View.GONE);
if (dataSnapshot.exists()) {
for (DataSnapshot wallpaperSnapshot : dataSnapshot.getChildren()) {
id = wallpaperSnapshot.getKey();
itemName = wallpaperSnapshot.child("name").getValue(String.class);
itemPrice = wallpaperSnapshot.child("price").getValue(String.class);
menu = new Menu(id, itemName, itemPrice, category);
menuList.add(menu);
Log.d("FOOD-DETAIL", String.valueOf(menu));
}
adapter.notifyDataSetChanged();
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
}
#Override
public void imageClicked(Menu m) {
new Database(getApplicationContext()).addToCart(new Order(
Integer.parseInt(id),
menu.getItemName(),
"1",
menu.getItemPrice()
));
foodId += 1;
Toast.makeText(getBaseContext(), itemName+" added to cart", Toast.LENGTH_SHORT).show();
}
#Override
public void viewClicked() {
}
}
Hello try making these changes in imageClicked() in MenuActivity
#Override
public void imageClicked(Menu m) {
new Database(getApplicationContext()).addToCart(new Order(
m.getId(),
m.getItemName(),
"1",
m.getItemPrice()
));
foodId += 1;
Toast.makeText(getBaseContext(), itemName+" added to cart", Toast.LENGTH_SHORT).show();
}
There should be more efficient way to set listener. Just set that listener (same way as it is now) in constructor of MenuViewHolder and assign to this. And in method onClick - check R.id of view and if it is addCart instead of calling itemclick.imageClicked(menu) just call item.click.imageClicked(getAdapterPosition())
This because onBindViewHolder() is calling multiple times and you will still create new listener. But in constructor you create that listener only if you need new MenuViewHolder and use the actual position of adapter.

When/How to declare recyclerView adapter while waiting for database to be fetched from Firebase

I'll appreciate if anyone can help me with this.
So what's happening is the Adapter is being declared before the SenderNames Array List is fetched from Firebase Database.So how do I wait for the SenderNames to be fetched first from database and then display them?
Tab 2 code
public class Tab2 extends Fragment {
private static RecyclerView.Adapter adapter;
private RecyclerView.LayoutManager layoutManager;
private static RecyclerView recyclerView;
private static ArrayList<String> reminderMessages;
protected static ArrayList<String> senderNames;
String receiverUID;
private DatabaseReference mDatabase;
int i =0;
private Button profile;
//Overriden method onCreateView
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
//Returning the layout file after inflating
//Change R.layout.tab1 in you classes
View v =inflater.inflate(R.layout.tab2, container, false);
final FirebaseUser user = FirebaseAuth.getInstance().getCurrentUser();
reminderMessages = new ArrayList<>();
receiverUID = user.getUid();
mDatabase = FirebaseDatabase.getInstance().getReference();
Query query = mDatabase.child("reminders").orderByChild("receiverUID").equalTo(receiverUID);
//Setting size of recycler view as constant
recyclerView = (RecyclerView) v.findViewById(R.id.my_recycler_view2);
recyclerView.setHasFixedSize(true);
//Setting Linear Layout
layoutManager = new LinearLayoutManager(getActivity());
recyclerView.setLayoutManager(layoutManager);
recyclerView.setItemAnimator(new DefaultItemAnimator());
query.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
senderNames = new ArrayList<>();
for (DataSnapshot ds : dataSnapshot.getChildren()) {
//Getting corresponding username of the ReceiverUID
//Getting senderUID
String sUID = ds.child("senderUID").getValue(String.class);
//Getting senders Name
GetSenderName getName = new GetSenderName();
getName.GetSenderssName(sUID);
//Getting message from database
String message = ds.child("reminderMessage").getValue(String.class);
//Adding database to ArrayList
reminderMessages.add(message);
//Getting corresponding username of the ReceiverUID
// Log.d("String names", receiverNames.toString());
}
adapter = new DataAdapter(reminderMessages,senderNames);
recyclerView.setAdapter(adapter);
}
#Override
public void onCancelled(DatabaseError databaseError) {
//Error in Reaching Database
Toast.makeText(getContext(), "Something went Wrong!", Toast.LENGTH_SHORT).show();
}
});
return v;
}
GetSenderName Class
import static com.example.admin.import2.Tab2.senderNames;
public class GetSenderName {private FirebaseAuth auth;
ListView listView;
private DatabaseReference mDatabase;
private String senderName;
public void GetSenderssName(String UID){
mDatabase = FirebaseDatabase.getInstance().getReference().child("users");
//Running a query to find matching UID
Query query = mDatabase.orderByKey().equalTo(UID);
query.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot2) {
// Getting user name with matching UID
for (DataSnapshot users : dataSnapshot2.getChildren()) {
senderName = users.child("username").getValue(String.class);
senderNames.add(senderName);
Log.d("sendername retrieved",senderNames.toString());
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
}
}
DataAdapter Class
public class DataAdapter extends RecyclerView.Adapter<DataAdapter.ViewHolder> {
private ArrayList<String> reminderMessage;
private ArrayList<String> receiverName;
public DataAdapter(ArrayList<String> reminderMessage,ArrayList<String> receiverName) {
this.reminderMessage = reminderMessage;
this.receiverName = receiverName;
}
#Override
public DataAdapter.ViewHolder onCreateViewHolder(ViewGroup viewGroup,int i) {
View view = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.cards_layout, viewGroup, false);
return new ViewHolder(view);
}
#Override
public void onBindViewHolder(DataAdapter.ViewHolder viewHolder, int i) {
viewHolder.reminderText.setText(reminderMessage.get(i));
viewHolder.receiverName.setText(receiverName.get(i));
}
#Override
public int getItemCount() {
return reminderMessage.size();
}
public class ViewHolder extends RecyclerView.ViewHolder{
private TextView reminderText;
private TextView receiverName;
public ViewHolder(View view) {
super(view);
reminderText = (TextView)view.findViewById(R.id.remindertext);
receiverName = (TextView)view.findViewById(R.id.receiverName);
}
}
}
To avoid problems like populate a list before the databases values are fetched, you should use a FirebaseRecyclerAdapter available in firebaseUI library.
It work in asynchronously so you dont need to do nothing. Just set up the recyclerview, the adapter and the query.
Take a look at the official repository
FirebaseUI
Instead of sending the data in constructor you can create some setter method to set the data and update the list,
Remove the arguments in Adapter constructor
Initialize the ArrayList while declaring as a global variable.
Create a setter method to set the data,
If you do your Adapter will be like this,
public class DataAdapter extends RecyclerView.Adapter<DataAdapter.ViewHolder> {
private ArrayList<String> reminderMessage = new ArrayList<>();
private ArrayList<String> receiverName = new ArrayList<>();
public DataAdapter(ArrayList<String> reminderMessage, ArrayList<String> receiverName) {
this.reminderMessage = reminderMessage;
this.receiverName = receiverName;
}
public void setData(ArrayList<String> reminderMessage, ArrayList<String> receiverName) {
if(reminderMessage == null || receiverName != null) {
return;
}
this.reminderMessage.clear();
this.receiverName.clear();
this.reminderMessage.addAll(reminderMessage);
this.receiverName.addAll(receiverName);
notifyDataSetChanged();
}
#Override
public DataAdapter.ViewHolder onCreateViewHolder(ViewGroup viewGroup, int i) {
View view = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.cards_layout, viewGroup, false);
return new ViewHolder(view);
}
#Override
public void onBindViewHolder(DataAdapter.ViewHolder viewHolder, int i) {
viewHolder.reminderText.setText(reminderMessage.get(i));
viewHolder.receiverName.setText(receiverName.get(i));
}
#Override
public int getItemCount() {
return reminderMessage.size();
}
public class ViewHolder extends RecyclerView.ViewHolder {
private TextView reminderText;
private TextView receiverName;
public ViewHolder(View view) {
super(view);
reminderText = (TextView) view.findViewById(R.id.remindertext);
receiverName = (TextView) view.findViewById(R.id.receiverName);
}
}
}
so from your activity you can call like this, adapter.setData(reminderMessages,senderNames); so that you can create the adapter and set in Recycle View before get the data from server.

Categories

Resources