RecyclerView not updating items with position - android

I am loading items into a recyclerview from the server using JSON, maintaining an Adapter class to set data by hashmap method. I am using pagination for the recyclerView. Each page contains 10 items and the page increments after 10 items are reached.
The issue is that, after loaded, it's not refreshing when the users click the items.
HomeClass is a launcher activity:
public class HomeClass extends AppCompatActivity {
protected void onCreate(Bundle savedInstanceState) {
sendID(url);
}
public void sendID(final String url){
if (progress == null) {
progress = new ProgressDialog(this);
progress.show();
}
Constant.Home_Posts.clear();
new Thread(new Runnable(){
#Override
public void run() {
///pagecount is 1 in HomeClass by default
JSONObject responseObj = new JSONObject(arg0);
HashMap<String, String> map = new HashMap<String, String>();
map.put(key,value);
Constant.Home_Posts.add(map);
}
}
if (progress!=null) {
if (progress.isShowing()) {
progress.dismiss();
progress = null;
Intent intent = new Intent(HomeClass.this, Home.class);
startActivity(intent);
finish();
}
}
The second class, Home, only contais onBindViewHolder
public class Home extends AppCompatActivity {
protected void onCreate(Bundle savedInstanceState) {
}
private void getPostCount(final String URl) {
if (progress == null) {
progress = new ProgressDialog(this);
progress.show();
}
new Thread(new Runnable() {
#Override
public void run() {
viewposition = viewposition + 10;
getPostUrl = "url+userid="+ userID+ "&page="+ page_count;
//pagecount is 2 in 'Home' by default and then icrements
JSONObject responseObj = new JSONObject(arg0);
HashMap<String, String> map = new HashMap<String, String>();
map.put(key,value);
Constant.Home_Posts.add(map);
'
'
}
}
}
page_count++;
Adapter Class:
class MyAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
public void onBindViewHolder(RecyclerView.ViewHolder holder,final int i) {
if (Constant.Home_Posts.size() - 1 == i) {
Constant.Home_Posts.clear();
getPostCount("url+ userID + "&page=" + page_count);
}
//set value using hashmap method from server
viewHolder.imgComment.setText(value) //with integer values
//OmCLick to update datas from user
viewHolder.imgComment.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
//get layout view by LayoutIflater and load data from server
// create alert dialog
final AlertDialog alertDialog = alertDialogBuilder.create();
//user can comment anyhting,if success comment value in count
//should increment or comments should not change
sendComment.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (commentStatus == 0) {
} else {
alertDialog.cancel();
String putLikesValue=(Integer.toString(Integer.parseInt(
Constant.Home_Posts.get(i).get("comments_count"))+1));
viewHolder.txtComment.setText(putLikesValue+"Comments");
notifyDataSetChanged();
notifyItemChanged(i);
});
}
The result is like,
the old items are listing with the updated item (newly inserted item).
How do I insert the item with position properly?

Hello use this for load all data.
public FriendsAdapterSwipe(List<FriendListModel> alFriendListModel,RecyclerView recyclerView,Context context)
{
this.alFriendListModel = alFriendListModel;
this.context=context;
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)) {
if (onLoadMoreListener != null) {
onLoadMoreListener.onLoadMore();
}
loading = true;
}
}
});
}
}
#Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
RecyclerView.ViewHolder vh;
if (viewType == VIEW_ITEM)
{
View itemView = LayoutInflater.from(parent.getContext()).inflate(R.layout.raw_friends_swipe, parent, false);
vh = new CustomViewHolder(itemView);
} else
{
View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.progressbar_item, parent, false);
vh = new ProgressViewHolder(v);
}
return vh;
}
#Override
public void onBindViewHolder(final RecyclerView.ViewHolder holder, int position) {
if (holder instanceof CustomViewHolder)
{
Typeface AvenirNextRegular = Fonts.AvenirNextRegular(context);
holder.setIsRecyclable(false);
FriendListModel model = alFriendListModel.get(position);
((CustomViewHolder) holder).txtUname.setText(model.getFullName());
((CustomViewHolder) holder).txtUname.setTypeface(AvenirNextRegular);
if (alFriendListModel.get(position).getIsImageAvaible().equalsIgnoreCase("1"))
{
Glide.clear(((CustomViewHolder) holder).imgProfile);
Glide.with(context).load(WebField.PROFILE_URL + alFriendListModel.get(position).getFriendId()
+ "_small.png").asBitmap()
.placeholder(R.drawable.user_pic).skipMemoryCache(true)
.diskCacheStrategy(DiskCacheStrategy.ALL).
fitCenter().into(new BitmapImageViewTarget(((CustomViewHolder) holder).imgProfile)
{
#Override
protected void setResource(Bitmap resource)
{
Drawable d = new BitmapDrawable(context.getResources(), resource);
((CustomViewHolder) holder).imgProfile.setImageDrawable(d);
}
});
}
}
else
{
((CustomViewHolder) holder).imgProfile.setImageResource(R.drawable.user_pic);
}
}
#Override
public int getItemCount() {
return alFriendListModel.size();
}
#Override
public int getItemViewType(int position) {
return alFriendListModel.get(position) != null ? VIEW_ITEM : VIEW_PROG;
}
public interface OnLoadMoreListener {
void onLoadMore();
}
public void setOnLoadMoreListener(OnLoadMoreListener onLoadMoreListener) {
this.onLoadMoreListener = onLoadMoreListener;
}
public static class CustomViewHolder extends RecyclerView.ViewHolder
{
TextView txtUname;
CircularImageView imgProfile;;
public CustomViewHolder(View itemView) {
super(itemView);
txtUname = (TextView) itemView.findViewById(R.id.txtUname);
imgProfile = (CircularImageView) itemView.findViewById(R.id.imgProfile);
}
}
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 setLoaded() {
loading = false;
}

