How can I create a ranked leaderboard in Firebase? - java

There is a point system in my application. I want to create an ordered list of points in a part. It will be in order from highest score to lowest score. In the code I wrote, this system does not work correctly. not ranked from highest to lowest score. Newly rated users appear at the top. How can I fix this problem? I want it sorted from highest score to lowest score.
Scoreboard class:
DatabaseReference UsersRef, RatingsRef;
int currentpage = 1 ;
static final int total_ITEMS = 10 ;
RecyclerView scorrecy ;
UsersRef = FirebaseDatabase.getInstance().getReference().child("Users");
RatingsRef = FirebaseDatabase.getInstance().getReference().child("Ratings");
RatingsRef.keepSynced(false);
getScor();
public void getScor(){
FirebaseRecyclerOptions<ScorModel> options =
new FirebaseRecyclerOptions.Builder<ScorModel>()
.setQuery(RatingsRef.orderByChild("puan").limitToLast(currentpage * total_ITEMS),ScorModel.class)
.build();
FirebaseRecyclerAdapter<ScorModel,ScorViewHolder> adapter
=new FirebaseRecyclerAdapter<ScorModel, ScorViewHolder>(options)
{
#Override
protected void onBindViewHolder(#NonNull final ScorBoard.ScorViewHolder holder, int position, #NonNull ScorModel model) {
final String visit_user_id = getRef(position).getKey();
UsersRef.child(visit_user_id).addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
if (dataSnapshot.hasChild("isim")){
final String myUsername = dataSnapshot.child("isim").getValue().toString();
holder.userName.setText(myUsername);
}
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
}
});
RatingsRef.child(visit_user_id).addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
if (dataSnapshot.hasChild("puan")){
final String myPoint = dataSnapshot.child("puan").getValue().toString();
holder.userPoint.setText(myPoint+" "+"Puan");
}else {
holder.userPoint.setText("0 Puan");
}
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
}
});
}
#NonNull
#Override
public ScorBoard.ScorViewHolder onCreateViewHolder(#NonNull ViewGroup viewGroup, int i) {
View view = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.scorboard_model_layout,viewGroup,false);
ScorBoard.ScorViewHolder viewHolder = new ScorBoard.ScorViewHolder(view);
return viewHolder;
}
};
adapter.startListening();
scorrecy.setAdapter(adapter);
}
public static class ScorViewHolder extends RecyclerView.ViewHolder{
TextView userName , userPoint;
View mView;
public ScorViewHolder(#NonNull View itemView) {
super(itemView);
mView= itemView;
userName =itemView.findViewById(R.id.rank_username);
userPoint =itemView.findViewById(R.id.point);
}
}
ScorModel;
public String scor, username , currentUserID ;
public ScorModel(){
}
public ScorModel(String scor,String username , String currentUserID) {
this.scor= scor;
this.username = username;
this.currentUserID = currentUserID;
}
public String getScor() {
return scor;
}
public void setScor(String scor) {
this.scor = scor;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
Myy DB Ratings ;
enter image description here
Update :
RatingsRef = FirebaseDatabase.getInstance().getReference().child("Ratings");
RatingsRef.child(currentUserID).child("Ratings").addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
double sum = 0.0;
try {
for (DataSnapshot ds: dataSnapshot.getChildren()) {
Map<String,Object> map = (Map<String, Object>) ds.getValue();
Object rating = map.get("rating");
Double pvalue = Double.parseDouble(String.valueOf(rating));
sum += pvalue;
Map userpoint = new HashMap();
userpoint .put("puan", String.valueOf(sum));
RatingsRef.child(currentUserID).updateChildren(userpoint );
}
}catch (Exception e){
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
throw databaseError.toException(); // don't ignore errors
}
});

You cannot get the desired results, because your puan field holds a value of type string and not a number. One thing to remember is that when you order strings the results are ordered lexicographically. For example, 10 is placed before 2. See an example below:
1, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 2, 20, 21, 3
So the best option that you have is to change the type of the field to be number and not string.

Related

How to sort data from Firebase realtime database?

