Can't retrieve data from cloud firestore firebase - android

I send data from the activity to the cloud firestore and I retrieve it in the second activity in recycler view.
but the data doesn't appear in the second activity.
I used FirestoreRecyclerAdapter and FirestoreOptions.
This is the activity in which I retrieve the data.
public class MyServicesActivity extends AppCompatActivity {
private FirestoreRecyclerAdapter adapter;
private RecyclerView recyclerView;
private FirebaseFirestore db;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_my_services);
db = FirebaseFirestore.getInstance();
Query query = db.collection("Services Requested");
recyclerView = findViewById(R.id.rv_my_services);
FirestoreRecyclerOptions<ServiceModel> response = new FirestoreRecyclerOptions
.Builder<ServiceModel>()
.setQuery(query, ServiceModel.class)
.build();
adapter = new FirestoreRecyclerAdapter<ServiceModel, ServiceHolder>(response) {
#NonNull
#Override
public ServiceHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.service_design, parent, false);
return new ServiceHolder(v);
}
#SuppressLint("SetTextI18n")
#Override
protected void onBindViewHolder(#NonNull ServiceHolder holder, int position, #NonNull ServiceModel model) {
holder.serviceImage.setImageResource(model.getServiceImage());
Log.d("DATA", "data isn't null" + position);
holder.serviceName.setText(model.getServiceName());
holder.servicePrice.setText(model.getPrice() + "" + " L.E");
}
};
recyclerView.setAdapter(adapter);
recyclerView.setHasFixedSize(true);
recyclerView.setLayoutManager(new LinearLayoutManager(this));
}
public class ServiceHolder extends RecyclerView.ViewHolder {
private ImageView serviceImage;
private TextView serviceName, servicePrice;
public ServiceHolder(#NonNull View itemView) {
super(itemView);
serviceImage = itemView.findViewById(R.id.polish_img);
serviceName = itemView.findViewById(R.id.polish_txt);
servicePrice = itemView.findViewById(R.id.price_txt);
}
}
#Override
protected void onStart() {
super.onStart();
adapter.startListening();
}
#Override
protected void onStop() {
super.onStop();
adapter.startListening();
}
}
This is the class model for retrieve data from cloud firestore
public class ServiceModel {
private String serviceName;
private int price;
private int serviceImage;
public ServiceModel(){}
public ServiceModel(String serviceName, int price, int serviceImage) {
this.serviceName = serviceName;
this.price = price;
this.serviceImage = serviceImage;
}
public void setServiceName(String serviceName) {
this.serviceName = serviceName;
}
public void setPrice(int price) {
this.price = price;
}
public void setServiceImage(int serviceImage) {
this.serviceImage = serviceImage;
}
public String getServiceName() {
return serviceName;
}
public int getPrice() {
return price;
}
public int getServiceImage() {
return serviceImage;
}
}

I see in your screenshot, that the name of the properties in the database are stored using whitespace between the words, and each word is starting with a capital letter, while in your class, there is no whitespace and the first word starts with a lower-case and the second with a capital letter. When you are using a public getter called getServiceName(), Firebase is looking in the database after a property called serviceName, which actually does not exist.
To solve this, you either change the properties in your database to match the one in the class, remove the actual data, and add a fresh one, or you can use an annotation called PropertyName in front of the getter, to match the actual naming.

Related

How to retrieve just specific data in Recycler View using Firebase Database?