You can use loader for set data based on page.
public EventAdapter(final List<EventsModel> myDataSet, RecyclerView recyclerView, Context context) {
mDataset = myDataSet;
this.context = context;
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 mDataset.get(position) != null ? VIEW_ITEM : VIEW_PROG;
}
#Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
RecyclerView.ViewHolder vh;
if (viewType == VIEW_ITEM) {
View itemView = LayoutInflater.from(parent.getContext()).inflate(R.layout.raw_eventlist, parent, false);
itemView.setOnClickListener(EventFragment.myOnClickListener);
vh = new TextViewHolder(itemView);
} else {
View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.progressbar_item, parent, false);
vh = new ProgressViewHolder(v);
}
return vh;
}
#Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
if (holder instanceof TextViewHolder) {
Typeface AvenirNextRegular = Fonts.AvenirNextRegular(context);
((TextViewHolder) holder).txtEventName.setTypeface(AvenirNextRegular);
((TextViewHolder) holder).txtEventDescription.setTypeface(AvenirNextRegular);
((TextViewHolder) holder).txtDate.setTypeface(AvenirNextRegular);
((TextViewHolder) holder).txtTime.setTypeface(AvenirNextRegular);
((TextViewHolder) holder).txtEventName.setText(mDataset.get(position).getStrEventName());
((TextViewHolder) holder).txtEventDescription.setText(mDataset.get(position).getStrDescription());
((TextViewHolder) holder).txtDate.setText(mDataset.get(position).getStrStartDate());
((TextViewHolder) holder).txtTime.setText(mDataset.get(position).getStrStartTime());
final RecyclerView.ViewHolder tempHolder = holder;
String eventId = mDataset.get(position).getStrEventId();
if (mDataset.get(position).getIsImageAvailable().equalsIgnoreCase("1"))
{
Glide.clear(((TextViewHolder) holder).imgProfile);
Glide.with(context).load(WebField.EVENT_URL + eventId + "_small.png").asBitmap()
.placeholder(R.drawable.event_img).skipMemoryCache(true).
diskCacheStrategy(DiskCacheStrategy.ALL).fitCenter()
.into(new BitmapImageViewTarget(((TextViewHolder) holder).imgProfile) {
#Override
protected void setResource(Bitmap resource) {
Drawable d = new BitmapDrawable(context.getResources(), resource);
((TextViewHolder) tempHolder).imgProfile.setImageDrawable(d);
}
});
}
else
{
((TextViewHolder) holder).imgProfile.setImageResource(R.drawable.event_img);
}
}
}
public void setLoaded() {
loading = false;
}
#Override
public int getItemCount() {
return mDataset.size();
}
public void setOnLoadMoreListener(OnLoadMoreListener onLoadMoreListener) {
this.onLoadMoreListener = onLoadMoreListener;
}
public interface OnLoadMoreListener {
void onLoadMore();
}
public static class TextViewHolder extends RecyclerView.ViewHolder {
CircularImageView imgProfile;
TextView txtEventName;
TextView txtEventDescription;
TextView txtDate;
TextView txtTime;
ImageView btnNext;
public TextViewHolder(View view) {
super(view);
this.imgProfile = (CircularImageView) view.findViewById(R.id.imgProfile);
this.txtEventName = (TextView) view.findViewById(R.id.txtEventName);
this.txtEventDescription = (TextView) view.findViewById(R.id.txtEventDescription);
this.txtDate = (TextView) view.findViewById(R.id.txtDate);
this.txtTime = (TextView) view.findViewById(R.id.txtTime);
this.btnNext = (ImageView) view.findViewById(R.id.btnNext);
}
}
public static class ProgressViewHolder extends RecyclerView.ViewHolder {
public ProgressBar progressBar;
public ProgressViewHolder(View v) {
super(v);
progressBar = (ProgressBar) v.findViewById(R.id.progressBar);
progressBar.getIndeterminateDrawable().setColorFilter(Color.BLUE, PorterDuff.Mode.MULTIPLY);
}
}

Related

Load 10 items by 10 items of Recyclerview

