How to check whether a query has been completed in firebase

Viewed 226

I have a MachineActivity. It has cardViews with an icon and text. So I have stored the names of the cardView in firebase database and the icons are stored in firebase storage. The cardView is custom and hence the adapter. Below is my Machine class and the MachineAdapter for cardView.

Machine.java

package com.example.tbiapphome;

import com.google.firebase.storage.StorageReference;

public class Machine {
    String machineName;
    StorageReference machineIcon;

    public Machine(String machineName, StorageReference machineIcon) {
        this.machineName = machineName;
        this.machineIcon = machineIcon;
    }

    public String getMachineName() {
        return machineName;
    }

    public StorageReference getMachineIcon() {
        return machineIcon;
    }

    public void setMachineName(String machineName) {
        this.machineName = machineName;
    }

    public void setMachineIcon(StorageReference machineIcon) {
        this.machineIcon = machineIcon;
    }
}

MachineAdapter.java

package com.example.tbiapphome;

import android.content.Context;
import android.content.DialogInterface;
import android.view.LayoutInflater;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.ImageView;
import android.widget.Spinner;
import android.widget.TextView;
import android.widget.Toast;

import androidx.annotation.NonNull;
import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.widget.PopupMenu;
import androidx.recyclerview.widget.RecyclerView;

import com.bumptech.glide.Glide;

import java.util.List;

import br.com.sapereaude.maskedEditText.MaskedEditText;

public class MachineAdapter extends RecyclerView.Adapter<MachineAdapter.MyViewHolder>  {

    private Context mContext;
    private List<Machine> machineList;

    public class MyViewHolder extends RecyclerView.ViewHolder{
        public TextView machineCardName;
        public ImageView overflow, machineCardImageView;

        public MyViewHolder(@NonNull View itemView) {
            super(itemView);
            machineCardName = itemView.findViewById(R.id.machineCardName);
            machineCardImageView = itemView.findViewById(R.id.machineCardImageView);
            overflow = (ImageView) itemView.findViewById(R.id.overflow);
        }

    }//myViewHolder class ended

    public MachineAdapter(Context mContext, List<Machine> machineList) {
        this.mContext = mContext;
        this.machineList = machineList;
    }

    @NonNull
    @Override
    public MachineAdapter.MyViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        View itemView = LayoutInflater.from(parent.getContext())
                .inflate(R.layout.machine_card, parent, false);
        return new MyViewHolder(itemView);
    }

    @Override
    public void onBindViewHolder(@NonNull final MachineAdapter.MyViewHolder holder, int position) {
        Machine machine = machineList.get(position);
        holder.machineCardName.setText(machine.getMachineName());

        // loading machine icons using Glide library
        Glide.with(mContext).load(machine.getMachineIcon()).into(holder.machineCardImageView);

        holder.overflow.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                showPopupMenu(holder.overflow);
            }
        });

    }

    /**
     * Showing popup menu when tapping on 3 dots
     */
    private void showPopupMenu(View view) {
        // inflate menu
        PopupMenu popup = new PopupMenu(mContext, view);
        MenuInflater inflater = popup.getMenuInflater();
        inflater.inflate(R.menu.menu_machine, popup.getMenu());
        popup.setOnMenuItemClickListener(new MyMenuItemClickListener());
        popup.show();
    }


    /**
     * Click listener for popup menu items
     */

    class MyMenuItemClickListener implements PopupMenu.OnMenuItemClickListener {

        public MyMenuItemClickListener() {
        }

        @Override
        public boolean onMenuItemClick(MenuItem menuItem) {
            switch (menuItem.getItemId()) {
                case R.id.book:
                    //setting up popup for register item
                    //setting machines array for spinner
                    final String[] machinesArray = {"Choose a Machine...", "CNC Machine", "Drill Machine", "Screwdriver", "Contact"," Demo1", "Demo2", "Demo3", "Demo4", "Demo5"};
                    AlertDialog.Builder builder = new AlertDialog.Builder(mContext);
                    LayoutInflater inflater = LayoutInflater.from(mContext);
                    final View view = inflater.inflate(R.layout.request_dialog, null);
                    final MaskedEditText dateEditText = view.findViewById(R.id.dateEditText);
                    final MaskedEditText startTimeEditText = view.findViewById(R.id.startTimeEditText);
                    final MaskedEditText endTimeEditText = view.findViewById(R.id.endTimeEditText);
                    builder.setTitle("Create request");
                    final Spinner spinner = view.findViewById(R.id.spinner);
                    ArrayAdapter<String> arrayAdapter = new ArrayAdapter<>(mContext, android.R.layout.simple_spinner_item, machinesArray);
                    arrayAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
                    spinner.setAdapter(arrayAdapter);
                    builder.setPositiveButton("Book", new DialogInterface.OnClickListener() {
                        @Override
                        public void onClick(DialogInterface dialog, int which) {
                            if (spinner.getSelectedItem().toString().equalsIgnoreCase("")){
                                Toast.makeText(mContext, "Choose a machine", Toast.LENGTH_SHORT).show();
                            }
                            if (dateEditText.getRawText().equalsIgnoreCase("")) {
                                Toast.makeText(mContext, "Enter date", Toast.LENGTH_SHORT).show();
                            }
                            if (startTimeEditText.getRawText().equalsIgnoreCase("") || endTimeEditText.getRawText().equalsIgnoreCase("")){
                                Toast.makeText(mContext, "Enter time", Toast.LENGTH_SHORT).show();
                            }
                        }
                    });
                    builder.setNegativeButton("Dismiss", new DialogInterface.OnClickListener() {
                        @Override
                        public void onClick(DialogInterface dialog, int which) {
                            dialog.dismiss();
                        }
                    });
                    builder.setView(view);
                    AlertDialog alertDialog = builder.create();
                    alertDialog.show();
                    return true;
                default:
            }
            return false;
        }
    }

    @Override
    public int getItemCount() {
        return machineList.size();
    }

}

