How to implement infinite scrolling in recyclerview

3

I have a recycler and inside that recycler cardviews are shown with info brought from a REST API and I would like to implement this feature in my application but I do not know how to do it, I have seen several examples online but I can not grasp what is going on in the adapter and what is in the main, if you could guide me or show me an easy example I would appreciate it very much

Adapter

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

    private ArrayList<Business> basicsList;

    Bitmap bitmap;
    private Context mContext;
    int idb;
    private Activity activity;
    private int layoutMolde;


    public SearchAdapter(Activity activity, ArrayList<Business> list, int layout ) {

        this.activity = activity;
        this.basicsList = list;
        layoutMolde = layout;
    }

    @Override
    public SearchAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.search_row, parent, false);
        return new ViewHolder(view);
    }

    @Override
    public void onBindViewHolder(ViewHolder holder, int position) {
        // holder.mTitle.setText(premiumsList.get(position));
        holder.mTitle.setText(basicsList.get(position).getName());

        //holder.mImg.setImageURI(Uri.parse(premiumsList.get(position).getLogo_url_string()));
        idb = basicsList.get(position).getId();

        if (basicsList.get(position).getRating()==null){
            holder.txtsearch.setText(0);

        }else {
            holder.txtsearch.setText(basicsList.get(position).getRating());
        }


        if(basicsList.get(position).getLogo_url_string()!=null){
            Glide.with(activity).load(basicsList.get(position).getLogo_url_string()).into(holder.mImg);
            Log.d("",String.valueOf(basicsList.get(position).getIcon_default()));
        }
        else{
            Glide.with(activity).load(basicsList.get(position).getIcon_default()).into(holder.mImg);
        }


    }


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



    public class ViewHolder extends RecyclerView.ViewHolder {

        public TextView mTitle;
        public ImageView mImg;
        public ImageView logo;
        public RatingBar rating_basic;
        public TextView txtsearch;
        public ViewHolder(View itemView) {
            super(itemView);
            mTitle = (TextView) itemView.findViewById(R.id.nom_search);
            mImg = (ImageView) itemView.findViewById(R.id.img_search);

            txtsearch=(TextView) itemView.findViewById(R.id.txtsearch_rating);
            rating_basic=(RatingBar) itemView.findViewById(R.id.rating_search);

            itemView.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {

                    Intent in = new Intent(v.getContext(), BusinessPremium.class);
                    int position = getAdapterPosition();
                    idb = basicsList.get(position).getId();
                    in.putExtra("no", idb);
                    v.getContext().startActivity(in);
                }
            });
        }
    }
}

Fragment

public class SearchFragment extends Fragment
{
    private ArrayList<Business> arrayBusiness,arrayBasics;

    private Gson gson;

    private static final Type BUSINESS_TYPE = new TypeToken<ArrayList<Business>>() {}.getType();
    private TextView textView;