From JSON file I get almost (200-300 image URL), I'm trying to load 10 images by 10 images to make the images load quickly instead of loading all the images (200-300) at once .but I have a problem RecyclerView Stop scrolling after the first 10 items, here's what I have tried:
InfiniteScrollListener.java
private void initInfiniteScrollListener(LinearLayoutManager mLayoutManager) {
infiniteScrollListener = new InfiniteScrollListener(mLayoutManager) {
#Override
public void onLoadMore(int page) {
pb.setVisibility(View.VISIBLE);
refreshContent();
}
};
recyclerView.addOnScrollListener(infiniteScrollListener);
}
Method to set adapter:
private void refreshContent() {
fetchRemoteData(new DataStatus() {
#Override
public void onSuccess(List<Post> posts) {
loading.setVisibility(View.GONE);
pb.setVisibility(View.GONE);
if (adapter == null) {
adapter = new MyAdapter(posts, getActivity(), new RecyclerViewClickListener() {
#Override
public void onClick(View view, Post post) {
}
});
recyclerView.setAdapter(adapter);
} else {
int position = adapter.getItemCount();
adapter.getItems().addAll(posts);
adapter.notifyItemRangeInserted(position, position + 10);
}
}
#Override
public void onError(Exception e) {
slowinternetconnection();
}
});
}
Fetching data:
private void fetchRemoteData(final DataStatus callback) {
StringRequest stringRequest = new StringRequest(Request.Method.GET,
URL_DATA,
new Response.Listener<String>() {
#Override
public void onResponse(String s) {
List<Post> listItems = new ArrayList<>();
List<Post> PagintationList = new ArrayList<>();
try {
JSONObject jsonObject = new JSONObject(s);
JSONArray array = jsonObject.getJSONArray("bgs");
for (int i = 0; i < array.length(); i++) {
JSONObject o = array.getJSONObject(i);
Post item = new Post(
o.optString("img"),
o.optString("name")
);
listItems.add(item);
}
for (int count = resetNumber; count < 10; count++) {
PagintationList.add(listItems.get(count));
}
resetNumber = PagintationList.size() + 1;
callback.onSuccess(PagintationList);
} catch (JSONException e) {
slowinternetconnection();
}
}
},
new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
callback.onError(error);
}
});
RequestQueue requestQueue = Volley.newRequestQueue(getActivity().getApplicationContext());
stringRequest.setShouldCache(false);
requestQueue.getCache().clear();
requestQueue.add(stringRequest);
}
What I want is:
From 250 images for example, I want to load 10 images each time user scroll recyclerview, until 250 image to have been completed
private void populateData() {
int i = 0;
while (i < 10) {
rowsArrayList.add("Item " + i);
i++;
}
}
private void initAdapter() {
recyclerViewAdapter = new RecyclerViewAdapter(rowsArrayList);
recyclerView.setAdapter(recyclerViewAdapter);
}
private void initScrollListener() {
recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
#Override
public void onScrollStateChanged(#NonNull RecyclerView recyclerView, int newState) {
super.onScrollStateChanged(recyclerView, newState);
}
#Override
public void onScrolled(#NonNull RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);
LinearLayoutManager linearLayoutManager = (LinearLayoutManager) recyclerView.getLayoutManager();
if (!isLoading) {
if (linearLayoutManager != null && linearLayoutManager.findLastCompletelyVisibleItemPosition() == rowsArrayList.size() - 1) {
//bottom of list!
loadMore();
isLoading = true;
}
}
}
});
}
private void loadMore() {
rowsArrayList.add(null);
recyclerViewAdapter.notifyItemInserted(rowsArrayList.size() - 1);
Handler handler = new Handler();
handler.postDelayed(new Runnable() {
#Override
public void run() {
rowsArrayList.remove(rowsArrayList.size() - 1);
int scrollPosition = rowsArrayList.size();
recyclerViewAdapter.notifyItemRemoved(scrollPosition);
int currentSize = scrollPosition;
int nextLimit = currentSize + 10;
while (currentSize - 1 < nextLimit) {
rowsArrayList.add("Item " + currentSize);
currentSize++;
}
recyclerViewAdapter.notifyDataSetChanged();
isLoading = false;
}
}, 2000);
}
In Adapter Class
public class RecyclerViewAdapter extends RecyclerView.Adapter {
private final int VIEW_TYPE_ITEM = 0;
private final int VIEW_TYPE_LOADING = 1;
public List<String> mItemList;
public RecyclerViewAdapter(List<String> itemList) {
mItemList = itemList;
}
#NonNull
#Override
public RecyclerView.ViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
if (viewType == VIEW_TYPE_ITEM) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_row, parent, false);
return new ItemViewHolder(view);
} else {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_loading, parent, false);
return new LoadingViewHolder(view);
}
}
#Override
public void onBindViewHolder(#NonNull RecyclerView.ViewHolder viewHolder, int position) {
if (viewHolder instanceof ItemViewHolder) {
populateItemRows((ItemViewHolder) viewHolder, position);
} else if (viewHolder instanceof LoadingViewHolder) {
showLoadingView((LoadingViewHolder) viewHolder, position);
}
}
#Override
public int getItemCount() {
return mItemList == null ? 0 : mItemList.size();
}
/**
* The following method decides the type of ViewHolder to display in the RecyclerView
*
* #param position
* #return
*/
#Override
public int getItemViewType(int position) {
return mItemList.get(position) == null ? VIEW_TYPE_LOADING : VIEW_TYPE_ITEM;
}
private class ItemViewHolder extends RecyclerView.ViewHolder {
TextView tvItem;
public ItemViewHolder(#NonNull View itemView) {
super(itemView);
tvItem = itemView.findViewById(R.id.tvItem);
}
}
private class LoadingViewHolder extends RecyclerView.ViewHolder {
ProgressBar progressBar;
public LoadingViewHolder(#NonNull View itemView) {
super(itemView);
progressBar = itemView.findViewById(R.id.progressBar);
}
}
private void showLoadingView(LoadingViewHolder viewHolder, int position) {
//ProgressBar would be displayed
}
private void populateItemRows(ItemViewHolder viewHolder, int position) {
String item = mItemList.get(position);
viewHolder.tvItem.setText(item);
}
Check out this link
https://www.journaldev.com/24041/android-recyclerview-load-more-endless-scrolling
you can load 10 items first then refreshing and load next 10.

Stop recyclerview scrolling when loading- Android

