Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

When using Paging Library, observer showing list size as zero

I am trying to use paging library with newer versions. I am using volley to fetch my data from network. Whenever I fetch data from network, the data is fetched but when the call goes to observer the list size shown there is zero. I am unsure what I am doing wrong.

I am new to android so don't know much about paging. Its been days since I m trying but still unable to figure it out.

My gradle is as follows

apply plugin: 'com.android.application'

android {
compileSdkVersion 27
defaultConfig {
    applicationId "com.example.athansys.mypagingapplication"
    minSdkVersion 22
    targetSdkVersion 27
    versionCode 1
    versionName "1.0"
    testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
}
buildTypes {
    release {
        minifyEnabled false
        proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
    }
}
}

dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation 'com.android.support:appcompat-v7:27.1.1'
implementation 'com.android.support:support-v4:27.1.1'
implementation 'com.android.support:cardview-v7:27.1.1'
implementation 'com.android.support:recyclerview-v7:27.1.1'
implementation 'com.android.volley:volley:1.1.0'
implementation 'com.google.code.gson:gson:2.8.1'
implementation 'com.android.support:design:27.1.1'
implementation 'com.android.support.constraint:constraint-layout:1.1.2'
testImplementation 'junit:junit:4.12'
androidTestImplementation 'com.android.support.test:runner:1.0.2'
androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'

implementation "android.arch.paging:runtime:1.0.1"
implementation "android.arch.lifecycle:runtime:1.1.1"
implementation "android.arch.lifecycle:extensions:1.1.1"
annotationProcessor "android.arch.lifecycle:compiler:1.1.1"

}

My MainActivity looks like:

package com.example.athansys.mypagingapplication;

import android.arch.lifecycle.Observer;
import android.arch.lifecycle.ViewModelProviders;
import android.arch.paging.PagedList;
import android.support.annotation.Nullable;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.view.View;

public class MainActivity extends AppCompatActivity {

private MyPatientAdapter mPatientAdapter;
private RecyclerView mRecyclerView;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    FilterModel viewModel = ViewModelProviders.of(this).get(FilterModel.class);
    viewModel.getData(this).observe(this, new Observer<PagedList<FilterPatientList>>() {
        @Override
        public void onChanged(@Nullable PagedList<FilterPatientList> results) {
            mPatientAdapter.submitList(results);
            //mPatientAdapter.setList(results);
            mPatientAdapter.notifyDataSetChanged();
            mRecyclerView.setAdapter(mPatientAdapter);
        }
    });
}

private void setAdapter() {

    mRecyclerView = findViewById(R.id.my_patient_recycler_view);
    RecyclerView.LayoutManager layoutManager = new LinearLayoutManager(this);
    mPatientAdapter = new MyPatientAdapter();
    mRecyclerView.setLayoutManager(layoutManager);
    mRecyclerView.setAdapter(mPatientAdapter);

}
}

FilterModel class is as follows:

package com.example.athansys.mypagingapplication;


import android.arch.lifecycle.LiveData;
import android.arch.lifecycle.ViewModel;
import android.arch.paging.LivePagedListBuilder;
import android.arch.paging.PagedList;
import android.content.Context;
import android.util.Log;

public class FilterModel extends ViewModel {
private LiveData<PagedList<FilterPatientList>> listLiveData;

LiveData<PagedList<FilterPatientList>> getData(Context context) {
    if (listLiveData == null) {

        PagedList.Config pagedListConfig =
                (new PagedList.Config.Builder()).setEnablePlaceholders(false)
                        .setPrefetchDistance(5)
                        .setPageSize(1).build();

        listLiveData = new LivePagedListBuilder<>
                (new MyPatientPagedListProvider(context)
                        .getAll()
                        , pagedListConfig).
                build();

    }
    return listLiveData;
}
}

MyProvider class is:

    package com.example.athansys.mypagingapplication;

import android.arch.paging.DataSource;
import android.arch.paging.LivePagedListProvider;
import android.content.Context;
import android.util.Log;

import java.util.List;


public class MyPatientPagedListProvider {

Context mBaseContext;

public MyPatientPagedListProvider(Context context) {
    mBaseContext = context;
    dataClass.getContextInstance(context);
}

private static final String TAG = MyPatientPagedListProvider.class.getName();

MyPatientData dataClass = new MyPatientData() {
    @Override
    public List<FilterPatientList> convertToItems(List<FilterPatientList> result, int size) {
        return result;
    }
};

public LivePagedListProvider<Integer, FilterPatientList> getAll() {
    return new LivePagedListProvider<Integer, FilterPatientList>() {
        @Override
        protected DataSource<Integer, FilterPatientList> createDataSource() {
            return dataClass;
        }
    };
}
}

