0

I'm new to Android development and need help with populating data from Firebase Realtime database into the FirebaseRecyclerAdapter.

My app has a list of workshops. A user can log in to my test app with a GitHub auth and I get a user email to sign in or out from the workshop if the relevant button is pressed.

So in some point, my workshop contains a list of users as per the example below in Firebase. enter image description here

The problem is that I need to highlight workshops that users have already signed into in the recycler view.

The main issue I face is when populating the info for each workshop. I can easily get the users to list separately later, but I don't know how to do this within one nice Workshop object from the very beginning.

I'm lost. Please help.

My FirebaseRecyclerAdapter:

public class WorkshopsFirebaseRecyclerAdapter extends FirebaseRecyclerAdapter<Workshop, WorkshopViewHolder> {

    private Context mContext;
    private ProgressBar progressBar;

    public WorkshopsFirebaseRecyclerAdapter(FirebaseRecyclerOptions<Workshop> options, Context context, ProgressBar view) {
        super(options);
        mContext = context;
        progressBar = view;
    }

    @Override
    public void onDataChanged() {
        if (progressBar != null) {
            progressBar.setVisibility(View.GONE);
        }
    }

    @Override
    protected void onBindViewHolder(@NonNull final WorkshopViewHolder holder, final int position, @NonNull final Workshop model) {

        final Workshop workshop = getItem(position);
        final String id = getRef(position).getKey();

        holder.date.setText(getUserFriendlyDate(workshop.getDate()));
        holder.description.setText(workshop.getDescription());

        if (workshop.getWorkshopAttendants() != null){
            Timber.i("onBindViewHolder workshop is %s", workshop.toString());
        }

        holder.getView().setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                TinyDB tinyDB = new TinyDB(mContext);
                tinyDB.putObject(mContext.getString(R.string.workshop_tinydb_key), workshop);
                Intent intent = new Intent(mContext, WorkshopDetailsActivity.class);
                intent.putExtra(mContext.getString(R.string.open_workshop_details_intent_key),
                        WorkshopDetailsActivity.INTENT_OPEN_UPDATE_WORKSHOP_DETAILS);
                intent.putExtra(mContext.getString(R.string.current_workshop_id_key), id);
                mContext.startActivity(intent);
            }
        });
    }

    @Override
    public WorkshopViewHolder onCreateViewHolder(@NonNull ViewGroup viewGroup, int i) {
        View itemView = LayoutInflater.from(viewGroup.getContext())
                .inflate(R.layout.workshop_rv_item, viewGroup, false);
        return new WorkshopViewHolder(itemView);
    }

    private String getUserFriendlyDate(String dateOld){
        Date date = new Date();
        SimpleDateFormat oldDateFormat = new SimpleDateFormat("dd-MM-yyyy", Locale.UK);
        try {
            date = oldDateFormat.parse(dateOld);
        } catch (ParseException e) {
            e.printStackTrace();
        }
        SimpleDateFormat newDateFormat = new SimpleDateFormat("dd MMM yyyy", Locale.UK);
        return newDateFormat.format(date);
    }

}

My method where I set adapter and query:

 private void loadWorkshopsForCity(String city) {
        Query query;
        if (city.equals(getString(R.string.spinner_cities_all_value))) {
            query = FirebaseDatabase.getInstance()
                    .getReference(getString(R.string.firebase_root_name))
                    .child(getString(R.string.firebase_workshops_root_name))
                    .limitToLast(50);
        } else {
            query = FirebaseDatabase.getInstance()
                    .getReference(getString(R.string.firebase_root_name))
                    .child(getString(R.string.firebase_workshops_root_name))
                    .orderByChild(getString(R.string.firebase_workshop_city_name_key))
                    .equalTo(city);
        }

        query.addListenerForSingleValueEvent(new ValueEventListener() {
            @Override
            public void onDataChange(@NonNull DataSnapshot dataSnapshot) {
                for (DataSnapshot workshopSnapshot : dataSnapshot.getChildren()) {
                    Workshop workshop = workshopSnapshot.getValue(Workshop.class);
                    for(DataSnapshot usersSnapshot : workshopSnapshot.child("users").getChildren()){
                        if (usersSnapshot.exists()){
                            WorkshopAttendant user = usersSnapshot.getValue(WorkshopAttendant.class);
                            if (user!=null){
                                users.add(user);
                            }
                        }
                    }
                    if (users.size()!=0){
                        workshop.setWorkshopAttendants(users);
                    }
                }
            }


            @Override
            public void onCancelled(@NonNull DatabaseError databaseError) {
                Timber.i(databaseError.toException());
            }
        });

        FirebaseRecyclerOptions<Workshop> options =
                new FirebaseRecyclerOptions.Builder<Workshop>()
                        .setQuery(query, Workshop.class)
                        .build();

        if (adapter != null) {
            adapter.stopListening();
        }

        adapter = new WorkshopsFirebaseRecyclerAdapter(options, this, progressBar);
        mRecyclerView.setLayoutManager(new LinearLayoutManager(this));
        mRecyclerView.setAdapter(adapter);
        adapter.startListening();

    }