When the RecyclerView Reaches the end it will load another pair of data
but while loading RecyclerView, the empty view of RecyclerView is visible and if the empty view is clicked it gives me ArrayBoundaryExeption
so i need to stop scrolling when it isLoading
mRecyclerView = (RecyclerView) findViewById(R.id.recycleView);
mRecyclerView.setLayoutManager(new LinearLayoutManager(this));
mUserAdapter = new UserAdapter();
mRecyclerView.setAdapter(mUserAdapter);
mUserAdapter.setOnLoadMoreListener(new OnLoadMoreListener() {
#Override
public void onLoadMore() {
/* mRecyclerView.stopNestedScroll();
mRecyclerView.stopScroll();
CustomGridLayoutManager ss= new CustomGridLayoutManager(WorkNow.this);
ss.setScrollEnabled(false);
mRecyclerView.setNestedScrollingEnabled(false);
linearLayoutManager.canScrollVertically(); */
// if (Choose.equals("Local")) {
Log.e("haint", "Load More");
mUsers.add(null);
mUserAdapter.notifyItemInserted(mUsers.size() - 1);
dataLoadMore();
//mRecyclerView.setNestedScrollingEnabled(false);
// mRecyclerView.stopScroll();
//Load more data for reyclerview
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
/* mRecyclerView.stopNestedScroll();
mRecyclerView.stopScroll();
CustomGridLayoutManager ss= new CustomGridLayoutManager(WorkNow.this);
ss.setScrollEnabled(false);
mRecyclerView.setNestedScrollingEnabled(false);
linearLayoutManager.canScrollVertically(); */
Log.e("haint", "Load More 2");
// mRecyclerView.setNestedScrollingEnabled(false);
// mRecyclerView.stopScroll();
//Remove loading item
if (!mUsers.isEmpty()) {
mUsers.remove(mUsers.size() - 1);
mUserAdapter.notifyItemRemoved(mUsers.size());
}
for (int i = 0; i < lenMore; i++) {
LocalListView localListView = new LocalListView();
localListView.setJob_local_id(job_local_idM[i]);
localListView.setJob_typess(job_typessM[i]);
mUsers.add(localListView);
}
mUserAdapter.notifyDataSetChanged();
mUserAdapter.setLoaded();
}
}, 5000);
}
});
RecycleClick.addTo(mRecyclerView).setOnItemClickListener(new RecycleClick.OnItemClickListener() {
#Override
public void onItemClicked(RecyclerView recyclerView, int position, View v) {
// YOUR CODE
if(mUserAdapter.isLoading){
//
/* mRecyclerView.stopNestedScroll();
mRecyclerView.stopScroll();
CustomGridLayoutManager ss= new
CustomGridLayoutManager(WorkNow.this);
ss.setScrollEnabled(false);
mRecyclerView.setNestedScrollingEnabled(false);
linearLayoutManager.canScrollVertically(); */
Toast.makeText(getApplicationContext(),"Loading please
wait...",Toast.LENGTH_LONG).show();
}else if(position!=-1){
Intent is = new Intent(getApplicationContext(), WorkProfileLocal.class);
is.putExtra("job_local_idG", mUsers.get(position).getJob_local_id());
is.putExtra("user_idsG", mUsers.get(position).getUser_ids());
startActivity(is);
}
}
});
static class UserViewHolder extends RecyclerView.ViewHolder {
public TextView tvJobTitle;
public TextView tvJobWork;
public UserViewHolder(View itemView) {
super(itemView);
tvHirerName = (TextView) itemView.findViewById(R.id.tvWhatWork);
tvJobTitle = (TextView) itemView.findViewById(R.id.tvJobTitle);
}
}
static class LoadingViewHolder extends RecyclerView.ViewHolder {
public ProgressBar progressBar;
public LoadingViewHolder(View itemView) {
super(itemView);
progressBar = (ProgressBar) itemView.findViewById(R.id.progressBar1);
}
}
class UserAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
private final int VIEW_TYPE_ITEM = 0;
private final int VIEW_TYPE_LOADING = 1;
private OnLoadMoreListener mOnLoadMoreListener;
private boolean isLoading;
private int visibleThreshold = 5;
private int lastVisibleItem, totalItemCount;
public UserAdapter() {
final LinearLayoutManager linearLayoutManager = (LinearLayoutManager) mRecyclerView.getLayoutManager();
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();
/* mRecyclerView.stopNestedScroll();
mRecyclerView.stopScroll();
CustomGridLayoutManager ss= new CustomGridLayoutManager(WorkNow.this);
ss.setScrollEnabled(false);
mRecyclerView.setNestedScrollingEnabled(false);
linearLayoutManager.canScrollVertically();*/
}
isLoading = true;
/* mRecyclerView.stopNestedScroll();
mRecyclerView.stopScroll();
CustomGridLayoutManager ss= new CustomGridLayoutManager(WorkNow.this);
ss.setScrollEnabled(false);
mRecyclerView.setNestedScrollingEnabled(false);
linearLayoutManager.canScrollVertically(); */
}
}
});
}
public void setOnLoadMoreListener(OnLoadMoreListener mOnLoadMoreListener) {
this.mOnLoadMoreListener = mOnLoadMoreListener;
}
#Override
public int getItemViewType(int position) {
return mUsers.get(position) == null ? VIEW_TYPE_LOADING : VIEW_TYPE_ITEM;
}
#Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
if (viewType == VIEW_TYPE_ITEM) {
View view = LayoutInflater.from(WorkNow.this).inflate(R.layout.list_view_local_jobs, parent, false);
return new UserViewHolder(view);
} else if (viewType == VIEW_TYPE_LOADING) {
View view = LayoutInflater.from(WorkNow.this).inflate(R.layout.layout_loading_item, parent, false);
/* mRecyclerView.stopNestedScroll();
mRecyclerView.stopScroll();
CustomGridLayoutManager ss= new CustomGridLayoutManager(WorkNow.this);
ss.setScrollEnabled(false);
mRecyclerView.setNestedScrollingEnabled(false);
linearLayoutManager.canScrollVertically(); */
return new LoadingViewHolder(view);
}
return null;
}
#Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
if (holder instanceof UserViewHolder) {
LocalListView localListView = mUsers.get(position);
UserViewHolder userViewHolder = (UserViewHolder) holder;
userViewHolder.tvHirerName.setText(localListView.getUser_names());
userViewHolder.tvJobTitle.setText(localListView.getJob_titles().replaceAll("_", " "));
if (localListView.getImage().isEmpty()) {
userViewHolder.hirerPicLocal.setImageResource(R.drawable.blank_low);
} else{
Picasso.with(getApplicationContext())
.load(localListView.getImage())
.into(userViewHolder.hirerPicLocal);
}
} else if (holder instanceof LoadingViewHolder) {
LoadingViewHolder loadingViewHolder = (LoadingViewHolder) holder;
loadingViewHolder.progressBar.setIndeterminate(true);
/* mRecyclerView.stopNestedScroll();
mRecyclerView.stopScroll();
CustomGridLayoutManager ss= new CustomGridLayoutManager(WorkNow.this);
ss.setScrollEnabled(false);
mRecyclerView.setNestedScrollingEnabled(false);
linearLayoutManager.canScrollVertically(); */
}
}
#Override
public int getItemCount() {
return mUsers == null ? 0 : mUsers.size();
}
public void setLoaded() {
isLoading = false;
}
}
This Class i got from StackOverFlow to StopScroll But it is not working.
public class CustomGridLayoutManager extends LinearLayoutManager {
private boolean isScrollEnabled = true;
public CustomGridLayoutManager(Context context) {
super(context);
}
public void setScrollEnabled(boolean flag) {
this.isScrollEnabled = flag;
}
#Override
public boolean canScrollVertically() {
//Similarly you can customize "canScrollHorizontally()" for managing horizontal scroll
return isScrollEnabled && super.canScrollVertically();
}
}
LinearLayoutManager linearLayoutManager = new LinearLayoutManager(WorkNow.this) {
#Override
public boolean canScrollVertically() {
return false;
}
};