    private RecyclerView.LayoutManager mLayoutManager;
    private RecyclerView.LayoutManager mLowerLayoutManager;

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
    {
        View android = inflater.inflate(R.layout.search_activity, container, false);
        textView = (TextView) android.findViewById(R.id.textView);
        Toolbar toolbar = (Toolbar) android.findViewById(R.id.toolbar);
        ((AppCompatActivity)getActivity()).setSupportActionBar(toolbar);
        setHasOptionsMenu(true);

        if (!internetConnectionCheck(SearchFragment.this.getActivity()))
        {
            Toast.makeText(getApplicationContext(), "Error de Conexión", Toast.LENGTH_LONG).show();
        }

        new PlifRequestBase(getActivity())
        {
            @Override

            public JsonObject onHttpOk(JsonObject response) throws JSONException
            {

                JsonObject data, pagination_details = null, businesses, cover_premium, cv, iurl;

                JsonArray premiums, basics;
                String url_img;

                if (response.get("pagination") == null)
                {

                    data =  response;
                }else {
                    pagination_details = response.get("pagination").getAsJsonObject();
                    data = response.get("data").getAsJsonObject();

                    businesses = data.get("businesses").getAsJsonObject();
                    premiums = businesses.get("premiums").getAsJsonArray();

                    //images_premiums=data.get("category_image").getAsJsonObject();

                    basics = businesses.get("basics").getAsJsonArray();

                    gson = new Gson();
                    arrayBusiness = new ArrayList<Business>();
                    arrayBasics= new ArrayList<Business>();

                    arrayBusiness = gson.fromJson(premiums, BUSINESS_TYPE);
                    arrayBasics=gson.fromJson(basics, BUSINESS_TYPE);
                    Log.d("size", String.valueOf(arrayBusiness.size()));
                    //Log.d("", String.valueOf(images_premiums));
                        if (getActivity() == null)
                        return response;
                    SearchFragment.this.getActivity().runOnUiThread(new Runnable()
                    {
                        @Override
                        public void run() {
                            RecyclerView recycler = (RecyclerView) SearchFragment.this.getActivity().findViewById(R.id.high_recycler_view);
                            SearchAdapter adapter = new SearchAdapter(getActivity(), arrayBusiness, R.layout.search_low_layout);
                            recycler.setNestedScrollingEnabled(false);
                            mLayoutManager = new GridLayoutManager(SearchFragment.this.getActivity(),2);
                            recycler.setLayoutManager(mLayoutManager);
                            recycler.setAdapter(adapter);

                            for (int i = 0; i < arrayBusiness.size(); i++)
                            {
                                Log.d("Imprime", arrayBusiness.get(i).getName());
                            }

                            GifTextView loading = (GifTextView)SearchFragment.this.getActivity().findViewById(R.id.loadingSearch);
                            TextView loadingText = (TextView)SearchFragment.this.getActivity().findViewById(R.id.loadingTextSearch);
                            loading.setVisibility(View.GONE);
                            loadingText.setVisibility(View.GONE);
                        }
                    });

                }
                if (pagination_details.isJsonNull())
                {
                    Log.d("Paginacion", pagination_details.toString());
                }
                return data;
            }
            @Override
            public void onHttpCreate(JsonObject response) throws JSONException
            {

            }

            @Override
            public void onHttpUnprocessableEntity(JsonObject response) throws JSONException {
                this.cancel(true);
                final String error = response.get("errors").toString();
                getActivity().runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        Toast.makeText(getActivity().getApplicationContext(), error, Toast.LENGTH_LONG).show();
                    }
                });
            }
        }.execute("businesses/search", "GET");
        return android;
    }

    @Override
    public void onPrepareOptionsMenu(Menu menu)
    {
        // MenuItem mSearchMenuItem = menu.findItem(R.id.action_search);

        final MenuItem mSearchMenuItem = menu.findItem(R.id.action_search);
        final SearchView searchView = (SearchView) mSearchMenuItem.getActionView();
        //final SearchView searchView = (SearchView) MenuItemCompat.getActionView(searchItem);
        searchView.setQueryHint(getText(R.string.search));
        searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener()
        {
            @Override
            public boolean onQueryTextSubmit(final String query)
            {
                //Toast.makeText(SearchFragment.this.getActivity(), R.string.buscado, Toast.LENGTH_SHORT).show();
                searchView.setQuery("", false);
                searchView.setIconified(true);
                new PlifRequestBase(getActivity()){
                    @Override
                    public JsonObject onHttpOk(JsonObject response) throws JSONException
                    {
                        JsonObject data, pagination_details = null, businesses, cover_premium, cv, iurl;
                        JsonArray premiums, basics;
                        if (response.get("pagination") == null)
                        {
                            data =  response;
                        }else {
                            pagination_details = response.get("pagination").getAsJsonObject();
                            data = response.get("data").getAsJsonObject();

                            businesses = data.get("businesses").getAsJsonObject();
                            premiums = businesses.get("premiums").getAsJsonArray();
                            basics = businesses.get("basics").getAsJsonArray();

                            gson = new Gson();
                            arrayBusiness = new ArrayList<Business>();
                            arrayBasics= new ArrayList<Business>();

                            arrayBusiness = gson.fromJson(premiums, BUSINESS_TYPE);
                            arrayBasics=gson.fromJson(basics, BUSINESS_TYPE);
                            Log.d("size", String.valueOf(arrayBusiness.size()));
                            //Log.d("", String.valueOf(images_premiums));

                            SearchFragment.this.getActivity().runOnUiThread(new Runnable()
                            {
                                @Override
                                public void run() {

                                    RecyclerView recycler = (RecyclerView) SearchFragment.this.getActivity().findViewById(R.id.high_recycler_view);
                                    RecyclerView recyclerbasics=(RecyclerView) SearchFragment.this.getActivity().findViewById(R.id.lower_recycler_view);

                                    SearchHorizontalAdapter adapter = new SearchHorizontalAdapter(getActivity(), arrayBusiness, R.layout.search_high_layout);
                                    SearchVerticalAdapter adapterbasics=new SearchVerticalAdapter(getActivity(),arrayBasics,R.layout.search_low_layout);

                                    recyclerbasics.setNestedScrollingEnabled(false);
                                    recycler.setNestedScrollingEnabled(false);

                                    mLowerLayoutManager = new GridLayoutManager(SearchFragment.this.getActivity(),2);
                                    recyclerbasics.setLayoutManager(mLowerLayoutManager);
                                    recyclerbasics.setAdapter(adapterbasics);

                                    mLayoutManager = new LinearLayoutManager(SearchFragment.this.getActivity(), LinearLayoutManager.HORIZONTAL, false);
                                    recycler.setLayoutManager(mLayoutManager);
                                    recycler.setAdapter(adapter);

                                    for (int i = 0; i < arrayBusiness.size(); i++)
                                    {
                                        Log.d("Imprime", arrayBusiness.get(i).getName());
                                    }
                                    for (int i = 0; i < arrayBasics.size(); i++)
                                    {
                                        Log.d("Imprime", arrayBasics.get(i).getName());
                                    }
                                    GifTextView loading = (GifTextView)SearchFragment.this.getActivity().findViewById(R.id.loadingSearch);
                                    TextView loadingText = (TextView)SearchFragment.this.getActivity().findViewById(R.id.loadingTextSearch);
                                    loading.setVisibility(View.GONE);
                                    loadingText.setVisibility(View.GONE);

                                }
                            });
                        }
                        if (pagination_details.isJsonNull()){
                            Log.d("Paginacion", pagination_details.toString());
                        }
                        return data;
                    }
                    @Override
                    public void onHttpCreate(JsonObject response) throws JSONException
                    {

                    }

                    @Override
                    public void onHttpUnprocessableEntity(JsonObject response) throws JSONException {
                        this.cancel(true);
                        final String error = response.get("errors").toString();
                        getActivity().runOnUiThread(new Runnable() {
                            @Override
                            public void run() {
                                Toast.makeText(getActivity().getApplicationContext(), error, Toast.LENGTH_LONG).show();
                            }
                        });
                    }
                }.execute("businesses/search", "GET", "q", "\'"+query+"\'");

                return true;
            }

            @Override
            public boolean onQueryTextChange(String newText) {
                textView.setText(newText);
                return true;
            }
        });

        View searchPlate = (View) searchView.findViewById(android.support.v7.appcompat.R.id.search_plate);
        searchPlate.setBackgroundResource(R.mipmap.textfield_custom);

        //return super.onCreateOptionsMenu(menu);
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        switch (item.getItemId()) {
            case R.id.action_settings:
                action(R.string.action_settings);
                return true;

            default:
                return super.onOptionsItemSelected(item);
        }
    }

    private void action(int resid) {
        Toast.makeText(this.getActivity(), getText(resid), Toast.LENGTH_SHORT).show();
    }
    public static boolean internetConnectionCheck(Activity CurrentActivity) {
        Boolean Connected = false;
        ConnectivityManager connectivity = (ConnectivityManager) CurrentActivity.getApplicationContext()
                .getSystemService(Context.CONNECTIVITY_SERVICE);
        if (connectivity != null) {
            NetworkInfo[] info = connectivity.getAllNetworkInfo();
            if (info != null) for (int i = 0; i < info.length; i++)
                if (info[i].getState() == NetworkInfo.State.CONNECTED) {
                    Log.e("My Network is: ", "Connected");
                    Connected = true;
                } else {}
        } else {
            Log.e("My Network is: ", "Not Connected");

            Toast.makeText(CurrentActivity.getApplicationContext(),
                    "Please Check Your internet connection",
                    Toast.LENGTH_LONG).show();
            Connected = false;

        }
        return Connected;
    }
}
    
