Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

fetch only 20 rows from server with setOnScrollListener

Tags:

android

Its the first time I am using onscroll listener. My problem is how to fetch 20 new rows every time I scroll down ?.

I understand when I scroll down the grid view this code will be executed.

public void onScroll(AbsListView view, int firstVisibleItem,
                             int visibleItemCount, int totalItemCount) {
            // TODO Auto-generated method stub

            this.currentFirstVisibleItem = firstVisibleItem;
            this.currentVisibleItemCount = visibleItemCount;
            this.totalItem = totalItemCount;

            if ((totalItemCount - visibleItemCount) <= (firstVisibleItem + 20)) {
               // the below when executed will get all the rows ,I only need 20 rows
             handler.execute().get();

            }
        }

this is my code

// the load more in the grid view, fetch new images.
mGridView.setOnScrollListener(new AbsListView.OnScrollListener() {
    private int currentVisibleItemCount;
    private int currentScrollState;
    private int currentFirstVisibleItem;
    private int totalItem;
    private LinearLayout lBelow;

    @Override
    public void onScrollStateChanged(AbsListView view, int scrollState) {
        // TODO Auto-generated method stub
        this.currentScrollState = scrollState;
        this.isScrollCompleted();
    }

    @Override
    public void onScroll(AbsListView view, int firstVisibleItem,
                         int visibleItemCount, int totalItemCount) {
        // TODO Auto-generated method stub

        this.currentFirstVisibleItem = firstVisibleItem;
        this.currentVisibleItemCount = visibleItemCount;
        this.totalItem = totalItemCount;

        if ((totalItemCount - visibleItemCount) <= (firstVisibleItem + 20)) {
           // load new 20 row but how to do that

        }
    }

    private void isScrollCompleted() {
        if (totalItem - currentFirstVisibleItem == currentVisibleItemCount
                && this.currentScrollState == SCROLL_STATE_IDLE) {
            Log.d("a", "poooppii");

        }
    }

    ;
});

this is where the connection happens

 protected void showList(){
        try {

            JSONObject jsonObj = new JSONObject(myJSON);
            peoples = jsonObj.getJSONArray("result");
            System.out.println("Length:"+peoples.length());
            int J_length=peoples.length()-1;


            jsonObj= peoples.getJSONObject(J_length);


                Listitem = new ArrayList<Listitem>();

                for (int i = 0; i < peoples.length(); i++) {
                    JSONObject c = peoples.getJSONObject(i);

                    String id = c.getString("id");
                    String url = c.getString("url");

                    int intid = 0;
                    try {
                        intid = Integer.parseInt(id.toString());
                    } catch (NumberFormatException nfe) {
                        System.out.println("Could not parse " + nfe);
                    }

                    Listitem.add(new Listitem(id, url));
                    System.out.println(Listitem);
                }
            //}
            if (mListener != null)
                  mListener.myMethod(Listitem);


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

    }
like image 950
Moudiz Avatar asked Jun 18 '16 16:06

Moudiz


2 Answers

You need to maintain base and limit for data load. Initialize your base and limit variable.

int base = 0, limit = 20;

Increase your base variable whenever loading new items.

base = base + limit;
handler.execute().get();

Pass base and limit variable in your API call, so that you can use it in query from API side.

Note : base is a value from which position you need to start fetching values. limit is a value for how many rows you need to fetch.

Refer this for limit query in sqlite.
Refer this for limit query in MySql.
Refer this for limit query in SQL.

like image 146
Ravi Avatar answered Oct 04 '22 12:10

Ravi


Here is an working code, Kindly modify as per your use -

Let assume following is your model -

public class MyModel {
    String name;
}

You need one interface -

public interface PagingListener<T> {
    void onItemUpdate(ArrayList<T> allData);
}

Design your adapter like this -

public class CouponsAdapter extends RecyclerView.Adapter<CouponsAdapter.CouponHolder> implements View.OnClickListener, PagingListener<MyModel> {
    private final static int TYPE_LOADING = 0;
    private final static int TYPE_DATA = 1;
    private FragmentActivity activity;
    private LayoutInflater inflater;
    private PagingRequestHandler<MyModel> pagingRequestHandler;
    private ArrayList<MyModel> data = null;

    public CouponsAdapter(FragmentActivity activity) {
        this.activity = activity;
        inflater = LayoutInflater.from(activity);
        this.data = new ArrayList<>();
        this.pagingRequestHandler = new PagingRequestHandler<>(data, this);
    }

    @Override
    public int getItemViewType(int position) {
        return position >= data.size() ? TYPE_LOADING : TYPE_DATA;
    }

    @Override
    public CouponHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        View view;
        if (viewType == TYPE_DATA) {
            view = inflater.inflate(R.layout.item_coupons_card_block, parent, false);
        } else {
            view = inflater.inflate(R.layout.item_drawer_payment_loading, parent, false);
        }
        return new CouponHolder(view, viewType);
    }

    @Override
    public void onBindViewHolder(CouponHolder holder, int position) {
        if (getItemViewType(position) == TYPE_DATA) {
            //Bind your view here
        }
        pagingRequestHandler.checkAndMakeRequestForMoreData(position); //Will check and make request
    }

    @Override
    public int getItemCount() {
        return data.size() + (pagingRequestHandler.isNoMoreDataLeft() ? 0 : 1); // If no data then it will return 1 to show loading
    }

    @Override
    public void onClick(View v) {
    }

    @Override
    public void onItemUpdate(ArrayList<MyModel> allData) {
        this.data = allData; // will update data with updated content
        notifyDataSetChanged();

    }


    public class CouponHolder extends RecyclerView.ViewHolder {
        public CouponHolder(View itemView, int itemType) {
            super(itemView);
            if (itemType == TYPE_DATA) {
            }
        }
    }
}