my Workshop that contains Attendants list:

public class Workshop {

    private String date;
    private String time;
    private String description;
    private String name;
    private String address;
    private String city;
    private List<WorkshopAttendant> workshopAttendants;

    private boolean isChecked;

    // empty constructor for firebase
    public Workshop() {
    }

    public Workshop(String date, String time, String description, String name, String address, String city,
                    List<WorkshopAttendant> workshopAttendants) {
        this.date = date;
        this.time = time;
        this.description = description;
        this.name = name;
        this.address = address;
        this.city = city;
        this.workshopAttendants = workshopAttendants;
    } .....

and other WorkshopAttendant that should be inside Workshop object.

public class WorkshopAttendant {

    private String email;
    private int role; // 1 - coach ; 0 - organiser ; 2 - student

    public WorkshopAttendant(String userEmail, int role) {
        this.email = userEmail;
        this.role = role;
    }

    // for firebase
    public WorkshopAttendant() {
    }
KENdi
  • 7,576
  • 2
  • 16
  • 31
  • Have you tried to use `workshop.getWorkshopAttendants` to get the list? – Alex Mamo Nov 26 '18 at 08:34
  • hi @AlexMamo, thanks for looking. I saw you replied in other Firebase related topics, so really appreciate you looked at my case too. I tried, but it's null for my loaded workshops. I added logging to each step in my query and I can users info there, but my workshops I get at the end don't have it. I worry I add them the wrong way. – Tania Kolesnik Nov 26 '18 at 14:13
  • You're welcome Tania! Have solved the issue `workshop.getWorkshopAttendants`? – Alex Mamo Nov 26 '18 at 14:14
  • you are very quick in replying. thank you :)) please see my edited comment above. – Tania Kolesnik Nov 26 '18 at 14:16
  • What does `workshop.getWorkshopAttendants()` return? – Alex Mamo Nov 26 '18 at 14:18
  • when I try to get a list in Adapter onBindViewHolder I catch NullPointerException, so null. – Tania Kolesnik Nov 26 '18 at 14:26
  • At which line of code? – Alex Mamo Nov 26 '18 at 14:33
  • in onBindViewHolder I do below : final Workshop workshop = getItem(position); try { List users = workshop.getWorkshopAttendants(); int size = users.size(); Timber.i("monday, monday users size is %d ", size); } catch (NullPointerException e) { e.printStackTrace(); Timber.i(e); } – Tania Kolesnik Nov 26 '18 at 14:37
  • Ok, at which line of code points that error? – Alex Mamo Nov 26 '18 at 14:46
  • List users = workshop.getWorkshopAttendants(); – Tania Kolesnik Nov 26 '18 at 16:44
  • It means that your workshop object is `null`. Are you sure you have items in your list? – Alex Mamo Nov 26 '18 at 16:48
  • yes, I have. I worry that all operations I did in query.addListenerForSingleValueEvent are not passed correctly further to my adapter. In my query I create a Workshop object, check if it has users and if snapshot "users" exists - create a User and add it to my newly created array list. then added this array of users to my workshop... but what next? How correctly send this updated Workshop to my adapter? I worry I'm on the wrong path to get Workshop created from one class with Array List of Users (different class) :((( – Tania Kolesnik Nov 27 '18 at 14:45
  • **[This](https://stackoverflow.com/questions/49383687/how-can-i-retrieve-data-from-firebase-to-my-adapter/49384849)** is a recommended way in which you can retrieve data from a Firebase Realtime database and display it in a `RecyclerView` using `FirebaseRecyclerAdapter`. – Alex Mamo Nov 27 '18 at 14:47
  • thank you for a link. I have no issues with FirebaseRecyclerAdapter to retrieve Strings values for Workshop module, I cannot retrieve ArrayList of User objects. – Tania Kolesnik Nov 27 '18 at 15:05
  • moved my ArrayList to Map and used GenericTypeIndicator - works now – Tania Kolesnik Nov 29 '18 at 22:32

1 Answers1

0

1) List workshopAttendants in Workshop model to Map users = new HashMap<>();

2) used new SnapshotParser for my Recycler options;

FirebaseRecyclerOptions<Workshop> options =
                new FirebaseRecyclerOptions.Builder<Workshop>()
                        .setQuery(query, new SnapshotParser<Workshop>() {
                            @NonNull
                            @Override
                            public Workshop parseSnapshot(@NonNull DataSnapshot snapshot) {
                                GenericTypeIndicator<Workshop> t = new GenericTypeIndicator<Workshop>() {};
                                Workshop workshop = snapshot.getValue(t);
                                return workshop;
                            }
                        })
                .build();

3) in my adapter I set check for users so now can mark workshops that have users signed for.

try {
            Map<String, User> users = workshop.getValue();
            if (users.size()!=0){holder.description.setBackgroundColor(mContext.getColor(R.color.colorPrimaryDark));
            }
        } catch (NullPointerException e){
            Timber.i(e, "no users for %s", workshop.getDescription());
        }

thanks, @AlexMamo for patience