MyDataSource is as follows:

    package com.example.athansys.mypagingapplication;

import android.arch.paging.TiledDataSource;
import android.content.Context;

import com.android.volley.AuthFailureError;
import com.android.volley.DefaultRetryPolicy;
import com.android.volley.Request;
import com.android.volley.Response;
import com.android.volley.VolleyError;
import com.android.volley.toolbox.StringRequest;
import com.android.volley.toolbox.Volley;
import com.google.gson.Gson;

import org.json.JSONException;
import org.json.JSONObject;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public abstract class MyPatientData extends TiledDataSource<FilterPatientList> {

private Context mContext;
private List<FilterPatientList> patientList;

@Override
public int countItems() {
    return 10;
}

@Override
public List<FilterPatientList> loadRange(int startPosition, int count) {
    String url = "My URl";
    return postStringRequestForMyPatient(url);
}

public List<FilterPatientList> postStringRequestForMyPatient(String url) {
    StringRequest stringRequest = new StringRequest(Request.Method.GET, url, new Response.Listener<String>() {
        @Override
        public void onResponse(String response) {
            JSONObject jsonObject = null;
            try {
                jsonObject = new JSONObject(response);
                String data = jsonObject.getString("patientsfordoctor");
                mPatientsForDoctor = new Gson().fromJson(data, PatientsForDoctor.class);
                mPatientList = new ArrayList<>();

                mPatientList.addAll(mPatientsForDoctor.getPatientList());

            } catch (JSONException e) {
                e.printStackTrace();
            }

        }
    }, new Response.ErrorListener() {
        @Override
        public void onErrorResponse(VolleyError error) {

        }
    }) {

        @Override
        protected Map<String, String> getParams() throws AuthFailureError {
            return super.getParams();
        }

        @Override
        public String getBodyContentType() {
            return super.getBodyContentType();
        }

        @Override
        public Map<String, String> getHeaders() throws AuthFailureError {
            return new HashMap<>();
        }
    };
    stringRequest.setRetryPolicy(new DefaultRetryPolicy(DefaultRetryPolicy.DEFAULT_TIMEOUT_MS,
            DefaultRetryPolicy.DEFAULT_MAX_RETRIES,
            DefaultRetryPolicy.DEFAULT_BACKOFF_MULT));
    Volley.newRequestQueue(mContext).add(stringRequest);
}

void getContextInstance(Context context) {
    mContext = context;
}

public abstract List<FilterPatientList> convertToItems(List<FilterPatientList> result, int size);
}

My Adapter class

    package com.example.athansys.mypagingapplication;
import android.arch.paging.PagedListAdapter;
import android.support.annotation.NonNull;
import android.support.v7.util.DiffUtil;
import android.support.v7.widget.RecyclerView;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;

public class MyPatientAdapter extends PagedListAdapter<FilterPatientList, MyPatientAdapter.PatientViewHolder> {

protected MyPatientAdapter() {
    super(FilterPatientList.DIFF_CALLBACK);
}

@NonNull
@Override
public PatientViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
    return null;
}

@Override
public void onBindViewHolder(@NonNull PatientViewHolder holder, int position) {

}


class PatientViewHolder extends RecyclerView.ViewHolder {
    TextView patientName, patientPhoneNumber, genderAge;

    PatientViewHolder(View itemView) {
        super(itemView);
    }
}
}

My POJO(MODEL CLASSES ARE AS FOLLOWS)

FilterPatientList class:

    package com.example.athansys.mypagingapplication;
import android.os.Parcel;
import android.os.Parcelable;
import android.support.v7.util.DiffUtil;

import com.google.gson.annotations.SerializedName;

public class FilterPatientList implements Parcelable {

private long patientId;

private Patient patientDetails;

protected FilterPatientList(Parcel in) {
    patientId = in.readLong();
    patientDetails = in.readParcelable(Patient.class.getClassLoader());
}

public static final Creator<FilterPatientList> CREATOR = new Creator<FilterPatientList>() {
    @Override
    public FilterPatientList createFromParcel(Parcel in) {
        return new FilterPatientList(in);
    }

    @Override
    public FilterPatientList[] newArray(int size) {
        return new FilterPatientList[size];
    }
};

public long getPatientId() {
    return patientId;
}

public void setPatientId(long patientId) {
    this.patientId = patientId;
}

public Patient getPatientDetails() {
    return patientDetails;
}

public void setPatientDetails(Patient patientDetails) {
    this.patientDetails = patientDetails;
}


@Override
public int describeContents() {
    return 0;
}

@Override
public void writeToParcel(Parcel dest, int flags) {
    dest.writeLong(patientId);
    dest.writeParcelable(patientDetails, flags);
}

public static final DiffUtil.ItemCallback<FilterPatientList> DIFF_CALLBACK = new DiffUtil.ItemCallback<FilterPatientList>() {
    @Override
    public boolean areItemsTheSame(FilterPatientList oldItem, FilterPatientList newItem) {
        return false;
    }

    @Override
    public boolean areContentsTheSame(FilterPatientList oldItem, FilterPatientList newItem) {
        return false;
    }
};
}

