Home > Mobile >  Android Studio Firebase DataChange Async and Bundle Issue (Java)
Android Studio Firebase DataChange Async and Bundle Issue (Java)

Time:03-06

I have been getting certain issues with the onDataChange method when I am calling from Firebase Realtime Database. These issues would include data disappearing outside of the DataChange method. I tried a solution from this link, How to return DataSnapshot value as a result of a method?, it has worked, however, when I tried passing it to a fragment bundle within the callback method, it says the values are null and there isn't any data in it. Is there any workaround for this problem that I am facing? Help is really appreciated, thanks!

import edu.ntu.ssp4_rzdns_outhink.R;
import edu.ntu.ssp4_rzdns_outhink.modals.Attraction;

public class MostPopularRecyclerViewAdapter extends RecyclerView.Adapter<MostPopularRecyclerViewAdapter.ViewHolder>{

    private static final String TAG = "MostPopularRecyclerViewAdapter";
    private static final String SHARED_PREFS = "attractionsFile";
    private ArrayList<Attraction> pops;
    private Attraction attraction;
    private Context mContext;
    private FragmentManager fm;
    private Bundle bundle;
    SharedPreferences.Editor editor;
    SharedPreferences attractionFile;

    public MostPopularRecyclerViewAdapter(ArrayList<Attraction> pops, Context mContext, FragmentManager fm, Bundle bundle) {
        this.pops = pops;
        this.mContext = mContext;
        this.fm = fm;
        this.bundle = bundle;
    }

    @NonNull
    @Override
    public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        Log.d(TAG, "OnCreateViewHolder Called");
        View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.view_more_list, parent, false);
        ViewHolder holder = new ViewHolder(view);
        return holder;
    }

    @Override
    public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
        Log.d(TAG, "onBindViewHolder Called");
        Glide.with(mContext).asBitmap().load(pops.get(position).photo_url).into(holder.attractionImage);
        holder.locationName.setText(pops.get(position).att_name);
        holder.locationRating.setText(pops.get(position).att_rating.toString());
        holder.locationAddress.setText(pops.get(position).att_address);
        holder.parentLayout.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                String attraction_id = pops.get(holder.getBindingAdapterPosition()).id;
                readData(new FirebaseCallback() {
                    @Override
                    public void onCallBack(Attraction attr) {
                        bundle.putString("attid", attr.id);
                        bundle.putString("name", attr.att_name);
                        bundle.putString("address", attr.att_address);
                        bundle.putString("desc", attr.att_desc);
                        bundle.putDouble("rating", attr.att_rating);
                        bundle.putString("url", attr.att_url);
                        bundle.putSerializable("ophrs", attr.att_op_hr);
                        bundle.putSerializable("adminrate",attr.att_admin_rate);
                        bundle.putString("photo_url", attr.photo_url);
                    }
                },attraction_id);
            }
        });
    }

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

    public static class ViewHolder extends RecyclerView.ViewHolder{

        ImageView attractionImage;
        TextView locationName;
        TextView locationAddress;
        TextView locationRating;
        RelativeLayout parentLayout;

        public ViewHolder(@NonNull View itemView){
            super(itemView);
            attractionImage = itemView.findViewById(R.id.viewmoreImage);
            locationName = itemView.findViewById(R.id.viewmoreName);
            locationAddress = itemView.findViewById(R.id.viewmoreLocation);
            locationRating = itemView.findViewById(R.id.viewmoreRating);
            parentLayout = itemView.findViewById(R.id.parent_layout_view_more);
        }
    }

    private void readData(FirebaseCallback firebaseCallback, String attrId){

        Query query = FirebaseDatabase.getInstance().getReference("attractions");
        query.addListenerForSingleValueEvent(new ValueEventListener() {
            @Override
            public void onDataChange(@NonNull DataSnapshot snapshot) {
                if (!snapshot.exists()) {
                    System.out.println("Attraction Does Not Exist");
                } else {
                    for (DataSnapshot attr : snapshot.getChildren()) {
                        if (attr.getKey().equals(attrId)) {
                            attraction = attr.getValue(Attraction.class);
                            attraction.setId(attr.getKey());
                        }
                    }
                    firebaseCallback.onCallBack(attraction);
                }
            }

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

            }
        });
    }


    private interface FirebaseCallback{
        void onCallBack(Attraction attraction);
    }
}

CodePudding user response:

According to your last comment:

When I try to put these variables in the bundle, it’ll just disappear and become null.

Please note that this is the expected behavior. There are multiple inconsistencies in your code. First of all, that's not how you should handle the click event in your adapter class. Attaching a click listener to each element you display, isn't a feasible solution. You should create an interface for that as you can see in this repo.

Now, each time you click a particular element in your RecyclerView, you call the readData() method. When you receive the data, you add that data to the Bundle. The problem is that the operation that is opening the new fragment is happening faster than you get the data from the database. That's the reason why you are getting null.

To solve this, you either navigate to the next fragment, only when the data is available or you can make another call, right from the second fragment.

  • Related