I'm using GraphView library. My code below gets data from Firebase real-time database and updates the graph with values from database, but it isn't sorted. I need it to be sorted in ascending order in X axis. The data in X axis is Long type, then it's converted to date.
I've tried adding dp[index] to array list and using different sorting methods, but nothing seems to work.
#Override
public void onStart() {
reference.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot snapshot) {
FirebaseAuth auth;
auth = FirebaseAuth.getInstance();
FirebaseUser user = auth.getCurrentUser();
String id = user.getUid();
DataPoint[] dp = new DataPoint[(int) snapshot.child(id).getChildrenCount()];
int index = 0;
for(DataSnapshot myDataSnapshot : snapshot.child(id).getChildren()){
PointValue pointValue = myDataSnapshot.getValue(PointValue.class);
dp[index] = new DataPoint(pointValue.getxValue(), pointValue.getyValue());
index ++;
}
lineGraphSeries.resetData(dp);
}
#Override
public void onCancelled(#NonNull DatabaseError error) {
}
});
super.onStart();
}
AlertDialog, where data is being written to the database:
builder.setPositiveButton("ADD",
new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialogInterface, int i) {
if(TextUtils.isEmpty(weightEditText.getText().toString()) || TextUtils
.isEmpty(dateEditText.getText().toString())) {
Toast.makeText(getActivity(),"Please provide weight and date",
Toast.LENGTH_SHORT).show();
} else{
linearLayout.addView(createNewTextView(weightEditText.getText().toString(),
dateEditText.getText().toString()));
String id = user.getUid();
String randomId = reference.push().getKey();
try {
Date date = sdf.parse(dateEditText.getText().toString());
long x = date.getTime();
int y = Integer.parseInt(weightEditText.getText().toString());
PointValue pointValue = new PointValue(x,y);
reference.child(id).child(randomId).setValue(pointValue);
} catch (ParseException e) {
e.printStackTrace();
}
}
}
});
builder.setView(view);
builder.show();
PointValue class:
public class PointValue {
long xValue;
int yValue;
public PointValue() {
}
public PointValue(long xValue, int yValue) {
this.xValue = xValue;
this.yValue = yValue;
}
public long getxValue() {
return xValue;
}
public int getyValue() {
return yValue;
}
}
#EDIT
Thanks to #Frank van Puffelen, I've managed to sort my data from Firebase Database using orderByChild()
https://firebase.google.com/docs/database/android/lists-of-data#sort_data
below working solution:
#Override
public void onStart() {
FirebaseAuth auth;
auth = FirebaseAuth.getInstance();
FirebaseUser user = auth.getCurrentUser();
String id = user.getUid();
Query dateAscendingOrder = database.getReference("users")
.child(id).orderByChild("xValue");
dateAscendingOrder.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot snapshot) {
DataPoint[] dp = new DataPoint[(int) snapshot.getChildrenCount()];
int index = 0;
for (DataSnapshot myDataSnapshot : snapshot.getChildren()){
PointValue pointValue = myDataSnapshot.getValue(PointValue.class);
dp[index] = new DataPoint(pointValue.getxValue(), pointValue.getyValue());
index++;
}
lineGraphSeries.resetData(dp);
}

Firebase search by multiple queries and add to RecyclerView Android Studio