PATIENT CLASS:

   package com.example.athansys.mypagingapplication;
import android.os.Parcel;
import android.os.Parcelable;

import com.google.gson.annotations.SerializedName;

public class Patient implements Parcelable{

private long localPatientId;


private long apptDoctorId;

private long patientId;
private boolean isLocalPatient;

private String firstName;
private String lastName;
private String phoneNumber;
private String email;
private String dob;
private int age;
private int height;
private int weight;
private String patientSex;
private String patientSystemRegistrationDate;
private int bloodGroup;


protected Patient(Parcel in) {
    localPatientId = in.readLong();
    apptDoctorId = in.readLong();
    patientId = in.readLong();
    isLocalPatient = in.readByte() != 0;
    firstName = in.readString();
    lastName = in.readString();
    phoneNumber = in.readString();
    email = in.readString();
    dob = in.readString();
    age = in.readInt();
    height = in.readInt();
    weight = in.readInt();
    patientSex = in.readString();
    patientSystemRegistrationDate = in.readString();
    bloodGroup = in.readInt();
}

public static final Creator<Patient> CREATOR = new Creator<Patient>() {
    @Override
    public Patient createFromParcel(Parcel in) {
        return new Patient(in);
    }

    @Override
    public Patient[] newArray(int size) {
        return new Patient[size];
    }
};

public long getLocalPatientId() {
    return localPatientId;
}

public void setLocalPatientId(long localPatientId) {
    this.localPatientId = localPatientId;
}

public long getApptDoctorId() {
    return apptDoctorId;
}

public void setApptDoctorId(long apptDoctorId) {
    this.apptDoctorId = apptDoctorId;
}

public long getPatientId() {
    return patientId;
}

public void setPatientId(long patientId) {
    this.patientId = patientId;
}

public boolean isLocalPatient() {
    return isLocalPatient;
}

public void setLocalPatient(boolean localPatient) {
    isLocalPatient = localPatient;
}

public String getFirstName() {
    return firstName;
}

public void setFirstName(String firstName) {
    this.firstName = firstName;
}

public String getLastName() {
    return lastName;
}

public void setLastName(String lastName) {
    this.lastName = lastName;
}

public String getPhoneNumber() {
    return phoneNumber;
}

public void setPhoneNumber(String phoneNumber) {
    this.phoneNumber = phoneNumber;
}

public String getEmail() {
    return email;
}

public void setEmail(String email) {
    this.email = email;
}

public String getDob() {
    return dob;
}

public void setDob(String dob) {
    this.dob = dob;
}

public int getAge() {
    return age;
}

public void setAge(int age) {
    this.age = age;
}

public int getHeight() {
    return height;
}

public void setHeight(int height) {
    this.height = height;
}

public int getWeight() {
    return weight;
}

public void setWeight(int weight) {
    this.weight = weight;
}

public String getPatientSex() {
    return patientSex;
}

public void setPatientSex(String patientSex) {
    this.patientSex = patientSex;
}

public String getPatientSystemRegistrationDate() {
    return patientSystemRegistrationDate;
}

public void setPatientSystemRegistrationDate(String patientSystemRegistrationDate) {
    this.patientSystemRegistrationDate = patientSystemRegistrationDate;
}

public int getBloodGroup() {
    return bloodGroup;
}

public void setBloodGroup(int bloodGroup) {
    this.bloodGroup = bloodGroup;
}

@Override
public int describeContents() {
    return 0;
}

@Override
public void writeToParcel(Parcel dest, int flags) {
    dest.writeLong(localPatientId);
    dest.writeLong(apptDoctorId);
    dest.writeLong(patientId);
    dest.writeByte((byte) (isLocalPatient ? 1 : 0));
    dest.writeString(firstName);
    dest.writeString(lastName);
    dest.writeString(phoneNumber);
    dest.writeString(email);
    dest.writeString(dob);
    dest.writeInt(age);
    dest.writeInt(height);
    dest.writeInt(weight);
    dest.writeString(patientSex);
    dest.writeString(patientSystemRegistrationDate);
    dest.writeInt(bloodGroup);
}
}