I have a problem with retrieving specific data from Firebase Realtime Database. My problem is that I want to display in RecyclerView just the materials that has the Course_ID (as you can see in the image below) equals to the Course_ID (see Course -> Teacher-Courses in Firebase). How can I accomplish that thing? I will attach the code used in the RecyclerView and the class that contains the model.
As a mention: 1.I have tried to add all the course id's from Firebase and store them to a List, but the app doesn't show anything and 2. In another class I have an Intent that sends me here and also send a extra String with Course_ID that I have accesed.
I am waiting for your responses. Thank you!
FileMaterial.class
public class FileMaterial {
private String Course_ID;
private String Denumire_material;
private String Locatie_material;
private String Teacher_ID;
public FileMaterial() {
}
public FileMaterial(String course_ID, String denumire_material, String locatie_material, String teacher_ID) {
Course_ID = course_ID;
Denumire_material = denumire_material;
Locatie_material = locatie_material;
Teacher_ID = teacher_ID;
}
public String getCourse_ID() {
return Course_ID;
}
public void setCourse_ID(String course_ID) {
Course_ID = course_ID;
}
public String getDenumire_material() {
return Denumire_material;
}
public void setDenumire_material(String denumire_material) {
Denumire_material = denumire_material;
}
public String getLocatie_material() {
return Locatie_material;
}
public void setLocatie_material(String locatie_material) {
Locatie_material = locatie_material;
}
public String getTeacher_ID() {
return Teacher_ID;
}
public void setTeacher_ID(String teacher_ID) {
Teacher_ID = teacher_ID;
}
CourseMaterial.class
public class CourseMaterial extends AppCompatActivity {
private RecyclerView recyclerView;
private DatabaseReference reference, userReference;
private FirebaseAuth mAuth;
FirebaseRecyclerOptions<FileMaterial> options;
FirebaseRecyclerAdapter<FileMaterial, CourseMaterial.FileViewHolder> adapter;
ImageView btnAddMaterial;
ImageView deleteMaterial;
StorageReference storageReference;
FirebaseStorage firebaseStorage;
String urlReference;
String value;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_course_material);
value = getIntent().getStringExtra("course id").toString();
mAuth = FirebaseAuth.getInstance();
reference = FirebaseDatabase.getInstance().getReference().child("Materials").child(mAuth.getCurrentUser().getUid());
recyclerView = findViewById(R.id.recyclerView_fileMaterials);
recyclerView.setLayoutManager(new LinearLayoutManager(getApplicationContext()));
btnAddMaterial = findViewById(R.id.addMaterials);
btnAddMaterial.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
startActivity(new Intent(CourseMaterial.this, UploadFile.class));
}
});
}
#Override
public void onStart() {
super.onStart();
options = new FirebaseRecyclerOptions.Builder<FileMaterial>().setQuery(reference, FileMaterial.class).build();
adapter = new FirebaseRecyclerAdapter<FileMaterial, FileViewHolder>(options) {
#Override
protected void onBindViewHolder(#NonNull final FileViewHolder fileViewHolder, int i, #NonNull final FileMaterial fileMaterial) {
fileViewHolder.denumire_material.setText(fileMaterial.getDenumire_material());
}
#NonNull
#Override
public FileViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.youtube_view,parent, false);
FileViewHolder fileViewHolder = new FileViewHolder(v);
return fileViewHolder;
}
};
adapter.startListening();
recyclerView.setAdapter(adapter);
}
public static class FileViewHolder extends RecyclerView.ViewHolder{
TextView denumire_material, dataMaterial;
ImageView deleteMaterial;
public FileViewHolder(#NonNull View itemView) {
super(itemView);
denumire_material = itemView.findViewById(R.id.txtDenMaterial);
deleteMaterial = itemView.findViewById(R.id.imgDeleteMaterial);
}
}
Maybe make a query and pass it to the options of the adapter:
#Override
public void onStart() {
super.onStart();
Query query = reference.orderByChild("Course_ID").equalTo(value);
options = new FirebaseRecyclerOptions.Builder<FileMaterial>().setQuery(query, FileMaterial.class).build();
.......
.......
.......

Retrieve Image and name from firebase database in recycler view [duplicate]

everyone, I was trying to make a music app, and for this, I Created a Horizontal RecyclerView in my HomeFragment and my horizontal RecyclerView is getting an image with artist name.
But after clicking I load another Activity. In my other activity, I was trying to load SongsData from firebase in a listView with RecyclerView.
But the problem is I am not getting data from Firebase and it is returning null data. I provided my code below and here is the screenshot of my Firebase database:- ScreenShot
My List Class:-
public class TestUploads
{
private String songName;
private String songImageUri;
private String songUrl;
private String artistName;
public TestUploads() {
}
public String getSongName() {
return songName;
}
public void setSongName(String SongName) {
this.songName = SongName;
}
public String getSongImageUri() {
return songImageUri;
}
public void setSongImageUri(String SongImageUri) {
this.songImageUri = SongImageUri;
}
public String getSongUrl() {
return songUrl;
}
public void setSongUrl(String SongUrl) {
this.songUrl = songUrl;
}
public TestUploads(String SongImageUri, String SongName, String SongUrl ) {
this.songName = SongName;
this.artistName = SongImageUri;
this.songUrl = SongUrl;
}
}
My Adapter Class:-
public class TestAdapter extends RecyclerView.Adapter<TestAdapter.TestViewHolder>{
private Context mContext;
private List<TestUploads> mUploads;
public TestAdapter(Context context , List<TestUploads> uploads) {
mContext = context;
mUploads = uploads;
}
#NonNull
#Override
public TestViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View v = LayoutInflater.from(mContext).inflate(R.layout.test_package_layout , parent ,false);
return new TestViewHolder(v);
}
#Override
public void onBindViewHolder(#NonNull TestViewHolder holder, int position) {
TestUploads uploadcurrent = mUploads.get(position);
holder.name.setText(uploadcurrent.getSongName());
Glide.with(mContext)
.load(uploadcurrent.getSongImageUri())
.into(holder.image_view);
}
#Override
public int getItemCount() {
return mUploads
.size();
}
public class TestViewHolder extends RecyclerView.ViewHolder {
public TextView name;
public TextView artist_name;
public CircleImageView image_view;
public TestViewHolder(#NonNull View itemView) {
super(itemView);
name = itemView.findViewById(R.id.test_package_song_name);
artist_name = itemView.findViewById(R.id.test_package_artist_name);
image_view = itemView.findViewById(R.id.test_package_image_name);
}
}
}
My Activity:-
public class TestActivity extends AppCompatActivity {
private ValueEventListener listener;
private DatabaseReference reference;
private List<TestUploads> mUploads;
private RecyclerView mRecyclerView;
private TestAdapter adapter;
#Override
protected void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.test_package_activity);
reference = FirebaseDatabase.getInstance().getReference("ArtistView").child(getIntent().getStringExtra("Artist"))
.child("Songs");
Toast.makeText(this, "" + getIntent().getStringExtra("Artist"), Toast.LENGTH_SHORT).show();
mUploads = new ArrayList<>();
mRecyclerView = findViewById(R.id.test_pacakge_recyclerView);
mRecyclerView.setHasFixedSize(true);
mRecyclerView.setLayoutManager(new LinearLayoutManager(this));
mRecyclerView.smoothScrollToPosition(0);
adapter = new TestAdapter(this , mUploads);
mRecyclerView.setAdapter(adapter);
listener = reference.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
mUploads.clear();
for (DataSnapshot postSnapshot : dataSnapshot.getChildren()) {
TestUploads uploads =postSnapshot.getValue(TestUploads.class);
mUploads.add(uploads);
}
adapter.notifyDataSetChanged();
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
}
});
}
}
Sorry for so much code but this is not hard to solve. If you find the solution please reply to me. Thanks for reading this.
The problem in your code lies in the fact that the names of the fields in your TestUploads class are different than the name of the properties in your database. You have in your TestUploads class a field named songName but in your database, I see it as SongName and this is not correct. The names must match. When you are using a getter named getSongName(), Firebase is looking in the database for a field named songName and not SongName. See the lowercase s letter vs. capital letter S?
There are two ways in which you can solve this problem. The first one would be to remove the data in your database and add it again using field names that start with lowercase, as exist in your TestUploads class.
If you are not allowed to use the first solution, then the second approach will be to use annotations. So you should use the PropertyName annotation in front of the getters. So in your TestUploads class, a getter should look like this:
#PropertyName("SongName")
public String getSongName() {
return songName;
}

