performing background task on firebase database - android

So the problem is following - When mProducts is trying to get the products from the DB in onDataChange() call, then the fragment jumps to onCreateView(), sets the adapter with an empty array and after that performs the database task.
Am I missing something or what am I doing wrong?
Please point out the reason behind this weird behavior.
Thanks.
Fragment class
public class MainViewFragment extends Fragment {
private static final String TAG = "MainViewFragment";
private RecyclerView mView;
private List<Product> mProducts;
private DatabaseReference mRef;
private MainViewAdapter mAdapter;
public MainViewFragment() {
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
View v = inflater.inflate(R.layout.fragment_main_view, container, false);
mView = (RecyclerView)v.findViewById(R.id.mainViewRecyclerView);
// mProducts = MockData.getProductData();
mView.setLayoutManager(new LinearLayoutManager(getActivity(),LinearLayoutManager.HORIZONTAL,false));
mAdapter = new MainViewAdapter(mProducts,getActivity());
mView.setAdapter(mAdapter);
return v;
}
#Override
public void onAttach(Context context) {
super.onAttach(context);
mRef = FirebaseDatabase.getInstance().getReference().child("products");
mProducts = new ArrayList<>();
new Thread(new Runnable() {
#Override
public void run() {
mRef.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
mProducts = Db.getDatabase(getActivity(),mRef).getProducts();
}
#Override
public void onCancelled(DatabaseError databaseError) {}
});
}
}).start();
}
}
Database Class
public class Db {
private DatabaseReference mRef;
private Context ctx;
private static Db sDb;
private List<Product> mProduct;
public static Db getDatabase(Context ctx, DatabaseReference mRef) {
if(sDb == null) {
sDb = new Db(ctx,mRef);
}
return sDb;
}
private Db(Context ctx,DatabaseReference mRef) {
this.ctx = ctx;
this.mRef = mRef;
this.mRef = FirebaseDatabase.getInstance().getReference().child("products");
}
public List<Product> getProducts() {
mProduct = new ArrayList<>();
mRef.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
Iterator<DataSnapshot> dataSnapshotIterator = dataSnapshot.getChildren().iterator();
Product product = null;
while (dataSnapshotIterator.hasNext()) {
DataSnapshot dataSnapshotChild = dataSnapshotIterator.next();
product = dataSnapshotChild.getValue(Product.class);
mProduct.add(product);
}
}
#Override
public void onCancelled(DatabaseError databaseError) {}
});
return mProduct;
}
}

In your adapter class, you should have a setter method for your dataset:
public void setData (Dataset dataset) {
mDataset = dataset;
notifyDataSetChanged();
}
In the onAttach:
#Override
public void onAttach(Context context) {
super.onAttach(context);
mRef = FirebaseDatabase.getInstance().getReference().child("products");
mProducts = new ArrayList<>();
new Thread(new Runnable() {
#Override
public void run() {
mRef.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
mProducts = Db.getDatabase(getActivity(),mRef).getProducts();
mAdapter.setData(mProducts)
}
#Override
public void onCancelled(DatabaseError databaseError) {}
});
}
}).start();

It could be this line that has the problem
product = dataSnapshotChild.getValue(Product.class);
is not giving the desired result, in which case, I usually desiarialize this way:
Lets say the Product class has two components - name and price which are String and int respectively, I'd have done it this way, if I had a constructor in the Product class with both components as parameters
String name = dataSnapshotChild.child("name").getValue(String.class);
int price= dataSnapshotChild.child("price").getValue(Integer.class);
product = new Product(name, price);
mProduct.add(product);
where "name" and "price" are the node names in your database

Related

Call a method from Adapter to Fragment and pass a variable with it Android Studio

