I have implemented pagination in my app but I am having trouble with incrementing the page index. I am getting data from unsplash api and have formed the request url like below:
private String url = Constants.SEARCH_URL + "top30&page="+ PAGE_INDEX;
and this is the url used below:
https://api.unsplash.com/search/photos?client_id=api_key&order_by=latest&query=top30&page=1
In my fragment, I have a constant int like private static int PAGE_INDEX = 1; which tracks the current page and used for getting the next pages till page limit.
The first request runs fine and when scrolling towards the last item, more items are fetched. However, these items are same as from the first page index and after logging the url, I get the same as in first request like below:
https://api.unsplash.com/search/photos?client_id=api_key&order_by=latest&query=top30&page=1
I have attached my scroll listener in recyclerview like this and incremented the PAGE_INDEX but not getting the next page in url but in log cat it shows the page index as 2. Here's the listener attached:
top30RV.addOnScrollListener(new PaginationScrollListener(llm) {
#Override
protected void loadMoreItems() {
isLoading = true;
PAGE_INDEX = PAGE_INDEX + 1;
Log.d(TAG, "PIn:\t" + PAGE_INDEX);
loadNextPage();
}
#Override
protected int getTotalPageCount() {
return PAGE_COUNT;
}
#Override
public boolean isLoading() {
return isLoading;
}
#Override
public boolean isLastPage() {
return isLastPage;
}
});
and my PaginationScrollListener class code:
public abstract class PaginationScrollListener extends RecyclerView.OnScrollListener {
LinearLayoutManager llm;
public PaginationScrollListener(LinearLayoutManager llm) {
this.llm = llm;
}
#Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);
int visisbleItemCount = recyclerView.getChildCount();
int totalItemCount = llm.getItemCount();
int firstVisibleItemPosn = llm.findFirstVisibleItemPosition();
if (!isLoading() && !isLastPage()){
if ((visisbleItemCount + firstVisibleItemPosn) >= totalItemCount && firstVisibleItemPosn > 0){
loadMoreItems();
}
}
}
protected abstract void loadMoreItems();
protected abstract int getTotalPageCount();
public abstract boolean isLoading();
public abstract boolean isLastPage();
}
in my adapter I have called the method to addLoadingFooter and it works but also the progressbar is not dismissed and removeLoadingFooter is called but doesn't work because of the page index is less than the page limit.
public class Top30Adapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
private static final String TAG = Top30Adapter.class.getSimpleName();
private final Context context;
private List<UnsplashImages> itemsList;
private UnsplashImages unsplashImages;
private static final int ITEMS = 0;
private static final int PROGRESS = 1;
private boolean isLoadingAdded = false;
private boolean retryPageLoad = false;
private String errorMsg;
private PaginationAdapterCallback mCallback;
public Top30Adapter(Context context, List<UnsplashImages> itemsList) {
this.context = context;
this.itemsList = itemsList;
}
#Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
switch (viewType){
case ITEMS:
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.wallpaper_items_layout, parent, false);
return new WallpaperItemViewHolder(view);
case PROGRESS:
View pv = LayoutInflater.from(parent.getContext()).inflate(R.layout.progress_items_layout, parent, false);
return new LoadingViewHolder(pv);
}
return null;
}
#Override
public void onBindViewHolder(RecyclerView.ViewHolder viewholder, final int position) {
switch (getItemViewType(position)){
case ITEMS:
WallpaperItemViewHolder wallpaperItemViewHolder = (WallpaperItemViewHolder) viewholder;
unsplashImages = (UnsplashImages) itemsList.get(position);
Picasso.with(context)
.load(unsplashImages.getRegularImg())
.placeholder(R.drawable.drawer_header_trimmed)
.into(wallpaperItemViewHolder.wallpaperItemImg);
wallpaperItemViewHolder.favoriteWP_IV.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Favorites favorites = new Favorites();
favorites.setFavoritesId(UUID.randomUUID().toString());
favorites.setLargeImgURL(unsplashImages.getRegularImg());
favorites.setPreviewImgURL(unsplashImages.getRegularImg());
favorites.save();
Toast.makeText(context, "Added to Favorites", Toast.LENGTH_SHORT).show();
}
});
wallpaperItemViewHolder.setWallPaper_TV.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
final WallpaperManager wpm = WallpaperManager.getInstance(context);
Picasso.with(context)
.load(((UnsplashImages) itemsList.get(position)).getRegularImg())
.into(new Target() {
#Override
public void onBitmapLoaded(Bitmap bitmap, Picasso.LoadedFrom from) {
try {
wpm.setBitmap(bitmap);
Toast.makeText(context, "Your New Wallpaper Has Been Set", Toast.LENGTH_SHORT).show();
} catch (IOException e) {
e.printStackTrace();
}
}
#Override
public void onBitmapFailed(Drawable errorDrawable) {
Log.d(TAG, "Bitmap Load Failed");
Toast.makeText(context, "Could Not Set Wallpaper...Choose Another", Toast.LENGTH_SHORT).show();
}
#Override
public void onPrepareLoad(Drawable placeHolderDrawable) {
Log.d(TAG, "Prep to Load Bitmap");
}
});
}
});
break;
case PROGRESS:
LoadingViewHolder loadingViewHolder = (LoadingViewHolder) viewholder;
if (retryPageLoad){
loadingViewHolder.mErrorLayout.setVisibility(View.VISIBLE);
loadingViewHolder.mProgressBar.setVisibility(View.GONE);
loadingViewHolder.mErrorTxt.setText(errorMsg != null
? errorMsg
: context.getString(R.string.error_msg_unknown));
} else {
loadingViewHolder.mErrorLayout.setVisibility(View.GONE);
loadingViewHolder.mProgressBar.setVisibility(View.VISIBLE);
}
break;
}
}
#Override
public int getItemCount() {
if (itemsList == null) {
return 0;
}
return itemsList.size();
}
#Override
public int getItemViewType(int position) {
return (position == itemsList.size() - 1 && isLoadingAdded) ? PROGRESS : ITEMS;
}
public void addImage(UnsplashImages images){
itemsList.add(images);
notifyItemInserted(itemsList.size() - 1);
}
public void addAllImages(List<UnsplashImages> list){
for (UnsplashImages images : list){
addImage(images);
}
}
public void addLoadingFooter() {
isLoadingAdded = true;
addImage(new UnsplashImages());
}
public void removeLoadingFooter(){
isLoadingAdded = false;
int position = itemsList.size() - 1;
UnsplashImages unsplashImages = getItem(position);
if (unsplashImages != null){
itemsList.remove(unsplashImages);
notifyItemRemoved(position);
}
}
private UnsplashImages getItem(int position) {
return itemsList.get(position);
}
public void showRetry(boolean show, #Nullable String errorMsg){
retryPageLoad = true;
notifyItemChanged(itemsList.size() - 1);
if (errorMsg != null){this.errorMsg = errorMsg; } else { errorMsg = "Can't Fetch Wallpapers Now..."; }
}
}
Full fragment code:
public class Top30Fragment extends Fragment {
private static final String TAG = Top30Fragment.class.getSimpleName();
private RecyclerView top30RV;
private List<UnsplashImages> itemsList = new ArrayList<>();
private Top30Adapter adapter;
private int PAGE_COUNT;
private static int PAGE_INDEX = 1;
private static int PER_PAGE = 20;
private static int CURRENT_PAGE = PAGE_INDEX;
private boolean isLoading = false;
private boolean isLastPage = false;
private String url = Constants.SEARCH_URL + "top30&page="+ PAGE_INDEX;
public Top30Fragment() {
// Required empty public constructor
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
View vtop = inflater.inflate(R.layout.fragment_top30, container, false);
top30RV = vtop.findViewById(R.id.top30RV);
top30RV.setHasFixedSize(true);
LinearLayoutManager llm = new LinearLayoutManager(getActivity());
top30RV.setLayoutManager(llm);
if (Utils.isNetwork(getActivity())){
fetchWallpapers();
} else {
Snackbar.make(getActivity().findViewById(android.R.id.content), "Check Connection", Snackbar.LENGTH_LONG).show();
}
adapter = new Top30Adapter(getActivity(), itemsList);
top30RV.setAdapter(adapter);
top30RV.addOnScrollListener(new PaginationScrollListener(llm) {
#Override
protected void loadMoreItems() {
isLoading = true;
PAGE_INDEX = PAGE_INDEX + 1;
Log.d(TAG, "PIn:\t" + PAGE_INDEX);
loadNextPage();
}
#Override
protected int getTotalPageCount() {
return PAGE_COUNT;
}
#Override
public boolean isLoading() {
return isLoading;
}
#Override
public boolean isLastPage() {
return isLastPage;
}
});
adapter.notifyDataSetChanged();
return vtop;
}
private void loadNextPage() {
int newIndex = PAGE_INDEX +=1;
Log.d(TAG, "Next Page:\t" + newIndex);
Log.d(TAG, "Next Page Index:\t" + newIndex);
Log.d(TAG, "Next Page URL:\t" + url);
AndroidNetworking.get(url)
.setTag("Load Next Top30")
.setPriority(Priority.HIGH)
.build()
.getAsJSONObject(new JSONObjectRequestListener() {
#Override
public void onResponse(JSONObject response) {
Log.d(TAG, "Next Page Response:\t" + response.toString());
if (response != null){
isLoading = false;
adapter.removeLoadingFooter();
try {
JSONObject jsonObject = new JSONObject(response.toString());
JSONArray results = jsonObject.getJSONArray("results");
for (int p = 0; p < results.length(); p++){
JSONObject items = results.getJSONObject(p);
UnsplashImages images = new UnsplashImages();
images.setImageId(items.getString("id"));
JSONObject urls = items.getJSONObject("urls");
images.setRawImg(urls.getString("raw"));
images.setFullImg(urls.getString("full"));
images.setRegularImg(urls.getString("regular"));
images.setSmallImg(urls.getString("small"));
images.setThumbImg(urls.getString("thumb"));
itemsList.add(images);
adapter.notifyDataSetChanged();
Log.d(TAG, "New List Size:\t" + itemsList.size());
if (CURRENT_PAGE != PAGE_COUNT){
adapter.addLoadingFooter();
} else {
isLastPage = true;
}
}
} catch (JSONException e) {
e.printStackTrace();
}
}
}
#Override
public void onError(ANError anError) {
}
});
}
private void fetchWallpapers() {
// String url = Constants.SEARCH_URL + "top30&page="+ PAGE_INDEX + "per_page=" + PER_PAGE;
Log.d(TAG, "Top30 Unsplash URL:\t" + url);
AndroidNetworking.get(url)
.setPriority(Priority.HIGH)
.setTag("Get Seasons Wallpapers")
.build()
.getAsJSONObject(new JSONObjectRequestListener() {
#Override
public void onResponse(JSONObject response) {
Log.d(TAG, "Un-Response:\t" + response.toString());
if (response != null){
try {
JSONObject jsonObject = new JSONObject(response.toString());
PAGE_COUNT = jsonObject.getInt("total_pages");
Log.d(TAG, "Page Count:\t" + PAGE_COUNT);
JSONArray results = jsonObject.getJSONArray("results");
for (int p = 0; p < results.length(); p++){
JSONObject items = results.getJSONObject(p);
UnsplashImages images = new UnsplashImages();
images.setImageId(items.getString("id"));
JSONObject urls = items.getJSONObject("urls");
images.setRawImg(urls.getString("raw"));
images.setFullImg(urls.getString("full"));
images.setRegularImg(urls.getString("regular"));
images.setSmallImg(urls.getString("small"));
images.setThumbImg(urls.getString("thumb"));
itemsList.add(images);
adapter.notifyDataSetChanged();
Log.d(TAG, "List Size:\t" + itemsList.size());
}
} catch (JSONException e) {
e.printStackTrace();
}
}
}
#Override
public void onError(ANError anError) {
}
});
}
Is there another way to construct the request url to increment the page index? Thanks.
Related
I am currently working on an app, that finds all MP3s on a users phone and then puts them into a list. This works very fine and is very quick, even with many songs. Now I populate a new list with an object for each item of the list to then display it inside my recyclerview. The problem is, that I have 700+ songs on my phone and this blocks the UI thread quite some time.
Now, I want to use the recyclerview to not load all items from the list into the objects all at once but rather only when they are about to be displayed - but I have NO clue over how to do this. Right now, all objects are build and then displayed in a very long scrollview from the recyclerview after the UI thread has been blocked for a good 30 seconds. Can please anyone help me? Here is my code:
namespace Media_Player
{
[Activity(Label = "Media_Player", MainLauncher = true)]
public class MainActivity : Activity
{
static public MediaPlayer mediaPlayer;
List<MP3object> mp3;
MediaMetadataRetriever reader;
public static Button btn_StartOrPause, btn_Stop;
public static TextView txt_CurrentSong;
public static bool stopIsActive = false, firstStart = true;
public static Android.Net.Uri CurrentActiveSongUri;
RecyclerView mRecyclerView;
RecyclerView.LayoutManager mLayoutManager;
PhotoAlbumAdapter mAdapter;
protected override void OnCreate(Bundle savedInstanceState)
{
base.OnCreate(savedInstanceState);
SetContentView(Resource.Layout.test);
reader = new MediaMetadataRetriever();
PopulateMP3List(ReturnPlayableMp3(true));
mediaPlayer = new MediaPlayer();
InitRecView();
}
private void InitRecView()
{
// Instantiate the adapter and pass in its data source:
mAdapter = new PhotoAlbumAdapter(mp3);
// Get our RecyclerView layout:
mRecyclerView = FindViewById<RecyclerView>(Resource.Id.recyclerView);
// Plug the adapter into the RecyclerView:
mRecyclerView.SetAdapter(mAdapter);
mLayoutManager = new LinearLayoutManager(this);
mRecyclerView.SetLayoutManager(mLayoutManager);
}
private void PopulateMP3List(List<string> content)
{
mp3 = new List<MP3object>();
foreach (string obj in content)
{
WriteMetaDataToFileList(obj);
}
}
void WriteMetaDataToFileList(string obj)
{
reader.SetDataSource(obj);
//Write Mp3 as object to global list
MP3object ob = new MP3object();
{
if(reader.ExtractMetadata(MediaMetadataRetriever.MetadataKeyTitle) != "" && reader.ExtractMetadata(MediaMetadataRetriever.MetadataKeyTitle) != null)
{
ob.SongName = reader.ExtractMetadata(MediaMetadataRetriever.MetadataKeyTitle);
}
else
{
ob.SongName = Resources.GetString(Resource.String.Unknown);
}
if (reader.ExtractMetadata(MediaMetadataRetriever.MetadataKeyArtist) != "" && reader.ExtractMetadata(MediaMetadataRetriever.MetadataKeyArtist) != null)
{
ob.ArtistName = reader.ExtractMetadata(MediaMetadataRetriever.MetadataKeyArtist);
}
else
{
ob.ArtistName = Resources.GetString(Resource.String.Unknown);
}
if (reader.ExtractMetadata(MediaMetadataRetriever.MetadataKeyAlbum) != "" && reader.ExtractMetadata(MediaMetadataRetriever.MetadataKeyAlbum) != null)
{
ob.AlbumName = reader.ExtractMetadata(MediaMetadataRetriever.MetadataKeyAlbum);
}
else
{
ob.AlbumName = Resources.GetString(Resource.String.Unknown);
}
if (reader.ExtractMetadata(MediaMetadataRetriever.MetadataKeyYear) != "" && reader.ExtractMetadata(MediaMetadataRetriever.MetadataKeyYear) != null)
{
ob.Year = reader.ExtractMetadata(MediaMetadataRetriever.MetadataKeyYear);
}
else
{
ob.Year = Resources.GetString(Resource.String.Unknown);
}
if (reader.ExtractMetadata(MediaMetadataRetriever.MetadataKeyYear) != "" && reader.ExtractMetadata(MediaMetadataRetriever.MetadataKeyYear) != null)
{
ob.Year = reader.ExtractMetadata(MediaMetadataRetriever.MetadataKeyYear);
}
else
{
ob.Year = Resources.GetString(Resource.String.Unknown);
}
ob.Mp3Uri = obj; // can never be unknown!
ob.DurationInSec = int.Parse(reader.ExtractMetadata(MediaMetadataRetriever.MetadataKeyDuration)) / 1000; // can never be unknown, div by 1000 to get sec not millis
}
mp3.Add(ob);
}
public List<string> ReturnPlayableMp3(bool sdCard)
{
List<string> res = new List<string>();
string phyle;
string path1 = null;
if(sdCard) // get mp3 from SD card
{
string baseFolderPath = "";
try
{
bool getSDPath = true;
Context context = Application.Context;
Java.IO.File[] dirs = context.GetExternalFilesDirs(null);
foreach (Java.IO.File folder in dirs)
{
bool IsRemovable = Android.OS.Environment.InvokeIsExternalStorageRemovable(folder);
bool IsEmulated = Android.OS.Environment.InvokeIsExternalStorageEmulated(folder);
if (getSDPath ? IsRemovable && !IsEmulated : !IsRemovable && IsEmulated)
baseFolderPath = folder.Path;
}
}
catch (Exception ex)
{
Console.WriteLine("GetBaseFolderPath caused the following exception: {0}", ex);
}
string xy = baseFolderPath.Remove(18); // This is result after this, but this hard coded solution could be a problem on different phones.: "/storage/05B6-2226/Android/data/Media_Player.Media_Player/files"
path1 = xy;
// path to SD card and MUSIC "/storage/05B6-2226/"
}
else // get Mp3 from internal storage
{
path1 = Android.OS.Environment.ExternalStorageDirectory.ToString();
}
var mp3Files = Directory.EnumerateFiles(path1, "*.mp3", SearchOption.AllDirectories);
foreach (string currentFile in mp3Files)
{
phyle = currentFile;
res.Add(phyle);
}
return res;
}
}
public class PhotoViewHolder : RecyclerView.ViewHolder
{
public ImageView Image { get; private set; }
public TextView Caption { get; private set; }
public PhotoViewHolder(View itemView) : base(itemView)
{
// Locate and cache view references:
Image = itemView.FindViewById<ImageView>(Resource.Id.imageView);
Caption = itemView.FindViewById<TextView>(Resource.Id.textView);
}
}
public class PhotoAlbumAdapter : RecyclerView.Adapter
{
public List<MP3object> mp3;
public PhotoAlbumAdapter(List<MP3object> mp3)
{
this.mp3 = mp3;
}
public override RecyclerView.ViewHolder OnCreateViewHolder(ViewGroup parent, int viewType)
{
View itemView = LayoutInflater.From(parent.Context).
Inflate(Resource.Layout.lay, parent, false);
PhotoViewHolder vh = new PhotoViewHolder(itemView);
return vh;
}
public override void OnBindViewHolder(RecyclerView.ViewHolder holder, int position)
{
PhotoViewHolder vh = holder as PhotoViewHolder;
vh.Caption.Text = mp3[position].SongName;
}
public override int ItemCount
{
get { return mp3.Count(); }
}
}
}
So getting the list of strings with the locations of the Mp3 works very quickly, but then "WriteMetaDataToFileList(obj)" kicks in, comming from "PopulateMP3List(List content)" and this is what takes so long. What I think I need is for the recyclerview to only build the first 20 objects, and when the user starts scrolling, builds the next 20 objects and attaches them to list for them to also be scrolled. Please help me out here :)
Here is an abstract class:
public abstract class PaginationScrollListener extends RecyclerView.OnScrollListener {
private LinearLayoutManager linearLayoutManager;
protected PaginationScrollListener(LinearLayoutManager linearLayoutManager) {
this.linearLayoutManager = linearLayoutManager;
}
#Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);
int visibleItemCount = linearLayoutManager.getChildCount();
int totalItemCount = linearLayoutManager.getItemCount();
int firstVisibleItemPosition = linearLayoutManager.findFirstVisibleItemPosition();
if (!isLoading() && !isLastPage()) {
if ((visibleItemCount + firstVisibleItemPosition) >= totalItemCount && firstVisibleItemPosition >= 0) {
loadMoreItems();
}
}
}
protected abstract void loadMoreItems();
public abstract boolean isLastPage();
public abstract boolean isLoading();
}
and In your adapter you must follow this pattern:
public class ConsultancyAdapter extends RecyclerView.Adapter<ConsultancyAdapter.ConsultancyVH> {
private static final int ITEM = 0;
private static final int LOADING = 1;
private boolean isLoadingAdded = false;
public ConsultancyAdapter(List<Consultancy> consultancies, ConsultancyAdapterListener listener) {
}
#NonNull
#Override
public ConsultancyVH onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
RecyclerView.ViewHolder viewHolder = null;
LayoutInflater layoutInflater = LayoutInflater.from(parent.getContext());
switch (viewType) {
case ITEM:
viewHolder = getViewHolder(parent, layoutInflater);
break;
case LOADING:
View v2 = layoutInflater.inflate(R.layout.item_progress, parent, false);
viewHolder = new ConsultancyVH(v2);
break;
}
return (ConsultancyVH) viewHolder;
}
#NonNull
private RecyclerView.ViewHolder getViewHolder(ViewGroup parent, LayoutInflater inflater) {
RecyclerView.ViewHolder viewHolder;
View v1 = inflater.inflate(R.layout.item_consultancy, parent, false);
viewHolder = new ConsultancyVH(v1);
return viewHolder;
}
#Override
public void onBindViewHolder(#NonNull ConsultancyVH holder, int position) {
Consultancy consultancy = consultancies.get(position);
switch (getItemViewType(position)) {
case ITEM:
ConsultancyVH mySingeCounseller = holder;
holder.title.setText(consultancy.getTitle()); // set cardTitle
holder.fieldArea.setText(consultancy.getField_filedoctorskills());
break;
case LOADING:
break;
}
}
#Override
public int getItemCount() {
return consultancies.size();
}
#Override
public int getItemViewType(int position) {
return (position == consultancies.size() - 1 && isLoadingAdded) ? LOADING : ITEM;
}
public void add(Consultancy mc) {
consultancies.add(mc);
notifyItemInserted(consultancies.size() - 1);
}
public void addAll(List<Consultancy> mcList) {
for (Consultancy mc : mcList) {
add(mc);
}
}
public void remove(Consultancy city) {
int position = consultancies.indexOf(city);
if (position > -1) {
consultancies.remove(position);
notifyItemRemoved(position);
}
}
public Consultancy getItem(int position) {
return consultancies.get(position);
}
public void clear() {
isLoadingAdded = false;
while (getItemCount() > 0) {
remove(getItem(0));
}
}
public boolean isEmpty() {
return getItemCount() == 0;
}
public void addLoadingFooter() {
isLoadingAdded = true;
add(new Consultancy());
}
public void removeLoadingFooter() {
isLoadingAdded = false;
int position = consultancies.size() - 1;
Consultancy item = getItem(position);
if (item != null) {
consultancies.remove(position);
notifyItemRemoved(position);
}
}
public interface ConsultancyAdapterListener {
void onCaseClicked(int position, String nid, String fieldArea, String title);
}
protected class ConsultancyVH extends RecyclerView.ViewHolder {
private TextView title, fieldArea;
private CircleImageView iconProfile;
private MaterialRippleLayout caseButtonRipple;
public ConsultancyVH(View itemView) {
super(itemView);
caseButtonRipple = itemView.findViewById(R.id.case_button_ripple);
this.title = itemView.findViewById(R.id.docName);
this.fieldArea = itemView.findViewById(R.id.fieldArea);
this.iconProfile = itemView.findViewById(R.id.icon_profile);
}
}
}
and in your activity:
private void setScrollListener() {
recyclerView.addOnScrollListener(new PaginationScrollListener(linearLayoutManager) {
#Override
protected void loadMoreItems() {
isLoading = true;
currentPage += 1;
loadNextPage();
}
#Override
public boolean isLastPage() {
return isLastPage;
}
#Override
public boolean isLoading() {
return isLoading;
}
});
loadFirstPage();
}
and in my loadFirstPage i talk to a API and you need some your code:
private void loadFirstPage() {
CallData().enqueue(new DefaultRetrofitCallback<List<Consultancy>>() {
#Override
protected void onFailure(Throwable t) {
super.onFailure(t);
}
#Override
protected void onSuccess(List<Consultancy> response) {
swipeRefreshLayout.setRefreshing(false);
dataList = response;
adapter.addAll(dataList);
recyclerView.setAdapter(adapter);
if (!checkLast(response)) adapter.addLoadingFooter();
else isLastPage = true;
}
#Override
protected void onOtherStatus(Response<List<Consultancy>> response) {
super.onOtherStatus(response);
}
#Override
protected void always() {
super.always();
}
});
}
and loadNextPage:
private void loadNextPage() {
CallData().enqueue(new DefaultRetrofitCallback<List<Consultancy>>() {
#Override
protected void onFailure(Throwable t) {
super.onFailure(t);
}
#Override
protected void onSuccess(List<Consultancy> response) {
swipeRefreshLayout.setRefreshing(false);
adapter.removeLoadingFooter();
isLoading = false;
swipeRefreshLayout.setRefreshing(false);
adapter.addAll(response);
if (!checkLast(response)) adapter.addLoadingFooter();
else isLastPage = true;
}
#Override
protected void onOtherStatus(Response<List<Consultancy>> response) {
super.onOtherStatus(response);
}
#Override
protected void always() {
super.always();
}
});
}
I haven't found yet the proper examples of how to make an app load more items from Retrofit onResponse while scrolling down the RecyclerView.
Here is how I'm loading my fist 20 items:
List<ModelPartners> model = new ArrayList<>();
Call<ResponsePartners> call = ApiClient.getRetrofit().getPartnerList(params);
call.enqueue(this);
My RecyclerView
PartnersAdapter adapter = new PartnersAdapter(getContext(), recyclerView, model);
recyclerView.setAdapter(adapter);
And here is my Retrofit onResponse:
#Override
public void onResponse(Call<ResponsePartners> call, Response<ResponsePartners> response) {
if (getActivity() != null && response.isSuccessful()) {
List<ModelPartners> body = response.body().getData();
//Rest of the code to add body to my Adapter and notifyDataSetChanged
}
}
My Problem is, every time I add the method to load more items on scroll, onResponse keeps loading non-stop till the last page. Even if I have put set loading to false.
Can someone please show how to properly use pagination in Retrofit? What libraries you used with Retrofit or show me how you did it your way? Thank you in advance
You need three things to achieve this, you need:
You need an onscroll listener for the recycler view.
You need a method to add new items to the recycler adapter
You need to call your paginated endpoint
Assuming you have a model like this from the server
public class PagedList<T> {
private int page = 0;
private List<T> results = new ArrayList<>();
private int totalResults = 0;
private int totalPages = 0;
public int getPage() {
return page;
}
public void setPage(int page) {
this.page = page;
}
public List<T> getResults() {
return results;
}
public void setResults(List<T> results) {
this.results = results;
}
public int getTotalResults() {
return totalResults;
}
public void setTotalResults(int totalResults) {
this.totalResults = totalResults;
}
public int getTotalPages() {
return totalPages;
}
public void setTotalPages(int totalPages) {
this.totalPages = totalPages;
}
}
Your OnScroll Listener: -
In your activity this is what you would have, so add the second method to your activity
public void onCreate(Bundle savedInstance) {
// setup your view components
// ...
// get the layout manager
LinearLayoutManager layoutManager = new LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false);
// rest endpoint
apiEndpoint = retrofit.create(RetrofitEndpoint.class);
// initialise loading state
mIsLoading = false;
mIsLastPage = false;
// amount of items you want to load per page
final int pageSize = 20;
// set up scroll listener
recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
#Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);
// number of visible items
int visibleItemCount = layoutManager.getChildCount();
// number of items in layout
int totalItemCount = layoutManager.getItemCount();
// the position of first visible item
int firstVisibleItemPosition = layoutManager.findFirstVisibleItemPosition();
boolean isNotLoadingAndNotLastPage = !mIsLoading && !mIsLastPage;
// flag if number of visible items is at the last
boolean isAtLastItem = firstVisibleItemPosition + visibleItemCount >= totalItemCount;
// validate non negative values
boolean isValidFirstItem = firstVisibleItemPosition >= 0;
// validate total items are more than possible visible items
boolean totalIsMoreThanVisible = totalItemCount >= pageSize;
// flag to know whether to load more
boolean shouldLoadMore = isValidFirstItem && isAtLastItem && totalIsMoreThanVisible && isNotLoadingAndNotLastPage
if (shouldLoadMore) loadMoreItems(false);
}
});
// load the first page
loadMoreItems(true);
}
private void loadMoreItems(boolean isFirstPage) {
// change loading state
mIsLoading = true;
mCurrentPage = mCurrentPage + 1;
// update recycler adapter with next page
apiEndpoint.getPagedList(mCurrentPage).enqueue(new Callback<PagedList<Object>>() {
#Override
public void onResponse(Call<PagedList<Object>> call, Response<PagedList<Object>> response) {
PagedList<Object> result = response.body();
if (result == null) return;
else if (!isFirstPage) mAdapter.addAll(result.getResults());
else mAdapter.setList(result.getResults());
mIsLoading = false;
mIsLastPage = mCurrentPage == result.getTotalPages();
}
#Override
public void onFailure(Call<PagedList<Object>> call, Throwable t) {
Log.e("SomeActivity", t.getMessage());
}
});
}
Recycler Adapter: -
For the recycler adapter all you need is to add a method that adds items to its list, as below
public class SomeAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
private List<Object> list;
// .. other overridden members
public void setList(List<Object> list) {
this.list = list;
notifyDataSetChanged();
}
public void addAll(List<Object> newList) {
int lastIndex = list.size() - 1;
list.addAll(newList);
notifyItemRangeInserted(lastIndex, newList.size());
}
}
Then finally your retrofit interface that takes the page, as below:
interface RetrofitEndpoint {
#GET("paged/list/endpoint")
Call<PagedList<Object>> getPagedList(#Query("page") int page);
}
Hope that helps.
#Alimov Shohrukh, I also tried for many ways for Pagination
1) Check this link,This is one way
2) I mention it step by step
from API side - you need to pass pageConunt, pageIndex and get data based on above parameters
pageConunt - means how many data you want get from server for i.e - 10
pageIndex - page number for i.e 1,2,3 etc
public class DemoActivity extends BaseActivity{
List<BaseModel> orderList = new ArrayList<>();
ListAdapter listAdapter;
LinearLayoutManager layoutManager;
OrderListAdapter orderListAdapter;
int pageIndex = 1; // you can pass 1,2,3...
int pageCount = 10; //you can pass 10,20...
boolean isApiSuccess = false;
//if api get success == true then you need to work with load more sp we take one boolean variable
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_demo);
findView();
setRecyclerViewPagination();
}
private void findView() {
//recyclerview
rv_po_order_number = findViewById(R.id.rv_po_order_number);
}
//custom OnScrollListener
private RecyclerView.OnScrollListener recyclerViewOnScrollListener = new RecyclerView.OnScrollListener() {
#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);
if (isApiSuccess) {
pageIndex++;
listTestApiCall(pageIndex, searchQuery);
Log.e(TAG, pageIndex + " page count ");
orderListAdapter.showLoading(true);
rv_po_order_number.post(new Runnable() {
public void run() {
// There is no need to use notifyDataSetChanged()
orderListAdapter.notifyDataSetChanged();
}
});
}
}
};
private void setRecyclerViewPagination() {
orderList = new ArrayList<>();
orderListAdapter = new OrderListAdapter(mActivity, orderList);
layoutManager = new LinearLayoutManager(mActivity, LinearLayoutManager.VERTICAL, false);
rv_po_order_number.setLayoutManager(layoutManager);
rv_po_order_number.setHasFixedSize(true);
rv_po_order_number.setAdapter(orderListAdapter);
rv_po_order_number.addOnScrollListener(recyclerViewOnScrollListener);
listTestApiCall(pageCount,pageIndex);
}
private void listTestApiCall(final int pageCount,final int pageIndex) {
// if (CommonUtils.isConnectingToInternet(mActivity)) {
if (validateInternetConn(mActivity)) {//check internet
final boolean isFirstPage = pageIndex == 1 ? true : false;
if (isFirstPage)
//do your stuff - if you want to show loader
Call<BaseModel> call = ApiClient.getClient().listApiCall(pageCount, pageIndex);
call.enqueue(new Callback<BaseModel>() {
#Override
public void onResponse(Call<BaseModel> call, Response<BaseModel> response) {
try {
if (response.isSuccessful()) {
boolean success = response.body().getStatus();
isApiSuccess = response.body().getStatus();
if (success) {
List<BaseModel> list = new ArrayList<>();
if (response.body().getData() != null) {
list = response.body().getData();
if (isFirstPage)
orderList.clear();
orderList.addAll(response.body().getData());
}
if (list != null && list.size() > 0) {
isApiSuccess = true;
} else {
isApiSuccess = false;
}
} else if (!success) {
isApiSuccess = false;
String message = response.body().getMessage();
}
listAdapter.showLoading(false);
listAdapter.notifyDataSetChanged();
}
} catch (Exception e) {
e.printStackTrace();
Log.e("Tag", "error=" + e.toString());
isApiSuccess = false;
}
}
#Override
public void onFailure(Call<BaseModel> call, Throwable t) {
Log.e("Tag", "error" + t.toString());
isApiSuccess = false;
}
});
}
}
}
here is OrderListAdapter
public class OrderListAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder>{
Activity mActivity;
List<OrderListBaseModel.DataBean> mList;
PurchaseOrderReceiveOnClick purchaseOrderReceiveOnClick;
DeleteUpdatePOOnClick deleteUpdatePOOnClick;
public static final int TYPE_FOOTER = 1;
public static final int TYPE_ITEM = 2;
protected boolean showLoader = true;
public OrderListAdapter(Activity mActivity, List<OrderListBaseModel.DataBean> mList, PurchaseOrderReceiveOnClick purchaseOrderReceiveOnClick,DeleteUpdatePOOnClick deleteUpdatePOOnClick) {
this.mActivity = mActivity;
this.purchaseOrderReceiveOnClick = purchaseOrderReceiveOnClick;
this.deleteUpdatePOOnClick = deleteUpdatePOOnClick;
this.mList = mList;
}
public OrderListAdapter(Activity mActivity, List<OrderListBaseModel.DataBean> mList) {
this.mActivity = mActivity;
this.mList = mList;
}
#Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
if (viewType == TYPE_ITEM) {
View v = LayoutInflater.from(parent.getContext())
.inflate(R.layout.row_purchase_order_receive, parent, false);
return new DataViewHolder(v, purchaseOrderReceiveOnClick);
} else if (viewType == TYPE_FOOTER) {
View v = LayoutInflater.from(parent.getContext())
.inflate(R.layout.loading_layout, parent, false);
return new FooterViewHolder(v);
} else
return null;
}
#Override
public void onBindViewHolder(final RecyclerView.ViewHolder holder, final int position) {
if (holder instanceof DataViewHolder) {
final DataViewHolder dataViewHolder = (DataViewHolder) holder;
final OrderListBaseModel.DataBean dataBean = getItem(position);
if (dataBean != null) {
dataViewHolder.setPosition(position);
dataViewHolder.setSingleBean(dataBean);
}
}
}
private OrderListBaseModel.DataBean getItem(int position) {
if (mList.size() > 0)
return mList.get(position);
else
return null;
}
public void showLoading(boolean status) {
showLoader = status;
}
#Override
public int getItemViewType(int position) {
if ((position == mList.size() - 1) && showLoader) {
return TYPE_FOOTER;
}
return TYPE_ITEM;
}
public void removeItem(int position) {
mList.remove(position);
notifyItemRemoved(position);
}
#Override
public int getItemCount() {
return mList.size();
}
public static class DataViewHolder extends RecyclerView.ViewHolder {
int position;
OrderListBaseModel.DataBean dataBean;
private TextView tv_row_po_no,textViewOptions;
public DataViewHolder(View v, final PurchaseOrderReceiveOnClick purchaseOrderReceiveOnClick) {
super(v);
tv_row_po_no = v.findViewById(R.id.tv_row_po_no);
textViewOptions = v.findViewById(R.id.textViewOptions);
}
public void setPosition(int position) {
this.position = position;
}
public void setSingleBean(OrderListBaseModel.DataBean dataBean) {
this.dataBean = dataBean;
}
}
private class FooterViewHolder extends RecyclerView.ViewHolder {
public FooterViewHolder(View view) {
super(view);
}
}
}
here is xml code
loading_layout.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"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="#+id/linearRoot"
android:gravity="center_horizontal"
android:layout_marginTop="#dimen/_5sdp">
<com.app.trackpoint.custom_loader.MYLoader
android:layout_width="#dimen/_30sdp"
app:my_color="#color/colorAccent"
android:layout_height="#dimen/_30sdp" />
</LinearLayout>
I have been very meticulous in following this guide to implement pagination in my RecyclerView. Only difference is I'm using Retrofit to retrieve data from the API.
When I open my activity it stops after a while, and when I check Logcat, it says: IndexOutOfBoundsException: Inconsistency detected. Invalid view holder adapter positionViewHolder{31a22aa position=4 id=-1, oldPos=2,... This is what my RecyclerView adapter looks like:
public class CuratedSectionAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
private static int VIEW_TYPE_HEADER = 0;
private static int VIEW_TYPE_ITEM = 1;
private static int VIEW_TYPE_LOADING = 2;
private RecyclerView mRecyclerView;
private OnLoadMoreListener mOnLoadMoreListener;
private boolean isLoading;
private int visibleThreshold = 2;
private int lastVisibleItem, totalItemCount;
private List<Object> itemList;
public CuratedSectionAdapter(List<Object> itemList, RecyclerView recyclerView, LinearLayoutManager layoutManager) {
this.itemList = itemList;
this.mRecyclerView = recyclerView;
final LinearLayoutManager linearLayoutManager = layoutManager;
mRecyclerView.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 (!isLoading && totalItemCount <= (lastVisibleItem + visibleThreshold)) {
if (mOnLoadMoreListener != null) {
mOnLoadMoreListener.onLoadMore();
}
isLoading = true;
}
}
});
}
public void setOnLoadMoreListener(OnLoadMoreListener mOnLoadMoreListener) {
this.mOnLoadMoreListener = mOnLoadMoreListener;
}
private class ItemViewHolder extends RecyclerView.ViewHolder {
RecyclerView itemRecyclerView;
CuratedSectionNestedAdapter nestedAdapter;
LinearLayoutManager layoutManager;
ItemViewHolder(View view) {
super(view);
itemRecyclerView = view.findViewById(R.id.recyclerView_nested);
layoutManager = new LinearLayoutManager(view.getContext(), LinearLayoutManager.HORIZONTAL, false);
}
}
private class HeaderViewHolder extends RecyclerView.ViewHolder {
TextView textViewHeader;
Typeface montserratMedium = Typeface.createFromAsset(getApplicationContext().getAssets(), "fonts/Montserrat-Medium.ttf");
HeaderViewHolder(View view) {
super(view);
textViewHeader = view.findViewById(R.id.textView_header);
textViewHeader.setTypeface(montserratMedium);
}
}
private class LoadingViewHolder extends RecyclerView.ViewHolder {
ProgressBar progressBar;
LoadingViewHolder(View itemView) {
super(itemView);
progressBar = itemView.findViewById(R.id.progress_bar);
}
}
#Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
if (holder.getItemViewType() == VIEW_TYPE_HEADER) {
HeaderViewHolder viewHolder = (HeaderViewHolder) holder;
CuratedSectionHeader header = (CuratedSectionHeader) itemList.get(position);
viewHolder.textViewHeader.setText(header.getHeaderName());
} else if (holder.getItemViewType() == VIEW_TYPE_ITEM){
ItemViewHolder viewHolder = (ItemViewHolder) holder;
List<CuratedSectionItem> items = (List<CuratedSectionItem>) itemList.get(position);
if (viewHolder.nestedAdapter != null) {
viewHolder.nestedAdapter.setItems(items);
} else {
viewHolder.nestedAdapter = new CuratedSectionNestedAdapter(items);
viewHolder.itemRecyclerView.setLayoutManager(viewHolder.layoutManager);
viewHolder.itemRecyclerView.setAdapter(viewHolder.nestedAdapter);
}
} else if (holder.getItemViewType() == VIEW_TYPE_LOADING){
LoadingViewHolder viewHolder = (LoadingViewHolder) holder;
viewHolder.progressBar.setIndeterminate(true);
}
}
#Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
if (viewType == VIEW_TYPE_HEADER) {
return new HeaderViewHolder(LayoutInflater.from(parent.getContext())
.inflate(R.layout.main_explore_header_row, parent, false));
} else if (viewType == VIEW_TYPE_ITEM) {
return new ItemViewHolder(LayoutInflater.from(parent.getContext())
.inflate(R.layout.main_explore_row, parent, false));
} else if (viewType == VIEW_TYPE_LOADING) {
return new LoadingViewHolder(LayoutInflater.from(parent.getContext())
.inflate(R.layout.layout_loading_item, parent, false));
}
throw new RuntimeException("Adapter " + viewType + "not found");
}
#Override
public int getItemCount() {
return itemList.size();
}
#Override
public int getItemViewType(int position) {
if(isHeader(position)) {
return VIEW_TYPE_HEADER;
} else if(isLoading(position)) {
return VIEW_TYPE_LOADING;
} else {
return VIEW_TYPE_ITEM;
}
}
public boolean isHeader(int position) {
return itemList.get(position) instanceof CuratedSectionHeader;
}
public boolean isLoading(int position) {
return position > itemList.size();
}
public void setLoaded() {
isLoading = false;
}
}
It may have something to do with how I constructed LoadingViewHolder, but I think I did that one correctly. On the other hand, this is what the activity looks like:
public class ExploreFeedActivity extends Activity {
private RecyclerView recyclerView;
private CuratedSectionAdapter curatedSectionAdapter;
private LinearLayoutManager layoutManager;
private Sections curated;
int mStart = 0;
int mLimit = 2;
#Override
protected void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_explore);
curated = new Sections();
curated.loadSections(mStart, mLimit);
recyclerView = findViewById(R.id.recycler_view_main);
layoutManager = new LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false);
}
private class Sections {
ArrayList<CuratedSection> sections = new ArrayList<>();
public Thread[] thread;
private Sections() {}
public void setSections(ArrayList<CuratedSection> sections) {
this.sections = sections;
}
public void setSectionStories(String sectionId, List<CuratedSectionItem> stories) {
for(CuratedSection s : sections){
if(s.id != null && s.id.equals(sectionId)) {
s.stories = stories;
}
}
}
public void loadStories(String sessionKey) {
thread = new Thread[sections.size()];
for( int s = 0; s < sections.size(); s++) {
thread[s] = new Thread(new LoadStories(sessionKey, sections.get(s)));
thread[s].start();
}
for( int f = 0; f < sections.size(); f++) {
try {
thread[f].join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
curatedSectionAdapter = new CuratedSectionAdapter(this.getAdapterInfo(), recyclerView, layoutManager);
recyclerView.setLayoutManager(layoutManager);
recyclerView.setAdapter(curatedSectionAdapter);
curatedSectionAdapter.setOnLoadMoreListener(new OnLoadMoreListener() {
#Override
public void onLoadMore() {
Log.e("haint", "Load More");
curated.sections.add(null);
curatedSectionAdapter.notifyItemInserted(curated.sections.size() - 1);
// Load more data for recyclerview
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
Log.e("haint", "Load Further");
// Remove loading item
curated.sections.remove(curated.sections.size() - 1);
curatedSectionAdapter.notifyItemRemoved(curated.sections.size());
// Load data
curated.loadSections(2, 2);
curatedSectionAdapter.notifyDataSetChanged();
curatedSectionAdapter.setLoaded();
}
}, 5000);
}
});
}
public void loadSections(int start, int limit) {
swipeRefreshLayout.setRefreshing(false);
LoadSections load = new LoadSections(start, limit);
load.run();
}
public List<Object> getAdapterInfo() {
List<Object> list = new ArrayList<>();
for (int i = 0; i < sections.size(); i++) {
CuratedSection section = sections.get(i);
CuratedSectionHeader header = new CuratedSectionHeader();
header.setHeaderName(section.header);
list.add(header);
list.add(section.stories);
}
return list;
}
}
private class LoadSections implements Runnable {
int start, limit;
LoadSections(int start, int limit) {
this.start = start;
this.limit = limit;
}
#Override
public void run() {
SharedPreferences prefs = getSharedPreferences("user_session", MODE_PRIVATE);
final String sessionKey = prefs.getString("session_key", null);
Call<JsonArray> call;
call = TravelersApi.endpoint().getCuratedSections(sessionKey);
call.enqueue(new Callback<JsonArray>() {
#Override
public void onResponse(Call<JsonArray> call, Response<JsonArray> response) {
if(response.code() != 200) {
Toast.makeText(getApplicationContext(), "Cannot load page as of the moment.", Toast.LENGTH_SHORT).show();
return;
}
JsonArray rawSections = response.body();
if(rawSections.size() == 0) {
//TODO: show placeholder
return;
}
for(int i = start; i < start+limit; i++) {
JsonObject jSection = rawSections.get(i).getAsJsonObject();
final CuratedSection section = new CuratedSection();
section.id = jSection.get("id").getAsString();
section.header = jSection.get("section_header").getAsString();
section.isShown = jSection.get("is_shown").getAsBoolean();
section.stories = new ArrayList<>();
curated.sections.add(section);
}
curated.setSections(curated.sections);
curated.loadStories(sessionKey);
}
#Override
public void onFailure(Call<JsonArray> call, Throwable t) {
Log.d("ERROR!", t.toString());
t.printStackTrace();
}
});
}
}
private class LoadStories implements Runnable {
String sessionKey;
CuratedSection section;
LoadStories(String sessionKey, CuratedSection section) {
this.sessionKey = sessionKey;
this.section = section;
}
#Override
public void run() {
Call<JsonArray> subCall;
subCall = TravelersApi.endpoint().getCuratedSectionTopics(sessionKey, section.id);
try {
Response<JsonArray> response = subCall.execute();
if(response.code() != 200) {
Toast.makeText(getApplicationContext(), "Cannot load page as of the moment.", Toast.LENGTH_SHORT).show();
return;
}
JsonArray rawStories = response.body();
if(rawStories.size() == 0) {
//TODO: show placeholder
return;
}
ArrayList<CuratedSectionItem> stories = new ArrayList<>();
for(int i = 0; i < rawStories.size(); i++) {
JsonObject jStories = rawStories.get(i).getAsJsonObject();
JSONObject temp = new JSONObject(jStories.toString());
JsonObject author = jStories.get("author").getAsJsonObject();
CuratedSectionItem story = new CuratedSectionItem();
story.title = jStories.get("title").getAsString();
story.avatar = author.get("profile_photo").getAsString();
stories.add(story);
}
section.stories = stories;
} catch (IOException e) {
Log.d("ERROR!", e.toString());
e.printStackTrace();
} catch (JSONException e) {
e.printStackTrace();
}
}
}
It's interesting to note that my RecyclerView adapter curatedSectionAdapter was instantiated in the method loadStories inside the private class Sections. I have tried moving that part to onCreate but then the activity won't display anything. I also suspect that the way I constructed the for loop in the callback in LoadSections has something to do with the crash.
i m integrate recycleview with multiple view so below is my code
public class ActivityProdcutListWithMulipleView extends AppCompatActivity {
RecyclerView mRecyclerView;
Toolbar mToolbar;
PostParseGet mPostParseGet;
AllMethods mAllMethods;
GetProductListing mGetProductListing;
RecyclerView.LayoutManager mLayoutManager;
ProgressDialog mProgressDialog;
int page = 1;
int total = 0;
int totalFeature = 0;
int totalbanner = 0;
ImageView mImageViewBack;
ArrayList<GetProductListing.ListingBlock> mListingBlocks;
ArrayList<GetProductListing.ListingBlock> mListingBlocksFeature;
ArrayList<GetProductListing.ListingBlock> mListingBlocksBanner;
ArrayList<OrderItemDemo> mOrderItemDemos = new ArrayList<OrderItemDemo>();
GridLayoutManager mLayoutManagerGrid;
DifferentRowAdapter adapter;
private Handler handler;
ArrayList<GetProductListing.ListingBlock> adapterData;
public static Activity mActivity;
#RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
#Override
protected void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.layout_product_list);
mListingBlocks = new ArrayList<>();
mActivity = this;
mListingBlocksFeature = new ArrayList<>();
mListingBlocksBanner = new ArrayList<>();
mRecyclerView = (RecyclerView) findViewById(R.id.recycle);
mToolbar = (Toolbar) findViewById(R.id.toolbar);
mImageViewBack = (ImageView) mToolbar.findViewById(R.id.imgBack);
WebAPIApplication.mArrayListingAllProductBlocks.clear();
mPostParseGet = new PostParseGet(ActivityProdcutListWithMulipleView.this);
mAllMethods = new AllMethods(ActivityProdcutListWithMulipleView.this);
mGetProductListing = new GetProductListing();
mLayoutManagerGrid = new GridLayoutManager(ActivityProdcutListWithMulipleView.this, 2);
mLayoutManager = new LinearLayoutManager(ActivityProdcutListWithMulipleView.this);
mRecyclerView.setHasFixedSize(true);
mRecyclerView.setLayoutManager(mLayoutManagerGrid);
handler = new Handler();
adapterData = new ArrayList<>();
mRecyclerView.addOnScrollListener(new EndlessRecyclerGridOnScrollListener(mLayoutManagerGrid) {
#Override
public void onLoadMore(int current_page) {
if (WebAPIApplication.mArrayListingAllProductBlocks.size() < total) {
page++;
new getProductData(false, true).execute();
}
}
});
adapter = new DifferentRowAdapter(mOrderItemDemos);
mRecyclerView.setAdapter(adapter);
mLayoutManagerGrid.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() {
#Override
public int getSpanSize(int position) {
return adapter.getItemViewType(position) == OrderItemDemo.BANNER_TYPE ? 2 : 1;
}
});
if (mAllMethods.check_Internet() == true) {
new getProductData(true, false).execute();
} else {
mAllMethods.ShowDialog(ActivityProdcutListWithMulipleView.this, "", getString(R.string.net_not_available), "OK");
}
mImageViewBack.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
finish();
}
});
}
public static class DifferentRowAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
private int visibleThreshold = 5;
private int lastVisibleItem, totalItemCount;
private boolean loading;
boolean isLoading = false, isMoreDataAvailable = true;
private List<OrderItemDemo> mList;
OnLoadMoreListener loadMoreListener;
public DifferentRowAdapter(List<OrderItemDemo> list) {
this.mList = list;
}
#Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view;
switch (viewType) {
case OrderItemDemo.NORMAL_TYPE:
view = LayoutInflater.from(parent.getContext()).inflate(R.layout.row_list_file, parent, false);
return new ProductListRow(view);
case OrderItemDemo.FEATURE_TYPE:
view = LayoutInflater.from(parent.getContext()).inflate(R.layout.row_list_feature_file, parent, false);
return new ProductListRow(view);
case OrderItemDemo.BANNER_TYPE:
view = LayoutInflater.from(parent.getContext()).inflate(R.layout.row_list_file, parent, false);
return new ProductListRow(view);
}
return null;
}
#Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
if (position >= getItemCount() - 1 && isMoreDataAvailable && !isLoading && loadMoreListener != null) {
isLoading = true;
loadMoreListener.onLoadMore();
}
final OrderItemDemo object = mList.get(position);
if (object != null) {
switch (object.getmType()) {
case OrderItemDemo.NORMAL_TYPE:
((ProductListRow) holder).name.setText(object.getId() + " " + object.getTitle());
((ProductListRow) holder).price.setText(object.getType());
Picasso.with(mActivity)
.load(object.getImage())
.into(((ProductListRow) holder).mImageViewProduct);
((ProductListRow) holder).mImageViewBanner.setVisibility(View.GONE);
((ProductListRow) holder).mRelativeLayout.setVisibility(View.VISIBLE);
break;
case OrderItemDemo.FEATURE_TYPE:
((ProductListRow) holder).name.setText(object.getId() + " " + object.getTitle());
((ProductListRow) holder).price.setText(object.getType());
((ProductListRow) holder).mImageViewBanner.setVisibility(View.GONE);
((ProductListRow) holder).mRelativeLayout.setVisibility(View.VISIBLE);
Picasso.with(mActivity)
.load(object.getImage())
.into(((ProductListRow) holder).mImageViewProduct);
break;
case OrderItemDemo.BANNER_TYPE:
((ProductListRow) holder).price.setText(object.getType());
((ProductListRow) holder).mImageViewBanner.setVisibility(View.VISIBLE);
((ProductListRow) holder).mRelativeLayout.setVisibility(View.GONE);
break;
}
}
}
public void setMoreDataAvailable(boolean moreDataAvailable) {
isMoreDataAvailable = moreDataAvailable;
}
public void notifyDataChanged() {
notifyDataSetChanged();
isLoading = false;
}
interface OnLoadMoreListener {
void onLoadMore();
}
public void setLoadMoreListener(OnLoadMoreListener loadMoreListener) {
this.loadMoreListener = loadMoreListener;
}
#Override
public int getItemCount() {
if (mList == null)
return 0;
return mList.size();
}
#Override
public int getItemViewType(int position) {
if (mList != null) {
OrderItemDemo object = mList.get(position);
if (object != null) {
return object.getmType();
}
}
return 0;
}
}
public abstract class EndlessRecyclerGridOnScrollListener extends
RecyclerView.OnScrollListener {
public String TAG = EndlessRecyclerGridOnScrollListener.class
.getSimpleName();
private int previousTotal = 0;
private boolean loading = true;
private int visibleThreshold = 5;
int firstVisibleItem, visibleItemCount, totalItemCount;
private int current_page = 1;
private LinearLayoutManager mLinearLayoutManager;
public EndlessRecyclerGridOnScrollListener(
GridLayoutManager linearLayoutManager) {
this.mLinearLayoutManager = linearLayoutManager;
}
#Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);
visibleItemCount = recyclerView.getChildCount();
totalItemCount = mLinearLayoutManager.getItemCount();
firstVisibleItem = mLinearLayoutManager.findFirstVisibleItemPosition();
visibleThreshold = total;
if (loading) {
if (totalItemCount > previousTotal) {
loading = false;
previousTotal = totalItemCount;
}
}
if (!loading
&& (totalItemCount - visibleItemCount) <= (firstVisibleItem + visibleThreshold)) {
// End has been reached
// Do something
current_page++;
onLoadMore(current_page);
loading = true;
}
}
public abstract void onLoadMore(int current_page);
}
public class getProductData extends AsyncTask<Void, Void, Void> {
boolean showLoading;
boolean pagination;
public getProductData(boolean showLoading, boolean page) {
this.showLoading = showLoading;
this.pagination = page;
}
#Override
protected void onPreExecute() {
super.onPreExecute();
if (showLoading == true) {
mProgressDialog = ProgressDialog.show(ActivityProdcutListWithMulipleView.this, "", "Loading..");
}
}
#Override
protected Void doInBackground(Void... voids) {
mGetProductListing = (GetProductListing) mPostParseGet.getTopSearchData(mGetProductListing, page);
return null;
}
#Override
protected void onPostExecute(Void aVoid) {
super.onPostExecute(aVoid);
if (showLoading == true) {
if (mProgressDialog != null) {
mProgressDialog.dismiss();
}
}
if (mGetProductListing != null) {
try {
total = Integer.parseInt(mGetProductListing.getListing().getTotal());
if (mGetProductListing.getListing().getData().size() > 0) {
mListingBlocks = getProductBlock();
Log.e("FeatureSize", String.valueOf(mListingBlocksFeature.size()));
Log.e("BannerSize", String.valueOf(mListingBlocksBanner.size()));
for (int i = 0; i < WebAPIApplication.mArrayListingAllProductBlocks.size(); i++) {
if (WebAPIApplication.mArrayListingAllProductBlocks.get(i).getType().equalsIgnoreCase("product")) {
mOrderItemDemos.add(new OrderItemDemo(WebAPIApplication.mArrayListingAllProductBlocks.get(i).getId(), WebAPIApplication.mArrayListingAllProductBlocks.get(i).getTitle(), WebAPIApplication.mArrayListingAllProductBlocks.get(i).getType(), WebAPIApplication.mArrayListingAllProductBlocks.get(i).getMedium_image(), OrderItemDemo.NORMAL_TYPE));
} else if (WebAPIApplication.mArrayListingAllProductBlocks.get(i).getType().equalsIgnoreCase("featured")) {
mOrderItemDemos.add(new OrderItemDemo(WebAPIApplication.mArrayListingAllProductBlocks.get(i).getId(), WebAPIApplication.mArrayListingAllProductBlocks.get(i).getTitle(), WebAPIApplication.mArrayListingAllProductBlocks.get(i).getType(), WebAPIApplication.mArrayListingAllProductBlocks.get(i).getMedium_image(), OrderItemDemo.FEATURE_TYPE));
} else {
mOrderItemDemos.add(new OrderItemDemo(WebAPIApplication.mArrayListingAllProductBlocks.get(i).getId(), WebAPIApplication.mArrayListingAllProductBlocks.get(i).getTitle(), WebAPIApplication.mArrayListingAllProductBlocks.get(i).getType(), WebAPIApplication.mArrayListingAllProductBlocks.get(i).getMedium_image(), OrderItemDemo.BANNER_TYPE));
}
}
adapter = new DifferentRowAdapter(mOrderItemDemos);
if (pagination == false) {
mRecyclerView.setAdapter(adapter);
}
adapter.notifyDataSetChanged();
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
/*Get Product data */
public ArrayList<GetProductListing.ListingBlock> getProductBlock() {
ArrayList<GetProductListing.ListingBlock> mArrayListParserLog = new ArrayList<GetProductListing.ListingBlock>();
for (int i = 0; i < mGetProductListing.getListing().getData().size(); i++) {
GetProductListing.ListingBlock mParserLog = new GetProductListing.ListingBlock();
mParserLog.setId(mGetProductListing.getListing().getData().get(i).getId());
mParserLog.setType(mGetProductListing.getListing().getData().get(i).getType());
mParserLog.setTitle(mGetProductListing.getListing().getData().get(i).getTitle());
mParserLog.setDiscountSale(mGetProductListing.getListing().getData().get(i).getDiscountSale());
mParserLog.setDiscountSelling(mGetProductListing.getListing().getData().get(i).getDiscountSelling());
mParserLog.setPrice(mGetProductListing.getListing().getData().get(i).getPrice());
mParserLog.setAupc(mGetProductListing.getListing().getData().get(i).getAupc());
mParserLog.setSale_end(mGetProductListing.getListing().getData().get(i).getSale_end());
mParserLog.setSale_start(mGetProductListing.getListing().getData().get(i).getSale_start());
mParserLog.setSelling_price(mGetProductListing.getListing().getData().get(i).getSelling_price());
mParserLog.setProduct_rating(mGetProductListing.getListing().getData().get(i).getProduct_rating());
mParserLog.setSlug(mGetProductListing.getListing().getData().get(i).getSlug());
mParserLog.setSold_out(mGetProductListing.getListing().getData().get(i).getSold_out());
mParserLog.setImage(mGetProductListing.getListing().getData().get(i).getImage());
mParserLog.setSku_id(mGetProductListing.getListing().getData().get(i).getSku_id());
mParserLog.setMedium_image(mGetProductListing.getListing().getData().get(i).getMedium_image());
mArrayListParserLog.add(mParserLog);
WebAPIApplication.mArrayListingAllProductBlocks.add(mParserLog);
}
return mArrayListParserLog;
}
}
When i run above code in first page i get proper value but when i call second page at that time first page value will append again with second page data so any idea how can i solve this ? your all suggestions are appreciable
Try arraylist.clear() before loading Updated data into ArrayList to Avoid Duplicate Values.
1.Add this Code Before Oncreate
ArrayList<GetProductListing.ListingBlock> mArrayListParserLog = new ArrayList<GetProductListing.ListingBlock>();
and remove it from getProductBlock()
Add mArrayListParserLog.clear(); with in getProductBlock() method
public ArrayList<GetProductListing.ListingBlock> getProductBlock(){
mArrayListParserLog.clear();
I'm trying create a ListView to paginate results of a webservice RestFull. The problem is with onLoadMore that execute always in onCreateView when I set setOnScrollListener and this always returns all data from webservice. My doubt is how could I execute this onLoadMore only when I need more data touching on ListView and not when it open in onCreateView.
I'm trying this.
EndlessScrollListener
public abstract class EndlessScrollListener implements AbsListView.OnScrollListener {
// The minimum amount of items to have below your current scroll position
// before loading more.
private int visibleThreshold = 2;
// The current offset index of data you have loaded
private int currentPage = 0;
// The total number of items in the dataset after the last load
private int previousTotalItemCount = 0;
// True if we are still waiting for the last set of data to load.
private boolean loading = true;
// Sets the starting page index
private int startingPageIndex = 0;
public EndlessScrollListener() {
}
public EndlessScrollListener(int visibleThreshold) {
this.visibleThreshold = visibleThreshold;
}
public EndlessScrollListener(int visibleThreshold, int startPage) {
this.visibleThreshold = visibleThreshold;
this.startingPageIndex = startPage;
this.currentPage = startPage;
}
// This happens many times a second during a scroll, so be wary of the code you place here.
// We are given a few useful parameters to help us work out if we need to load some more data,
// but first we check if we are waiting for the previous load to finish.
#Override
public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount)
{
// If the total item count is zero and the previous isn't, assume the
// list is invalidated and should be reset back to initial state
if (totalItemCount < previousTotalItemCount) {
this.currentPage = this.startingPageIndex;
this.previousTotalItemCount = totalItemCount;
if (totalItemCount == 0) { this.loading = true; }
}
// If it’s still loading, we check to see if the dataset count has
// changed, if so we conclude it has finished loading and update the current page
// number and total item count.
if (loading && (totalItemCount > previousTotalItemCount)) {
loading = false;
previousTotalItemCount = totalItemCount;
currentPage++;
}
// If it isn’t currently loading, we check to see if we have breached
// the visibleThreshold and need to reload more data.
// If we do need to reload some more data, we execute onLoadMore to fetch the data.
if (!loading && (totalItemCount - visibleItemCount)<=(firstVisibleItem + visibleThreshold)) {
onLoadMore(currentPage + 1, totalItemCount);
loading = true;
}
}
// Defines the process for actually loading more data based on page
public abstract void onLoadMore(int page, int totalItemsCount);
#Override
public void onScrollStateChanged(AbsListView view, int scrollState) {
// Don't take any action on changed
}
}
Fragment
public class NoticiaFrag extends Fragment {
private ListView lvNoticias;
private List<Noticia> listaNoticias = new ArrayList<Noticia>();
private NoticiaListAdapter noticiaLA;
private static final String TAG = "NoticiaFrag";
protected ProgressDialog progressDialog;
//offset start in 0
private static Integer OFFSET = 0;
//singleton
private static NoticiaFrag mFrag;
public static NoticiaFrag newInstance() {
if(mFrag == null){
mFrag = new NoticiaFrag();
}
return mFrag;
}
public NoticiaFrag() {
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
View view = inflater.inflate(R.layout.noticia_frag, container, false);
lvNoticias = (ListView)view.findViewById(R.id.lvNoticias);
lvNoticias.setOnScrollListener(new EndlessScrollListener() {
#Override
public void onLoadMore(int page, int totalItemsCount) {
OFFSET += 2;
moreData();
}
});
return view;
}
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
getAllNoticias();
}
/** retorna todas as noticias */
private void getAllNoticias(){
progressDialog = new CustomProgressDialog().getCustomProgress(null, getView().getContext());
progressDialog.show();
try {
JsonObjectRequest app = new NoticiaDAO().getAllNoticias(OFFSET, new NoticiasAdapter() {
#Override
public void getAllNoticias(List<Noticia> lista) {
Log.w("SIZELIST->", lista.size() + "") ;
if(!lista.isEmpty()){
listaNoticias = lista;
noticiaLA = new NoticiaListAdapter(getView().getContext(), listaNoticias);
lvNoticias.setAdapter(noticiaLA);
}else{
Toast.makeText(getView().getContext(), "Nenhuma noticia encontrada", Toast.LENGTH_SHORT).show();
}
progressDialog.dismiss();
}
});
CustomVolleySingleton.getInstance().addToRequestQueue(app);
}catch (Exception e ){
Log.e("ERROR: " + TAG, "Method: " + "getAllNoticias: " + e);
}
}
// Append more data into the adapter
public void moreData() {
progressDialog = new CustomProgressDialog().getCustomProgress(null, getView().getContext());
progressDialog.show();
try {
JsonObjectRequest app = new NoticiaDAO().getAllNoticias(OFFSET, new NoticiasAdapter() {
#Override
public void getAllNoticias(List<Noticia> lista) {
if(listaNoticias.size() > 0){
noticiaLA.changeLista(lista);
Log.w("MORE_DATA->", noticiaLA.getCount() + "");
}else{
Toast.makeText(getView().getContext(), "Nenhuma noticia encontrada", Toast.LENGTH_SHORT).show();
}
progressDialog.dismiss();
}
});
CustomVolleySingleton.getInstance().addToRequestQueue(app);
}catch (Exception e ){
Log.e("ERROR: " + TAG, "Method: " + "getAllNoticias: " + e);
}
}
#Override
public void onResume() {
super.onResume();
ChangeActionBar.changeActionBar(getActivity(), "Notícias", false, "");
}
#Override
public void onPause() {
super.onPause();
CustomVolleySingleton.getInstance().cancelPendingRequests(CustomVolleySingleton.TAG);
ChangeActionBar.changeActionBar(getActivity(), null, false, "");
OFFSET = 0;
}
}
Problem solved.
Fragment
public class NoticiaFrag extends Fragment {
private ListView lvNoticias;
private ProgressBar pbProgress;
private List<Noticia> listaNoticias = new ArrayList<Noticia>();
private NoticiaListAdapter noticiaLA;
private static final String TAG = "NoticiaFrag";
protected ProgressDialog progressDialog;
//offset start in 0
private static Integer OFFSET = 0;
//singleton
private static NoticiaFrag mFrag;
public static NoticiaFrag newInstance() {
if(mFrag == null){
mFrag = new NoticiaFrag();
}
return mFrag;
}
public NoticiaFrag() {
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
View view = inflater.inflate(R.layout.noticia_frag, container, false);
lvNoticias = (ListView)view.findViewById(R.id.lvNoticias);
pbProgress = (ProgressBar)view.findViewById(R.id.pbProgress);
lvNoticias.setOnScrollListener(new EndlessScrollListener() {
#Override
public void onLoadMore(int page, int totalItemsCount) {
moreData();
}
});
return view;
}
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
getAllNoticias();
}
/** retorna todas as noticias */
private void getAllNoticias(){
pbProgress.setVisibility(View.VISIBLE);
try {
JsonObjectRequest app = new NoticiaDAO().getAllNoticias(OFFSET, new NoticiasAdapter() {
#Override
public void getAllNoticias(List<Noticia> lista) {
Log.w("SIZELIST->", lista.size() + "") ;
if(!lista.isEmpty()){
listaNoticias = lista;
noticiaLA = new NoticiaListAdapter(getView().getContext(), listaNoticias);
lvNoticias.setAdapter(noticiaLA);
}else{
Toast.makeText(getView().getContext(), "Nenhuma noticia encontrada", Toast.LENGTH_SHORT).show();
}
pbProgress.setVisibility(View.GONE);
}
});
CustomVolleySingleton.getInstance().addToRequestQueue(app);
}catch (Exception e ){
Log.e("ERROR: " + TAG, "Method: " + "getAllNoticias: " + e);
}
}
// Append more data into the adapter
public void moreData() {
OFFSET += 5;
Log.i("OFFSET", OFFSET + "");
pbProgress.setVisibility(View.VISIBLE);
try {
JsonObjectRequest app = new NoticiaDAO().getAllNoticias(OFFSET, new NoticiasAdapter() {
#Override
public void getAllNoticias(List<Noticia> lista) {
if(listaNoticias.size() > 0){
if(noticiaLA == null){
listaNoticias = lista;
noticiaLA = new NoticiaListAdapter(getView().getContext(), listaNoticias);
lvNoticias.setAdapter(noticiaLA);
}else{
noticiaLA.changeLista(lista);
}
Log.w("MORE_DATA->", noticiaLA.getCount() + "");
}else{
Toast.makeText(getView().getContext(), "Nenhuma noticia encontrada", Toast.LENGTH_SHORT).show();
}
pbProgress.setVisibility(View.GONE);
}
});
CustomVolleySingleton.getInstance().addToRequestQueue(app);
}catch (Exception e ){
Log.e("ERROR: " + TAG, "Method: " + "getAllNoticias: " + e);
}
}
#Override
public void onResume() {
super.onResume();
ChangeActionBar.changeActionBar(getActivity(), "Notícias", false, "");
}
#Override
public void onPause() {
super.onPause();
CustomVolleySingleton.getInstance().cancelPendingRequests(CustomVolleySingleton.TAG);
ChangeActionBar.changeActionBar(getActivity(), null, false, "");
OFFSET = 0;
}
}
Adapter
public class NoticiaListAdapter extends BaseAdapter {
private Context context;
private List<Noticia> lista;
public NoticiaListAdapter(Context context, List<Noticia> lista) {
this.context = context;
this.lista = lista;
}
public void changeLista(List<Noticia> lista){
this.lista.addAll(lista);
notifyDataSetChanged();
}
#Override
public int getCount() {
return lista.size();
}
#Override
public Object getItem(int position) {
return lista.get(position);
}
#Override
public long getItemId(int position) {
return position;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
final ViewHolder holder;
Noticia noticia = lista.get(position);
if (convertView == null) {
holder = new ViewHolder();
LayoutInflater inflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
convertView = inflater.inflate(R.layout.noticia_listadapter, parent, false);
holder.llNoticiaListAdapter = (LinearLayout) convertView.findViewById(R.id.llNoticiaListAdapter);
holder.sivNoticia = (SmartImageView)convertView.findViewById(R.id.sivNoticia);
holder.tvTitulo = (TextView) convertView.findViewById(R.id.tvTitulo);
holder.wvDescricao = (WebView) convertView.findViewById(R.id.wvDescricao);
holder.tvData = (TextView) convertView.findViewById(R.id.tvData);
holder.tvAutor = (TextView) convertView.findViewById(R.id.tvAutor);
convertView.setTag(holder);
}else{
holder = (ViewHolder)convertView.getTag();
}
if(noticia.getImage() == null){
holder.sivNoticia.setImageDrawable(context.getResources().getDrawable(R.drawable.no_image_news));
}else{
holder.sivNoticia.setImageUrl(WebServiceURL.getBaseWebServiceURL() + "app/webroot/img/noticias/" + noticia.getImage());
}
holder.tvTitulo.setText(noticia.getTitulo());
holder.wvDescricao.loadData(formatDescricao(noticia.getDescricao()), "text/html; charset=utf-8", null);
holder.tvData.setText(new DateControl().getDataHoraFormat(noticia.getCreated()));
holder.tvAutor.setText("Por: " + noticia.getUsuario());
return convertView;
}
private String formatDescricao(String descricao){
StringBuilder html = new StringBuilder();
html.append("<html>");
html.append("<body>");
html.append("<small>");
html.append("<p align=\"justify\" style=\"color:gray\">");
html.append(descricao);
html.append("</p");
html.append("</small>");
html.append("</body>");
html.append("</html>");
return html.toString();
}
private static class ViewHolder{
LinearLayout llNoticiaListAdapter;
SmartImageView sivNoticia;
TextView tvTitulo;
WebView wvDescricao;
TextView tvData;
TextView tvAutor;
}
}
WebService CakePHP
public function getAllNoticias(){
$json = $this->request->input("json_decode", true);
//$limit = $json["limit"];
$offset = $json["offset"];
$noticias = $this->Noticia->find("all", array("fields"=> array(
"Noticia.id",
"Noticia.titulo",
"Noticia.descricao",
"Noticia.usuario",
"Noticia.image",
"Noticia.created"
),
"order"=>"Noticia.created desc",
"offset"=>$offset,
"limit"=>5,
));
$this->set("noticias", $noticias);
$this->set("_serialize", array("result"=>"noticias"));
}