And now this is the paging request handler, that will keep track on page number and will make request for next page -

public class PagingRequestHandler<T> {
    public static final int PAGE_SIZE = 10;
    private final PagingListener listener;
    private final ArrayList<MyModel> arrayList;
    private final String url = "Your Url here";
    private boolean noMoreDataLeft;
    private int pagingIndex = 0;
    private boolean requestGoingOn;


    public PagingRequestHandler(ArrayList<MyModel> data, PagingListener<MyModel> listener) {
        this.listener = listener;
        this.arrayList = data;
        fetchMoreData();

    }

    private void fetchMoreData() {
        requestGoingOn = true;
        Call<MyModel[]> getCoupons = Utils.getRetrofit().getCoupons(url + "/" + pagingIndex); // I am using retrofit for network call, you can use your own
        getCoupons.enqueue(new Callback<MyModel[]>() {
            @Override
            public void onResponse(Response<MyModel[]> response, Retrofit retrofit) {
                try {
                    requestGoingOn = false;
                    MyModel[] couponModelDses = response.body();
                    if (couponModelDses != null) {
                        for (MyModel couponModelDse : couponModelDses) {
                            arrayList.add(couponModelDse);
                        }
                        if (couponModelDses.length < PAGE_SIZE)
                            noMoreDataLeft = true;
                        listener.onItemUpdate(arrayList);
                    }
                } catch (Exception e) {
                    e.printStackTrace();

                }
            }

            @Override
            public void onFailure(Throwable t) {
                requestGoingOn = false;
            }
        });
    }

    public boolean isNoMoreDataLeft() {
        return noMoreDataLeft;
    }

    public void checkAndMakeRequestForMoreData(int position) {
        if (!noMoreDataLeft && !requestGoingOn && position > (PAGE_SIZE * pagingIndex)) {
            if ((position % PAGE_SIZE) > (int) (PAGE_SIZE * .7)) {
                pagingIndex++;
                fetchMoreData();
            }
        }
    }
}

How it works - The adapter is initialising the Handler, which make network call for first time. The adapter now calls handler api to check if 70% of page is scrolled on every onBind. Now if 70% of data has been shown then it makes network call againe and makes a variable called requestGoingOn true, so you can show a loader in list. Wher request completed the handler is adding data to the arraylist and updating adapter by calling the callback onItemUpdate.

Hope it will help, please let me know if you need further assistance :)

like image 31
Neo Avatar answered Oct 04 '22 11:10

Neo