So what I want is on click of a button from my recycler view a method/function which is in my fragment should be called along with that it should send a variable too. I know I can use Listener or Interface but I have looked and implemented several solutions but none of them are working usually null pointer exception I don't know what mistake am doing so it would be helpful if someone will let me know how to do exactly by looking at my code I have removed some unnecessary part from my adapter too..
Adapter
public class AddPartAdapter extends RecyclerView.Adapter<AddPartAdapter.ViewHolder> {
private Context mContext;
private List<User> mUsers;
EventListener listener;
public interface EventListener {
void AddParticipant(String id);
}
public void addEventListener(EventListener listener){
this.listener = listener;
}
public void removeEventListener(){
listener = null;
}
public AddPartAdapter(Context mContext, List<User> mUsers) {
this.mContext = mContext;
this.mUsers = mUsers;
}
#NonNull
#Override
public AddPartAdapter.ViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
ViewGroup viewGroup = (ViewGroup) LayoutInflater.from(mContext).inflate(R.layout.add_part_item, parent, false);
return new AddPartAdapter.ViewHolder(viewGroup);
}
#Override
public void onBindViewHolder(#NonNull AddPartAdapter.ViewHolder holder, int position) {
final User user = mUsers.get(position);
holder.username.setText(user.getUsername());
holder.dt.setText(user.getDt());
if (user.getImageUrl().equals("default")) {
holder.dp.setImageResource(R.drawable.user);
} else {
Glide.with(mContext).load(user.getImageUrl()).into(holder.dp);
}
holder.addpart_btn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
String Variable = user.getId();//This is the variable that should pass
//Send call that method and send the variablethat variable to Fragment
listener.AddParticipant(Variable);
}
});
}
The Fragment
public class AddParticipantsFragment extends Fragment implements AddPartAdapter.EventListener {
private RecyclerView recyclerView;
private List<User> mUsers;
DatabaseReference databaseReference;
FirebaseUser firebaseUser;
private List<Chatlist>usersList;
private AddPartAdapter addPartAdapter;
public String groupId;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
View view = inflater.inflate(R.layout.fragment_add_participants, container, false);
recyclerView = view.findViewById(R.id.recycler_view);
recyclerView.setHasFixedSize(true);
recyclerView.setLayoutManager(new LinearLayoutManager(getContext()));
usersList = new ArrayList<>();
firebaseUser = FirebaseAuth.getInstance().getCurrentUser();
databaseReference = FirebaseDatabase.getInstance().getReference("Chatlist").child(firebaseUser.getUid());
databaseReference.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot snapshot) {
usersList.clear();
for(DataSnapshot snapshot1 : snapshot.getChildren()){
Chatlist chatlist = snapshot1.getValue(Chatlist.class);
usersList.add(chatlist);
}
chatList();
}
#Override
public void onCancelled(#NonNull DatabaseError error) {
}
});
AddParticipants activity = (AddParticipants) getActivity();
assert activity != null;
groupId = activity.getMyData();
return view;
}
private void chatList() {
mUsers = new ArrayList<>();
databaseReference = FirebaseDatabase.getInstance().getReference("Users");
databaseReference.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot snapshot) {
mUsers.clear();
for (DataSnapshot snapshot1 : snapshot.getChildren()){
User user = snapshot1.getValue(User.class);
for (Chatlist chatlist : usersList){
assert user != null;
if(user.getId().equals(chatlist.getId())){
if(chatlist.getFriends().equals("Messaged")){
mUsers.add(user);
}if (chatlist.getFriends().equals("Requested")){
//DoNothing
}
if(chatlist.getFriends().equals("Blocked")){
//Dont do anything
}
}
}
}
AddPartAdapter addPartAdapter = new AddPartAdapter(getContext(), mUsers);
addPartAdapter.addEventListener();//Here inside the bracket what to add.
recyclerView.setAdapter(addPartAdapter);
}
#Override
public void onCancelled(#NonNull DatabaseError error) {
}
});
}
public void AddParticipant(String id) {
//And it should initialize this method
DatabaseReference databaseReference = FirebaseDatabase.getInstance().getReference("Grouplist").child(groupId);
HashMap<String, String> hashMap1 = new HashMap<>();
hashMap1.put("id", id);
hashMap1.put("admin","false");
databaseReference.setValue(hashMap1);
}
public void onDestroy() {
super.onDestroy();
addPartAdapter.removeEventListener();
}
}
And Heres the logcat
java.lang.NullPointerException: Attempt to invoke interface method 'void com.margsapp.messenger.Adapter.AddPartAdapter$EventListener.AddParticipant(java.lang.String)' on a null object reference
at com.margsapp.messenger.Adapter.AddPartAdapter$1.onClick(AddPartAdapter.java:70)
at android.view.View.performClick(View.java:7125)
at android.view.View.performClickInternal(View.java:7102)
at android.view.View.access$3500(View.java:801)
at android.view.View$PerformClick.run(View.java:27336)
at android.os.Handler.handleCallback(Handler.java:883)
at android.os.Handler.dispatchMessage(Handler.java:100)
at android.os.Looper.loop(Looper.java:214)
at android.app.ActivityThread.main(ActivityThread.java:7356)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:492)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:930)
Try this way,
In your adapter class, create 2 method. Add & remove listener.
public addEventListener(EventListener listener){
this.listener = listener;
}
public removeEventListener(){
listener = null;
}
Fragment class
public class AddParticipantsFragment extends Fragment implements AddPartAdapter.EventListener {
private RecyclerView recyclerView;
private List<User> mUsers;
DatabaseReference databaseReference;
FirebaseUser firebaseUser;
private List<Chatlist>usersList;
public String groupId;
private AddPartAdapter addPartAdapter
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
View view = inflater.inflate(R.layout.fragment_add_participants, container, false);
recyclerView = view.findViewById(R.id.recycler_view);
recyclerView.setHasFixedSize(true);
recyclerView.setLayoutManager(new LinearLayoutManager(getContext()));
usersList = new ArrayList<>();
firebaseUser = FirebaseAuth.getInstance().getCurrentUser();
databaseReference = FirebaseDatabase.getInstance().getReference("Chatlist").child(firebaseUser.getUid());
databaseReference.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot snapshot) {
usersList.clear();
for(DataSnapshot snapshot1 : snapshot.getChildren()){
Chatlist chatlist = snapshot1.getValue(Chatlist.class);
usersList.add(chatlist);
}
chatList();
}
#Override
public void onCancelled(#NonNull DatabaseError error) {
}
});
AddParticipants activity = (AddParticipants) getActivity();
assert activity != null;
groupId = activity.getMyData();
return view;
}
private void chatList() {
mUsers = new ArrayList<>();
databaseReference = FirebaseDatabase.getInstance().getReference("Users");
databaseReference.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot snapshot) {
mUsers.clear();
for (DataSnapshot snapshot1 : snapshot.getChildren()){
User user = snapshot1.getValue(User.class);
for (Chatlist chatlist : usersList){
assert user != null;
if(user.getId().equals(chatlist.getId())){
if(chatlist.getFriends().equals("Messaged")){
mUsers.add(user);
}if (chatlist.getFriends().equals("Requested")){
//DoNothing
}
if(chatlist.getFriends().equals("Blocked")){
//Dont do anything
}
}
}
}
addPartAdapter = new AddPartAdapter(getContext(), mUsers);
adapter.addEventListener(this)
recyclerView.setAdapter(addPartAdapter);
}
#Override
public void onCancelled(#NonNull DatabaseError error) {
}
});
}
//This is the method that should be called and id is the variable I want
public void AddParticipant(String id) {
//And it should initialize this method
DatabaseReference databaseReference = FirebaseDatabase.getInstance().getReference("Grouplist").child(groupId);
HashMap<String, String> hashMap1 = new HashMap<>();
hashMap1.put("id", id);
hashMap1.put("admin","false");
databaseReference.setValue(hashMap1);
}
override fun onDestroy() {
super.onDestroy()
adapter.removeEventListener()
}
}