Unable to retrieve firestore database using recyclerView

I am using recyclerView and Adapter to fetch the data in profileActivity
here is my
public class studentDetailsRecyclerActivity extends AppCompatActivity {
//recyclerview to set the details for UI in the student profile activity
private RecyclerView mRecyclerView;
private storeDetailsAdapter mStoreDetailsAdapter;
private List<storeStudentDetails> studentDetailsList;
private FirebaseFirestore dbReference;
private ProgressBar mProgressBar;
private String TAG = studentDetailsRecyclerActivity.class.getSimpleName();
#Override
protected void onCreate(Bundle savedInstanceState) {
dbReference = FirebaseFirestore.getInstance();
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_recycler_details);
mProgressBar = findViewById(R.id.progressbar);
mRecyclerView = (RecyclerView)findViewById(R.id.recyclerView_products);
mRecyclerView.setHasFixedSize(true);
mRecyclerView.setLayoutManager(new LinearLayoutManager(this));
studentDetailsList = new ArrayList<>();
mStoreDetailsAdapter = new storeDetailsAdapter(this,studentDetailsList);
mRecyclerView.setAdapter(mStoreDetailsAdapter);
//to get the "details" this is our collection from firestore so we must fetch them
//by calling the addOnSuccessListener
dbReference.collection("details").get()
.addOnSuccessListener(new OnSuccessListener<QuerySnapshot>() {
#Override
public void onSuccess(QuerySnapshot queryDocumentSnapshots) { //we must have to hide the progress bar when the data gets loaded
//here queryDocumentsSnapshot will hold all the "details" which is your collection in firestore
if(!queryDocumentSnapshots.isEmpty()){
//we must have to create empty list so that to store all
//details from DocumentsSnapshots
List<DocumentSnapshot> list = queryDocumentSnapshots.getDocuments();
//enhanced for loop because we have to give every index documentSnapShot
for(DocumentSnapshot d: list){
storeStudentDetails sd = d.toObject(storeStudentDetails.class);
studentDetailsList.add(sd);
Log.d(TAG, "onSuccess: " + sd.toString());
}
//to refresh and sync we must have to use notifyDataSetChanged
mStoreDetailsAdapter.notifyDataSetChanged();
}
}
}) .addOnFailureListener(new OnFailureListener() {
#Override
public void onFailure(#NonNull Exception e) {
Toast.makeText(getApplicationContext(), "Error getting data!!!", Toast.LENGTH_LONG).show();
}
});
}
}
and here is my storeDetailsAdapter
import java.util.List;
public class storeDetailsAdapter extends RecyclerView.Adapter<storeDetailsAdapter.StudentViewHolder>{
private Context context;
private List<storeStudentDetails> studentDetailsList;
public storeDetailsAdapter(Context context, List<storeStudentDetails> studentDetailsList) {
this.context = context;
this.studentDetailsList = studentDetailsList;
}
#NonNull
#Override
public StudentViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
return new StudentViewHolder(
LayoutInflater.from(context).inflate(R.layout.profile_activity, parent, false)
);
}
#Override
public void onBindViewHolder(#NonNull StudentViewHolder holder, int position) {
storeStudentDetails mStoreDetails = studentDetailsList.get(position);
holder.studName.setText(mStoreDetails.getStudentName());
holder.rollNum.setText(mStoreDetails.getRollNo());
holder.bookName.setText( mStoreDetails.getBook());
holder.fine.setText("Fine:" + mStoreDetails.getFine());
holder.dept.setText(mStoreDetails.getDept());
}
#Override
public int getItemCount() {
return studentDetailsList.size();
}
class StudentViewHolder extends RecyclerView.ViewHolder {
TextView studName,rollNum,bookName,dept,fine;
public StudentViewHolder(View itemView) {
super(itemView);
studName=itemView.findViewById(R.id.studentName_prof);
rollNum = itemView.findViewById(R.id.rollNumber_prof);
bookName = itemView.findViewById(R.id.bookName_prof);
fine = itemView.findViewById(R.id.fineAmt_prof);
dept = itemView.findViewById(R.id.department_prof);
}
}
}
and here is my StoreStudentDetails class:
public class storeStudentDetails implements Serializable {
private String studentName;
private String rollNo;
private String book;
private Double fine;
private String dept;
#Exclude private String id;
public storeStudentDetails() {
}
public storeStudentDetails(String studentName, String rollNo,String book, double fine ,String dept) {
this.studentName = studentName;
this.rollNo = rollNo;
this.book = book;
this.fine = fine;
this.dept = dept;
}
public void setId(String id) {
this.id = id;
}
public String getStudentName() {
return studentName;
}
public String getRollNo() {
return rollNo;
}
public String getBook() {
return book;
}
public Double getFine() {
return fine;
}
public String getDept() {
return dept;
}
public String getId() {
return id;
}
}
To solve this, please move the following lines of code:
mStoreDetailsAdapter = new storeDetailsAdapter(this,studentDetailsList);
mRecyclerView.setAdapter(mStoreDetailsAdapter);
Right before the following line of code:
mStoreDetailsAdapter.notifyDataSetChanged();
And this is because onSuccess() method has an asynchronous behavior and by the time you are setting the adapter outside the callback your list is empty.
As you can see, the easiest solution for this problem is to move those lines of code inside the callback. but if you want to use the value of your studentDetailsList outside the onSuccess() method, I recommend you see the last part of my anwser from this post in which I have explained how it can be done using a custom callback. You can also take a look at this video for a better understanding.