I'm attempting to replicate a search function in a messaging app with Firebase and display the results in a RecyclerView.
I would like to return users whose firstname, username, or lastname start with the search input text in the same recyclerview, in that order.
I am able to successfully search by one of the children, in this case I'm searching for a user's first name, but I'm really stuck as to how to add the results from the username and lastname, and in such a way that there is no duplication (e.g. if I search "A", a user with firstname "Anna" and lastname "Albury" doesn't appear twice.
Any and all help appreciated, thanks.
Activity searchUsers method:
private void searchUsers(String s){
searchInput = search_users.getText().toString();
FirebaseRecyclerOptions<Friends> retrievedFriends = new FirebaseRecyclerOptions.Builder<Friends>()
.setQuery(FriendsRef.orderByChild("refFirstName")
.startAt(searchInput).endAt(searchInput+"\uf8ff"), Friends.class)
.build();
FirebaseRecyclerAdapter<Friends, FriendsViewHolder> adapter =
new FirebaseRecyclerAdapter<Friends, FriendsViewHolder>(retrievedFriends) {
#Override
protected void onBindViewHolder(#NonNull #NotNull FriendsViewHolder holder, int position, #NonNull #NotNull Friends model) {
final String usersIDs = getRef(position).getKey();
UsersRef.child(usersIDs).addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull #NotNull DataSnapshot dataSnapshot) {
if (dataSnapshot.child("Details").hasChild("profileImage")) {
String userImage = dataSnapshot.child("Details").child("profileImage").child("imageUrl").getValue().toString();
String profileFirstName = dataSnapshot.child("Details").child("firstname").getValue().toString();
String profileLastName = dataSnapshot.child("Details").child("lastname").getValue().toString();
String profileStatus = dataSnapshot.child("Details").child("status").getValue().toString();
String profileName = profileFirstName + " " + profileLastName;
holder.userName.setText(profileName);
holder.userStatus.setText(profileStatus);
Picasso.get().load(userImage).into(holder.profileImage);
} else {
String profileFirstName = dataSnapshot.child("Details").child("firstname").getValue().toString();
String profileLastName = dataSnapshot.child("Details").child("lastname").getValue().toString();
String profileName = profileFirstName + " " + profileLastName;
holder.userName.setText(profileName);
}
}
#Override
public void onCancelled(#NonNull #NotNull DatabaseError databaseError) {
}
});
}
#NonNull
#NotNull
#Override
public FriendsViewHolder onCreateViewHolder(#NonNull #NotNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.users_message_layout, parent, false);
return new FriendsViewHolder(view);
}
};
myFriendsList.setAdapter(adapter);
adapter.startListening();
}
Activity onCreate method
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_new_message);
//default function
myFriendsList = (RecyclerView) findViewById(R.id.new_message_friends_list);
myFriendsList.setLayoutManager(new LinearLayoutManager(this));
mAuth = FirebaseAuth.getInstance();
currentUserID = mAuth.getCurrentUser().getUid();
FriendsRef = FirebaseDatabase.getInstance().getReference().child("Users").child(currentUserID).child("Friends");
UsersRef = FirebaseDatabase.getInstance().getReference().child("Users");
//search function
search_users = findViewById(R.id.new_message_search_edittext);
search_users.addTextChangedListener(new TextWatcher() {
#Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
#Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
int length = search_users.length();
if (length > 0) {
searchUsers(s.toString());
} else {
cancelSearch();
}
}
#Override
public void afterTextChanged(Editable s) {
}
});
}
Friends class:
public class Friends {
public String firstName, lastName, status, image, uid;
public Friends (){
}
public Friends(String firstName, String lastName, String status, String image, String uid) {
this.firstName = firstName;
this.lastName = lastName;
this.status = status;
this.image = image;
this.uid = uid;
}
public String getFirstName() {return firstName;}
public void setFirstName(String firstName) {this.firstName = firstName;}
public String getLastName() {return lastName;}
public void setLastName(String lastName) {this.lastName = lastName;}
public String getStatus() {return status;}
public void setStatus(String lastName) {this.status = status;}
public String getImage() {return image;}
public void setImage(String image) {this.image = image;}
public String getUid() {return uid;}
public void setUid(String uid) {this.uid = uid;}
}
Sample of my database:
According to your last comment:
What I'm looking for is a way to get around this by effectively search three times, once for first names, once for last names, and once for usernames, and collate the resulting users in a single RecyclerView.
In this case, you should perform three different queries and collect all the results using Tasks.whenAllSuccess() method:
DatabaseReference rootRef = FirebaseDatabase.getInstance().getReference();
Query firstQuery = rootRef...
Query secondQuery = rootRef...
Query thirdQuery = rootRef...
Task firstTask = firstQuery.get();
Task secondTask = secondQuery.get();
Task thirdTask = thirdQuery.get();
Task combinedTask = Tasks.whenAllSuccess(firstTask, secondTask, thirdTask).addOnSuccessListener(new OnSuccessListener<List<Object>>() {
#Override
public void onSuccess(List<Object> list) {
//Do what you need to do with your list
}
});
But remember, to avoid duplicates, add a name to the list only if it does not exist. Then simply pass the list to an adapter, and display only the results without duplicates in a RecyclerView.

DatabaseException:Expected a List while deserializing, but got a class java.util.HashMap