Cast arraylist in recyclerview firebase

I have an array of data which I am retrieving from firebase. I am using a recyclerview to display the data but my adapter is not working correctly.I tried adding the arraylist in the adapter but this is not working.
It is saying the adapter is not attached and I am having a blank activity.
Any help on this ?
Here are my details.
Modal Class
public class Order {
private String ProductId;
private String ProductName;
private String Quantity;
public Order() {
}
public String getProductId() {
return ProductId;
}
public void setProductId(String productId) {
ProductId = productId;
}
public String getProductName() {
return ProductName;
}
public void setProductName(String productName) {
ProductName = productName;
}
public String getQuantity() {
return Quantity;
}
public void setQuantity(String quantity) {
Quantity = quantity;
}
public Order(String productId, String productName, String quantity) {
ProductId = productId;
ProductName = productName;
Quantity = quantity;
}
}
Adapter
public class AllOrdersAdapter extends RecyclerView.Adapter<AllOrdersViewHolder> {
List<Order> myfoods;
public AllOrdersAdapter(List<Order> myfoods) {
this.myfoods = myfoods;
}
#NonNull
#Override
public AllOrdersViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View itemView = LayoutInflater.from(parent.getContext())
.inflate(R.layout.allorders_layout,parent,false);
return new AllOrdersViewHolder(itemView);
}
#Override
public void onBindViewHolder(#NonNull AllOrdersViewHolder holder, int position) {
holder.foodname.setText(myfoods.get(position).getProductName());
holder.foodquantity.setText(myfoods.get(position).getQuantity());
holder.foodId.setText(myfoods.get(position).getProductId());
}
#Override
public int getItemCount() {
return myfoods.size();
}
}
Test Class
public class Test extends AppCompatActivity {
FirebaseDatabase db;
DatabaseReference requests;
RecyclerView lstFoods;
RecyclerView.LayoutManager layoutManager;
TextView food_id,food_quan,food_name;
// List foods = new ArrayList<>();
// RecyclerView.Adapter<AllOrder> adapter;
// List<String> myOrders = new ArrayList<String>();
// ArrayList<String> foods=new ArrayList<>();
List<String> myfoods = new ArrayList<String>();
AllOrdersAdapter adapter;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_test);
//firebase
db = FirebaseDatabase.getInstance();
requests= db.getReference().child("Requests");
lstFoods = (RecyclerView)findViewById(R.id.lstAllFoods);
lstFoods.setHasFixedSize(true);
layoutManager = new LinearLayoutManager(this);
lstFoods.setLayoutManager(layoutManager);
loadOrderss();
}
private void loadOrderss() {
requests.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
for (DataSnapshot postSnapshot : dataSnapshot.getChildren()) {
if (postSnapshot.getValue() != null) {
// List ingredients = new ArrayList<>();
for (DataSnapshot ing : postSnapshot.child("foods").getChildren()) {
// String data = String.valueOf(postSnapshot.getValue(Order.class));
myfoods.add(ing.child("quantity").getValue(String.class));
myfoods.add(ing.child("productName").getValue(String.class));
myfoods.add(ing.child("productId").getValue(String.class));
// myfoods.add(String.valueOf(Order.class));
System.out.println("Gained data: " + ing.child("productName").getValue(String.class));
}
}
}
adapter = new AllOrdersAdapter((ArrayList<String>) myfoods);
lstFoods.setAdapter(adapter);
adapter.notifyDataSetChanged();
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
}
});
}
There seems to be a couple things wrong with the code. As it is posted I would be surprised if it compiles.
In your Adapter you have:
List<Order> myfoods;
and
public AllOrdersAdapter(List<Order> myfoods) {
this.myfoods = myfoods;
}
but in your activity code you pass:
adapter = new AllOrdersAdapter((ArrayList<String>) myfoods);
one is a ArrayList of String the other of Order !
You also need to change your adapter class to something like:
public class AllOrdersAdapter extends RecyclerView.Adapter<AllOrdersAdapter.AllOrdersViewHolder> {
private static final String TAG = AllOrdersAdapter.class.getSimpleName();
private ArrayList<Order> mData;
public class AllOrdersViewHolder extends RecyclerView.ViewHolder {
public TextView mTvFoodname;
public TextView mTvFoodQuantity;
public TextView mTvFoodId;
public AllOrdersViewHolder(View v){
super(v);
// TODO: You need to assign the appropriate View Id's instead of the placeholders ????
mTvFoodQuantity = v.findViewById(R.id.????);
mTvFoodname = v.findViewById(R.id.????);
mTvFoodId = v.findViewById(R.id.????);
}
}
public AllOrdersAdapter(ArrayList<Order> data){
this.mData = data;
}
#Override
public AllOrdersViewHolder onCreateViewHolder(ViewGroup parent, int viewType){
View itemView = LayoutInflater.from(parent.getContext()).inflate(R.layout.business_list_card_view, parent, false);
return new AllOrdersViewHolder(itemView);
}
#Override
public void onBindViewHolder(final AllOrdersViewHolder holder, final int position){
//TODO: You need to decide whether you want to pass a string or order object
Order data = mData.get(position);
final String name = data.getProductName();
final String quantity = data.getQuantity();
final String id = data.getProductId();
holder.mTvFoodname.setText(name);
holder.mTvFoodQuantity.setText(quantity );
holder.mTvFoodId.setText(id)
}
#Override
public int getItemCount(){
return mData.size();
}
}
Note: That since I can not know, whether an ArrayList of String or of Order should be used the parameters in either the Activity or Adapter will need to be changed. Also how you assign the data to the RecyclerView will be affected in the onBindViewHolder method.
You should also follow the advice given by Frank.
EDIT
Change your onDataChange() method to this:
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
for (DataSnapshot postSnapshot : dataSnapshot.getChildren()) {
if (postSnapshot.getValue() != null) {
List ingredients = new ArrayList<>();
for (DataSnapshot ing : postSnapshot.child("foods").getChildren()) {
String name = ing.child("productName").getValue(String.class);
String quantity = ing.child("quantity").getValue(String.class);
String productId = ing.child("productId").getValue(String.class);
// Using your overloaded class constructor to populate the Order data
Order order = new Order(productId, name, quantity);
// here we are adding the order to the ArrayList
myfoods.add(order);
Log.e(TAG, "Gained data: " + name)
}
}
}
adapter.notifyDataSetChanged();
}
In your Activity you will need to change the ArrayList class variable "myfoods" to this:
ArrayList(Order) myfoods = new ArrayList<>();
and in your onCreate() method you can now change:
adapter = new AllOrdersAdapter((ArrayList<String>) myfoods);
to simply this:
adapter = new AllOrdersAdapter(myfoods);
Also notice that I have made some changes in my original code above.
You'll want to create the adapter, and attach it to the view, straight in onCreate:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_test);
//firebase
db = FirebaseDatabase.getInstance();
requests= db.getReference().child("Requests");
lstFoods = (RecyclerView)findViewById(R.id.lstAllFoods);
lstFoods.setHasFixedSize(true);
layoutManager = new LinearLayoutManager(this);
lstFoods.setLayoutManager(layoutManager);
adapter = new AllOrdersAdapter((ArrayList<String>) myfoods);
lstFoods.setAdapter(adapter);
loadOrders();
}
This also means you should declare myfoods as a ArrayList<String>, which saves you from having to downcast it. Something like:
ArrayList<String> myfoods = new ArrayList<String>();
Now in loadOrders you simple add the items to the list, and then notify the adapter that its data has changed (so that it repaints the view):
private void loadOrders() {
requests.child("foods").addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
for (DataSnapshot postSnapshot : dataSnapshot.getChildren()) {
for (DataSnapshot ing: postSnapshot.getChildren()) {
myfoods.add(ing.child("quantity").getValue(String.class));
myfoods.add(ing.child("productName").getValue(String.class));
myfoods.add(ing.child("productId").getValue(String.class));
}
}
adapter.notifyDataSetChanged();
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
throw databaseError.toException(); // don't ignore errors
}
});
}