Android: reading a value from a child with FirebaseUI

I am using FirebaseUI to get some values from my real-time database to Firebase RecyclerView. So.. my data looks like that:
users:
userid:
info:
Name:Muhammad
I don't know how to get the value of Name which means what exactly should I do in the Users class? Here is my code (I think that the problem is in class user, I just don't know how to access child info)
public class User {
private String name;
private String email;
private String state;
private String image;
private String thumbnail;
public User(String name, String state, String image) {
this.name = name;
this.state = state;
this.image = image;
}
public User() {
}
public String getName() {
return name;
}
public String getState() {
return state;
}
public String getImage() {
return image;
}
}
my Main Activity
myDB refer to and on start method (updated after SUPERCILEX comment )
mDb = FirebaseDatabase.getInstance().getReference().child(App_Constants.USERS_COLUMN);
#Override
protected void onStart() {
super.onStart();
Query query = mDb;
FirebaseRecyclerOptions<User> options = new FirebaseRecyclerOptions.Builder<User>()
.setQuery(query, new SnapshotParser<User>() {
#NonNull
#Override
public User parseSnapshot(#NonNull DataSnapshot snapshot) {
String Name = snapshot.child(App_Constants.INFO_COLUMN).child(App_Constants.NAME_COLUMN).getValue().toString();
String State = snapshot.child(App_Constants.INFO_COLUMN).child(App_Constants.STATE_COLUMN).getValue().toString();
String Image = snapshot.child(App_Constants.INFO_COLUMN).child(App_Constants.IMAGE_COLUMN).getValue().toString();
User user = new User(Name,State,Image);
return user;
}
}).build();
FirebaseRecyclerAdapter<User,Users_ViewHolder> adapter = new FirebaseRecyclerAdapter<User, Users_ViewHolder>(options) {
#NonNull
#Override
public Users_ViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.single_user,parent,false);
return new Users_ViewHolder(view);
}
#Override
protected void onBindViewHolder(#NonNull Users_ViewHolder holder, int position, #NonNull User model) {
holder.Set_Name(model.getName());
holder.Set_Image(model.getImage());
holder.Set_State(model.getState());
}
};
mUsers.setAdapter(adapter);
}
my ViewHolder
public class Users_ViewHolder extends RecyclerView.ViewHolder{
View mView;
public Users_ViewHolder(View itemView) {
super(itemView);
mView = itemView;
}
public void Set_Name(String Name)
{
TextView mName = mView.findViewById(R.id.tv_single_user_name);
mName.setText(Name);
}
public void Set_Image(String url)
{
CircleImageView mImage = mView.findViewById(R.id.iv_single_user);
Picasso.get().load(url).placeholder(R.drawable.profile).into(mImage);
}
public void Set_State(String State)
{
TextView mState = mView.findViewById(R.id.tv_single_user_state);
mState.setText(State);
}
}
thanks
I believe it'll come in as a Map<String, Object> on the field info. However, you can always use a custom SnapshotParser to build your model to your liking: https://github.com/firebase/FirebaseUI-Android/blob/master/database/README.md#using-the-firebaserecycleradapter.
Some Advices :would you mind changing the set methods names?
from Set_State to setState,I too had similar problems please respect Java naming conventions
Also add the set methods in your custom model
Second:
FirebaseRecyclerOptions<User> options =
new FirebaseRecyclerOptions.Builder<User>()
.setQuery(query, User.class)
.build();
Start Listening:
#Override
protected void onStart() {
super.onStart();
adapter.startListening();
}
stopListening() call removes the event listener and all data in the adapter
#Override
protected void onStop() {
super.onStop();
adapter.stopListening();
}
Here you have a very good explained example

