0

FirestoreRecyclerAdapter is throwing a null object error when the adapter.startListening() method runs in onStart() method in my Fragment.

My Firestore Database

enter image description here

The (Desserts, Starters) are SubCollections of Menu Collection which is fetched dynamically with for loop.

MenuFragment.java

public class MenuFragment extends Fragment implements View.OnClickListener {

private View view;
private FirebaseFirestore db;
private FirebaseAuth mAuth;
private FirebaseUser mCurrentUser;
private String Ruid,mItemName,mItemPrice,mItemIsActive,mItemSpecs;
private FloatingActionButton mCreateNewMenuBtn;
private DocumentReference mResMenuCategoryRef, mMenuItemRef;
private ArrayList<String> categoryList;
private FirestoreRecyclerAdapter<MenuItemModel, MenuItemHolder> adapter;
LinearLayoutManager linearLayoutManager;
private RecyclerView mMenuItemRecyclerView;

public MenuFragment() {
    // Required empty public constructor
}

@Override
public View onCreateView(@NotNull LayoutInflater inflater, ViewGroup container,
                         Bundle savedInstanceState) {

    view = inflater.inflate(R.layout.fragment_menu,container,false);

    init();
    getMenuItems();
    mCreateNewMenuBtn.setOnClickListener(this);

    return view;
}

private void init() {
    mCreateNewMenuBtn = view.findViewById(R.id.createNewMenuBtn);
    mAuth = FirebaseAuth.getInstance();
    mCurrentUser = mAuth.getCurrentUser();
    assert mCurrentUser != null;
    Ruid = mCurrentUser.getUid();
    db = FirebaseFirestore.getInstance();
    mResMenuCategoryRef = db.collection("RestaurantList").document(Ruid);
    mMenuItemRecyclerView = view.findViewById(R.id.menuItemRecyclerView);
    linearLayoutManager = new LinearLayoutManager(requireActivity(), LinearLayoutManager.VERTICAL, false);
    mMenuItemRecyclerView.setLayoutManager(linearLayoutManager);
}

private void getMenuItems() {
    mResMenuCategoryRef.get().addOnCompleteListener(task -> {
        if (task.isSuccessful()){
            DocumentSnapshot documentSnapshot = task.getResult();
            assert documentSnapshot != null;
            if (documentSnapshot.exists()){
                categoryList = (ArrayList<String>) documentSnapshot.get("Categories");
                assert categoryList != null;
                Log.d("CATEGORIES", categoryList.toString());

                for(int i = 0 ; i < categoryList.size() ; i++){
                    String MenuItemSubCollection = categoryList.get(i);
                    CollectionReference menuItemReference = db.collection("Menu").document(Ruid).collection(MenuItemSubCollection);
                    menuItemReference.get().addOnCompleteListener(task1 -> {

                        if (task1.isSuccessful()){
                            for (QueryDocumentSnapshot document : Objects.requireNonNull(task1.getResult())) {

                                DocumentReference mMenuItemRef = menuItemReference.document(document.getId());
                                mMenuItemRef.get().addOnCompleteListener(task2 -> {

                                    if (task2.isSuccessful()){
                                        DocumentSnapshot mMenuItemSnapShot = task2.getResult();
                                        assert mMenuItemSnapShot != null;
                                        Query query = db.collection("Menu").document(Ruid).collection(MenuItemSubCollection);
                                        FirestoreRecyclerOptions<MenuItemModel> menuItemModel = new FirestoreRecyclerOptions.Builder<MenuItemModel>()
                                                .setQuery(query, MenuItemModel.class)
                                                .build();
                                            adapter = new FirestoreRecyclerAdapter<MenuItemModel, MenuItemHolder>(menuItemModel) {
                                            @Override
                                            public void onBindViewHolder(MenuItemHolder holder, int position, MenuItemModel model) {
                                                holder.mItemName.setText(model.getName());
                                                Log.d("SHOWING", model.getName());
                                                String specImage = model.getSpecification();
                                                if (specImage.equals("Veg")){
                                                    Glide.with(Objects.requireNonNull(requireActivity()))
                                                            .load(R.drawable.veg_symbol).into(holder.foodSpecification);
                                                }else {
                                                    Glide.with(Objects.requireNonNull(requireActivity()))
                                                            .load(R.drawable.non_veg_symbol).into(holder.foodSpecification);
                                                }
                                                holder.mItemPrice.setText(model.getPrice());
                                                holder.itemView.setOnClickListener(v -> {
                                                });
                                            }
                                            @Override
                                            public MenuItemHolder onCreateViewHolder(ViewGroup group, int i) {
                                                View view = LayoutInflater.from(group.getContext())
                                                        .inflate(R.layout.menu_item_details, group, false);
                                                return new MenuItemHolder(view);
                                            }
                                            @Override
                                            public void onError(FirebaseFirestoreException e) {
                                                Log.e("error", e.getMessage());
                                            }
                                        };
                                        adapter.notifyDataSetChanged();
                                        mMenuItemRecyclerView.setAdapter(adapter);
                                    }

                                });

                            }
                        }

                    });

                }
            }
        }

    });

}

public class MenuItemHolder extends RecyclerView.ViewHolder {
    @BindView(R.id.itemName)
    TextView mItemName;
    @BindView(R.id.foodMark)
    ImageView foodSpecification;
    @BindView(R.id.itemPrice)
    TextView mItemPrice;
    @BindView(R.id.itemActiveSwitch)
    Switch isActiveSwitch;