Firebase no such instance field 'databaseReference'

When I try to get all the data from my database as a list, I get the following error from debugger and the code returns a null List.
public static DbOps get(Context ctx) {
if (sDbOps == null) {
sDbOps = new DbOps(ctx);
}
return sDbOps;
}
private DbOps(Context ctx) {
dbRef = FirebaseDatabase.getInstance().getReference().child("products");
if(mProducts == null) {
getProducts();
}
}
public List<Product> getProducts() {
dbRef.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
Iterator<DataSnapshot> iterator = dataSnapshot.getChildren().iterator();
mProducts = new ArrayList<>();
while (iterator.hasNext()) {
Product pr = dataSnapshot.getValue(Product.class);
mProducts.add(pr);
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
return mProducts;
}
The error is because you are trying to access a variable that is not declared in the scope of that function.
To solve this, a simple solution is that, make the variable as private or public member of that class so that all member functions can access it.
Example
public class classname{
private FirebaseDatabase dbRef;
#Override
public void onStart(Intent intent, int startid) {
dbRef = FirebaseDatabase.getInstance().getReference().child("products");
}
//Or initialize in your own function
private DbOps(Context ctx) {
dbRef = FirebaseDatabase.getInstance().getReference().child("products");
if(mProducts == null) {
getProducts();
}
}
public List<Product> getProducts() {
dbRef.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
Iterator<DataSnapshot> iterator = dataSnapshot.getChildren().iterator();
mProducts = new ArrayList<>();
while (iterator.hasNext()) {
Product pr = dataSnapshot.getValue(Product.class);
mProducts.add(pr);
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
return mProducts;
}
}

Data from Firebase won't show in my RecyclerView

The data is being fetched in the fetchData() method in FirebaseHelper, but isn't actually being stored in the variables petInfo and imgURL in the CardViewAdapter. This results in no cards showing in the RecyclerView fragment. When the app initializes, the dataset is 0, runs through the fetchData and the dataset is the size of items but leaves petInfo and imgURL null.
FirebaseHelper:
public class FirebaseHelper {
private DatabaseReference mDatabase;
Boolean saved = null;
ArrayList<AnimalType> animal = new ArrayList<>();
public FirebaseHelper(DatabaseReference mDatabase) {
this.mDatabase = mDatabase;
}
//Save
public Boolean save (AnimalType animalType){
if (animalType==null){
saved = false;
}
else{
try{
mDatabase.child("AnimalType").push().setValue(animalType);
saved=true;
}catch (DatabaseException e){
e.printStackTrace();
saved=false;
}
}
return saved;
}
//Read
public ArrayList<AnimalType> retrieve(){
mDatabase.addChildEventListener(new ChildEventListener() {
#Override
public void onChildAdded(DataSnapshot dataSnapshot, String s) {
fetchData(dataSnapshot);
Log.i(TAG, "onChildAdded");
}
#Override
public void onChildChanged(DataSnapshot dataSnapshot, String s) {
fetchData(dataSnapshot);
Log.i(TAG, "onChildChanged");
}
#Override
public void onChildRemoved(DataSnapshot dataSnapshot) {
}
#Override
public void onChildMoved(DataSnapshot dataSnapshot, String s) {
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
return animal;
}
private void fetchData (DataSnapshot dataSnapshot){
animal.clear();
for (DataSnapshot ds : dataSnapshot.getChildren()){
AnimalType animalType = new AnimalType();
animalType.setPetInfo(ds.getValue(AnimalType.class).getPetInfo());
animalType.setImgURL(ds.getValue(AnimalType.class).getImgURL());
animal.add(animalType);
}
}
}
Adapter:
public class CardViewAdapter extends RecyclerView.Adapter<CardViewAdapter.ViewHolder> {
Context mContext;
private List<AnimalType> mAnimalData = new ArrayList<>();
public class ViewHolder extends RecyclerView.ViewHolder {
public TextView petInfo;
public ImageView imgURL;
public ViewHolder(View view){
super(view);
imgURL = (ImageView) view.findViewById(R.id.pet_image);
petInfo = (TextView) view.findViewById(R.id.pet_description);
}
}
//constructor
public CardViewAdapter(Context mContext, List<AnimalType> mAnimalData){
this.mAnimalData = mAnimalData;
}
//create new views
#Override
public CardViewAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType){
View itemView = LayoutInflater.from(parent.getContext()).inflate(R.layout.row_layout, parent, false);
ViewHolder viewHolder = new ViewHolder(itemView);
mContext = parent.getContext();
return viewHolder;
}
//replace contents of view
#Override
public void onBindViewHolder(ViewHolder holder, int position){
holder.petInfo.setText(mAnimalData.get(position).getPetInfo());
PicassoClient.downloadImage(mContext,mAnimalData.get(position).getImgURL(), holder.imgURL);
}
//return size of dataset
public int getItemCount(){
return mAnimalData.size();
}
}
Fragment:
public class DogFragment extends Fragment {
public static final String ARG_PAGE = "ARG_PAGE";
private int mPage;
private RecyclerView mRecyclerView;
private RecyclerView.Adapter mCardAdapter;
private RecyclerView.LayoutManager mCardLayoutManager;
DatabaseReference mDatabaseReference;
FirebaseHelper helper;
public static DogFragment newInstance(int page) {
DogFragment dogFragment = new DogFragment();
Bundle args = new Bundle();
args.putInt(ARG_PAGE, page);
dogFragment.setArguments(args);
return dogFragment;
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mPage = getArguments().getInt(ARG_PAGE);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
View rootView = inflater.inflate(R.layout.fragment_dog, container, false);
//cardview
mRecyclerView = (RecyclerView)rootView.findViewById(R.id.card_view);
//setup firebase
mDatabaseReference = FirebaseDatabase.getInstance().getReference();
helper= new FirebaseHelper(mDatabaseReference);
//create adapter class
//mCardAdapter = new CardViewAdapter(mAimalTypeList);
mCardAdapter = new CardViewAdapter(getActivity().getApplicationContext(), helper.retrieve());
mRecyclerView.setAdapter(mCardAdapter);
//add linear layout manager
mCardLayoutManager = new LinearLayoutManager(getActivity());
mRecyclerView.setLayoutManager(mCardLayoutManager);
//preparePetData();
return rootView;
}
}
Picasso:
public class PicassoClient {
public static void downloadImage(Context context, String url, ImageView img){
if(url != null && url.length()>0){
Picasso.with(context).load(url).placeholder(R.drawable.placeholder).into(img);
}
else {
Picasso.with(context).load(R.drawable.placeholder).into(img);
}
}
}
Your call to helper.retrieve() is kicking off mDatabase.addChildEventListener the results of which will come back asynchronously....in the meantime you're returning empty list from that method (default value of animal). You need to update adapter when results come back (after you've called fetchData(dataSnapshot);)

Android - Update and delete data in Firebase database

I'm trying to update and delete data in Firebase database.
SectionDetails model
public class SectionDetails {
private String sectionCode;
private String sectionSeats;
private String sectionKey;
public SectionDetails() {
}
public SectionDetails(String sectionCode, String sectionSeats) {
this.sectionCode = sectionCode;
this.sectionSeats = sectionSeats;
}
#Exclude
public String getSectionKey() {
return sectionKey;
}
public String getSectionCode() {
return sectionCode;
}
public String getSectionSeats() {
return sectionSeats;
}
}
FirebaseHelper class
public class FirebaseHelper {
DatabaseReference db;
ArrayList<SectionDetails> sectionDetailsArrayList = new ArrayList<>();
public FirebaseHelper(DatabaseReference db) {
this.db = db;
}
private void fetchData(DataSnapshot dataSnapshot) {
SectionDetails sectionDetails = dataSnapshot.getValue(SectionDetails.class);
sectionDetailsArrayList.add(sectionDetails);
adapter.notifyDataSetChanged();
}
public ArrayList<SectionDetails> retrieve() {
db.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) {
adapter.notifyDataSetChanged();
}
#Override
public void onChildMoved(DataSnapshot dataSnapshot, String s) {
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
return sectionDetailsArrayList;
}
}
CustomAdapter class
public class CustomAdapter extends BaseAdapter {
DatabaseReference updateRef;
String key;
Context c;
ArrayList<SectionDetails> sectionDetailsArrayList;
public CustomAdapter(Context c, ArrayList<SectionDetails> sectionDetailsArrayList) {
this.c = c;
this.sectionDetailsArrayList = sectionDetailsArrayList;
}
#Override
public int getCount() {
return sectionDetailsArrayList.size();
}
#Override
public Object getItem(int position) {
return sectionDetailsArrayList.get(position);
}
#Override
public long getItemId(int position) {
return position;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
final SectionDetails sd = (SectionDetails) this.getItem(position);
updateRef = FirebaseDatabase.getInstance().getReference().child(Constants.FIREBASE_COURSES).child("sections");
convertView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
final Dialog d = new Dialog(CustomAdapter.this);
d.setContentView(R.layout.section_custom_dialog);
Button btnUpdate = (Button) d.findViewById(R.id.btnUpdate);
Button btnDelete = (Button) d.findViewById(R.id.btnDelete);
btnUpdate.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
final String code = "1B";
final String seats = "20";
updateRef.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
for (DataSnapshot snapshot : dataSnapshot.getChildren()) {
SectionDetails updateSD = snapshot.getValue(SectionDetails.class);
if (sd.getSectionCode().equals(updateSD.getSectionCode())) {
key = snapshot.getKey().toString();
}
}
SectionDetails newSD = new SectionDetails(code, seats);
updateRef.child(key).setValue(newSD);
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
}
});
btnDelete.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
updateRef.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
for (DataSnapshot snapshot : dataSnapshot.getChildren()) {
SectionDetails deleteSD = snapshot.getValue(SectionDetails.class);
if (sd.getSectionCode().equals(deleteSD.getSectionCode())) {
updateSectionRef.child(snapshot.getKey().toString()).removeValue();
break;
}
}
adapter.notifyDataSetChanged();
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
}
});
d.show();
}
});
return convertView;
}
}
MainActivity class
public class MainActivity extends AppCompatActivity {
DatabaseReference mRef;
FirebaseHelper helper;
CustomAdapter adapter;
ListView lvSectionsListOne;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
lvSectionsListOne = (ListView) findViewById(R.id.lvSectionsList);
mRef = FirebaseDatabase.getInstance().getReference().child(Constants.FIREBASE_COURSES).child("sections");
helper = new FirebaseHelper(mRef);
adapter = new CustomAdapter(this, helper.retrieve());
lvSectionsListOne.setAdapter(adapter);
}
}
The data is deleted from database as expected, but the data that gets deleted remains inside the listview. I added adapter.notifyDataSetChanged() but still the listview is not updating.
The data is also updated as expected, but when update button is clicked, the data is updated infinitely. I can see the listview as well as the database keep on appending the data, and can only be stopped by closing the app.
I have tried to move SectionDetails newSD = new SectionDetails(code, seats) and updateRef.child(key).setValue(newSD) to outside for loop but the data doesn't get updated because the key is not passed to the path outside the for loop.
I haven't thoroughly looked at all the code you posted and may not understand your processing completely. There are two things that might be causing some of the problems you described.
In FirebaseHelper, method onChildChanged() calls fetchData(), which adds the changed section details to the array list. Shouldn't you be updating the existing section details instead of adding them again? Also, in onChildRemoved(), the section details are not removed from the array list. Don't they need to be removed?
In CustomAdapter the click listeners for your buttons add anonymous ValueEventListeners. Because they are anonymous, you have no way of removing them when they are no longer needed. ValueEventListeners added with addValueEventListener() remain active until removed. If your goal is to get the data once, use addListenerForSingleValueEvent().

Categories

Resources