How to delete duplicate data that I get after updating data in firebase console

I am developing an android app that displays the ranks of students based on their marks retrieved from the firebase database. Everything is working fine but, when I update the marks in the db, it keeps the old data and adds the new data in the recyclerView. I can restart the app to refresh the data. But while it is still running, it shows the old data too.
Below is my firebase data:
Student1: {
c: 70,
cPlus: 90,
java: 70,
name: "Samson",
regno: "16sksb7034",
unix: 60
}
Student2: {
c: 20,
cPlus: 85,
java: 68,
name: "Samson",
regno: "16sksb7034",
unix: 86
}
Student3: {
c: 70,
cPlus: 70,
java: 80,
name: "Samson",
regno: "16sksb7034",
unix: 90
}
Here is my dataModel class:
public class Marks {
private String name;
private String regno;
private int c;
private int cPlus;
private int java;
private int unix;
private int percentage;
public Marks() {}
public Marks(int c, int cPlus, int java, int unix) {
this.c = c;
this.cPlus = cPlus;
this.java = java;
this.unix = unix;
}
public int getPercentage() {
return percentage;
}
public void setPercentage(int percentage) {
this.percentage = percentage;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getRegno() {
return regno;
}
public void setRegno(String regno) {
this.regno = regno;
}
public int getC() {
return c;
}
public void setC(int c) {
this.c = c;
}
public int getcPlus() {
return cPlus;
}
public void setcPlus(int cPlus) {
this.cPlus = cPlus;
}
public int getJava() {
return java;
}
public void setJava(int java) {
this.java = java;
}
public int getUnix() {
return unix;
}
public void setUnix(int unix) {
this.unix = unix;
}
}
class MarksComparator implements Comparator<Marks> {
#Override
public int compare(Marks marks1, Marks marks2) {
int Marks1Total = marks1.getPercentage();
int Marks2Total = marks2.getPercentage();
if (Marks2Total < Marks1Total) {
return -1;
} else if (Marks2Total > Marks1Total) {
return 1;
} else {
return 0;
}
}
}
Here's my activity class:
public class MarksFragment extends Fragment{
private List<Marks> mMarksList = new ArrayList<>();
private RecyclerView mRecyclerView;
private MyAdapter mAdapter;
private RecyclerView.LayoutManager mLayoutManager;
private FirebaseDatabase mDatabase;
private DatabaseReference mReference;
private int total=0;
public MarksFragment() {
// Required empty public constructor
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
View view = inflater.inflate(R.layout.fragment_marks, container, false);
mRecyclerView = (RecyclerView) view.findViewById(R.id.recycler_view);
// use this setting to improve performance if you know that changes
// in content do not change the layout size of the RecyclerView
mRecyclerView.setHasFixedSize(true);
// use a linear layout manager
mLayoutManager = new LinearLayoutManager(getActivity());
mRecyclerView.setLayoutManager(mLayoutManager);
mRecyclerView.setItemAnimator(new DefaultItemAnimator());
// specify an adapter (see also next example)
/*mAdapter = new MyAdapter(getContext(),mMarksList);
mAdapter.notifyDataSetChanged();
mRecyclerView.setAdapter(mAdapter);*/
//get Firebase Reference
FirebaseDatabase.getInstance().setPersistenceEnabled(true);
mDatabase = FirebaseDatabase.getInstance();
mReference = mDatabase.getReference();
mReference.addChildEventListener(new ChildEventListener() {
#Override
public void onChildAdded(DataSnapshot dataSnapshot, String s) {
fetchData(dataSnapshot);
}
#Override
public void onChildChanged(DataSnapshot dataSnapshot, String s) {
fetchData(dataSnapshot);
}
#Override
public void onChildRemoved(DataSnapshot dataSnapshot) {
}
#Override
public void onChildMoved(DataSnapshot dataSnapshot, String s) {
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
return view;
}
public void findPercentage(Marks value) {
total =value.getC() + value.getcPlus() + value.getJava() + value.getUnix();
value.setPercentage(total);
}
private void fetchData(DataSnapshot dataSnapshot) {
Marks value = dataSnapshot.getValue(Marks.class);
Log.v("Marks Fragment", "" +value);
findPercentage(value);
mMarksList.add(value);
Collections.sort(mMarksList, new MarksComparator());
// specify an adapter (see also next example)
mAdapter = new MyAdapter(getContext(),mMarksList);
mAdapter.notifyDataSetChanged();
mRecyclerView.setAdapter(mAdapter);
Here is my adapter class:
public class MyAdapter extends RecyclerView.Adapter<MyAdapter.MyViewHolder>{
private Context mContext;
private List<Marks> marksList;
public MyAdapter(Context mContext, List<Marks> marksList) {
this.mContext = mContext;
this.marksList = marksList;
}
public class MyViewHolder extends RecyclerView.ViewHolder {
public TextView mItemName, mItemRegNo, mItemNo, mTotal;
CircleImageView mImageView;
public MyViewHolder(View view) {
super(view);
mItemName = (TextView) view.findViewById(R.id.card_name);
mItemRegNo = (TextView) view.findViewById(R.id.card_regno);
mItemNo = (TextView) view.findViewById(R.id.item_id);
mImageView = (CircleImageView) view.findViewById(R.id.item_photo);
mTotal = view.findViewById(R.id.card_total);
}
}
#Override
public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View itemView = LayoutInflater.from(parent.getContext())
.inflate(R.layout.card_item, parent, false);
return new MyViewHolder(itemView);
}
#Override
public void onBindViewHolder(final MyViewHolder holder, int position) {
Marks marks = marksList.get(position);
int count = position + 1;
holder.mItemName.setText("" + marks.getName());
holder.mItemRegNo.setText("" + marks.getRegno());
holder.mItemNo.setText("" + count);
holder.mImageView.setImageResource(R.drawable.after_cookie);
holder.mTotal.setText(""+ marks.getPercentage());
}
#Override
public int getItemCount() {
return marksList.size();
}
}
So the code does what its intended to do it retrieves the data and calculates the total and ranks the students. but when I update the data in firebase console the views in recyclerView duplicates temporarily. Like for example if I update Student1 unix value as 10 then two views will be shown in the recyclerView: 1 for previous value and 2 for updated value and again if I update the values it will yet show another views representing the new data without removing the old views. But if I restart recyclerView gets refreshed and its all ok but while I am running the app during the update it shows temporary duplicate views too.
I am new here and this is my first question so I can't even upload picture as you need 10 points to upload photo. I really hope someone help me out on this. I thank you in advance.
UPDATE
Here is link to the image:
When I start the app, the image is:
first Image
when I update the unix value of Student3, the image in recyclerView becomes like this:
After updating the data in firebase console
So, you see it adds new data as well as keeps the old data untill I restart.
Your problem is that you're never checking if the student already exists in your mMarksList so you're simply duplicating him by adding him again with new grades.
What I would do in you case is to add an unique id in firebase to each student.
Then you can check in your fetchData whether the student with that id is already in the array, delete him and add the new one.
private void fetchData(DataSnapshot dataSnapshot) {
Marks value = dataSnapshot.getValue(Marks.class);
Log.v("Marks Fragment", "" +value);
findPercentage(value);
// Get an iterator.
Iterator<Marks> ite = mMarksList.iterator();
while(ite.hasNext()) {
Marks iteValue = ite.next();
if(iteValue.getId().equals(value.getId())) ite.remove();
}
mMarksList.add(value);
....
}
Optionally To make that even cleaner, you can override the equals and hashcode methods in your Marks data model, so that a Marks object is considered the same if the id is equal. More
//ASSUMING THAT ID IS int
#Override
public int hashCode() {
return id;
}
#Override
public boolean equals(Object obj) {
if (this == obj) return true;
if (obj == null) return false;
if (this.getClass() != obj.getClass()) return false;
Marks other = (Marks) obj;
if (this.getId != other.getId) {
return false;
}
return true;
}
Then it's possible to either use a hashmap, which will override the old student automatically or a arraylist as is and iterate through it before and check if a student equals your new student, like this:
private void fetchData(DataSnapshot dataSnapshot) {
Marks value = dataSnapshot.getValue(Marks.class);
Log.v("Marks Fragment", "" +value);
findPercentage(value);
// Use an iterator.
Iterator<Marks> ite = mMarksList.iterator();
while(ite.hasNext()) {
Marks iteValue = ite.next();
if(iteValue.equals(value)) ite.remove();
}
mMarksList.add(value);
....
}

Categories

Resources