I tried using GenericTypeIndicator in a recycler view to set A Array of data to a recycler view inside a recycler view.
The GenericTypeIndicator throws an error that causes the application to crash.
I tried figuring out the error but it seems it was expecting a list but got a Hashmap instead.
public class ScheduleOrder extends AppCompatActivity implements IFirebaseLoadListener {
DeviceSession deviceSession;
UserSession userSession;
String Device_Id="",User_Id="";
IFirebaseLoadListener iFirebaseLoadListener;
RecyclerView my_recycler_view;
DatabaseReference myData;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_schedule_order);
deviceSession = new DeviceSession(getApplicationContext());
Device_Id = deviceSession.getDeviceDetails();
userSession = new UserSession(getApplicationContext());
final HashMap<String, String> user = userSession.getUserDetails();
User_Id = user.get(UserSession.User_Id);
FloatingActionButton myFab = (FloatingActionButton)findViewById(R.id.schedule_add);
myFab.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
Intent i = new Intent(getApplicationContext(),Schedule_Order.class);
startActivity(i);
finish();
}
});
myData=FirebaseDatabase.getInstance().getReference("Cart_Schedule"+"/"+Device_Id);
iFirebaseLoadListener=this;
my_recycler_view=findViewById(R.id.my_recyclr_view);
my_recycler_view.setHasFixedSize(true);
my_recycler_view.setLayoutManager(new LinearLayoutManager(this));
getFirebaseData();
}
private void getFirebaseData() {
myData.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
List<ItemGroup>itemGroups=new ArrayList<>();
for(DataSnapshot groupSnapShot:dataSnapshot.getChildren()){
ItemGroup itemGroup=new ItemGroup();
for(DataSnapshot newdatasnap:groupSnapShot.child("listItem").getChildren()){
itemGroup.setD_Time(groupSnapShot.child("d_Time").getValue(true).toString());
itemGroup.setF_Amount(groupSnapShot.child("f_Amount").getValue(true).toString());
GenericTypeIndicator<ArrayList<ItemData>> genericTypeIndicator=new GenericTypeIndicator<ArrayList<ItemData>>(){};
Log.d("JADOO", "onDataChange: ??? "+genericTypeIndicator);
// Log.d("JADOO", "onDataChange: ??? "+itemData1.getB_Quantity());
// Log.d("JADOO", "onDataChange: ??? "+itemData1.getC_Price());
itemGroup.setListItem(newdatasnap.getValue(genericTypeIndicator));
itemGroups.add(itemGroup);
}}
iFirebaseLoadListener.onFirebaseLoadSuccess(itemGroups);
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
iFirebaseLoadListener.onFirebaseLoadFailed(databaseError.getMessage());
}
});
}
#Override
public void onFirebaseLoadSuccess(List<ItemGroup> itemGroupList) {
MyItemGroupAdapter adapter = new MyItemGroupAdapter(this,itemGroupList);
my_recycler_view.setAdapter(adapter);
}
#Override
public void onFirebaseLoadFailed(String message) {
}
}
ItemData.java
private String a_Item_name;
private String b_Quantity;
private String c_Price;
private String d_Time;
private String e_ID;
private String f_Amount;
private String g_COD;
private String h_Address;
public ItemData(){
}
public ItemData(String a_Item_name,String b_Quantity,String c_Price, String d_Time, String e_ID,String f_Amount, String g_COD,String h_Address)
{
this.a_Item_name=a_Item_name;
this.b_Quantity=b_Quantity;
this.c_Price=c_Price;
this.d_Time=d_Time;
this.e_ID=e_ID;
this.f_Amount=f_Amount;
this.g_COD=g_COD;
this.h_Address=h_Address;
}
public String getA_Item_name() {
return a_Item_name;
}
public void setA_Item_name(String a_Item_name) {
this.a_Item_name = a_Item_name;
}
public String getB_Quantity() {
return b_Quantity;
}
public void setB_Quantity(String b_Quantity) {
this.b_Quantity = b_Quantity;
}
public String getC_Price() {
return c_Price;
}
public void setC_Price(String c_Price) {
this.c_Price = c_Price;
}
public String getD_Time() {
return d_Time;
}
public void setD_Time(String d_Time) {
this.d_Time = d_Time;
}
public String getE_ID() {
return e_ID;
}
public void setE_ID(String e_ID) {
this.e_ID = e_ID;
}
public String getF_Amount() {
return f_Amount;
}
public void setF_Amount(String f_Amount) {
this.f_Amount = f_Amount;
}
public String getG_COD() {
return g_COD;
}
public void setG_COD(String g_COD) {
this.g_COD = g_COD;
}
public String getH_Address() {
return h_Address;
}
public void setH_Address(String h_Address) {
this.h_Address = h_Address;
}
}
Error
E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.food.pilo, PID: 1501
com.google.firebase.database.DatabaseException: Expected a List while deserializing, but got a class java.util.HashMap
at com.google.firebase.database.core.utilities.encoding.CustomClassMapper.deserializeToParameterizedType(com.google.firebase:firebase-database##16.0.4:233)
at com.google.firebase.database.core.utilities.encoding.CustomClassMapper.deserializeToType(com.google.firebase:firebase-database##16.0.4:176)
at com.google.firebase.database.core.utilities.encoding.CustomClassMapper.convertToCustomClass(com.google.firebase:firebase-database##16.0.4:101)
at com.google.firebase.database.DataSnapshot.getValue(com.google.firebase:firebase-database##16.0.4:239)
at com.food.pilo.ScheduleOrder$2.onDataChange(ScheduleOrder.java:111)
at com.google.firebase.database.Query$1.onDataChange(com.google.firebase:firebase-database##16.0.4:183)
at com.google.firebase.database.core.ValueEventRegistration.fireEvent(com.google.firebase:firebase-database##16.0.4:75)
at com.google.firebase.database.core.view.DataEvent.fire(com.google.firebase:firebase-database##16.0.4:63)
at com.google.firebase.database.core.view.EventRaiser$1.run(com.google.firebase:firebase-database##16.0.4:55)
at android.os.Handler.handleCallback(Handler.java:873)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:214)
at android.app.ActivityThread.main(ActivityThread.java:7156)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:494)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:975)```
FireBase Database Screenshot attached with fields of data that needs to retracted
Based on the provided screenshot, the data at */someGroup/listItem/someChild has the shape of an ItemData object. Inside your onDataChange() handler you are trying to read the value of */someGroup/listItem/someChild as an array using a GenericTypeIndicator, which is failing because it's not an array. This is fixed by passing in the class reference to ItemData instead.
List<ItemGroup>itemGroups=new ArrayList<>();
for(DataSnapshot groupSnapShot:dataSnapshot.getChildren()){
// moved: outside of loop so that values only processed once (for performance)
String group_d_Time = groupSnapShot.child("d_Time").getValue(true).toString()
String group_f_Amount = groupSnapShot.child("f_Amount").getValue(true).toString()
for(DataSnapshot newdatasnap:groupSnapShot.child("listItem").getChildren()) {
ItemGroup itemGroup = new ItemGroup(); // moved: inside loop to create new object on each loop
itemGroup.setD_Time(group_d_Time);
itemGroup.setF_Amount(group_f_Amount);
itemGroup.setListItem(newdatasnap.getValue(ItemData.class)); // changed: value of newdatasnap is an ItemData object, not an array of ItemData objects
itemGroups.add(itemGroup);
}
}
iFirebaseLoadListener.onFirebaseLoadSuccess(itemGroups);

How to update total no of child from firebase child node everytime onDataChange from AddSingleValueEventListner?

Below image shows my Firebase database structure:
All data retrieved successfully. Here is my model class.
public class Post
{
public String lastname;
public String postid;
public long timestamp;
public HashMap<String,Boolean> count;
public Post()
{
}
public Post(String lastname, long timestamp, String postid,HashMap count)
{
this.lastname=lastname;
this.timestamp=timestamp;
this.postid=postid;
this.count=count;
}
public HashMap<String, Boolean> getCounts() {
return count;
}
public void setCounts(HashMap<String, Boolean> count) {
this.count = count;
}
In Main Activity i used to get data
mAdapter = new PostAdapter(MainActivity.this);
getAllPost(null);
postList.addOnScrollListener(new RecyclerView.OnScrollListener() {
#Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);
if (!recyclerView.canScrollVertically(1))
{
loaded=loaded+10;
if (totalPost== mAdapter.getItemCount())
{
Toast.makeText(MainActivity.this, "no more post", Toast.LENGTH_SHORT).show();
}
else
{
getAllPost(mAdapter.getLastItemId());
}
}
}
});
postList.setAdapter(mAdapter);
private void getAllPost(final String nodeId)
{
final Query query;
final int left= (int) (totalPost-mAdapter.getItemCount());
Toast.makeText(this, String .valueOf(left), Toast.LENGTH_SHORT).show();
if (nodeId == null)
{
query = PostRef
.orderByChild("timestamp")
.limitToLast(mPostsPerPage);
}
else
{
if (left<10)
{
query = PostRef
.orderByChild("timestamp")
.limitToFirst(left);
}
else
{
Long time=Long.parseLong(nodeId);
query = PostRef
.orderByChild("timestamp").endAt(time)
.limitToLast(10);
}
}
query.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
List<Post> userModels = new ArrayList<>();
for (DataSnapshot userSnapshot : dataSnapshot.getChildren())
{
userModels.add(userSnapshot.getValue(Post.class));
}
if (!(nodeId ==null))
{
if (left>10)
{
userModels.remove(9);
}
}
Collections.reverse(userModels);
mAdapter.addAll(userModels);
}
#Override
public void onCancelled(DatabaseError databaseError) {
throw databaseError.toException();
}
});
}
And in adapter:
public class PostAdapter extends RecyclerView.Adapter<PostHolder>
{
List<Post> mPost;
Context mContext;
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) {
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");
showCounts(postHolder,i);
setCountsButton(postHolder,i,currentUserID);
tapOnCounts(postHolder,i,currentUserID,post,PostKey);
}
private void tapOncounts(final PostHolder postHolder, final int i, final String currentUserID, final DatabaseReference post, final String postKey)
{
postHolder.countsButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v)
{
if (mPost.get(i).getCounts() !=null)
{
if(mPost.get(i).getCounts().containsKey(currentUserID))
{
post.child(postKey).child("counts").child(currentUserID).removeValue();
postHolder.countsButton.setImageResource(R.drawable.discounts);
}
else
{
postHolder.countsButton.setImageResource(R.drawable.counts);
post.child(postKey).child("counts").child(currentUserID).setValue(true);
}
}
else
{
postHolder.countsButton.setImageResource(R.drawable.counts);
post.child(postKey).child("counts").child(currentUserID).setValue(true);
}
}
});
}
private void setcountsButton(final PostHolder postHolder, int i, String currentUserID)
{
if (mPost.get(i).getCounts() !=null)
{
if(mPost.get(i).getCounts().containsKey(currentUserID))
{
postHolder.countsButton.setImageResource(R.drawable.counts);
}
else
{
postHolder.countsButton.setImageResource(R.drawable.discounts);
}
}
}
private void showCounts(PostHolder postHolder, int i)
{
if((mPost.get(i).getCounts() !=null))
{
postHolder.noOfcounts.setText(String.valueOf(mPost.get(i).getCounts().size()));
}
else
{
postHolder.noOfcounts.setText("0");
}
}
#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 String.valueOf(mPost.get(mPost.size() - 1).getTimestamp());
}
}
All is successfully but whenever total no. of child change(new child added OR old child removed) in count node recylerview is not update. It will only update when i tried to go another activity and come to rerun in MainActivity.
To get realtime updates, you should use Query's addValueEventListener(ValueEventListener listener) method:
Add a listener for changes in the data at this location.
When using addListenerForSingleValueEvent(ValueEventListener listener):
Add a listener for a single change in the data at this location.
Edit:
To get the size of your list, please change the following line of code:
holder.count.setText(String.valueOf(mPost.get(i).getCount().size));
to
holder.count.setText(String.valueOf(getItemCount());
Whenever total number of child changes then your list of Post modal also changes i.e. userModels in your case. Hence whenever your list of model changes your adapter needs to be notified. Hence my guess is to add notifyDataSetChanged to adapter.
Try this:
query.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
List<Post> userModels = new ArrayList<>();
for (DataSnapshot userSnapshot : dataSnapshot.getChildren()) {
userModels.add(userSnapshot.getValue(Post.class));
}
mAdapter.notifyDataSetChanged(); //<<changes made HERE
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
})
For this to work I hope userModels is instance variable to your MainActivity and is set to mAdapter during initialization.

Android retrieving data from Firebase doesn't work for data models even it works for other data model in the project with similar codes

I am new in Android and working on an Android app which can retrieve data from firebase. There is a weird problem. I already successfully implemented the retrieving function for one data model of my program, and I used same codes just changed the variables but it doesn't work for another data model. I did many tests and I think the problem is in FirebaseHelper cuz there is no any data returned from the data snapshot. The error is
java.lang.NullPointerException: Attempt to invoke virtual method 'void android.widget.ListView.setAdapter(android.widget.ListAdapter)' on a null object reference
The codes are shown below:
The Activity that shows the retrieved data in a listview.
public class TimeTableActivity extends AppCompatActivity {
DatabaseReference db;
FirebaseHelper firebasehelper;
TimeTableAdapter adapter;
ListView lv_CourseList;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_time_table);
//GET INTENT
Intent intent = this.getIntent();
String majorID = intent.getStringExtra("MAJOR_ID");
lv_CourseList = (ListView) findViewById(R.id.lv_CourseList);
//INITIALIZE FIREBASE DB
db= FirebaseDatabase.getInstance().getReference();
firebasehelper=new FirebaseHelper(db);
//ADAPTER
adapter = new TimeTableAdapter(getApplicationContext(),firebasehelper.retrieveCourse(majorID, new CourseCallbacks() {
#Override
public void onCourseCallback(ArrayList<CourseInfo> courseInfos) {
lv_CourseList.setAdapter(adapter);
}
}));
lv_CourseList.setAdapter(adapter);
}
}
FirebaseHelper:
public class FirebaseHelper{
private DatabaseReference db;
private ArrayList<Major> majors = new ArrayList<>();
private ArrayList<CourseInfo> courseInfos = new ArrayList<>();
public FirebaseHelper(DatabaseReference db) {
this.db = db;
}
//Save the Major info. into db
public Boolean saveMajor(Major major)
{
Boolean saved = null;
if(major==null)
{
saved =false;
}else
{
try
{
db.child("Major").push().setValue(major);
saved =true;
}catch (DatabaseException e)
{
e.printStackTrace();
saved =false;
}
}
return saved;
}
//Save the Course info. into db
public Boolean saveCourse(CourseInfo courseInfo)
{
Boolean saved = null;
if(courseInfo==null)
{
saved =false;
}else
{
try
{
db.child("CourseInfo").push().setValue(courseInfo);
saved =true;
}catch (DatabaseException e)
{
e.printStackTrace();
saved =false;
}
}
return saved;
}
public ArrayList<Major> retrieveMajor(final MajorCallbacks majorCallbacks){
ChildEventListener childEventListener = new ChildEventListener() {
#Override
public void onChildAdded(DataSnapshot dataSnapshot, String s) {
for (DataSnapshot ds : dataSnapshot.getChildren()) {
Major major = ds.getValue(Major.class);
if (major != null && major.getMajor_id() != null) {
majors.add(major);
}
}
majorCallbacks.onMajorCallback(majors);
}
#Override
public void onChildChanged(DataSnapshot dataSnapshot, String s) {
for (DataSnapshot ds : dataSnapshot.getChildren()) {
Major major = ds.getValue(Major.class);
if (major != null && major.getMajor_id() != null) {
majors.add(major);
}
}
majorCallbacks.onMajorCallback(majors);
}
#Override
public void onChildRemoved(DataSnapshot dataSnapshot) {
}
#Override
public void onChildMoved(DataSnapshot dataSnapshot, String s) {
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
};
db.addChildEventListener(childEventListener);
if (!majors.isEmpty()){
db.removeEventListener(childEventListener);
}
return majors;
}
public ArrayList<CourseInfo> retrieveCourse(String majorID, final CourseCallbacks courseCallbacks){
ChildEventListener childEventListener = new ChildEventListener() {
#Override
public void onChildAdded(DataSnapshot dataSnapshot, String prevChildKey) {
for (DataSnapshot ds : dataSnapshot.getChildren()) {
CourseInfo courseInfo = ds.getValue(CourseInfo.class);
if (courseInfo != null && courseInfo.getCourse_id() != null) {
courseInfos.add(courseInfo);
}
}
courseCallbacks.onCourseCallback(courseInfos);
}
#Override
public void onChildChanged(DataSnapshot dataSnapshot, String prevChildKey) {
for (DataSnapshot ds : dataSnapshot.getChildren()) {
CourseInfo courseInfo = ds.getValue(CourseInfo.class);
if (courseInfo != null && courseInfo.getCourse_id() != null) {
courseInfos.add(courseInfo);
}
}
courseCallbacks.onCourseCallback(courseInfos);
}
#Override
public void onChildRemoved(DataSnapshot dataSnapshot) {
}
#Override
public void onChildMoved(DataSnapshot dataSnapshot, String prevChildKey) {
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
};
db.child("CourseInfo").orderByChild("major_id").equalTo(majorID).addChildEventListener(childEventListener);
return courseInfos;
}
}
The retrieveMajor method works well even though it returns many null data and repetitive data, and I used the codes of retrieveMajor in retrieveCourse. It doesn't work, the courseInfos is always null. Even though I changed db.child("CourseInfo").orderByChild("major_id").equalTo(majorID).addChildEventListener(childEventListener);
to
db.addChildEventListener(childEventListener);
,still nothing is retrieved which means the problem is not the query (Probably the query is also wrong).
Adapter:
public class TimeTableAdapter extends BaseAdapter {
Context context;
ArrayList<CourseInfo> courseInfos;
public TimeTableAdapter(Context context, ArrayList<CourseInfo> courseInfos) {
this.context = context;
this.courseInfos = courseInfos;
}
#Override
public int getCount() {
return courseInfos.size();
}
#Override
public Object getItem(int pos) {
return courseInfos.get(pos);
}
#Override
public long getItemId(int pos) {
return pos;
}
#Override
public View getView(int position, View convertView, ViewGroup viewGroup) {
LayoutInflater inflater = LayoutInflater.from(context);
if(convertView == null)
{
convertView= LayoutInflater.from(context).inflate(R.layout.model_timetable,viewGroup,false);
}
TextView tv_courseid= (TextView) convertView.findViewById(R.id.tv_courseid);
TextView tv_coursename= (TextView) convertView.findViewById(R.id.tv_coursename);
TextView tv_courseinstructor= (TextView) convertView.findViewById(R.id.tv_courseinstructor);
TextView tv_courseavailable= (TextView) convertView.findViewById(R.id.tv_courseavailable);
final CourseInfo courseInfo= (CourseInfo) this.getItem(position);
tv_courseid.setText(courseInfo.getCourse_id());
tv_coursename.setText(courseInfo.getCourse_name());
tv_courseinstructor.setText(courseInfo.getCourse_instructor());
tv_courseavailable.setText(courseInfo.getCourse_available());
return convertView;
}
}
Data model:
#IgnoreExtraProperties
public class CourseInfo {
public String course_id;
public String course_name;
public int course_section;
public String course_type;
public double course_crdhrs;
public String course_days;
public String course_times;
public String course_location;
public int course_max;
public int course_cur;
public int course_available;
public int course_wl;
public double course_per;
public String course_instructor;
public String course_description;
public String course_prerequire;
public String major_id;
public CourseInfo() {
}
public CourseInfo(String course_id, String course_name, int course_section, String course_type, double course_crdhrs, String course_days, String course_times, String course_location, int course_max, int course_cur, int course_available, int course_wl, double course_per, String course_instructor, String course_description, String course_prerequire, String major_id) {
this.course_id = course_id;
this.course_name = course_name;
this.course_section = course_section;
this.course_type = course_type;
this.course_crdhrs = course_crdhrs;
this.course_days = course_days;
this.course_times = course_times;
this.course_location = course_location;
this.course_max = course_max;
this.course_cur = course_cur;
this.course_available = course_available;
this.course_wl = course_wl;
this.course_per = course_per;
this.course_instructor = course_instructor;
this.course_description = course_description;
this.course_prerequire = course_prerequire;
this.major_id = major_id;
}
public String getCourse_id() {
return course_id;
}
public String getCourse_name() {
return course_name;
}
public int getCourse_section() {
return course_section;
}
public String getCourse_type() {
return course_type;
}
public double getCourse_crdhrs() {
return course_crdhrs;
}
public String getCourse_days() {
return course_days;
}
public String getCourse_times() {
return course_times;
}
public String getCourse_location() {
return course_location;
}
public int getCourse_max() {
return course_max;
}
public int getCourse_cur() {
return course_cur;
}
public int getCourse_available() {
return course_available;
}
public int getCourse_wl() {
return course_wl;
}
public double getCourse_per() {
return course_per;
}
public String getCourse_instructor() {
return course_instructor;
}
public String getCourse_description() {
return course_description;
}
public String getCourse_prerequire() {
return course_prerequire;
}
public String getMajor_id() {
return major_id;
}
}
If you need more codes or information, please comment and let me know. I will really appreciate if you can also help me solve the null data and repetitive data problem cuz it makes the listview show many blank and repetitive items.
You cannot return something now that hasn't been loaded yet. With other words, you cannot just simply create a method that as a return type, an ArrayList<Major> and in the same time return that object. This is happening because those methods, onChildAdded(), onChildChanged() and so on, have an asynchronous behaviour, which means that are called even before you are getting/updating the data from/in the database. To solve this, you can move the declaration of that ArrayList inside one method and do what you need to do with it or dive into asynchronous world and use the last part of my answer from this post. You can take also a look at this video for a better understanding.

Categories