I have a pretty common scenario, but I am stuck trying to figure out how to retrieve data from certain json objects within the same json response but returning different size of items. To make it less confusing, here's my json response:
{
"totalResults": 5,
"meetings": [
{
"id": "754e6670-2376-4eb2-b5f6-ea63ca7c2669",
"dateStart": "2019-11-28T15:25:36.000Z",
"dateEnd": "2019-11-28T23:00:36.000Z",
"visitors": [
{
"visitId": "34608af6-bbe4-439c-b472-500790385f60",
"firstName": "Lord",
"lastName": "Wilkins",
"email": " lwilkins@df.dj",
},
{
"visitId": "fe61e1f0-34f1-4701-b806-45395980acfb",
"firstName": "cg",
"lastName": "cg",
"email": "cg@gg.hg",
},
{
"visitId": "226eed33-b2ca-4406-b085-8534c2f87c69",
"firstName": "ar",
"lastName": "fg",
"email": "ar@gg.hh",
}
]
},
{
"id": "cf6934c1-3800-4b79-9d0f-570934097d26",
"dateStart": "2019-11-30T00:00:06.000Z",
"dateEnd": "2019-11-30T02:00:06.000Z",
"visitors": [
{
"visitId": "03a01b91-f307-4a04-ae7a-71a5e3e183c5",
"firstName": "ar",
"lastName": "fg",
"email": "ar@gg.hh",
}
]
},
{
"id": "a46130c3-5b80-419e-8c57-e17428d4b735",
"dateStart": "2019-11-28T13:00:09.000Z",
"dateEnd": "2019-11-29T02:45:09.000Z",
"visitors": [
{
"visitId": "5068a774-1cf3-45e2-af65-b98ab4dfbff2",
"firstName": "dot",
"lastName": "mn",
"email": "dtmn@gg.gh",
}
]
}
]
}
If anyone's interested here's my model class: https://pastebin.com/fUmiBiQP
Now, I am trying to retrieve the date start and date end and place it on top of first and last name and email, something like this :
" Nov 28, 2:00pm - 6:00 pm
lord wilkins
lwilkins@df.dj
Nov 28, 2:00pm - 6:00 pm
cg cg
cg@gg.hg"
Notice how I repeat the same date that applies to entries grouped together , I want to achieve that, but currently I just am able to retrieve first and last name and email, but not the date based on how I have arranged my code. Everytime I try to modify the code to include meetings start and end date it crashes with either an index out of bounds exception due to size or null pointer exception.The issue happens in adapter. Here's my adapter code for reference:
public class UpcomingGuestListAdapter extends RecyclerView.Adapter<BaseViewHolder> {
private Context context;
private UpcomingGuestListAdapter.Callback mCallback;
private List<UpcomingGuestsList.Visitor> mUpcomingGuestListResponseList;
private List<UpcomingGuestsList.Meeting> mUpcomingGuestListResponseMeetingList;
public class MyViewHolder extends BaseViewHolder {
public TextView name, email, arrivalDate;
public MyViewHolder(@NonNull View itemView) {
super(itemView);
Timber.d("viewholder butterknife bind");
name = itemView.findViewById(R.id.upcoming_guest_name);
email = itemView.findViewById(R.id.upcoming_guest_email);
arrivalDate = itemView.findViewById(R.id.arrival_date);
ButterKnife.bind(this, itemView);
}
@Override
protected void clear() {
}
public void onBind(int position) {
super.onBind(position);
final UpcomingGuestsList.Visitor guest = mUpcomingGuestListResponseList.get(position);
final UpcomingGuestsList.Meeting meeting = mUpcomingGuestListResponseMeetingList.get(position);
String guestWholeName = guest.firstName + " "+ guest.lastName;
if( guest.getFirstName() != null && guest.getLastName() != null) {
name.setText(guestWholeName);
}
if (guest.getEmail() != null) {
email.setText(guest.getEmail());
} else {
email.setText("");
}
String meetingDate = meeting.dateStart + "-"+ meeting.dateEnd;
if( meeting.getDateStart() != null && meeting.getDateEnd() != null) {
arrivalDate.setText(meetingDate);
}
itemView.setOnClickListener(v -> {
if(mCallback != null) {
mCallback.onItemClick( guest.getFirstName(), guest.getLastName(), guest.getEmail());
}
});
}
}
@NonNull
@Override
public BaseViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View itemView = LayoutInflater.from(parent.getContext())
.inflate(R.layout.item_upcoming_guest, parent, false);
return new UpcomingGuestListAdapter.MyViewHolder(itemView);
}
public interface Callback {
void onItemClick(String guestFirstName, String guestLastName,String guestEmail);
}
@Override
public long getItemId(int position) {
Timber.d("item id for eventlist adapter : %s",position);
return position;
}
public void addItems(@NonNull List<UpcomingGuestsList.Visitor> repoList) {
mUpcomingGuestListResponseList.addAll(repoList);
notifyDataSetChanged();
}
public void addMeetingItems(@NonNull List<UpcomingGuestsList.Meeting> meetingList) {
mUpcomingGuestListResponseMeetingList.addAll(meetingList);
notifyDataSetChanged();
}
@Override
public void onBindViewHolder(BaseViewHolder holder, final int position) {
holder.onBind(position);
}
public UpcomingGuestListAdapter(Context context, List<UpcomingGuestsList.Visitor> visitorGuestList, List<UpcomingGuestsList.Meeting> meetingList) {
Timber.d("SearchGuestListAdapter constructor");
this.context = context;
this.mUpcomingGuestListResponseList = visitorGuestList;
this.mUpcomingGuestListResponseMeetingList = meetingList;
}
@Override
public int getItemCount() {
return (mUpcomingGuestListResponseList != null)?mUpcomingGuestListResponseList.size():0;
}
public void setCallback(UpcomingGuestListAdapter.Callback callback) {
mCallback = callback;
}
}
Here's the code in activity where it gets the data from :
@Override
public void updateUpcomingGuestList(List<UpcomingGuestsList.Visitor> guestList,List<UpcomingGuestsList.Meeting> meetingList) {
mUpcomingGuestAdapter.addItems(guestList);
mUpcomingGuestAdapter.addMeetingItems(meetingList);
mUpcomingGuestAdapter.notifyDataSetChanged();
}
In the same activity this is how I set my adapter on create :
guestList = new ArrayList<>();
mUpcomingGuestAdapter = new UpcomingGuestListAdapter(this, guestList, meetingList);
mUpcomingGuestAdapter.setCallback(this);
mLayoutManager.setOrientation(LinearLayoutManager.VERTICAL);
mRecyclerView.setLayoutManager(mLayoutManager);
mRecyclerView.setItemAnimator(new DefaultItemAnimator());
mRecyclerView.setAdapter(mUpcomingGuestAdapter);
mPresenter.onViewPrepared();
and the code for on viewprepared where i retrieve the json data :
@Override
public void onViewPrepared() {
getCompositeDisposable().add(getDataManager()
.getUpcomingGuestListApiCall(AppPreferencesHelper.getInstance().getCurrentUserId())
.subscribeOn(getSchedulerProvider().io())
.observeOn(getSchedulerProvider().ui())
.subscribe(response -> {
int sizercount = 0;
for (int i = 0; i <response.totalResults; i++) {
Objects.requireNonNull(getMvpView()).updateUpcomingGuestList(response.meetings.get(i).getVisitors(),response.getMeetings());
sizercount++;
}
totalGuests = sizercount;
Timber.d("total results value is : from upcomingguests %s",response.totalResults);
getDataManager().getUpcomingGuestsList();
AppPreferencesHelper.getInstance().setTotalUpcomingGuestCount(sizercount);
}, throwable -> {
if (!isViewAttached()) {
return;
}
// handle the error here
if (throwable instanceof ANError) {
ANError anError = (ANError) throwable;
Timber.d("it is ERROR in displaylocation in Registervisitorpresenter:%s", anError.getErrorDetail());
handleApiError(anError);
}
}));
}
As you can see from above, I try to retrieve the visitors list and meeting list together here: Objects.requireNonNull(getMvpView()).updateUpcomingGuestList(response.meetings.get(i).getVisitors(),response.getMeetings()); , but not sure if its the right way to do it as both visitors list and meetings list have different positions/size based on the data and this is probably causing the crash.Is there a way to go around this and update my code so I can assign the correct dates to the right visitors so I can achieve the output I listed above? Any help appreciated.
Thanks! Happy to share more info if needed.