    public MenuItemHolder(View itemView) {
        super(itemView);
        ButterKnife.bind(requireActivity(), itemView);
    }
}

@Override
public void onClick(View view) {

    switch (view.getId()){
        case R.id.createNewMenuBtn:
            Fragment fragment = new CreateNewMenuFragment();
            FragmentManager fragmentManager = Objects.requireNonNull(getActivity()).getSupportFragmentManager();
            FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
            fragmentTransaction.replace(R.id.fragmentContainer, fragment);
            fragmentTransaction.addToBackStack(null);
            fragmentTransaction.commit();
            break;
    }
}

@Override
public void onStart() {
    super.onStart();
    adapter.startListening();
}

@Override
public void onStop() {
    super.onStop();
    adapter.stopListening();
}

}

MenuItemModel.java

public class MenuItemModel {

private String name;
private String price;
private String specification;

public MenuItemModel(String name, String price, String specification) {
    this.name = name;
    this.price = price;
    this.specification = specification;
}

public String getName() {
    return name;
}

public void setName(String name) {
    this.name = name;
}

public String getPrice() {
    return price;
}

public void setPrice(String price) {
    this.price = price;
}

public String getSpecification() {
    return specification;
}

public void setSpecification(String specification) {
    this.specification = specification;
}

}

LogCat

2020-07-09 20:47:57.251 1689-1689/com.example.muncherestaurantpartner E/AndroidRuntime: FATAL EXCEPTION: main
    Process: com.example.muncherestaurantpartner, PID: 1689
    java.lang.NullPointerException: Attempt to invoke virtual method 'void com.firebase.ui.firestore.FirestoreRecyclerAdapter.startListening()' on a null object reference
        at Fragments.MenuFragment.onStart(MenuFragment.java:205)
        at androidx.fragment.app.Fragment.performStart(Fragment.java:2632)
        at androidx.fragment.app.FragmentManagerImpl.moveToState(FragmentManagerImpl.java:915)
        at androidx.fragment.app.FragmentManagerImpl.moveFragmentToExpectedState(FragmentManagerImpl.java:1238)
        at androidx.fragment.app.FragmentManagerImpl.moveToState(FragmentManagerImpl.java:1303)
        at androidx.fragment.app.BackStackRecord.executeOps(BackStackRecord.java:439)
        at androidx.fragment.app.FragmentManagerImpl.executeOps(FragmentManagerImpl.java:2079)
        at androidx.fragment.app.FragmentManagerImpl.executeOpsTogether(FragmentManagerImpl.java:1869)
        at androidx.fragment.app.FragmentManagerImpl.removeRedundantOperationsAndExecute(FragmentManagerImpl.java:1824)
        at androidx.fragment.app.FragmentManagerImpl.execPendingActions(FragmentManagerImpl.java:1727)
        at androidx.fragment.app.FragmentManagerImpl$2.run(FragmentManagerImpl.java:150)
        at android.os.Handler.handleCallback(Handler.java:873)
        at android.os.Handler.dispatchMessage(Handler.java:99)
        at android.os.Looper.loop(Looper.java:201)
        at android.app.ActivityThread.main(ActivityThread.java:6864)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:547)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:873)
Aditya Verma
  • 120
  • 2
  • 10

1 Answers1

2

You are initializing the adapter inside onCreateView() which is a method in the fragment lifecycle and it is called before onStart(), therefore after initializing the adapter inside getMenuItems(), you have to call startListening():

adapter.startListening();
adapter.notifyDataSetChanged();
mMenuItemRecyclerView.setAdapter(adapter);

Then inside onDestroyView(), you can call stopListening():

    @Override
    public void onDestroyView() {
        super.onDestroyView();
        adapter.stopListening();
    }
Peter Haddad
  • 78,874
  • 25
  • 140
  • 134