MachineActivit.java codeblock for cardView

 private void prepareMachineIcons() {
        final int[] count = {0};
        //querying the database
        //Using two array to store the name and iconurl
        DatabaseReference mDatabase;
        mDatabase = FirebaseDatabase.getInstance().getReference();
        Query machines = mDatabase.child("Machines");
        machines.addListenerForSingleValueEvent(new ValueEventListener() {
            @Override
            public void onDataChange(@NonNull DataSnapshot dataSnapshot) {
                count[0]++;
                String name = dataSnapshot.child("name").getValue().toString();
                StorageReference storageReference = FirebaseStorage.getInstance().getReference();
                String imagePath = "machine images/m"+String.valueOf(count)+".jpg";
                StorageReference iconPathReference = storageReference.child(imagePath);
                //updating machine UI
                Machine a;
                a = new Machine(name, iconPathReference);
                machineList.add(a);
                adapter.notifyDataSetChanged();

            }

            @Override
            public void onCancelled(@NonNull DatabaseError databaseError) {

            }
        });

    }

The error comes like this

2020-05-21 22:27:30.154 10397-10397/com.example.tbiapphome E/AndroidRuntime: FATAL EXCEPTION: main
    Process: com.example.tbiapphome, PID: 10397
    java.lang.NullPointerException: Attempt to invoke virtual method 'java.lang.String java.lang.Object.toString()' on a null object reference
        at com.example.tbiapphome.MachineActivity$2.onDataChange(MachineActivity.java:99)
        at com.google.firebase.database.Query$1.onDataChange(com.google.firebase:firebase-database@@19.3.0:179)
        at com.google.firebase.database.core.ValueEventRegistration.fireEvent(com.google.firebase:firebase-database@@19.3.0:75)
        at com.google.firebase.database.core.view.DataEvent.fire(com.google.firebase:firebase-database@@19.3.0:63)
        at com.google.firebase.database.core.view.EventRaiser$1.run(com.google.firebase:firebase-database@@19.3.0:55)
        at android.os.Handler.handleCallback(Handler.java:751)
        at android.os.Handler.dispatchMessage(Handler.java:95)
        at android.os.Looper.loop(Looper.java:154)
        at android.app.ActivityThread.main(ActivityThread.java:6077)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:866)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:756)

Here both the cardView text and image are fetched inside the addEventChildListener. The image is fetched using glide . But my problem here is that I can't get this code working because the cardViewtext and image are fetched at different times. The text loads faster than the image. Hence this code raises an exception. Is there any way I make make it such that the image is fetched after the text or Is there any way to do a task after a query is completed like we do in parse. Please help

1 Answers

It seems the method you're using is for changes in the child location.

As per the documentation, you should use the method addListenerForSingleValueEvent()

Documentation is here

Guide to read a single value is here

So your program should change like;

...
        DatabaseReference mDatabase;
        mDatabase = FirebaseDatabase.getInstance().getReference();
        Query machines = mDatabase.child("Machines");
        machines.addListenerForSingleValueEvent(new ValueEventListener() {
...
Related