I created a RecyclerView with data loaded locally using a standard model and adapter approach, the views that the RecyclerView recycles hold an image and 3 text views. I'd like to populate these views using data from a Firebase Database. I've created the data on Firebase which looks like this:
{
"items" : {
"item 1" : {
"colour-value" : "000000",
"manufacturer" : "Manufacturer 1",
"name" : "Name 1",
"type" : "Type 1"
},
"item 2" : {
"colour-value" : "ffff00",
"manufacturer" : "Manufacturer 2",
"name" : "Name 2",
"type" : "Type 2"
},
"item 3" : {
"colour-value" : "ff0000",
"manufacturer" : "Manufacturer 3",
"name" : "Name 3",
"type" : "Type 3"
}
}
}
I've already added the dependencies and have Firebase Auth set up and working. The data will never be changed by the user but may be changed manually in the back end from time to time. The image is a single white png with the colour changed based on the colour-value.
Everything that I've seen appears to be overly complex for what I need and I'm convinced it doesn't need to be but can't whittle down what I need to feed this data into the RecyclerView.
Any pointers? Thanks.
EDIT - All special characters have been removed from data.
ItemAdapter
public class ItemAdapter extends
RecyclerView.Adapter<ItemAdapter.MyViewHolder> {
private Context mContext;
private List<Item> itemList;
class MyViewHolder extends RecyclerView.ViewHolder {
TextView itemName, itemManufacturer, itemType;
private MyViewHolder (View view) {
super(view);
itemName = view.findViewById(R.id.item_name);
itemManufacturer = view.findViewById(R.id.item_manufacturer);
itemType = view.findViewById(R.id.item_type);
}
}
ItemAdapter(Context mContext, List<Item> itemList) {
this.mContext = mContext;
this.itemList = itemList;
}
#Override
public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View itemView = LayoutInflater.from(parent.getContext()).inflate(R.layout.item, parent, false);
return new MyViewHolder(itemView);
}
#Override
public void onBindViewHolder(final Item.MyViewHolder holder, int position) {
Item item = itemList.get(position);
holder.itemName.setText(item.getItemName());
holder.itemManufacturer.setText(item.getItemManufacturer());
holder.itemType.setText(item.getItemType());
}
void filter (ArrayList<Item> newList) {
itemList = new ArrayList<>();
itemList.addAll(newList);
notifyDataSetChanged();
}
#Override
public int getItemCount() {
return itemList.size();
}
}
The first problem here in your JSON you can not have a hyphen or spaces in your keys as firebase will do a mapping based on keys to POJO member variables and java does not allow special characters in namings.
So if you change your keys just do this
Make a POJO
public class SampleModel {
private int colorValue;
private String manufacturer;
private String name;
private String type;
public int getColorValue() {
return colorValue;
}
public void setColorValue(int colorValue) {
this.colorValue = colorValue;
}
public String getManufacturer() {
return manufacturer;
}
public void setManufacturer(String manufacturer) {
this.manufacturer = manufacturer;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
}
then create your database reference and get the data and update the list
#Override
protected void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
DatabaseReference myRef = FirebaseDatabase.getInstance().getReference("items");
myRef.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
//you have data now traverse
for (DataSnapshot child: dataSnapshot.getChildren()){
//your data may come up in map so handle here
HashMap<String,SampleModel> hashMap = (HashMap<String,SampleModel>)child.getValue();
//if everything is okay then just iterate over the map and create a list
List<SampleModel> sampleModels = new ArrayList<>()
for (HashMap.Entry<String,SampleModel> modelEntry:hashMap.entrySet()){
sampleModels.add(modelEntry.getValue());
}
mainList.addAll(sampleModels);
adapter.notifyDataSetChanged();
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
//for some reason data did't show up
}
});
Edit: Added
HashMap<String,SampleModel> hashMap = (HashMap<String,SampleModel>)child.getValue();
Related
I am trying to display the contents of my Firebase table/list called "Assets" into a recycler view. But I am getting an error that says:
com.google.firebase.database.DatabaseException: Can't convert object of type java.lang.String to type com.example.zakatone.Assets
I have tried to look upon all the associated classes but cannot find the error.
This is how my data looks in Firebase:
Assets.java
package com.example.zakatone;
public class Assets {
private String assetname;
private String assetamount;
public Assets() {
}
public String getAssetname() {
return assetname;
}
public void setAssetname(String assetname) {
this.assetname = assetname;
}
public String getAssetamount() {
return assetamount;
}
public void setAssetamount(String assetamount) {
this.assetamount = assetamount;
}
}
MyAdapter.java
public class MyAdapter extends RecyclerView.Adapter<MyAdapter.MyViewHolder> {
private Context context;
private ArrayList<Assets> assets;
MyAdapter(Context c, ArrayList<Assets> a)
{
context = c;
assets = a;
}
#NonNull
#Override
public MyViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
return new MyViewHolder(LayoutInflater.from(context).inflate(R.layout.cardview,parent, false));
}
#Override
public void onBindViewHolder(#NonNull MyViewHolder holder, int position) {
holder.name.setText(assets.get(position).getAssetname());
holder.amount.setText(assets.get(position).getAssetamount());
}
#Override
public int getItemCount() {
return assets.size();
}
class MyViewHolder extends RecyclerView.ViewHolder{
TextView name, amount;
public MyViewHolder(#NonNull View itemView) {
super(itemView);
name = itemView.findViewById(R.id.name);
amount = itemView.findViewById(R.id.amount);
}
}
}
This is where I am trying to display my data: overview.java
reference = FirebaseDatabase.getInstance().getReference().child("Assets");
recyclerView = findViewById(R.id.myRecycler);
recyclerView.setLayoutManager(new LinearLayoutManager(this));
reference = FirebaseDatabase.getInstance().getReference().child("Assets");
reference.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
list = new ArrayList<Assets>();
for(DataSnapshot dataSnapshot1: dataSnapshot.getChildren()){
Assets a = dataSnapshot1.getValue(Assets.class);
list.add(a);
}
adapter = new MyAdapter(overview.this,list);
recyclerView.setAdapter(adapter);
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
Toast.makeText(overview.this, "Something Fishy", Toast.LENGTH_SHORT).show();
}
});
I want to display the data in this manner:
I am getting error in overview.java class at line:
Assets a = dataSnapshot1.getValue(Assets.class);
Please help me out as nothing is showing on the overview page at the moment. I am assuming there is an error while accessing the database table but i am not sure.
First you have two fields assetName and assetAmount. In Java always use camelCase, first word lowercase and second word starts with capital letter.
Since you have those two fields, you need to also have them in the database to be able to map the object to the database. So when saving you need to change the structure to the following:
Assets
randomId
assetName : name
assetAmount : amt
randomId
assetName : name
assetAmount : amt
When retrieving refer to the node Assets and don't use a for loop to iterate since you will retrieve the values of type String and not of type Assets
Try editing like this
((Assets) getActivity()).getValue;
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;
}
Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 4 years ago.
Improve this question
I want to show this json in recyclerview. how can I do it?
I just want to list "user" and "exchangeName".
My Json;
{
"events": {
"101": {
"id": "0001",
"type": "exchange",
"user": "BTUser01",
"exchangeName": "BTCTurk",
"transactions": {
"send": "249",
"get": "24.1"
},
"certificate": [
"BTUser01Certificate"
]
},
"102": {
"id": "0002",
"type": "exchange",
"user": "BTUser02",
"exchangeName": "Koinim",
"transactions": {
"send": "300",
"get": "641"
},
"certificate": [
"BTUser02Certificate"
]
},
"103": {
"id": "0003",
"type": "exchange2",
"user": "BTUser03",
"exchangeName": "Koineks",
"transactions": {
"send": "823",
"get": "751"
},
"certificate": [
"BTUser03Certificate"
]
},
"104": {
"id": "0004",
"type": "exchange3",
"user": "BTUser04",
"exchangeName": "Paribu",
"transactions": {
"send": "543",
"get": "3.1"
},
"certificate": [
"BTUser04Certificate"
]
}
}
}
MainActivity;
public class MainActivity extends AppCompatActivity {
TextView ev, ev2;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ev = (TextView) findViewById(R.id.ev);
ev2 = (TextView) findViewById(R.id.ev2);
Retrofit retrofit = new Retrofit.Builder().baseUrl("MYAPÄ°_ADRESS_LINK").addConverterFactory(GsonConverterFactory.create()).build();
Service service = retrofit.create(Service.class);
Call<ResponseBody> call = service.getData();
call.enqueue(new Callback<ResponseBody>() {
#Override
public void onResponse(#NonNull Call<ResponseBody> call, #NonNull Response<ResponseBody> response) {
if (response.isSuccessful()) {
String res = null;
if (response.body() != null) {
try {
res = response.body().string();
parse(res);
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
#Override
public void onFailure(#NonNull Call<ResponseBody> call, #NonNull Throwable t) {
int a = 0;
}
});
}
Model parse(String str) {
Model model = new Model();
try {
String source = str.replace("\n", "").replace("\t", "").replace("\r", "");
String s = new Gson().toJson(source);
s = s.replace("\\","");
s = s.substring(1,s.length()-1);
JSONObject object = new JSONObject(s).getJSONObject("events");
Iterator<String> iter = object.keys();
while (iter.hasNext()) {
String key = iter.next();
try {
JSONObject value = new JSONObject(String.valueOf(object.get(key)));
model.setExternalId(Integer.parseInt(key));
model.setUser(value.getString("user"));
model.setSend(value.getString("send"));
ev.setText(model.user);
ev2.setText(model.send);
return model;
} catch (JSONException e) {
// Something went wrong!
}
}
} catch (JSONException e) {
e.printStackTrace();
}
return model;
}
}
My Model;
public class Model {
int externalId;
int id;
String type;
String user;
String exchangeName;
Transactions transactions;
List<certificate> certificateList;
public int getExternalId() {
return externalId;
}
public void setExternalId(int externalId) {
this.externalId = externalId;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public String getUser() {
return user;
}
public void setUser(String user) {
this.user = user;
}
public String getExchangeName() {
return exchangeName;
}
public void setExchangeName(String exchangeName) {
this.exchangeName = exchangeName;
}
public Transactions getTransactions() {
return transactions;
}
public void setTransactions(Transactions transactions) {
this.transactions = transactions;
}
public List<certificate> getCertificateList() {
return certificateList;
}
public void setCertificateList(List<certificate> certificateList) {
this.certificateList = certificateList;
}
class Transactions{
String send;
String get;
public String getSend() {
return send;
}
public void setSend(String send) {
this.send = send;
}
public String getGet() {
return get;
}
public void setGet(String get) {
this.get = get;
}
}
class certificate{
String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
}
First of all you could have found this answer easily in the hundreds of tutorials and guides available.
To achieve this you will need to create a custom adapter and a custom view for the adapter item.
To preface this answer. I wasn't sure if you want to show multiple Model items in the RecyclerView, or some other data. This example assumes that you use a List<Model>, however, it's an easy change to make it work with another list of objects.
Example of how the adapter could look like
public class MyAdapter extends RecyclerView.Adapter
{
private Context _context;
private List<Model> _items;
public void setItems(List<Model> items)
{
this._items = items;
notifyDataSetChanged();
}
#NonNull
#Override
public RecyclerView.ViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType)
{
_context = parent.getContext();
return new MyAdapter.ItemViewHolder(parent);
}
#Override
public void onBindViewHolder(#NonNull final RecyclerView.ViewHolder holder, int position)
{
final MyAdapter.ItemViewHolder viewHolder = (MyAdapter.ItemViewHolder) holder;
final Model item = _items.get(position);
viewHolder._user.setText(item.user);
viewHolder._exchangeName.setText(item.exchangeName);
}
#Override
public int getItemCount()
{
return _items != null ? _items.size() : 0;
}
private static class ItemViewHolder extends RecyclerView.ViewHolder
{
private TextView _user;
private TextView _exchangeName;
private ItemViewHolder(ViewGroup parent)
{
super(LayoutInflater.from(parent.getContext()).inflate(R.layout.adapter_view, parent, false));
this._user = itemView.findViewById(R.id.user);
this._exchangeName = itemView.findViewById(R.id.exchange_name);
}
}
}
R.layout.adapter_view
This needs to be a view containing at least the two TextView views references from the MyAdapter above. Simple example:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:background="#drawable/content_container"
android:orientation="vertical"
android:animateLayoutChanges="true"
android:padding="#dimen/padding_view_large"
android:layout_marginBottom="#dimen/padding_view_small">
<TextView
android:id="#+id/user"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="#string/placeholder"
android:textColor="#color/black"
android:textSize="#dimen/text_size_medium"
android:layout_marginTop="#dimen/padding_view_small"/>
<TextView
android:id="#+id/exchange_name"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="#string/placeholder"
android:textColor="#color/black"
android:textSize="#dimen/text_size_medium"
android:layout_marginTop="#dimen/padding_view_small"/>
</LinearLayout>
Binding the adapter
//First we set up the adapter and add our List<Model> object.
MyAdapter adapter = new MyAdapter();
adapter.setItems(... List<Model> items);
//Set up our RecyclerView and set the adapter.
final RecyclerView recyclerView = rootView.findViewById(R.id.model_list);
recyclerView.setLayoutManager(new LinearLayoutManager(_context));
recyclerView.setAdapter(adapter);
recyclerView.setHasFixedSize(true);
You need to first understand (and later create) the following things
RecyclerView Adapter
RecyclerView ViewHolder
After you read up on those two things the solution will be pretty clear. Just to point you in the right direction, you will have to create a custom adapter which you will use to populate your custom viewholders. Hope this helps get you going. Feel free to ask if you need any more help in this.
I have this DB structure:
{
"customers" : {
"-L-OcgJ0kwTNSm6HoSvG" : {
"address" : "Test Alamat",
"birthday" : "1990-12-03",
"email" : "Dodi#gmail.com",
"name" : "Dodi",
"outletID" : "2673",
"phone" : "09888777111"
}
}
}
Now i want to load all data of "customers" into ListView using FirebaseUI-Android library. And here is the codes:
Query query = FirebaseDatabase.getInstance().getReference().child("customers").limitToLast(50);
FirebaseListOptions<Customers> options = new FirebaseListOptions.Builder<Customers>()
.setLayout(R.layout.row_customer)
.setQuery(query, Customers.class)
.build();
FirebaseListAdapter<Customers> adapter = new FirebaseListAdapter<Customers>(options) {
#Override
protected void populateView(View view, Customers customer, int position) {
((TextView) view.findViewById(R.id.txtCustomerName)).setText(customer.name);
((TextView) view.findViewById(R.id.txtCustomerAddress)).setText(customer.address);
((TextView) view.findViewById(R.id.txtCustomerPhone)).setText(customer.phone);
//and i've set the adapter into ListView
((ListView)layout.findViewById(R.id.lvCustomerList)).setAdapter(adapter);
And here is Customers.java:
#IgnoreExtraProperties
public class Customers {
public String name, outletID, address, phone, birthday, email;
public Customers() {
}
public Customers(String name, String outletID, String address, String phone, String birthday, String email) {
this.name = name;
this.outletID = outletID;
this.address = address;
this.phone = phone;
this.birthday = birthday;
this.email = email;
}
}
Please help me what is the problem with my source code?
i've run it and the data failed to display (only blank on my listview). There's no errors on my Android Studio logs.
I recommend to you to create custom Adapter and to use a RecyclerView (it is faster and better than a ListView )
Something like this:
public class CustomerAdapter extends RecyclerView.Adapter<CustomerAdapter.MessageViewHolder> {
private List<Customer> customerList;
private Context context;
public CustomerAdapter(List<Customer> customerList, Context context) {
this.customerList= customerList;
this.context = context;
}
#Override
public CustomerAdapter.MessageViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View v = LayoutInflater.from(parent.getContext())
.inflate(R.layout.your_layout, parent, false);
return new CustomerAdapter.MessageViewHolder(v);
}
public class CustomerViewHolder extends RecyclerView.ViewHolder {
public TextView customername, customeraddress, customerphone;
public CustomerViewHolder(View view) {
super(view);
customername = view.findViewById(R.id.txtCustomerName);
customeraddress = view.findViewById(R.id.txtCustomerAddress);
customerphone = view.findViewById(R.id.txtCustomerPhone);
}
}
#Override
public int getItemCount() {
return customerList.size();
}
#Override
public void onBindViewHolder(final CustomerAdapter.MessageViewHolder holder, final int position) {
holder.customername.setText(customerList.get(position).getName;
holder.customeraddress.setText(customerList.get(position).getAddress;
holder.customerphone.setText(customerList.get(position).getPhone;
}
And you can get the data like this:
FirebaseDatabase.getInstance().getReference().child("customers").addValueEventListener(new ValueEventlistener{
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
List<Customer> custoemrList = new ArrayList<>();
for (final DataSnapshot snapshot : dataSnapshot.getChildren()) {
Customer customer = new Customer();
customer.setName(snapshot.child("name").getValue().toString();
...
...
customerList.add(customer);
}
customerAdapter= new customerAdapter(customerList, YourActivity.this);
recyclerView.setAdapter(chatsAdapter);
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
});
And in your Customer class you have to add getters and setters.
Press Alt + Insert -> Getters and Setters -> Select All -> Enter
This should be it
Change this line of code:
Query query = FirebaseDatabase.getInstance().getReference().child("customers").limitToLast(50)
with
Query query = FirebaseDatabase.getInstance().getReference()
.child("customers")
.orderByChild("name")
.limitToLast(50);
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);
....
}