recyclerview incremental endless addonscrolllistener java android-cardview android-recyclerview onscrolllistener endlessscroll

java - incremental - load recyclerview android



Cómo implementar setOnScrollListener en RecyclerView (5)

¿Cómo muestro la barra de progreso en la parte inferior cuando el usuario llegó a los elementos que están visibles en una lista?

He escrito un código en el que obtengo datos usando el servicio web, ahora me gustaría rellenar registros parciales, porque tengo alrededor de 630 registros en mi JSON.

Aquí está mi código completo que estoy usando para obtener datos de JSON y rellenar en RecyclerView.

Aquí es cómo se ve mi JSON, pero el JSON real contiene más de 600 registros:

http://walldroidhd.com/api.php

¿Alguien me puede guiar donde tengo que hacer cambios en mi código?

Quiero rellenar más registros cada vez que el usuario se desplace hacia abajo con la barra de progreso, todavía estoy mostrando todos los registros.

RecyclerViewFragment.java:

public class RecyclerViewFragment extends Fragment { RecyclerView mRecyclerView; LinearLayoutManager mLayoutManager; RecyclerView.Adapter mAdapter; ArrayList<NatureItem> actorsList; private int previousTotal = 0; private boolean loading = true; private int visibleThreshold = 5; int firstVisibleItem, visibleItemCount, totalItemCount; public static RecyclerViewFragment newInstance() { return new RecyclerViewFragment(); } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { return inflater.inflate(R.layout.fragment_recyclerview_advance, container, false); } @Override public void onViewCreated(View view, Bundle savedInstanceState) { super.onViewCreated(view, savedInstanceState); actorsList = new ArrayList<NatureItem>(); new JSONAsyncTask().execute("my JSON url"); mRecyclerView = (RecyclerView) view.findViewById(R.id.recycler_view); mRecyclerView.setHasFixedSize(true); mLayoutManager = new GridLayoutManager(getActivity(), 2); mRecyclerView.setLayoutManager(mLayoutManager); mRecyclerView.setOnScrollListener(new RecyclerView.OnScrollListener() { @Override public void onScrolled(RecyclerView recyclerView, int dx, int dy) { super.onScrolled(recyclerView, dx, dy); visibleItemCount = mRecyclerView.getChildCount(); totalItemCount = mLayoutManager.getItemCount(); firstVisibleItem = mLayoutManager.findFirstVisibleItemPosition(); if (loading) { if (totalItemCount > previousTotal) { loading = false; previousTotal = totalItemCount; } } if (!loading && (totalItemCount - visibleItemCount) <= (firstVisibleItem + visibleThreshold)) { // End has been reached Log.i("...", "end called"); // Do something loading = true; } } }); // mAdapter = new CardAdapter(); mAdapter = new RecyclerViewMaterialAdapter(new CardAdapter(getActivity(), actorsList), 2); mRecyclerView.setAdapter(mAdapter); MaterialViewPagerHelper.registerRecyclerView(getActivity(), mRecyclerView, null); mRecyclerView.addOnItemTouchListener( new RecyclerItemClickListener(getActivity(), new RecyclerItemClickListener.OnItemClickListener() { @Override public void onItemClick(View view, int position) { Toast.makeText(getActivity(), String.valueOf(position), Toast.LENGTH_LONG).show(); } }) ); } class JSONAsyncTask extends AsyncTask<String, Void, Boolean> { ProgressDialog dialog; @Override protected void onPreExecute() { super.onPreExecute(); dialog = new ProgressDialog(getActivity()); dialog.setMessage("Loading, please wait"); dialog.setTitle("Connecting server"); dialog.show(); dialog.setCancelable(false); } @Override protected Boolean doInBackground(String... urls) { try { //------------------>> HttpGet httppost = new HttpGet(urls[0]); HttpClient httpclient = new DefaultHttpClient(); HttpResponse response = httpclient.execute(httppost); // StatusLine stat = response.getStatusLine(); int status = response.getStatusLine().getStatusCode(); if (status == 200) { HttpEntity entity = response.getEntity(); String data = null; try { data = EntityUtils.toString(entity); } catch (IOException e) { e.printStackTrace(); } JSONObject jsono = null; try { jsono = new JSONObject(data); } catch (JSONException e) { e.printStackTrace(); } JSONArray jarray = jsono.getJSONArray("wallpapers"); for (int i = 0; i < jarray.length(); i++) { JSONObject object = jarray.getJSONObject(i); NatureItem actor = new NatureItem(); actor.setName(object.getString("id")); actor.setThumbnail(object.getString("thumb_url")); actorsList.add(actor); } return true; } //------------------>> } catch (ParseException e1) { e1.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } catch (JSONException e) { e.printStackTrace(); } return false; } protected void onPostExecute(Boolean result) { dialog.cancel(); mAdapter.notifyDataSetChanged(); if (result == false) { Toast.makeText(getActivity(), "Unable to fetch data from server", Toast.LENGTH_LONG).show(); } else { } } } }

CardAdapter.java:

public class CardAdapter extends RecyclerView.Adapter<CardAdapter.ViewHolder> { private ArrayList<NatureItem> mItems; private Context mContext; public CardAdapter(Context context, ArrayList<NatureItem> feedItemList) { this.mItems = feedItemList; this.mContext = context; } @Override public ViewHolder onCreateViewHolder(ViewGroup viewGroup, int i) { View v = LayoutInflater.from(viewGroup.getContext()) .inflate(R.layout.recycler_view_card_item, viewGroup, false); ViewHolder viewHolder = new ViewHolder(v); return viewHolder; } @Override public void onBindViewHolder(ViewHolder viewHolder, int i) { NatureItem nature = mItems.get(i); viewHolder.tvNature.setText(nature.getName()); Picasso.with(mContext).load(nature.getThumbnail()) .error(R.mipmap.ic_launcher) .placeholder(R.mipmap.ic_launcher) .into(viewHolder.imgThumbnail); } @Override public int getItemCount() { return mItems.size(); } class ViewHolder extends RecyclerView.ViewHolder{ public ImageView imgThumbnail; public TextView tvNature; public ViewHolder(View itemView) { super(itemView); imgThumbnail = (ImageView)itemView.findViewById(R.id.img_thumbnail); tvNature = (TextView)itemView.findViewById(R.id.tv_nature); } } }

Aquí es cómo he implementado Endless también, usando this :

mRecyclerView.setOnScrollListener(new EndlessRecyclerOnScrollListener(linearLayoutManager) { @Override public void onLoadMore(int current_page) { // do something... } });

Nota: Personalmente preferiría la función RecyclerView onScroll para realizar mi trabajo.


Así es como detecto si RecyclerView debería actualizarse mediante OnScrollListener , OnScrollListener un vistazo:

recyclerView.setOnScrollListener(new RecyclerView.OnScrollListener() { int ydy = 0; @Override public void onScrollStateChanged(RecyclerView recyclerView, int newState) { super.onScrollStateChanged(recyclerView, newState); } @Override public void onScrolled(RecyclerView recyclerView, int dx, int dy) { super.onScrolled(recyclerView, dx, dy); int offset = dy - ydy; ydy = dy; boolean shouldRefresh = (linearLayoutManager.findFirstCompletelyVisibleItemPosition() == 0) && (recyclerView.getScrollState() == RecyclerView.SCROLL_STATE_DRAGGING) && offset > 30; if (shouldRefresh) { //swipeRefreshLayout.setRefreshing(true); //Refresh to load data here. return; } boolean shouldPullUpRefresh = linearLayoutManager.findLastCompletelyVisibleItemPosition() == linearLayoutManager.getChildCount() - 1 && recyclerView.getScrollState() == RecyclerView.SCROLL_STATE_DRAGGING && offset < -30; if (shouldPullUpRefresh) { //swipeRefreshLayout.setRefreshing(true); //refresh to load data here. return; } swipeRefreshLayout.setRefreshing(false); } });

Espero que estés inspirado. Buena suerte ~


Clase de actividad con recylcerview en archivo de diseño xml

public class WallpaperActivity extends AppCompatActivity implements OnTaskCompleted { private static final String TAG = "WallpaperActivity"; private Toolbar toolbar; private RecyclerView mRecyclerView; private WallPaperDataAdapter mAdapter; private LinearLayoutManager mLayoutManager; // to keep track which pages loaded and next pages to load public static int pageNumber; private List<WallPaper> wallpaperImagesList; protected Handler handler; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.wallpaper_main); toolbar = (Toolbar) findViewById(R.id.toolbar); mRecyclerView = (RecyclerView) findViewById(R.id.my_recycler_view); pageNumber = 1; wallpaperImagesList = new ArrayList<WallPaper>(); handler = new Handler(); if (toolbar != null) { setSupportActionBar(toolbar); getSupportActionBar().setTitle("WallPapers"); } // use this setting to improve performance if you know that changes // in content do not change the layout size of the RecyclerView mRecyclerView.setHasFixedSize(true); mLayoutManager = new LinearLayoutManager(this); // use a linear layout manager mRecyclerView.setLayoutManager(mLayoutManager); // create an Object for Adapter mAdapter = new WallPaperDataAdapter(wallpaperImagesList, mRecyclerView); // set the adapter object to the Recyclerview mRecyclerView.setAdapter(mAdapter); getWebServiceData(); mAdapter.setOnLoadMoreListener(new OnLoadMoreListener() { @Override public void onLoadMore() { //add null , so the adapter will check view_type and show progress bar at bottom wallpaperImagesList.add(null); mAdapter.notifyItemInserted(wallpaperImagesList.size() - 1); ++pageNumber; getWebServiceData(); } }); } public void getWebServiceData() { BackGroundTask backGroundTask = new BackGroundTask(this, this, pageNumber); backGroundTask.execute(); } @Override public void onTaskCompleted(String response) { parsejosnData(response); } public void parsejosnData(String response) { try { JSONObject jsonObject = new JSONObject(response); // String json = jsonObject.toString(); JSONArray jsonArray = jsonObject.getJSONArray("wallpapers"); if (jsonArray != null) { // looping through All albums if (pageNumber > 1) { wallpaperImagesList.remove(wallpaperImagesList.size() - 1); mAdapter.notifyItemRemoved(wallpaperImagesList.size()); } for (int i = 0; i < jsonArray.length(); i++) { JSONObject c = jsonArray.getJSONObject(i); // Storing each json item values in variable String id = c.getString("id"); String orig_url = c.getString("orig_url"); String thumb_url = c.getString("thumb_url"); String downloads = c.getString("downloads"); String fav = c.getString("fav"); // Creating object for each product WallPaper singleWall = new WallPaper(id, orig_url, thumb_url, downloads, fav); // adding HashList to ArrayList wallpaperImagesList.add(singleWall); handler.post(new Runnable() { @Override public void run() { mAdapter.notifyItemInserted(wallpaperImagesList.size()); } }); } mAdapter.setLoaded(); } else { Log.d("Wallpapers: ", "null"); } } catch (JSONException e) { e.printStackTrace(); } } }

Clase de adaptador

public class WallPaperDataAdapter extends RecyclerView.Adapter { private final int VIEW_ITEM = 1; private final int VIEW_PROG = 0; private List<WallPaper> imagesList; // The minimum amount of items to have below your current scroll position // before loading more. private int visibleThreshold = 5; private int lastVisibleItem, totalItemCount; private boolean loading; private OnLoadMoreListener onLoadMoreListener; public WallPaperDataAdapter(List<WallPaper> imagesList1, RecyclerView recyclerView) { imagesList = imagesList1; if (recyclerView.getLayoutManager() instanceof LinearLayoutManager) { final LinearLayoutManager linearLayoutManager = (LinearLayoutManager) recyclerView .getLayoutManager(); recyclerView .addOnScrollListener(new RecyclerView.OnScrollListener() { @Override public void onScrolled(RecyclerView recyclerView, int dx, int dy) { super.onScrolled(recyclerView, dx, dy); totalItemCount = linearLayoutManager.getItemCount(); lastVisibleItem = linearLayoutManager .findLastVisibleItemPosition(); if (!loading && totalItemCount <= (lastVisibleItem + visibleThreshold)) { // End has been reached // Do something if (onLoadMoreListener != null) { onLoadMoreListener.onLoadMore(); } loading = true; } } }); } } @Override public int getItemViewType(int position) { return imagesList.get(position) != null ? VIEW_ITEM : VIEW_PROG; } @Override public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { RecyclerView.ViewHolder vh; if (viewType == VIEW_ITEM) { View v = LayoutInflater.from(parent.getContext()).inflate( R.layout.wallpaper_row, parent, false); vh = new WallPaperViewHolder(v); } else { View v = LayoutInflater.from(parent.getContext()).inflate( R.layout.progress_item, parent, false); vh = new ProgressViewHolder(v); } return vh; } @Override public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { if (holder instanceof WallPaperViewHolder) { WallPaper singleWallPaper = (WallPaper) imagesList.get(position); Glide.with(((WallPaperViewHolder) holder).thumbIcon.getContext()) .load(singleWallPaper.getThumbUrl()) .centerCrop() .placeholder(R.drawable.bg) .crossFade() .into(((WallPaperViewHolder) holder).thumbIcon); } else { ((ProgressViewHolder) holder).progressBar.setIndeterminate(true); } } public void setLoaded() { loading = false; } @Override public int getItemCount() { return imagesList.size(); } public void setOnLoadMoreListener(OnLoadMoreListener onLoadMoreListener) { this.onLoadMoreListener = onLoadMoreListener; } // public static class WallPaperViewHolder extends RecyclerView.ViewHolder { public ImageView thumbIcon; public WallPaperViewHolder(View v) { super(v); thumbIcon = (ImageView) v.findViewById(R.id.thumbIcon); } } public static class ProgressViewHolder extends RecyclerView.ViewHolder { public ProgressBar progressBar; public ProgressViewHolder(View v) { super(v); progressBar = (ProgressBar) v.findViewById(R.id.progressBar1); } } }

wallpaper_row.xml

<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="wrap_content"> <ImageView android:id="@+id/thumbIcon" android:layout_width="160dp" android:layout_height="160dp" android:layout_centerInParent="true" android:layout_margin="2dp" android:gravity="center" /> </RelativeLayout>

progress_item.xml

<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical" > <ProgressBar android:id="@+id/progressBar1" android:layout_width="wrap_content" android:layout_gravity="center" android:layout_height="wrap_content" /> </LinearLayout>

BackGroundTask.java separado

public class BackGroundTask extends AsyncTask<Object, Void, String> { private ProgressDialog pDialog; public OnTaskCompleted listener = null;//Call back interface Context context; int pageNumber; public BackGroundTask(Context context1, OnTaskCompleted listener1, int pageNumber) { context = context1; listener = listener1; //Assigning call back interface through constructor this.pageNumber = pageNumber; } @Override protected void onPreExecute() { super.onPreExecute(); } @Override protected String doInBackground(Object... params) { //My Background tasks are written here synchronized (this) { String url = Const.URL_WALLPAPERS_HD + pageNumber; String jsonStr = ServiceHandler.makeServiceCall(url, ServiceHandler.GET); Log.i("Url: ", "> " + url); Log.i("Response: ", "> " + jsonStr); return jsonStr; } } @Override protected void onPostExecute(String result) { super.onPostExecute(result); listener.onTaskCompleted(result); } }

ServiceHanlder.java

public class ServiceHandler { static String response = null; public final static int GET = 1; public final static int POST = 2; public ServiceHandler() { } /** * Making service call * * @url - url to make request * @method - http request method */ public static String makeServiceCall(String url, int method) { return makeServiceCall(url, method, null); } /** * Making service call * * @url - url to make request * @method - http request method * @params - http request params */ public static String makeServiceCall(String url, int method, List<NameValuePair> params) { try { // http client DefaultHttpClient httpClient = new DefaultHttpClient(); HttpEntity httpEntity = null; HttpResponse httpResponse = null; // Checking http request method type if (method == POST) { HttpPost httpPost = new HttpPost(url); // adding post params if (params != null) { httpPost.setEntity(new UrlEncodedFormEntity(params)); } Log.e("Selltis Request URL", url); httpResponse = httpClient.execute(httpPost); } else if (method == GET) { // appending params to url if (params != null) { String paramString = URLEncodedUtils .format(params, "utf-8"); url += paramString; Log.i("Request URL", url); } HttpGet httpGet = new HttpGet(url); httpResponse = httpClient.execute(httpGet); } httpEntity = httpResponse.getEntity(); response = EntityUtils.toString(httpEntity); } catch (UnsupportedEncodingException e) { e.printStackTrace(); return "Fail"; } catch (ClientProtocolException e) { e.printStackTrace(); return "Fail"; } catch (IOException e) { e.printStackTrace(); return "Fail"; } return response; } }

Interfaz para cargar más

public interface OnLoadMoreListener { void onLoadMore(); }

Interfaz para conocer los datos del servicio web cargados desde asynctask.

public interface OnTaskCompleted{ void onTaskCompleted(String response); }

Por favor, hágamelo saber si esto funciona o si hay algún problema para usted. Es mejor usar las bibliotecas Volley o okHttp para redes.

Para ImageLoading usé Glide Library.


En el método onScroll

if (!loading && (totalItemCount - visibleItemCount) <= (firstVisibleItem + visibleThreshold)) { // End has been reached Log.i("...", "end called"); // Do something new JSONAsyncTask().execute("http://walldroidhd.com/api.php"); loading = true; }


La idea de implementar load-more es:

Obtener todos los registros en una colección. Tome otra colección que poblará registros parciales, digamos 10 registros. Ahora, cuando llegue al final, complete los siguientes 10 registros de la colección y notifique a la lista.

Entonces tu código será algo como esto:

ArrayList<NatureItem> tempList; // which holds partial records tempList = getList(limit, 10); mAdapter = new RecyclerViewMaterialAdapter(new CardAdapter(getActivity(), tempList), 2); mRecyclerView.setAdapter(mAdapter);

Ahora, codifique para cargar los siguientes registros:

limit += 10; tempList.addAll(getList(limit, 10)); mAdapter.notifyDataSetChanged();

Para mostrar el cargador / progreso, es mejor usar la biblioteca load-more


Otro ejemplo . Configure la barra de progreso en la parte inferior y cambie su visibilidad de acuerdo con el desplazamiento / carga y sus registros. Nota: debe llamar a notificationDataSetChanged (); Método para agregar / actualizar datos al adaptador

recyclerView.setOnScrollListener(new RecyclerView.OnScrollListener() { @Override public void onScrolled(RecyclerView recyclerView, int dx, int dy) { super.onScrolled(recyclerView, dx, dy); int total = linearLayoutManager.getItemCount(); int firstVisibleItemCount = linearLayoutManager.findFirstVisibleItemPosition(); int lastVisibleItemCount = linearLayoutManager.findLastVisibleItemPosition(); //to avoid multiple calls to loadMore() method //maintain a boolean value (isLoading). if loadMore() task started set to true and completes set to false if (!isLoading) { if (total > 0) if ((total - 1) == lastVisibleItemCount){ loadMore();//your HTTP stuff goes in this method loadingProgress.setVisibility(View.VISIBLE); }else loadingProgress.setVisibility(View.GONE); } } @Override public void onScrollStateChanged(RecyclerView recyclerView, int newState) { super.onScrollStateChanged(recyclerView, newState); } });