When I receive data from network in Data source class(MyPatientData) the call automatically goes to observer in main activity. There the list size shown is zero whereas the list when fetched from network had a size of 10 items.

Can you please help me out. I am really stuck for days with no clue what to do next. Thanks a lot in advance. :)

like image 239
Matrix Avatar asked Jul 23 '18 10:07

Matrix


3 Answers

You can implement BoundaryCallback in LivePagedListBuilder. It contains method onZeroItemsLoaded.

listLiveData = new LivePagedListBuilder<>
                (new MyPatientPagedListProvider(context)
                        .getAll()
                        , pagedListConfig)
                        .setBoundaryCallback(new PagedList.BoundaryCallback() {
                    @Override
                    public void onZeroItemsLoaded() {
                        super.onZeroItemsLoaded();
 // do smth here. For example, post boolean value to MutableLiveData to notify activity //that result is empty
                    }
                })
                .build();
like image 131
Mike Makhovyk Avatar answered Oct 11 '22 19:10

Mike Makhovyk


To get the size of the item inserted or size of that RecyclerView, we need to register an AdapterDataObserver to our RecyclerView.

1) Create an AdapterDataObserver and override the functions you want.

public class SearchListAdapterDataObserver extends RecyclerView.AdapterDataObserver {

    private RecyclerView mRecyclerView;
    private ChangeListener mChangeListener;

    public SearchListAdapterDataObserver(RecyclerView view, ChangeListener changeListener){
        this.mRecyclerView = view;
        this.mChangeListener = changeListener;
    }

    @Override
    public void onChanged() {
        super.onChanged();
        sendItemCount();
    }

    private void sendItemCount() {
        if(mRecyclerView.getAdapter() != null) {
            mChangeListener.onChanged(getSize());
        }
    }

    @Override
    public void onItemRangeInserted(int positionStart, int itemCount) {
        super.onItemRangeInserted(positionStart, itemCount);
        sendItemCount();
    }

    @Override
    public void onItemRangeChanged(int positionStart, int itemCount) {
        super.onItemRangeChanged(positionStart, itemCount);
        sendItemCount();
    }

    @Override
    public void onItemRangeRemoved(int positionStart, int itemCount) {
        super.onItemRangeRemoved(positionStart, itemCount);
        sendItemCount();
    }

    public int getSize() {
        if(mRecyclerView.getAdapter() != null) {
            return mRecyclerView.getAdapter().getItemCount();
        }
        return 0;
    }

    public interface ChangeListener {
        void onChanged(int size);
    }
}

2) Register it to your adapter and listen to the changes.

if(mViewModel.getSearchPaginatedAdapter() != null){
        mViewModel.getSearchPaginatedAdapter().registerAdapterDataObserver
                (new SearchListAdapterDataObserver(mRecyclerView, new SearchListAdapterDataObserver.ChangeListener() {
            @Override
            public void onChanged(int size) {
                onListChanges(size);
            }
        }));
    }
like image 39
SureshCS50 Avatar answered Oct 11 '22 19:10

SureshCS50


Here is the simple solution of pagination .

First time private void jsonRequestList(int pageCount) { will called with pageCount=1 and next time increment with 2,3,4...

Inside private void jsonRequestList(int pageCount) {method (JSON REQUEST) first time if (!isScrollCalled) { will called & next time else block will called.

Activity/Fragment :

     private boolean loading = false;
     private boolean isScrollCalled;
     int isLastPage = 10;
     int pageCount = 1;

     //Paigination
        recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
            @Override
            public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
                super.onScrollStateChanged(recyclerView, newState);

                int lastvisibleitemposition = linearLayoutManager.findLastVisibleItemPosition();

                if (lastvisibleitemposition == adapter.getItemCount() - 1) {

                    if (!loading && pageCount != isLastPage) {
                        loading = true;
                        jsonRequestList(++pageCount);
                        isScrollCalled = Boolean.TRUE;
                    }


                }
            }
        });


 private void jsonRequestList(int pageCount) {
  //Json Request

  if (!isScrollCalled) {
          adapter = new FlowerListAdapter(FlowerListActivity.this, list);
          recyclerView.setAdapter(adapter);
          adapter.notifyDataSetChanged();
               //  Log.e("LIST_SIZE", "" + list.size());
          } else {
          adapter.updateList(list);
          //Log.e("LIST_SIZE", "" + list.size());

        }

       loading = false;
}

Recycler Adapter :

 ArrayList<YourModelClass> list;
 Context context;

 //Pagination
public void updateList(ArrayList<YourModelClass> list) {
    this.list.addAll(list);
    this.notifyDataSetChanged();
}
like image 39
Abhishek kumar Avatar answered Oct 11 '22 19:10

Abhishek kumar