asked by Heber Solis 22.03.2017 в 19:49
source

1 answer

1

You can get it in different ways, then I'll show you how I got it.

In your Activity or Fragment layout xml we are going to add a SwipeToRefreshLayout to be able to refresh the data:

    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto">


        <android.support.v4.widget.SwipeRefreshLayout
            android:id="@+id/swipe_refresh_layout"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            >

            <android.support.v7.widget.RecyclerView
                android:id="@+id/my_recycler_view"
                android:scrollbars="vertical"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:layout_marginTop="6dp" />


        </android.support.v4.widget.SwipeRefreshLayout>

        <ProgressBar
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:id="@+id/progressBar"
            android:indeterminate="true"
            android:layout_gravity="center_horizontal"
            android:padding="6dp"
            android:visibility="gone"
            android:layout_centerVertical="true"
            android:layout_centerHorizontal="true" />



    </RelativeLayout>

Declare the following variables in your Fragment or Activity:

private final int VISIBLE_THRESHOLD = 5; // Numero de celdas restantes antes de realizar una nueva petición
private int firstVisibleItem, visibleItemCount, totalItemCount, previousTotal = 0;
private boolean loading = false;

private int offset = 0; //Numero de items cargados
private int limit = 15; //Numero de items por petición

private RecyclerView mRecyclerView;
private LinearLayoutManager mLayoutManager;
private MySuperAdapter mAdapter;

In your onCreate () or onCreateView () method:

mSwipeRefreshLayout = (SwipeRefreshLayout) view.findViewById(R.id.swipe_refresh_layout);

mRecyclerView = (RecyclerView)view.findViewById(R.id.my_recycler_view);
mLayoutManager = new LinearLayoutManager(activity);
mRecyclerView.setLayoutManager(mLayoutManager);