delay in downloading image from server with volley

I try to downloading image from server with volley and show them in recyclerview.
it is work correctly but the downloading image is very low.
(the size of each image approximately 50 kb).
what can i do?
is there better and optimize code than it?
this is my helper class:
public class StartActivity {
// for recyclerView - downLoad Data
private static final int LIMIT = 6;
OnLoadMoreListener onLoadMoreListener;
int idImage = 1;
private List<StructUser> structList = new ArrayList<>();
private AdapterUser adapter;
private int CURRENT_ITEM = 1;
private Context context;
private String TAG = StartActivity.class.getSimpleName();
//----------------------------------------------------
public StartActivity(Context context) {
this.context = context;
}
public void getDataAndSetInRecyclerView(RecyclerView recyclerView) {
loadData(CURRENT_ITEM);
recyclerView.setLayoutManager(new LinearLayoutManager(context));
adapter = new AdapterUser(recyclerView, structList, context);
onLoadMoreListener = new OnLoadMoreListener() {
#Override
public void onLoadMore() {
structList.add(null);
adapter.notifyDataSetChanged();
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
structList.remove(structList.size() - 1);
// adapter.notifyItemRemoved(structList.size());
loadData(CURRENT_ITEM);
}
}, 2000);
}
};
adapter.setOnLoadMoreListener(onLoadMoreListener);
recyclerView.setAdapter(adapter);
}
private void loadData(final int CURRENT_ITEM) {
String url = Config.DATA_URL + CURRENT_ITEM;
JsonArrayRequest jsonArrayRequest = new JsonArrayRequest(url,
new Response.Listener<JSONArray>() {
#Override
public void onResponse(JSONArray response) {
ActivityMain.hideProgressBar();
try {
for (int i = 0; i < response.length(); i++) {
JSONObject jsonObject = response.getJSONObject(i);
StructUser structUser = new StructUser();
if (!jsonObject.isNull(Config.TAG_TITLE))
structUser.setNetworkImageView(jsonObject.getString(Config.TAG_TITLE));
if (!jsonObject.isNull(Config.TAG_IMAGE_URL)) {
structUser.setNetworkImageView(Config.IMG_SERVER + idImage + ".png");
idImage++;
}
structList.add(structUser);
}
adapter.notifyDataSetChanged();
adapter.setLoaded();
// not show progressBar at end of list when get all data
if (response.toString().contains("[]")) {
adapter.reachEndList();
Toast.makeText(context, "not More Data to Show", Toast.LENGTH_SHORT).show();
}
} catch (JSONException e) {
e.printStackTrace();
}
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
// hide progressBar
ActivityMain.hideProgressBar();
Log.e(TAG, "Login Error: " + error.getMessage());
Toast.makeText(context,
error.getMessage(), Toast.LENGTH_LONG).show();
}
});
AppController.getInstance().addToRequestQueue(jsonArrayRequest, TAG);
this.CURRENT_ITEM = this.CURRENT_ITEM + LIMIT;
}
}
this is my adapter:
public class AdapterUser extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
private final int VIEW_TYPE_ITEM = 0;
private final int VIEW_TYPE_LOADING = 1;
public int visibleThreshold = 2;
boolean isLoading;
private int lastVisibleItem, totalItemCount;
private List<StructUser> structList = new ArrayList<>();
private OnLoadMoreListener mOnLoadMoreListener;
private Context context;
// load image from server -------------------------------------------------
private static ImageLoader imageLoader = ImageLoader.getInstance();
public static DisplayImageOptions options = new DisplayImageOptions.Builder()
.showImageOnLoading(R.mipmap.ic_cloud_download)
.showImageForEmptyUri(R.mipmap.ic_picture)
.showImageOnFail(android.R.drawable.ic_dialog_alert)
.cacheInMemory(true)
.cacheOnDisk(false)
.considerExifParams(true)
.bitmapConfig(Bitmap.Config.RGB_565)
.build();
//---------------------------------------------------------------
public AdapterUser(RecyclerView mRecyclerView, List<StructUser> structList, Context context) {
this.context = context;
this.structList = structList;
final LinearLayoutManager linearLayoutManager = (LinearLayoutManager) mRecyclerView.getLayoutManager();
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 <= visibleThreshold + (lastVisibleItem)) {
if (mOnLoadMoreListener != null) {
mOnLoadMoreListener.onLoadMore();
}
isLoading = true;
}
}
});
}
public void setLoaded() {
isLoading = false;
}
public void reachEndList() {
isLoading = true;
}
//========================================================
#Override
public int getItemViewType(int position) {
return structList.get(position) == null ? VIEW_TYPE_LOADING : VIEW_TYPE_ITEM;
}
#Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup viewGroup, int viewType) {
if (viewType == VIEW_TYPE_ITEM) {
View view = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.adapter_start_activity , viewGroup, false);
return new UserViewHolder(view);
} else if (viewType == VIEW_TYPE_LOADING) {
View view = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.layout_loading_item, viewGroup, false);
return new LoadingViewHolder(view);
}
return null;
}
#Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
if (holder instanceof UserViewHolder) {
UserViewHolder userViewHolder = (UserViewHolder) holder;
StructUser user = structList.get(position);
userViewHolder.title.setText(user.getTitle());
// load image from server
imageLoader.displayImage(user.getNetworkImageView(), userViewHolder.networkImageView, options);
} else if (holder instanceof LoadingViewHolder) {
LoadingViewHolder loadingViewHolder = (LoadingViewHolder) holder;
loadingViewHolder.progressBar.setIndeterminate(true);
}
}
#Override
public int getItemCount() {
return structList == null ? 0 : structList.size();
}
public void setOnLoadMoreListener(OnLoadMoreListener mOnLoadMoreListener) {
this.mOnLoadMoreListener = mOnLoadMoreListener;
}
class UserViewHolder extends RecyclerView.ViewHolder {
public TextView title;
// for download & cash image
public ImageView networkImageView;
public UserViewHolder(View itemView) {
super(itemView);
title = (TextView) itemView.findViewById(R.id.txtTitle);
networkImageView = (ImageView) itemView.findViewById(R.id.networkImageView);
}
}
class LoadingViewHolder extends RecyclerView.ViewHolder {
public ProgressBar progressBar;
public LoadingViewHolder(View itemView) {
super(itemView);
progressBar = (ProgressBar) itemView.findViewById(R.id.progressBar1);
}
}
}
Use Glide for downloading Image...
Glide.with(ActivityName.this)
.load(image_url)
.into(imageView_object);
It will download image and set in ImageView.

