My adapter list is refreshing on broadcast receiver .
Everything is working fine if adapter list size is greater than 1 ,
means if my recyclerview has already one row shwoing then list refreshing just fine .
But if list size goes from 0 to 1 then my adapter notify dataset
Changed stop working . No data shows on recyclerview. I don't know why it is not working .
Recyclerview Class:
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
v = inflater.inflate(R.layout.job_recyclerview, container, false);
getActivity());
initialise(v);
init();
showNoTaskMessage();
new loadListTask().executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
mMyBroadcastReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
// Here you can refresh your listview or other UI
SlidingTab.slidingTab.getTabAt(0).setText("New (" + SingleTon.getInstance().getNewjob() + ")");
SlidingTab.slidingTab.getTabAt(1).setText("In Progress (" + SingleTon.getInstance().getInprogressjob() + ")");;
SlidingTab.slidingTab.getTabAt(2).setText("Completed (" + SingleTon.getInstance().getCompletedjob() + ")");
}
};
try {
IntentFilter filter = new IntentFilter("newJob");
LocalBroadcastManager.getInstance(context).registerReceiver(mMyBroadcastReceiver,
filter);
} catch (Exception e) {
// TODO: handle exception
e.printStackTrace();
}
return v;
}
Adapter class :
public JobAdapter(ArrayList<Info> myDataset, Context context) {
this.mDataset = myDataset;
this.mAct = context;
}
public void addApplications(ArrayList<Info> candidates) {
if (this.filterList == null) {
filterList = new ArrayList<>();
}
this.mDataset.clear();
this.mDataset.addAll(candidates);
this.filterList.addAll(mDataset);
this.notifyItemRangeInserted(0, candidates.size() - 1);
}
public void clearApplications() {
int size = this.mDataset.size();
if (size > 0) {
for (int i = 0; i < size; i++) {
mDataset.remove(0);
filterList.remove(0);
}
this.notifyItemRangeRemoved(0, size);
}
}
#Override
public int getItemViewType(int position) {
return VIEW_NORMAL;
}
#Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.single_job_card, parent, false);
ViewHolder fh = new ViewHolder(v);
return fh;
}
#Override
public void onBindViewHolder(final ViewHolder holder, final int position) {
// holder.jobPhone.setText(mDataset.get(position).mobileNo);
holder.jobNumber.setText(mDataset.get(position).jobNumber);
holder.jobTime.setText(mDataset.get(position).time);
holder.jobAddress.setText(mDataset.get(position).address);
// holder.jobInstructionText.setText(mDataset.get(position).spclInstruction);
if (mDataset.get(position).jobStatus != null && mDataset.get(position).jobStatus.equalsIgnoreCase("Completed")) {
holder.endsat.setText("Submitted at");
holder.jobTime.setText(mDataset.get(position).completedOnString);
holder.jobTimeLeft.setVisibility(View.INVISIBLE);
holder.timerImage.setVisibility(View.INVISIBLE);
} else {
if (mDataset.get(position).status.equalsIgnoreCase("Active")) {
holder.jobTimeLeft.setText(mDataset.get(position).appointmentTime);
} else {
holder.jobTimeLeft.setText("-" + mDataset.get(position).appointmentTime);
}
}
holder.jobLayout1.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
SingleTon.getInstance().setWorkDescHolder(mDataset.get(position).descHolder);
FragmentManager fragmentManager = ((FragmentActivity) mAct).getSupportFragmentManager();
FragmentTransaction ft = ((FragmentActivity) mAct).getSupportFragmentManager().beginTransaction();
ft.setCustomAnimations(R.anim.glide_fragment_horizontal_in, R.anim.glide_fragment_horizontal_out);
ft.replace(R.id.content_frame1, new DetailsFragment(), "persondetails");
ft.addToBackStack("persondetails");
// Start the animated transition.
ft.commit();
}
});
}
#Override
public int getItemCount() {
return mDataset.size();
}
public class ViewHolder extends RecyclerView.ViewHolder {
private TextView jobNumber, jobTimeLeft, jobStatus, jobAddress, jobEmail, jobPhone, timeTimer, jobInstructionText, jobTime, endsat;
private ImageView timerImage;
private FrameLayout frameLayout;
private CardView cardView;
private LayoutRipple jobLayout1;
public ViewHolder(View v) {
super(v);
this.jobNumber = (TextView) v.findViewById(R.id.job_number);
this.jobTime = (TextView) v.findViewById(R.id.job_time);
this.jobTimeLeft = (TextView) v.findViewById(R.id.job_timertext);
this.timerImage = (ImageView) v.findViewById(R.id.timerimage);
this.cardView = (CardView) v.findViewById(R.id.card_view);
// this.jobStatus = (TextView) v.findViewById(R.id.job_status);
this.jobAddress = (TextView) v.findViewById(R.id.job_addresstext);
// this.jobInstructionText = (TextView) v.findViewById(R.id.instruction_text);
// this.jobLayout = (LayoutRipple)v.findViewById(R.id.job_cardLayout);
this.jobLayout1 = (LayoutRipple) v.findViewById(R.id.cardLayout1);
this.endsat = (AppCompatTextView) v.findViewById(R.id.endsat);
this.jobNumber.setTypeface(Utils.RegularTypeface(mAct));
this.jobAddress.setTypeface(Utils.RegularTypeface(mAct));
this.jobTimeLeft.setTypeface(Utils.RegularTypeface(mAct));
this.jobTime.setTypeface(Utils.RegularTypeface(mAct));
}
}
}
Please help me finding the bug or some other approach . Thanks
Call the data loading task inside the onReceive() of BroadcastReceiver
mMyBroadcastReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
// Here you can refresh your listview or other UI
new loadListTask().executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
SlidingTab.slidingTab.getTabAt(0).setText("New (" + SingleTon.getInstance().getNewjob() + ")");
SlidingTab.slidingTab.getTabAt(1).setText("In Progress (" + SingleTon.getInstance().getInprogressjob() + ")");;
SlidingTab.slidingTab.getTabAt(2).setText("Completed (" + SingleTon.getInstance().getCompletedjob() + ")");
}
};
And also do following changes in your Adapter class.
public void addApplications(ArrayList<Info> candidates) {
if (this.filterList == null) {
filterList = new ArrayList<>();
}
this.mDataset.clear();
this.mDataset.addAll(candidates);
this.filterList.addAll(mDataset);
this.notifyItemRangeInserted(0, candidates.size());
}
public void clearApplications() {
int size = this.mDataset.size();
if (size > 0) {
for (int i = 0; i < size; i++) {
mDataset.remove(i);
filterList.remove(i);
}
this.notifyItemRangeRemoved(0, size);
}
}
Hope that works!
Change this:
mMyBroadcastReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
// Here you can refresh your listview or other UI
recycleAdapter.addItems(SingleTon.getInstance()
.getInfoArrayList());
// I'm assuming your "SingleTon.getInstance().getInfoArrayList()" is the received data.
}
On your Adapter
public void addItems(List<Info> itemsList) {
// This check could be avoided if you declared your mDataset final
if(mDataset == null) {
mDataset = new ArrayList<>();
}
int prevSize = mDataset.size();
mDataset.addAll(itemsList);
notifyItemRangeInserted(prevSize, itemsList.size());
}
You shouldn't call notifyDataSetChanged() after this.notifyItemRangeInserted(0, candidates.size() - 1); try something like this:
put this method to your adapter class
public void setData(ArrayList<Info> infos) {
this.mDataset = infos;
notifyDataSetChanged();
}
and call it like this:
ArrayList<Info> list = SingleTon.getInstance().getInfoArrayList().isEmpty();
if (list != null && !list.isEmpty()) {
recycleAdapter.setData(list);
}
correct this method in your adapter
#Override
public int getItemCount() {
return mDataset != null && !mDataset.isEmpty() ? mDataset.size() : 0;
}
Base on your code, we need a variable list to store your info data.
//Declare the info list
private ArrayList<Info> mInfos = new ArrayList<Info>()
In your onCreateView(), set mInfos to your recycleAdapter
recycleAdapter = new JobAdapter(mInfos, getActivity());
recyclerView.setAdapter(recycleAdapter);
So, every time you want to set new info list. Just assign it to mInfos
and make sure, you clear your previous list data to avoid duplicate data.
mInfos.clear()
mInfos.addAll(SingleTon.getInstance().getInfoArrayList());
//refresh data
recycleAdapter.notifyDataSetChanged();
I am not sure where you are using clearApplications() in JobAdapter.class.
But, it seems to be wrong. In the for-loop, you are trying to remove the value at index 0 every time rather than index 'i'. Hope this helps.
when you are using custom adapter then notifyDatasetChange() not called from outside that adapter so make addItem function in adapter and add new List in Adapter list and call notifyDataSetChanged
public void addItem(List<Model> list) {
if (lit != null) {
clear();
adapterList.addAll(list);
}
notifyDataSetChanged();
}
Do Change In your recyclerview class.
//Change condition ">1" to "!=null"
if (SingleTon.getInstance().getInfoArrayList().size() != null) {
recycleAdapter.addApplications(SingleTon.getInstance().getInfoArrayList());
recycleAdapter.notifyDataSetChanged();
and then do change in your adapter.
public void addApplications(ArrayList<Info> candidates) {
if (this.filterList == null) {
filterList = new ArrayList<>();
}
this.mDataset.clear();
this.mDataset.addAll(candidates);
this.filterList.addAll(mDataset);
this.notifyItemRangeInserted(0, mDataset.size()); //notify to mDataset
}
hope this will work!
Related
The problem is that in my tablayout when im switching between tabs my list duplicating. So i need to remove list on onStop() to recreate it then. Or might be other better solution.
I have tried the following solutions
https://code-examples.net/en/q/1c97047
How to reset recyclerView position item views to original state after refreshing adapter
Remove all items from RecyclerView
My code of adapter
public class OnlineUsersAdapter extends RecyclerView.Adapter<OnlineUsersAdapter.OnlineUserViewHolder> {
private List<OnlineUser> onlineUsers = new ArrayList<>();
private OnItemClickListener.OnItemClickCallback onItemClickCallback;
private OnItemClickListener.OnItemClickCallback onChatClickCallback;
private OnItemClickListener.OnItemClickCallback onLikeClickCallback;
private Context context;
public OnlineUsersAdapter(Context context) {
this.onlineUsers = new ArrayList<>();
this.context = context;
}
#NonNull
#Override
public OnlineUsersAdapter.OnlineUserViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
context = parent.getContext();
View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_user, parent, false);
return new OnlineUsersAdapter.OnlineUserViewHolder(v);
}
#Override
public void onBindViewHolder(#NonNull OnlineUsersAdapter.OnlineUserViewHolder holder, int position) {
OnlineUser user = onlineUsers.get(position);
Log.d("testList", "rating " + user.getRating() + " uid " + user.getUid());
holder.bind(user, position);
}
#Override
public int getItemCount() {
return onlineUsers.size();
}
class OnlineUserViewHolder extends RecyclerView.ViewHolder {
RelativeLayout container;
ImageView imageView, likeBtn, chatBtn;
TextView name, country;
private LottieAnimationView animationView;
OnlineUserViewHolder(View itemView) {
super(itemView);
context = itemView.getContext();
container = itemView.findViewById(R.id.item_user_container);
imageView = itemView.findViewById(R.id.user_img);
likeBtn = itemView.findViewById(R.id.search_btn_like);
chatBtn = itemView.findViewById(R.id.search_btn_chat);
name = itemView.findViewById(R.id.user_name);
country = itemView.findViewById(R.id.user_country);
animationView = itemView.findViewById(R.id.lottieAnimationView);
}
void bind(OnlineUser user, int position) {
ViewCompat.setTransitionName(imageView, user.getName());
if (FirebaseUtils.isUserExist() && user.getUid() != null) {
new FriendRepository().isLiked(user.getUid(), flag -> {
if (flag) {
likeBtn.setBackground(ContextCompat.getDrawable(context, R.drawable.ic_favorite));
animationView.setVisibility(View.VISIBLE);
} else {
likeBtn.setBackground(ContextCompat.getDrawable(context, R.drawable.heart_outline));
animationView.setVisibility(View.GONE);
}
});
}
if (user.getUid() != null) {
chatBtn.setOnClickListener(new OnItemClickListener(position, onChatClickCallback));
likeBtn.setOnClickListener(new OnItemClickListener(position, onLikeClickCallback));
}
imageView.setOnClickListener(new OnItemClickListener(position, onItemClickCallback));
imageView.setScaleType(ImageView.ScaleType.FIT_XY);
if (user.getImage().equals(Consts.DEFAULT)) {
Glide.with(context).load(context.getResources().getDrawable(R.drawable.default_avatar)).into(imageView);
} else {
Glide.with(context).load(user.getImage()).thumbnail(0.5f).into(imageView);
}
country.setText(user.getCountry());
ValueAnimator animator = ValueAnimator.ofFloat(0f, 1f).setDuration(500);
animator.addUpdateListener(valueAnimator ->
animationView.setProgress((Float) valueAnimator.getAnimatedValue()));
if (animationView.getProgress() == 0f) {
animator.start();
} else {
animationView.setProgress(0f);
}
}
}
public OnlineUsersAdapter(OnItemClickListener.OnItemClickCallback onItemClickCallback,
OnItemClickListener.OnItemClickCallback onChatClickCallback,
OnItemClickListener.OnItemClickCallback onLikeClickCallback) {
this.onItemClickCallback = onItemClickCallback;
this.onChatClickCallback = onChatClickCallback;
this.onLikeClickCallback = onLikeClickCallback;
}
public void addUsers(List<OnlineUser> userList) {
int initSize = userList.size();
onlineUsers.addAll(userList);
// notifyItemRangeInserted(onlineUsers.size() - userList.size(), onlineUsers.size());
}
public String getLastItemId() {
return onlineUsers.get(onlineUsers.size() - 1).getUid();
}
public void clearData() {
List<OnlineUser> data = new ArrayList<>();
addUsers(data);
notifyDataSetChanged();
}
My code in fragment
#Override
public void onStop() {
super.onStop();
firstUid = "";
stopDownloadList = false;
List<OnlineUser> list = new ArrayList<>();
mAdapter.addUsers(list);
mAdapter.notifyDataSetChanged();
}
`users are added after callback
#Override
public void addUsers(List<OnlineUser> onlineUsers) {
if (firstUid.equals("")){
firstUid = onlineUsers.get(0).getUid();
}
if (!firstUid.equals("") && onlineUsers.contains(firstUid)){
stopDownloadList = true;
}
if (!stopDownloadList){
mAdapter.addUsers(onlineUsers);
}
setRefreshProgress(false);
isLoading = false;
isMaxData = true;
}
The line mAdapter.addUsers(onlineUsers); from addUsers method gets called twice. Looks like your asynchronous operation gets triggered twice (e. g. from repeating lifecycle methods like onCreate/onCreateView/onViewCreated).
Solution #1: request users a single time
Move your user requesting machinery to onCreate or onAttach. This will save network traffic but could lead to showing outdated data.
Solution #2: replaceUsers
Your clearData calls mAdapter.addUsers(new ArrayList<>()); (btw, take a look at Collections.emptyList()). Looks like you're trying to replace adapter data but appending instead. Replacement method could look like
public void replaceUsers(List<OnlineUser> userList) {
int oldSize = userList.size();
onlineUsers = userList;
notifyItemRangeRemoved(0, oldSize);
notifyItemRangeInserted(0, userList.size);
}
This version still requeses users every time your fragment gets focused but shows fresher data.
In my project, there is need of searching data from server using keyword. After search, i am displaying results using RecyclerView . While searching fast, the data in RecyclerView is duplicating. If searching slowly, it's working fine. Any suggestions are appreciated. Thank you.
The below code for making server call:
private void callSearchUserApi(final String searchText, int currentPage, boolean clearData) {
isApiCallInProcess = true;
String URL = "userinfo/api/v1/user-search/" + "?page=" + currentPage;
if (!Connectivity.isConnected(activity)) {
Common.snackBarNoConnection(activity, activity.getString(R.string.no_conection));
//setOnProgressbarVisibility(View.GONE);
return;
}
if (clearData) {
globalSearchUsersModelList.clear();
//BS globalSearchUserResultsAdapter.notifyDataSetChanged();
}
ApiInterface apiCall = ApiClient.getApiService(activity);
final Call<SearchUsersModel> globalUserSearchApiCall = apiCall.searchUser(
URL,
searchText);
globalUserSearchApiCall.enqueue(new Callback<SearchUsersModel>() {
#Override
public void onResponse(Call<SearchUsersModel> call, Response<SearchUsersModel> response) {
if (response.isSuccessful() && response.body().getStatus().equalsIgnoreCase(Common.SUCCESS_RESPONSE)) {
//BS globalSearchUsersModelList.addAll(response.body().getData().getData());
for (int i = 0; i < response.body().getData().getData().size(); i++) {
SearchUsersModel.DataBeanX.DataBean dataBean = new SearchUsersModel.DataBeanX.DataBean();
dataBean.setDesignation(response.body().getData().getData().get(i).getDesignation());
dataBean.setFull_name(response.body().getData().getData().get(i).getFull_name());
dataBean.setGender(response.body().getData().getData().get(i).getGender());
dataBean.setId(response.body().getData().getData().get(i).getId());
dataBean.setPlace(response.body().getData().getData().get(i).getPlace());
dataBean.setProfile_pic(response.body().getData().getData().get(i).getProfile_pic());
globalSearchUsersModelList.add(dataBean);
/*BS if (!globalSearchUsersModelList.contains(response.body().getData().getData().get(i)))
globalSearchUsersModelList.add(response.body().getData().getData().get(i));*/
}
CURRENT_PAGE = response.body().getData().getPage();
isLoading = false;
if (response.body().getData().isNext() == false)
isLastPage = true;
else
isLastPage = false;
if (globalSearchUsersModelList.size() == 0) {
rv_GlobalsearchList.setVisibility(View.GONE);
rl_placeholderGSPeople.setVisibility(View.VISIBLE);
tv_placeholderGSPeople.setText(activity.getString(R.string.no_search_found) + " " + searchText);
} else {
rv_GlobalsearchList.setVisibility(View.VISIBLE);
rl_placeholderGSPeople.setVisibility(View.GONE);
}
new Handler(Looper.getMainLooper()).post(new Runnable() {
#Override
public void run() {
globalSearchUserResultsAdapter.notifyDataSetChanged();
}
});
}
if (searchTextsList.size() > 0) {
String sText = searchTextsList.get(0);
searchTextsList.remove(0);
callSearchUserApi(sText, FIRST_PAGE, true);
} else
isApiCallInProcess = false;
}
#Override
public void onFailure(Call<SearchUsersModel> call, Throwable t) {
isApiCallInProcess = false;
}
});
}
This is my Adapter.
public class GlobalSearchUserResultsAdapter extends RecyclerView.Adapter<GlobalSearchUserResultsAdapter.SearchViewHolder> {
private Context context;
private List<SearchUsersModel.DataBeanX.DataBean> searchUserList;
public GlobalSearchUserResultsAdapter(Context context, List<SearchUsersModel.DataBeanX.DataBean> searchUserList){
this.context = context;
this.searchUserList = searchUserList;
}
#Override
public long getItemId(int position) {
return position;
}
#Override
public int getItemViewType(int position) {
return position;
}
#Override
public SearchViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
Log.v("Search", "Adapter Activity : "+context);
View view = LayoutInflater.from(context).inflate(R.layout.global_search_row, parent, false);
return new GlobalSearchUserResultsAdapter.SearchViewHolder(view);
}
#Override
public void onBindViewHolder(GlobalSearchUserResultsAdapter.SearchViewHolder holder, int position) {
if ( searchUserList.get(position).getGender().equals("M")) {
holder.iv_userImage.setBackgroundResource(R.drawable.white_border_with_circle_appblue);
Common.setGlideImage((GlobalSearchActivity)context,
holder.iv_userImage,
/*searchUsersModel*/searchUserList.get(position).getProfile_pic(),
R.drawable.male,
true);
} else if (searchUserList.get(position).getGender().equals("F")) {
holder.iv_userImage.setBackgroundResource(R.drawable.white_border_with_circle_pink);
Common.setGlideImage((GlobalSearchActivity)context,
holder.iv_userImage,
searchUserList.get(position).getProfile_pic(),
R.drawable.female,
true);
} else {
Common.setGlideImage((GlobalSearchActivity)context,
holder.iv_userImage,
searchUserList.get(position).getProfile_pic(),
R.drawable.deafult_profilepic,
true);
}
holder.tv_userName.setText(searchUserList.get(position).getFull_name());
holder.tv_userName.setTypeface(Common
.getFontTypeface(context, GlobalConstants.FONT_AVENIR_MEDIUM));
holder.tv_place.setText(searchUserList.get(position).getPlace());
holder.tv_place.setTypeface(Common
.getFontTypeface(context, GlobalConstants.FONT_AVENIR_MEDIUM));
holder.designation.setText(searchUserList.get(position).getDesignation());
}
#Override
public int getItemCount() {
return searchUserList.size();
}
public class SearchViewHolder extends RecyclerView.ViewHolder{
private ImageView iv_userImage;
private TextView tv_userName;
private TextView tv_place;
private TextView designation;
public SearchViewHolder(View itemView) {
super(itemView);
this.iv_userImage = (ImageView) itemView.findViewById(R.id.imageSearch);
this.tv_userName = (TextView) itemView.findViewById(R.id.nameSearch);
tv_userName.setTypeface(Common.getFontTypeface(context,
GlobalConstants.FONT_AVENIR_MEDIUM));
this.designation = (TextView) itemView.findViewById(R.id.designation);
designation.setTypeface(Common.getFontTypeface(context,
GlobalConstants.FONT_AVENIR_MEDIUM));
this.tv_place = (TextView) itemView.findViewById(R.id.placeSearch);
tv_place.setTypeface(Common.getFontTypeface(context,
GlobalConstants.FONT_AVENIR_LIGHT));
itemView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
context.startActivity(new Intent(context, ProfileActivity.class)//ThirdParty
.putExtra(GlobalConstants.KEY_THIRD_PARTY_ID, searchUserList.get(getAdapterPosition()).getId()));
}
});
}
}
}
You just had to clear the globalSearchUsersModelList list just before for loop, because API call is asynchronous.
globalSearchUsersModelList.clear();// Important one
for (int i = 0; i < response.body().getData().getData().size(); i++) {
// do your stuff
}
I think the issue come from your getItemId implementation. The way you implement it, the recycler view will identify an item according to its position in the list.
If you change this and use unique identification for instance searchUserList.get(position).id (if your User object has an unique ID) the problem should be fixed
You can also add in your activity adapter.setHasStableIds(true)
I am using parse-server to develop the app which uses RecyclerView to display image items.
but the problem is that the items displayed in the view changed every time I scrolled up and down.
I want to know what is the problem on my code.
if you see below images, you can find the items are changing their position.
I tried to make holder image become null before call the holder again. but it's not working. I guess that the item's position number is changed when I call the item again.but I can't find the cause of the situation
enter image description here
enter image description here
RecyclerParseAdapter.java
public class MyTimelineAdapter extends RecyclerParseAdapter {
private interface OnQueryLoadListener<ParseObject> {
public void onLoading();
public void onLoaded(List<ParseObject> objects, Exception e);
}
private static ParseQueryAdapter.QueryFactory<ParseObject> queryFactory;
private static List<OnQueryLoadListener<ParseObject>> onQueryLoadListeners;
private static List<List<ParseObject>> objectPages;
private static ArrayList<ParseObject> items;
private static int currentPage;
private static RequestManager requestManager;
public MyTimelineAdapter(Context context, RequestManager requestManager) {
super(context);
this.requestManager = requestManager;
this.onQueryLoadListeners = new ArrayList<>();
this.currentPage = 0;
this.objectPages = new ArrayList<>();
this.items = new ArrayList<>();
this.queryFactory = new ParseQueryAdapter.QueryFactory<ParseObject>() {
#Override
public ParseQuery<ParseObject> create() {
ParseQuery<ParseObject> query = ParseQuery.getQuery("ImageClassName");
query.setCachePolicy(ParseQuery.CachePolicy.CACHE_THEN_NETWORK);
query.whereEqualTo("status", true);
query.orderByDescending("createdAt");
return query;
}
};
loadObjects(currentPage);
}
#Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View timelineView;
timelineView = LayoutInflater.from(parent.getContext()).inflate(R.layout.list_item_timeline_item2, parent, false);
TimelineItemViewHolder timelineItemViewHolder = new TimelineItemViewHolder(timelineView);
return timelineItemViewHolder;
}
#Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
final ParseObject timelineOb = getItem(position);
FunctionPost functionPost = new FunctionPost(context);
functionPost.TimelineArtistPostAdapterBuilder( timelineOb, holder, requestManager);
//기능 추가
}
#Override
public int getItemCount() {
return items.size();
}
#Override
public ParseObject getItem(int position) {
return items.get(position);
}
#Override
public void loadObjects(final int page) {
final ParseQuery<ParseObject> query = this.queryFactory.create();
if (this.objectsPerPage > 0 && this.paginationEnabled) {
this.setPageOnQuery(page, query);
}
this.notifyOnLoadingListeners();
if (page >= objectPages.size()) {
objectPages.add(page, new ArrayList<ParseObject>());
}
query.findInBackground(new FindCallback<ParseObject>() {
#Override
public void done(List<ParseObject> foundObjects, ParseException e) {
if ((e != null) && ((e.getCode() == ParseException.CONNECTION_FAILED) || (e.getCode() != ParseException.CACHE_MISS))) {
hasNextPage = true;
} else if (foundObjects != null) {
// Only advance the page, this prevents second call back from CACHE_THEN_NETWORK to
// reset the page.
if (page >= currentPage) {
currentPage = page;
// since we set limit == objectsPerPage + 1
hasNextPage = (foundObjects.size() > objectsPerPage);
}
if (paginationEnabled && foundObjects.size() > objectsPerPage) {
// Remove the last object, fetched in order to tell us whether there was a "next page"
foundObjects.remove(objectsPerPage);
}
List<ParseObject> currentPage = objectPages.get(page);
currentPage.clear();
currentPage.addAll(foundObjects);
syncObjectsWithPages(items, objectPages);
// executes on the UI thread
notifyDataSetChanged();
}
notifyOnLoadedListeners(foundObjects, e);
}
});
}
public void loadNextPage() {
if (items.size() == 0) {
loadObjects(0);
} else {
loadObjects(currentPage + 1);
}
}
public void syncObjectsWithPages(ArrayList<ParseObject> items, List<List<ParseObject>> objectPages) {
items.clear();
for (List<ParseObject> pageOfObjects : objectPages) {
items.addAll(pageOfObjects);
}
}
protected void setPageOnQuery(int page, ParseQuery<ParseObject> query) {
query.setLimit(this.objectsPerPage + 1);
query.setSkip(page * this.objectsPerPage);
}
public void addOnQueryLoadListener(OnQueryLoadListener<ParseObject> listener) {
this.onQueryLoadListeners.add(listener);
}
public void removeOnQueryLoadListener(OnQueryLoadListener<ParseObject> listener) {
this.onQueryLoadListeners.remove(listener);
}
public void notifyOnLoadingListeners() {
for (OnQueryLoadListener<ParseObject> listener : this.onQueryLoadListeners) {
listener.onLoading();
}
}
public void notifyOnLoadedListeners(List<ParseObject> objects, Exception e) {
for (OnQueryLoadListener<ParseObject> listener : this.onQueryLoadListeners) {
listener.onLoaded(objects, e);
}
}
}
I did find the problem
I add overide method in the adapter then It works find.
#Override
public int getItemViewType(int position) {
return position;
}
I am not sure why it happens now. any one help me to know the cause of problem?
I has a similar problem the other day see this post. onBindViewHolder needs to know how to display the row when it's called. I returned two different view types depending on the need in getItemViewType, inflated the view type conditionally in onCreateViewHolder, then I was able to set the data on the ViewHolder as needed.
I inserted/removing from particular position in ArrayList onBindViewHolder . Now , i want to show this modified list on recyclerview .
Adapter Code:
public class MyAdapter extends RecyclerView.Adapter<MyAdapter.MyAdapterViewHolder> {
private List<Info> dataList;
private Context mAct;
private List<Info> totalCandidatesList;
private String TAG = "OWD";
public MyAdapter(List<Info> dataList, Context context) {
this.dataList = dataList;
this.mAct = context;
}
public void addApplications(List<Info> candidates) {
if(this.totalCandidatesList == null){
totalCandidatesList = new ArrayList<>();
}
this.dataList.addAll(candidates);
this.totalCandidatesList.addAll(candidates);
this.notifyItemRangeInserted(0, candidates.size() - 1);
}
public void clearApplications() {
int size = this.dataList.size();
if (size > 0) {
for (int i = 0; i < size; i++) {
dataList.remove(0);
totalCandidatesList.remove(0);
}
this.notifyItemRangeRemoved(0, size);
}
}
#Override
public int getItemCount() {
return dataList.size();
}
public void onBindViewHolder(MyAdapterViewHolder mAdapterViewHolder, int i) {
if (i % 2 == 1) {
mAdapterViewHolder.cardView.setCardBackgroundColor(Color.parseColor("#ecf5fe"));
mAdapterViewHolder.layoutRipple.setBackgroundColor(Color.parseColor("#ecf5fe"));
} else {
mAdapterViewHolder.cardView.setCardBackgroundColor(Color.parseColor("#e2f1ff"));
mAdapterViewHolder.layoutRipple.setBackgroundColor(Color.parseColor("#e2f1ff"));
}
final WorkHolders workHolders = SingleTon.getInstance().getWorkHolders();
final String customerName = SingleTon.getInstance().getCustomerName();
String siteName = null;
if(customerName !=null) {
String[] sitenamearray = customerName.split("--");
if (sitenamearray.length > 1) {
siteName = sitenamearray[1];
}
}
final Info ci = dataList.get(i);
mAdapterViewHolder.title.setText(ci.heading1);
mAdapterViewHolder.jobNumber.setText(ci.heading2);
mAdapterViewHolder.distance.setText(ci.distance);
if(siteName != null && siteName.equalsIgnoreCase(ci.heading2)) {
mAdapterViewHolder.cardView.setCardBackgroundColor(Color.parseColor("#a7ffeb"));
mAdapterViewHolder.layoutRipple.setBackgroundColor(Color.parseColor("#a7ffeb"));
if(i!=0){
> //Here i removed and inserted item in list .
> dataList.remove(i);
> dataList.add(0,ci);
}
}
final String finalSiteName = siteName;
final Bundle bundle = new Bundle();
mAdapterViewHolder.layoutRipple.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Fragment fragment;
String name = ci.heading1 + "--" + ci.heading2;
Log.d(TAG,"new Jobname : "+ name);
if (finalSiteName == null || finalSiteName.equalsIgnoreCase("")) {
bundle.putString("name", customerName);
bundle.putString("oldwork", "yes");
bundle.putString("running_job_selected", "yes");
} else {
Log.d(TAG,"StartedOn Before Sending Bundle :" + workHolders.startedOn);
Log.d(TAG, "running Job is not selected");
bundle.putString("name", name);
bundle.putString("oldwork", "yes");
bundle.putString("running_job_selected", "no");
}
FragmentTransaction ft = ((FragmentActivity) mAct).getSupportFragmentManager().beginTransaction();
ft.setCustomAnimations(R.anim.glide_fragment_horizontal_in, R.anim.glide_fragment_horizontal_out);
fragment = new WorkDescriptionFragment();
fragment.setArguments(bundle);
ft.addToBackStack("myadapter");
ft.replace(R.id.content_frame, fragment).commit();
SingleTon.getInstance().setWorkStatus("start");
}
});
}
#Override
public MyAdapterViewHolder onCreateViewHolder(ViewGroup viewGroup, int i) {
View itemView = LayoutInflater.
from(viewGroup.getContext()).
inflate(R.layout.single_item1, viewGroup, false);
return new MyAdapterViewHolder(itemView);
}
public static class MyAdapterViewHolder extends RecyclerView.ViewHolder {
protected TextView title;
protected TextView dateTime;
protected TextView distance;
protected TextView jobNumber;
protected CardView cardView;
protected LayoutRipple layoutRipple;
public MyAdapterViewHolder(View v) {
super(v);
title = (TextView) v.findViewById(R.id.title);
dateTime = (TextView) v.findViewById(R.id.dateTimeTextView);
distance = (TextView) v.findViewById(R.id.distanceTextView);
jobNumber = (TextView) v.findViewById(R.id.jobNumber);
cardView = (CardView) v.findViewById(R.id.cv);
layoutRipple = (LayoutRipple)v.findViewById(R.id.singleitemripple);
}
}
}
you will see following lines in above code where i am removing/inserting item in a list onBindview and would like to show same in recyclerview .
But right now i am getting normal datalist(unchanged) .
//Here i removed and inserted item in list .
dataList.remove(i);
dataList.add(0,ci);
Please help me to achieve this .
onBindViewHolder is not the place where you should update your adapter. The staregy is to update item inside your Adapter data list and then notifyDataChanged(). For example thise are the methods for updating info inside my adapter:
public void update(Track track) {
tracks.remove(track);
add(track);
}
public void add (Track track) {
tracks.add(track);
this.notifyDataSetChanged();
}
public void addTracks(List<Track> tracks){
this.tracks.addAll(tracks);
this.notifyDataSetChanged();
}
public void clearAndAddTracks(List<Track> tracks) {
for (int i = 0; i < this.tracks.size(); i++) {
if (!this.tracks.get(i).isRunning()){
}
}
this.tracks.clear();
this.tracks.addAll(tracks);
this.notifyDataSetChanged();
}
I am receiving new item data from server and set it to adapter of my RecyclerView. When I first start the async-task to get data then the fetched data is displayed from top. But when I start async-task again to get new data then the new data is attached below the (invisible) old ones, although I am setting adapter = null before I start server request.
General Process:
1) start Activity and AsyncTask to get data from server: asynctask.execute();
2) call mRecyclerView.setAdapter(mAdapter); and mAdapter.notifyDataSetChanged(); and data will be shown from top on
3) initate asynctask again: first set mAdapter = null; and load another data
Problem in 3): now new loaded data will not be shown from top on, rather below the data that were there in 1) but no more visible because of mAdapter = null;. It is like RecyclerView did not "delete" the space of the old data that were shown in 1).
This is weird, has somebody any idea why this behavior occurs?
Code:
a) My Adapter:
public class Adapter_New extends RecyclerView.Adapter<Adapter_New.CustomViewHolder> {
private List<Data_B> feedItemList;
private Context mContext;
private int lastPosition = -1, b_height;
int width, height, targetHeight;
private ViewHolderState viewHolderState = ViewHolderState.getInstance();
public Adapter_New(Context context, List<Data_B> feedItemList) {
this.feedItemList = feedItemList;
this.mContext = context;
}
#Override
public CustomViewHolder onCreateViewHolder(ViewGroup viewGroup, int i) {
DisplayMetrics metrics = mContext.getResources().getDisplayMetrics();
int calc_width= metrics.widthPixels;
int calc_height=metrics.heightPixels;
int dens=metrics.densityDpi;
double wi=(double)calc_width/(double)dens;
double hi=(double)calc_height/(double)dens;
double x = Math.pow(wi,2);
double y = Math.pow(hi,2);
double screenInches = Math.sqrt(x + y);
if (screenInches >= 7.0){
width = metrics.widthPixels/3;
height = metrics.heightPixels / 4;
}else{
width = metrics.widthPixels/2;
height = metrics.heightPixels / 4;
}
View view = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.list_item_grid, null);
CustomViewHolder viewHolder = new CustomViewHolder(view);
return viewHolder;
}
#Override
public void onViewDetachedFromWindow(CustomViewHolder holder) {
super.onViewDetachedFromWindow(holder);
((CustomViewHolder) holder).clearAnimation();
((CustomViewHolder) holder).cleanup();
}
#Override
public void onBindViewHolder(final CustomViewHolder customViewHolder, int i) {
Data_Borrow data = feedItemList.get(i);
final Target target = new Target() {
#Override
public void onPrepareLoad(Drawable placeHolderDrawable) {
}
#Override
public void onBitmapLoaded(Bitmap bitmap, Picasso.LoadedFrom from) {
b_height = bitmap.getHeight();
customViewHolder.frame.getLayoutParams().height = b_height; //setting height dynamically
customViewHolder.imageView.getLayoutParams().height = b_height; //setting height dynamically
customViewHolder.imageView.setImageBitmap(bitmap);
}
#Override
public void onBitmapFailed(Drawable errorDrawable) {
}
};
customViewHolder.imageView.setTag(target);
Picasso.with(mContext)
.load(data.getImageUrl())
.resize(width, height)
.into(target);
// Animation apply
setAnimation(customViewHolder.rel_container, i);
}
//Animation
private void setAnimation(View viewToAnimate, int position) {
// If the bound view wasn't previously displayed on screen, it's animated
if (position > lastPosition) {
Animation animation = AnimationUtils.loadAnimation(mContext, R.anim.slide_in_up);
viewToAnimate.startAnimation(animation);
lastPosition = position;
}
}
#Override
public int getItemCount() {
return (null != feedItemList ? feedItemList.size() : 0);
}
public void add_new(List<Data_Borrow> datas) {
//feedItemList.clear();
feedItemList.addAll(datas);
notifyDataSetChanged();
}
public void clear() {
feedItemList.clear();
notifyDataSetChanged();
}
public class CustomViewHolder extends RecyclerView.ViewHolder {
protected ImageView imageView;
protected RelativeLayout rel_container;
protected FrameLayout frame;
protected CardView card_view;
public CustomViewHolder(View view) {
super(view);
this.imageView = (ImageView) view.findViewById(R.id.thumbnail);
this.title = (TextView) view.findViewById(R.id.title);
this.rel_container = (RelativeLayout) view.findViewById(R.id.rel_grid_item);
this.frame = (FrameLayout) view.findViewById(R.id.frame_current);
this.frame.getLayoutParams().width = width; //setting width dynamically
this.card_view = (CardView) view.findViewById(R.id.card_view);
}
public void cleanup() {
Picasso.with(mContext)
.cancelRequest(imageView);
}
public void clearAnimation() {
rel_container.clearAnimation();
}
}
}
b) My Activity:
public class MyActivity extends AppCompatActivity implements FetchDataListener, SearchView.OnQueryTextListener, AdapterView.OnItemSelectedListener {
private List<Data_B> feedsList = null;
private RecyclerView mRecyclerView;
private Adapter_New mAdapter;
StaggeredGridLayoutManager StaggeredGridLayoutManager;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.my_activity);
StaggeredGridLayoutManager = new StaggeredGridLayoutManager(3, 1);
StaggeredGridLayoutManager.setGapStrategy(StaggeredGridLayoutManager.GAP_HANDLING_NONE);
mRecyclerView.setAdapter(new Data_Borrow_Adapter_New(this, feedsList)); // first add empty adapter
mRecyclerView.setLayoutManager(StaggeredGridLayoutManager);
initView(); //start initView when activity starts
//******* WHEN I CLICK TO GET NEW FILTERED DATA, then new data is not shown from top on ****//
btn_start_filtered_asynctask = (Button) findViewById(R.id.btn_filter);
btn_start_filtered_asynctask.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
initViewFilterd();
}
});
}
private void initView() {
String url = "http://xxx/xx.php";
String show_from = "0";
FetchDataTask_ALL task = new FetchDataTask_ALL(this);
task.execute(url, show_from);
loading = true;
}
private void initViewFilterd() {
String url = "http://xxx/xx.php";
String show_from = "0";
String result_category_pos = "2";
FetchDataTask_Filtered task = new FetchDataTask_Filtered(this);
task.execute(url, result_category_pos, show_from);
mAdapter = null; //setting adapter null
loading = true;
}
#Override
public void onFetchComplete(List<Data_B> data) {
if (mAdapter == null)
{
mAdapter = new Adapter_New(getApplicationContext(), data);
mRecyclerView.setAdapter(mAdapter);
mAdapter.notifyDataSetChanged();
} else {
mAdapter.add_new(data);
}
searchItem.collapseActionView();
loading = false;
mRecyclerView.setVisibility(View.VISIBLE);
}
}
you should not set adapter to null, you should update the data in the adapter (in your case, add the new item at the beginning of the datasource (list, array, anything) and then call notifyDataSetChanged()
EDIT: I suggest to change this two methods: remove adapter = null, and always add item first. (you may need to add that method to the adapter)
private void initViewFilterd() {
String url = "http://xxx/xx.php";
String show_from = "0";
String result_category_pos = "2";
FetchDataTask_Filtered task = new FetchDataTask_Filtered(this);
task.execute(url, result_category_pos, show_from);
loading = true;
}
#Override
public void onFetchComplete(List<Data_B> data) {
mAdapter.addFirstAndUpdate(data);
searchItem.collapseActionView();
loading = false;
mRecyclerView.setVisibility(View.VISIBLE);
}
In adapter:
public void addFirstAndUpdate(List<Data_Borrow> datas) {
// TODO: add data in feedItemList
notifyDataSetChanged();
}