adapter = new MySuperAdapter(context);//Con los params que necesitemos

mRecyclerView.setAdapter(adapter);

mSwipeRefreshLayout.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {


            @Override
            public void onRefresh() {

                    offset = 0;
                     obtenerItemsDelServidor(url,limit,offset,true);

            }

        });

        mRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
            @Override
            public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
                totalItemCount = mLayoutManager.getItemCount();
                visibleItemCount = mLayoutManager.getChildCount();
                firstVisibleItem = mLayoutManager.findFirstVisibleItemPosition();

                if (loading) {
                    if (totalItemCount > previousTotal) {

                        previousTotal = totalItemCount;
                    }
                }
                if (!loading && (totalItemCount - visibleItemCount) <= (firstVisibleItem + VISIBLE_THRESHOLD)) {


                    // Hemos llegado al final
                    if(adapter.getItemCount()>1) {
                        offset = offset + limit;
                         obtenerItemsDelServidor(url,limit,offset,false);
                    }

                }
            }
        });

// Obtiene datos y actualiza adapter
obtenerItemsDelServidor(url,limit,offset,true);

Next we must create the function to consult our data source:

public void obtenerItemsDelServidor(String url, int limit, int offset,boolean peticionInicial){

//Antes de realizar petición (onPreExecute si utilizamos AsynkTask)

 if (!peticionInicial) {
        loading = true;
        adapter.addItem(null);
        adapter.notifyDataSetChanged();
  }

  //realizamos petición en background (doInBackground si utilizamos AsynkTask)
  JSONArray responseArray = obtenerJSONServidor(url,params);


  //Recibimos respuesta JSON (onPostExecute si utilizamos AsynkTask)

  if (isPullToRefresh) {
    adapter.clear();
    adapter.notifyDataSetChanged();
  }

  if (!peticionInicial) {
      adapter.removeItem(adapter.getItemCount() - 1);
      loading = false;
   }

  for (int i = 0; i < responseArray.length(); i++) {

    JSONObject object = responseArray.getJSONObject(i);
    ListItem item = new ListItem();

    item.setUserName(object.optString("username",""));

    adapter.addItem(item);

  }

  adapter.notifyDataSetChanged();

  if (mSwipeRefreshLayout.isRefreshing()) {
    mSwipeRefreshLayout.setRefreshing(false);
  }

}

Finally we have to configure our adapter.

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

ArrayList<ListItem> list;
Context context;


private final int VIEW_NORMAL = 0;
private final int VIEW_PROGRESS = 1;

String username;

public MySuperAdapter(Context context) {
    this.context = context;

}

@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {


    RecyclerView.ViewHolder vh = null;
    View view;

    switch (viewType) {
        case VIEW_PROGRESS:
            view = LayoutInflater.from(parent.getContext()).inflate(R.layout.list_item_loadmore, parent, false);
            vh = new ProgressViewHolder(view);
            break;

        case VIEW_NORMAL:
            view = LayoutInflater.from(parent.getContext()).inflate(R.layout.card, parent, false);
            vh = new NormalViewHolder(view);
            break;

    }


    return vh;


}

@Override
public void onBindViewHolder(final RecyclerView.ViewHolder holder, int position) {

    final ListItem currentItem = list.get(position);

    if (holder instanceof NormalViewHolder) { 



    }  else {
        ((ProgressViewHolder) holder).progressBar.setIndeterminate(true);
    }

}


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



public class NormalViewHolder extends RecyclerView.ViewHolder {

    TextView userName;

    public NormalViewHolder(View itemView) {
        super(itemView);

        userName = (TextView) itemView.findViewById(R.id.username);

    }

}


public static class ProgressViewHolder extends RecyclerView.ViewHolder {
    public ProgressBar progressBar;

    public ProgressViewHolder(View v) {
        super(v);
        progressBar = (ProgressBar) v.findViewById(R.id.progressBar);
    }
}


public void clear() {

    list.clear();

}

public void addItem(ListItem item) {

    list.add(item);
}

public void addItemAtPosition(ListItem item, int position) {

    list.add(position, item);
}

public void removeItem(int position) {

    list.remove(position);

}

public ListItem getItemAtPosition(int position) {

    return list.get(position);

}

@Override
public int getItemViewType(int position) {

        if (list.get(position) != null) {
            return VIEW_NORMAL;
        } else {
            return VIEW_PROGRESS;
        }

}

}

Key points:

  • Before starting a request other than the initial one, we add a Progress cell in the last position of the adapter array and update with notifyDataSetChanged (). When the petition has finished we eliminated the progress view, we added the items that we returns the request and we update again with notifyDataSetChanged ().
  • The event that triggers the requests according to the scroll position in what we find is the mRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener()
answered by 23.03.2017 в 16:15