ClassCastException:MyViewHolder cannot be cast to ProgressViewHolder

Iam trying to implement Endless Infinite Scrolling with RecyclerView, but I am only getting all records and even not getting any progress while trying to scroll at bottom.
and see this my code
this is my News_Adapter
public class NewsAdapter extends RecyclerView.Adapter {
private final int VIEW_ITEM = 1;
private final int VIEW_PROG = 0;
private List<News> newsList;
private Context context;
// 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 NewsAdapter(List<News> newsList , RecyclerView recyclerView){
this.newsList = newsList;
this.context = context;
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 void onScrollStateChanged(RecyclerView recyclerView, int newState) {
super.onScrollStateChanged(recyclerView, newState);
// When went to the end of the list, load more posts
if (newState == RecyclerView.SCROLL_STATE_IDLE) {
if (linearLayoutManager.findLastVisibleItemPosition() >= linearLayoutManager.getItemCount() - 1) {
// Grow List
}
}
}
});
}
}
#Override
public int getItemViewType(int position){
//return newsList.get(position) instanceof News ? VIEW_ITEM : VIEW_PROG;
return (position >= newsList.size()) ? VIEW_PROG : VIEW_ITEM;
}
#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.news_list_row, parent, false);
vh = new MyViewHolder(v);
} else {
View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.progress_item, parent, false);
vh = new ProgressViewHolder(v);
}
return vh;
}
public class MyViewHolder extends RecyclerView.ViewHolder {
public TextView title;
public ImageView image,nextArrowimage;
public TextView desc;
private News news;
public MyViewHolder(View view) {
super(view);
ProgressBar progressBar = null;
title = (TextView) view.findViewById(R.id.News_title);
image = (ImageView) view.findViewById(R.id.News_imageView);
nextArrowimage = (ImageView)view.findViewById(R.id.news_NextArrow);
desc = (TextView) view.findViewById(R.id.News_desc);
view.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
String title = news.getTitle();
String desc = news.getDesc();
String image = "http://bitstobyte.in/upload/"+news.getImage();
Intent intent = new Intent(context, News_Activity.class);
intent.putExtra("title", title);
intent.putExtra("desc",desc);
intent.putExtra("imageUrl", image);
context.startActivity(intent);
Toast.makeText(v.getContext(), "OnClick :" + news.getTitle() + " \n "+news.getImage(),Toast.LENGTH_SHORT).show();
}
});
}
}
#Override
public void onBindViewHolder(RecyclerView.ViewHolder holder,int position){
//if (holder instanceof MyViewHolder) {
// if (getItemViewType(position)==VIEW_ITEM) {
if (newsList.get(position)!=null && getItemViewType(position)==VIEW_ITEM ) {
final News single_news= newsList.get(position);
((MyViewHolder) holder).title.setText(single_news.getTitle());
((MyViewHolder) holder).desc.setText(single_news.getDesc());
((MyViewHolder) holder).nextArrowimage.setImageResource(R.drawable.nextblackbutton);
context = ((MyViewHolder) holder).image.getContext();
Picasso.with(context).load("http://bitstobyte.in/upload/"+single_news.getImage()).placeholder(R.drawable.ic_favorite_white_24dp).error(R.drawable.ic_map_24dp).resize(100,100).into(((MyViewHolder) holder).image);
((MyViewHolder) holder).news= single_news;
} else {
((ProgressViewHolder) holder).progressBar.setIndeterminate(true);
}
}
public void setLoaded() {
loading = false;
}
#Override
public int getItemCount() {
return newsList.size()+1;
}
public void setOnLoadMoreListener(OnLoadMoreListener onLoadMoreListener) {
this.onLoadMoreListener = onLoadMoreListener;
}
public static class ProgressViewHolder extends RecyclerView.ViewHolder {
public ProgressBar progressBar;
public ProgressViewHolder(View v) {
super(v);
progressBar = (ProgressBar)v.findViewById(R.id.progressBar1);
}
}
}
You are getting error at below line right ?
((ProgressViewHolder) holder).progressBar.setIndeterminate(true);
Can you tell why you have used two ViewHolders ?
FYI :You can't use two ViewHolder means can't extends two ViewHolder.
Just change this function:
#Override
public int getItemViewType(int position){
//return newsList.get(position) instanceof News ? VIEW_ITEM : VIEW_PROG;
return (position >= newsList.size() || newsList.get(position)==null) ? VIEW_PROG : VIEW_ITEM;
}
And
#Override
public void onBindViewHolder(RecyclerView.ViewHolder holder,int position){
if (getItemViewType(position)==VIEW_ITEM ) {
final News single_news= newsList.get(position);
((MyViewHolder) holder).title.setText(single_news.getTitle());
((MyViewHolder) holder).desc.setText(single_news.getDesc());
((MyViewHolder) holder).nextArrowimage.setImageResource(R.drawable.nextblackbutton);
context = ((MyViewHolder) holder).image.getContext();
Picasso.with(context).load("http://bitstobyte.in/upload/"+single_news.getImage()).placeholder(R.drawable.ic_favorite_white_24dp).error(R.drawable.ic_map_24dp).resize(100,100).into(((MyViewHolder) holder).image);
((MyViewHolder) holder).news= single_news;
} else {
((ProgressViewHolder) holder).progressBar.setIndeterminate(true);
}
}

Add ProgressBar when recyclerView hit scroll

I have to add Pagination in recyclerView. But I am stuck in adding a progressbar when recyclerView scroll.
I have been trying for a day but unfortunately not got a valid solution to add a progress bar at run time while recyclerView scrolling.I have three ViewHolder.
RecyclerView Scroll Listener
rvRewardItems.addOnScrollListener(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);
int visibleItemCount = recyclerView.getChildCount();
int totalItemCount = wrapperLinearLayout.getItemCount();
int firstVisibleItem = wrapperLinearLayout.findFirstVisibleItemPosition();
int lastInScreen = firstVisibleItem + visibleItemCount;
if ((lastInScreen == totalItemCount) && !isLoadingMore) {
if (!mStopLoadingData) {
try {
isLoadingMore = true;
// Add item for progress ba
new Handler().post(new Runnable() {
#Override
public void run() {
adapter.addProgressView();
}
});
loadReviews(false, false);
}catch (IllegalStateException e){
e.printStackTrace();
}
}
}
}
});
RewardFinalAdapter.class
public class RewardFinalAdapter extends RecyclerView.Adapter<MainViewHolder>
{
private Context context;
private ArrayList<RewardItemBO> rewardArray;
private OnItemClickListener mItemClickListener;
public static final int VIEW_TYPE_PROGRESS = 0;
public static final int VIEW_TYPE_ITEM = 1;
public static final int VIEW_TYPE_HEADER = 2;
public RewardFinalAdapter(Context context, ArrayList<RewardItemBO> mainItems) {
this.context = context;
rewardArray = getFilterRewards(mainItems);
}
public void resetArray(ArrayList<RewardItemBO> latestArray)
{
rewardArray = getFilterRewards(latestArray);
}
public void setArrayItems(ArrayList<RewardItemBO> latestArray) {
rewardArray = latestArray;
}
#Override
public int getItemViewType(int position) {
if(rewardArray.get(position).isHeader())
return VIEW_TYPE_HEADER;
else if(rewardArray.get(position).isShowProgress())
return VIEW_TYPE_PROGRESS;
else
return VIEW_TYPE_ITEM;
}
#Override
public int getItemCount() {
return rewardArray.size();
}
public RewardItemBO getItem(int position) {
return rewardArray.get(position);
}
public void addItems( ArrayList<RewardItemBO> overallItem){
rewardArray = getFilterRewards(overallItem);
// notifyItemInserted(items.size() - 1);
this.notifyDataSetChanged();
}
// Create new views (invoked by the layout manager)
#Override
public MainViewHolder onCreateViewHolder(ViewGroup viewGroup, int viewType) {
switch (viewType){
case VIEW_TYPE_HEADER:
View itemView = LayoutInflater.from(viewGroup.getContext())
.inflate(R.layout.order_list_header, viewGroup, false);
return new RewardListViewHolderHeader(itemView);
case VIEW_TYPE_ITEM:
View view = LayoutInflater.from(context).inflate(R.layout.item_rewards, viewGroup, false);
return new RewardViewHolder(view);
case VIEW_TYPE_PROGRESS:
Log.v("view_type_progress","I am in VIEW_TYPE_PROGRESS");
View progressView = LayoutInflater.from(context).inflate(R.layout.progress_loader, viewGroup, false);
return new ProgressViewHolder(progressView);
}
return null;
}
// Replace the contents of a view (invoked by the layout manager)
#Override
public void onBindViewHolder(MainViewHolder viewHolder, int position) {
RewardItemBO rewardItemBO= rewardArray.get(position);
if(viewHolder instanceof RewardViewHolder)
{
RewardViewHolder rewardViewHolder=(RewardViewHolder) viewHolder;
rewardViewHolder.tvRewardTitle.setText(rewardArray.get(position).getRewardTitle());
rewardViewHolder.tvRewardDescription.setText(rewardArray.get(position).getRewardMessage());
String formatedDate = DateTimeOp.oneFormatToAnother(rewardArray.get(position).getRewardExpiryDate(), Constants.dateFormat18, Constants.dateFormat6);
rewardViewHolder.tvRewardExpiry.setText("Expires " + formatedDate);
if(rewardArray.get(position).getRewardShowRedeem().equals("1"))
{
rewardViewHolder.btnGrey.setVisibility(View.VISIBLE);
rewardViewHolder.btnGrey.setText("Redeemed");
}
else if(rewardArray.get(position).getRewardExpired().equals("1"))
{
rewardViewHolder.btnGrey.setVisibility(View.VISIBLE);
rewardViewHolder.btnGrey.setText("Expired");
}
else
{
rewardViewHolder.btnOrange.setVisibility(View.VISIBLE);
rewardViewHolder.btnOrange.setText("Get Code");
}
}
else if(viewHolder instanceof RewardListViewHolderHeader)
{
RewardListViewHolderHeader holder = (RewardListViewHolderHeader ) viewHolder;
holder.tvHeader.setText(rewardItemBO.getHeaderTitle());
}
else if(viewHolder instanceof ProgressViewHolder)
{
ProgressViewHolder progressViewHolder = (ProgressViewHolder) viewHolder;
progressViewHolder.progressBar.setIndeterminate(true);
}
}
public void addOnTop(ArrayList<RewardItemBO> topItemList) {
Collections.reverse(topItemList);
rewardArray.addAll(0, topItemList);
notifyItemRangeInserted(0, topItemList.size());
}
public interface OnItemClickListener {
public void onItemClick(View view , int position);
}
public void SetOnItemClickListener(final OnItemClickListener mItemClickListener) {
this.mItemClickListener = mItemClickListener;
}
#Override
public long getItemId(int position) {
return position;
}
public ArrayList<RewardItemBO> getFilterRewards(ArrayList<RewardItemBO> mainItems){
ArrayList<RewardItemBO> currentRewardList = new ArrayList<RewardItemBO>();
ArrayList<RewardItemBO> pastRewardList = new ArrayList<RewardItemBO>();
ArrayList<RewardItemBO> dummyArray = new ArrayList<>();
for (RewardItemBO rewardItemBO : mainItems) {
try {
//because reward item with progress have everything null in it.
if(rewardItemBO.getRewardExpired()!=null && !rewardItemBO.isShowProgress())
{
int isExpired = Integer.parseInt(rewardItemBO.getRewardExpired());
if(isExpired==1)
pastRewardList.add(rewardItemBO);
else
currentRewardList.add(rewardItemBO);
}
}catch (NumberFormatException e){
e.printStackTrace();
}
}
if(currentRewardList.size()>0){
currentRewardList.add(0, new RewardItemBO(context.getResources().getString(R.string.Current)));
dummyArray.addAll(currentRewardList);
}
if(pastRewardList.size()>0){
pastRewardList.add(0, new RewardItemBO(context.getResources().getString(R.string.Past)));
dummyArray.addAll(pastRewardList);
}
return dummyArray;
}
public void addProgressView()
{
rewardArray.add(new RewardItemBO(true));
//notifyItemChanged(rewardArray.size());
notifyDataSetChanged();
}
public void removeProgressView(){
int position = rewardArray.size() -1;
rewardArray.remove(position);
notifyItemRemoved(position);
notifyItemRangeChanged(position, rewardArray.size());
}
public static class RewardListViewHolderHeader extends MainViewHolder {
protected TextView tvHeader;
public RewardListViewHolderHeader (View v) {
super(v);
tvHeader = (TextView) v.findViewById(R.id.header_text);
}
}
public class RewardViewHolder extends MainViewHolder implements View.OnClickListener{
public TextView tvRewardTitle;
public TextView tvRewardDescription;
public TextView tvRewardExpiry;
public Button btnOrange,btnGrey;
public RewardViewHolder(View v) {
super(v);
tvRewardTitle = (TextView) itemView.findViewById(R.id.tv_reward_title);
tvRewardDescription = (TextView) itemView.findViewById(R.id.tv_reward_description);
tvRewardExpiry = (TextView) itemView.findViewById(R.id.tv_reward_expiry_date);
btnOrange = (Button) itemView.findViewById(R.id.btn_item_reward_orange);
btnGrey = (Button) itemView.findViewById(R.id.btn_item_reward_grey);
btnOrange.setOnClickListener(this);
btnGrey.setOnClickListener(this);
}
#Override
public void onClick(View v) {
//Toast.makeText(context, tvName.getText().toString(), Toast.LENGTH_SHORT).show();
if (mItemClickListener != null) {
mItemClickListener.onItemClick(v,getAdapterPosition());
}
}
}
}

Categories

Resources