I have a recycler view with with multiple toggle buttons on click of which the state is changed and the newly updated state is sent to the server by calling a service on changing the state of the toggle button.
The problem i am facing is that whenever the recycler view is scrolled the toggle buttons are getting checked randomly because of the recycling of the views and the service is called multiple times at the same time, because of which an indeterminate progress bar is shown.
I have tried multiple ways to handle this by intially setting the adapter to null. and also storing the state of the checked/toggle state of the button.
But nothing seems to help.
Below is the code of the recycler adapter class
public class NotificationsIllnessAdapter extends RecyclerView.Adapter<NotificationsIllnessAdapter.NotificationIllnessViewHolder> {
Context context = null;
ArrayList<NotificationIllnessdata> notificationIllnessdatas;
ArrayList<NotificationIllnessdata> notificationIllnessArraylist = null;
NetworkStatus mNetworkStatus = null;
static AlertDialog mShowDialog = null;
Button mButton_alerts;
public NotificationsIllnessAdapter(Context context,ArrayList<NotificationIllnessdata> notificationIllnessdataArrayList,Button button_alerts) {
this.context = context;
this.notificationIllnessdatas=notificationIllnessdataArrayList;
this.mButton_alerts=button_alerts;
for(int i=0;i<this.notificationIllnessdatas.size();i++)
{
Log.e("nIllnessadapter","inside constructor"+this.notificationIllnessdatas.get(i).getIsNotification());
}
}
#Override
public NotificationIllnessViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
mNetworkStatus = new NetworkStatus(context);
View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.notifications_inflater, parent, false);
notificationIllnessArraylist = new ArrayList<>();
NotificationIllnessViewHolder viewHolder = new NotificationIllnessViewHolder(context,v);
viewHolder.setClickListener(new MyClickListener() {
#Override
public void onClickListener(View v, int position, boolean isLongClick) {
Toast.makeText(context,"OnClick",Toast.LENGTH_SHORT).show();
}
});
return viewHolder;
}
#Override
public void onBindViewHolder(final NotificationIllnessViewHolder holder, final int position) {
holder.mTextView_symptom.setText(notificationIllnessdatas.get(position).getIllnessCategory());
if(notificationIllnessdatas.get(position).getIsNotification())
{
Log.e("nIllnessadapter","true"+position);
holder.mToggleButton_symptom.setChecked(true);
}
else
{
Log.e("nIllnessadapter","false"+position);
holder.mToggleButton_symptom.setChecked(false);
}
//in some cases, it will prevent unwanted situations
holder.mToggleButton_symptom.setOnCheckedChangeListener(null);
//if true the togglebutton will be selected else unselected.
holder.mToggleButton_symptom.setChecked(notificationIllnessdatas.get(position).getIsNotification());
holder.mToggleButton_symptom.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
ArrayList<UpdateNotificationRequestData> Updatenoti;
#Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
if(isChecked)
{
//toggle button enabled
UpdateNotificationsRequestModel requestModel = new UpdateNotificationsRequestModel();
requestModel.setUserID(AppPreferences.readString(context, AppPreferenceNames.sUserid,""));
requestModel.setAppVersion(CommonUtils.APP_VERSION);
requestModel.setDeviceInfo(CommonUtils.DeviceInfo);
requestModel.setDeviceTypeID(CommonUtils.DEVICE_TYPE_ID);
Updatenoti = new ArrayList<UpdateNotificationRequestData>();
UpdateNotificationRequestData requestData = new UpdateNotificationRequestData();
Log.e("illadapter","status-->"+notificationIllnessdatas.get(position).getIsNotification());
requestData.setIsNotification("1");
requestData.setNotificationSettingID(notificationIllnessdatas.get(position).getNotificationSettingID());
Updatenoti.add(requestData);
requestModel.setUpdateNotification(Updatenoti);
/**
* Call the Update Notifications service
*/
if (mNetworkStatus.isNetWorkAvailable(context) == true) {
update_notifications(requestModel);
} else {
CommonUtils.showAlertDialog(context,"No Network Available. Please connect to network");
}
//set the objects last status
holder.mToggleButton_symptom.setChecked(isChecked);
}
else
{
//toggle button disabled
UpdateNotificationsRequestModel requestModel = new UpdateNotificationsRequestModel();
requestModel.setUserID(AppPreferences.readString(context, AppPreferenceNames.sUserid,""));
requestModel.setAppVersion(CommonUtils.APP_VERSION);
requestModel.setDeviceInfo(CommonUtils.DeviceInfo);
requestModel.setDeviceTypeID(CommonUtils.DEVICE_TYPE_ID);
Updatenoti = new ArrayList<UpdateNotificationRequestData>();
UpdateNotificationRequestData requestData = new UpdateNotificationRequestData();
Log.e("illadapter","status 2-->"+notificationIllnessdatas.get(position).getIsNotification());
requestData.setIsNotification("0");
requestData.setNotificationSettingID(notificationIllnessdatas.get(position).getNotificationSettingID());
Updatenoti.add(requestData);
requestModel.setUpdateNotification(Updatenoti);
/**
* Call the UpdateNotifications service
*/
if (mNetworkStatus.isNetWorkAvailable(context) == true) {
update_notifications(requestModel);
} else {
CommonUtils.showAlertDialog(context,"No Network Available. Please connect to network");
}
//set the objects last status
holder.mToggleButton_symptom.setChecked(false);
}
}
});
}
#Override
public int getItemCount() {
return notificationIllnessdatas.size();
}
/**
* View Holder for Adapter
*/
class NotificationIllnessViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener
{
MyClickListener clickListener;
public TextView mTextView_symptom;
public ToggleButton mToggleButton_symptom;
public NotificationIllnessViewHolder(Context context,View itemView) {
super(itemView);
mTextView_symptom = (TextView)itemView.findViewById(R.id.TextView_Symptom);
mToggleButton_symptom = (ToggleButton) itemView.findViewById(R.id.ToggleButton_Symptoms);
}
#Override
public void onClick(View v) {
// If not long clicked, pass last variable as false.
clickListener.onClickListener(v, getPosition(), false);
}
public void setClickListener(MyClickListener clickListener) {
this.clickListener = clickListener;
}
}
/**
* Update the notification settings
*/
public void update_notifications(UpdateNotificationsRequestModel object) {
/**
* Start the progress Bar.
*/
CommonUtils.show_progressbar(context);
/**
* call api
*/
Call<UpdateNotificationsResponseModel> responsecall = VirusApplication.getRestClient().getAPIService().updateNotifications(object);
responsecall.enqueue(new Callback<UpdateNotificationsResponseModel>() {
#Override
public void onResponse(Response<UpdateNotificationsResponseModel> response, Retrofit retrofit) {
/**
* Stop the progress Bar
*/
CommonUtils.stop_progressbar();
if (response.isSuccess()) {
//Server Success
UpdateNotificationsResponseModel responseModel = response.body();
if (responseModel.getErrorCode().equalsIgnoreCase("0")) {
//Data Success
Log.e("nf", "data success");
//CommonUtils.showAlertDialog(context, responseModel.getMessage());
AlertDialog.Builder builder = new AlertDialog.Builder(context);
builder.setMessage(responseModel.getMessage())
.setPositiveButton(R.string.ok, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
/**
* Downloads mychildren details.
*/
if (mNetworkStatus.isNetWorkAvailable(context)) {
getNotificationSettings();
} else {
CommonUtils.showAlertDialog(context, context.getString(R.string.network_unavailable));
}
dialog.dismiss();
}
});
mShowDialog = builder.create();
mShowDialog.show();
} else {
CommonUtils.showAlertDialog(context, responseModel.getMessage());
}
} else {
CommonUtils.showAlertDialog(context, "Server Error");
}
}
#Override
public void onFailure(Throwable t) {
/**
* Stop the progress Bar
*/
CommonUtils.stop_progressbar();
}
});
}
/**
* Get Notification Settings
*/
public void getNotificationSettings(){
//hit the getnotifications API to fetch the notification details
CommonUtils.show_progressbar(context);
/**
* Calls WebAPI
*/
Call<NotificationsModel> notificationsModelCall = VirusApplication.getRestClient().getAPIService().notifications(getNotificationsrequest());
notificationsModelCall.enqueue(new Callback<NotificationsModel>() {
#Override
public void onResponse(Response<NotificationsModel> response, Retrofit retrofit) {
/**
* Stops the Progresss bar
*/
CommonUtils.stop_progressbar();
if(response.isSuccess()) {
NotificationsModel notificationsModel = response.body();
if (notificationsModel.getErrorCode().equalsIgnoreCase("0")) {// Data Success
Log.e("notificationsAdapter","data success");
int i = 1;
notificationIllnessArraylist.clear();
for (NotificationIllnessdata notificationIllnessdata : notificationsModel.getNotificationIllnessdata()) {
notificationIllnessArraylist.add(notificationIllnessdata);
Log.e("notificationsAdapter","getnotificationsmethod"+i +notificationIllnessdata.getIsNotification() );
i++;
}
Log.e("sonu", "Symptoms ArraySize-->" + notificationIllnessArraylist.size());
if (notificationIllnessArraylist.size() > 0) {
ArrayList<NotificationIllnessdata> arrayTrue = new ArrayList<NotificationIllnessdata>();
ArrayList<NotificationIllnessdata> arrayFalse = new ArrayList<NotificationIllnessdata>();
for(int j=0;j<notificationIllnessArraylist.size();j++)
{
if(notificationIllnessArraylist.get(j).getIsNotification()){
arrayTrue.add(notificationIllnessArraylist.get(j));
}
else
if(!notificationIllnessArraylist.get(j).getIsNotification())
{
arrayFalse.add(notificationIllnessArraylist.get(j));
}
}
if(notificationIllnessArraylist.size()==arrayTrue.size())
{
mButton_alerts.setText("DeSelect All");
mButton_alerts.setBackgroundResource(R.drawable.togglebutton_on);
}
else
if(notificationIllnessArraylist.size()==arrayFalse.size())
{
mButton_alerts.setText("Select All");
mButton_alerts.setBackgroundResource(R.drawable.togglebutton_off);
}
else {
mButton_alerts.setText("Select All");
mButton_alerts.setBackgroundResource(R.drawable.togglebutton_off);
}
}
}
}
}
#Override
public void onFailure(Throwable t) {
}
});
}
/**
* Request values to Get notifications.
*
* #return map object
*/
public Map<String, Object> getNotificationsrequest() {
Map<String, Object> getChildrenValues = new HashMap<>();
getChildrenValues.put("appVersion", CommonUtils.APP_VERSION);
getChildrenValues.put("deviceTypeID", CommonUtils.DEVICE_TYPE_ID);
getChildrenValues.put("deviceInfo", CommonUtils.DeviceInfo);
getChildrenValues.put("userID", AppPreferences.readString(context, AppPreferenceNames.sUserid, ""));
return getChildrenValues;
}
}
Please help me with this. Have been trying from many days but haven't found any solution even after following many answers on stack overflow.
Try out this :
public class NotificationsIllnessAdapter extends RecyclerView.Adapter<NotificationsIllnessAdapter.NotificationIllnessViewHolder> {
Context context = null;
ArrayList<NotificationIllnessdata> notificationIllnessdatas;
NetworkStatus mNetworkStatus = null;
static AlertDialog mShowDialog = null;
Button mButton_alerts;
public NotificationsIllnessAdapter(Context context,ArrayList<NotificationIllnessdata> notificationIllnessdataArrayList,Button button_alerts) {
this.context = context;
this.mNetworkStatus = new NetworkStatus(context);
this.notificationIllnessdatas=notificationIllnessdataArrayList;
this.mButton_alerts=button_alerts;
}
#Override
public NotificationIllnessViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.notifications_inflater, parent, false);
NotificationIllnessViewHolder viewHolder = new NotificationIllnessViewHolder(context,v);
return viewHolder;
}
#Override
public void onBindViewHolder(final NotificationIllnessViewHolder holder, final int position) {
holder.mTextView_symptom.setText(notificationIllnessdatas.get(position).getIllnessCategory());
holder.mToggleButton_symptom.setChecked(notificationIllnessdatas.get(position).getIsNotification());
holder.mToggleButton_symptom.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
ArrayList<UpdateNotificationRequestData> Updatenoti;
#Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
int position = getAdapterPosition();
if( position == RecyclerView.NO_POSITION ) {
return;
}
if(isChecked)
{
notificationIllnessdatas.get(position).setNotification(true);
}
else
{
notificationIllnessdatas.get(position).setNotification(false);
}
}
});
}
The toggling of checkboxes / toggle buttons happens due to the fact that the states are not maintained in your model class. You already have a isNotification field in your model class, set it as soon as the toggle happens as I've illustrated in the code. I have other code clean up suggestions, but those can wait.
Let me know if you need more clarifications.
Update : Answer only applicable for retaining states of toggle
buttons.
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.
So I've got an adapter, which is holding a list of objects that I'm displaying. I'm using the MVVP approach with LiveData and ViewModel that come with the android architecture framework.
In my fragment, I connect the livedata to the adapter:
viewModel.getAlarms().observe(this, alarms -> {
Timber.d("Updating alarm list");
alarmAdapter.updateAlarms(alarms);
});
And in my adapter, I update the list...
void updateAlarms(List<Alarm> alarms){
this.alarms = alarms;
notifyDataSetChanged();
}
So even if I make a small change on a single item from the list (item update, item create, item delete..), the whole list will update. That messes up all of my animations. Is there a way to prevent that?
I don't want to copy everything, but as requested here's the bigger picture:
Fragment:
#Override
public void onActivityCreated(#Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
viewModel = ViewModelProviders.of(this, factory).get(HomeViewModel.class);
// Get everything..
viewModel.getAlarms().observe(this, alarms -> {
Timber.d("Updating alarm list");
alarmAdapter.updateAlarms(alarms);
});
}
#OnClick(R.id.home_fbtn_add_alarm)
void addAlarm(){
viewModel.createAlarm(new Alarm(13,39));
}
private void onAlarmStatusChanged(int alarmId, boolean isActive){
// TODO Make it so it doesn't update the whole list...
viewModel.setAlarmStatus(alarmId, isActive);
}
private void onAlarmDeleted(int alarmId){
this.showSnackbar(String.format("Alarm %s deleted", alarmId), clContainer);
viewModel.deleteAlarm(alarmId);
}
Adapter:
class AlarmsAdapter extends RecyclerView.Adapter<AlarmsAdapter.AlarmHolder> {
private List<Alarm> alarms;
private BiConsumer<Integer, Boolean> onStatusChange;
private Consumer<Integer> onDelete;
AlarmsAdapter(BiConsumer<Integer, Boolean> onStatusChange, Consumer<Integer> onDelete) {
this.alarms = new ArrayList<>();
this.onStatusChange = onStatusChange;
this.onDelete = onDelete;
}
void updateAlarms(List<Alarm> alarms){
this.alarms = alarms;
notifyDataSetChanged();
}
#NonNull
#Override
public AlarmHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
Context parentContext = parent.getContext();
int alarmLayoutId = R.layout.item_alarm;
View view = LayoutInflater.from(parentContext).inflate(alarmLayoutId, parent, false);
return new AlarmHolder(view);
}
#Override
public void onBindViewHolder(#NonNull AlarmHolder alarmViewHolder, int position) {
Alarm alarm = alarms.get(position);
alarmViewHolder.setAlarm(alarm);
}
#Override
public int getItemCount() {
return alarms == null ? 0 : alarms.size();
}
class AlarmHolder extends RecyclerView.ViewHolder {
#BindView(R.id.item_alarm_tv_time)
TextView tvTime;
#BindView(R.id.item_alarm_tv_repeat)
TextView tvRepeat;
#BindView(R.id.item_alarm_tv_punishments)
TextView tvPunishment;
#BindView(R.id.item_alarm_swt_active)
Switch swtActive;
#BindView(R.id.item_alarm_img_delete)
ImageView imgDelete;
#BindView(R.id.item_alarm_foreground)
ConstraintLayout foreground;
#BindView(R.id.item_alarm_background)
RelativeLayout background;
AlarmHolder(#NonNull View itemView) {
super(itemView);
ButterKnife.bind(this, itemView);
}
void setAlarm(Alarm alarm){
Timber.i("Setting alarm: %s", this.getAdapterPosition());
boolean isActive = alarm.getActive();
tvTime.setText(alarm.getTime());
tvRepeat.setText(alarm.getRepetitionDays());
tvPunishment.setText(alarm.getPunishments());
swtActive.setChecked(isActive);
}
private void setStatus(boolean isActive) {
AlphaAnimation animation;
if(!isActive){
animation = new AlphaAnimation(1.0f, 0.3f);
} else {
animation = new AlphaAnimation(0.3f, 1f);
}
animation.setDuration(300);
animation.setFillAfter(true);
this.itemView.startAnimation(animation);
// TODO Make it so it doesn't update the whole list...
}
#OnCheckedChanged(R.id.item_alarm_swt_active)
void onStatusClick(boolean checked) {
onStatusChange.accept(getAdapterPosition(), checked);
setStatus(checked);
}
#OnClick(R.id.item_alarm_img_delete)
void onDeleteClick() {
onDelete.accept(getAdapterPosition());
}
}}
And the LiveData:
public class HomeViewModel extends ViewModel {
private final AlarmRepository alarmRepository;
private LiveData<List<Alarm>> alarms;
public HomeViewModel(AlarmRepository alarmRepository) {
this.alarmRepository = alarmRepository;
}
/**
* Gets the Alarms' Observable...
* #return Alarms' observable
*/
LiveData<List<Alarm>> getAlarms() {
Timber.d("Fetching alarms..");
if(alarms == null) {
Timber.i("No alarms are cached. Going to DB!");
alarms = alarmRepository.getAllAlarms();
}
return alarms;
}
/**
* Deletes the selected
* #param alarmPosition alarm to be deleted
*/
void deleteAlarm(int alarmPosition) {
Timber.d("Deleting alarm %d", alarmPosition);
getAlarmAtPosition(alarmPosition)
.ifPresent(alarmRepository::deleteAlarm);
}
/**
* Changes the status of the selected alarm
* #param alarmPosition The selected alarm
* #param status The new status
*/
void setAlarmStatus(int alarmPosition, boolean status){
Timber.d("Alarm: %d is changing active status to %s", alarmPosition, status);
getAlarmAtPosition(alarmPosition)
.ifPresent(alarm -> alarmRepository.updateStatus(alarm, status));
}
/**
* Gets the alarm at the selected position.
* #param position The position of the alarm
* #return The alarm of the selected position. Else returns empty.
*/
private Optional<Alarm> getAlarmAtPosition(int position){
Optional<List<Alarm>> alarms =
Optional.ofNullable(this.alarms)
.map(LiveData::getValue);
if(!alarms.isPresent()) {
return Optional.empty();
}
try {
return Optional.of(alarms.get().get(position));
} catch (Exception e){
Timber.e(e, "Could not get alarm at position: %d", position);
return Optional.empty();
}
}
/**
* Creates a new alarm. If null, does nothing.
* #param alarm The alarm to be saved in the DB
*/
void createAlarm(Alarm alarm) {
Timber.d("Adding new alarm.");
if(alarm == null) {
Timber.w("Cannot save null alarm");
return;
}
alarmRepository.createAlarm(alarm);
}
}
I would suggest using ListAdapter (part of recyclerView library)
class AlarmsAdapter extends ListAdapter<Alarm , AlarmsAdapter.AlarmHolder> {
public AlarmsAdapter(
#NonNull ItemCallback<Feed> diffCallback) {
super(diffCallback);
}.....
}
pass this to AlarmsAdapter
private final ItemCallback<Alarm > diffCallback = new ItemCallback<Feed>() {
#Override
public boolean areItemsTheSame(#NonNull Alarm oldItem, #NonNull Alarm newItem) {
return oldItem==newItem;
}
#Override
public boolean areContentsTheSame(#NonNull Alarm oldItem, #NonNull Alarm newItem) {
return oldItem==newItem;
}
};
Model Class
public class TestListModel {
private String testlist_id;
private String test_price;
private String test_name;
private boolean isSelected;
public TestListModel(String testlist_id, String test_price, String test_name,boolean isSelected) {
this.testlist_id = testlist_id;
this.test_price = test_price;
this.test_name = test_name;
this.isSelected = isSelected;
}
public String getTestlist_id() {
return testlist_id;
}
public void setTestlist_id(String testlist_id) {
this.testlist_id = testlist_id;
}
public String getTest_price() {
return test_price;
}
public void setTest_price(String test_price) {
this.test_price = test_price;
}
public String getTest_name() {
return test_name;
}
public void setTest_name(String test_name) {
this.test_name = test_name;
}
public boolean isSelected() {
return isSelected;
}
public boolean setSelected(boolean isSelected) {
this.isSelected = isSelected;
return isSelected;
}
}
Recycler Adapter Class
public class RecyclerAdapter extends RecyclerView.Adapter<RecyclerAdapter.ViewHolder> {
private ArrayList<TestListModel> android;
public RecyclerAdapter(ArrayList<TestListModel> android) {
this.android = android;
}
#Override
public RecyclerAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.test_list_row,parent,false);
return new ViewHolder(view);
}
#Override
public void onBindViewHolder(RecyclerAdapter.ViewHolder holder, final int position) {
holder.test_name.setText(android.get(position).getTest_name());
holder.test_price.setText(android.get(position).getTest_price());
holder.chkSelected.setChecked(android.get(position).isSelected());
holder.chkSelected.setTag(android.get(position));
holder.chkSelected.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
CheckBox cb = (CheckBox) v;
TestListModel contact = (TestListModel) cb.getTag();
contact.setSelected(cb.isChecked());
android.get(position).setSelected(cb.isChecked());
Toast.makeText(
v.getContext(),
"Clicked on Checkbox: " + cb.getText() + " is "
+ cb.isChecked(), Toast.LENGTH_LONG).show();
}
});
}
#Override
public int getItemCount() {
return android.size();
}
public class ViewHolder extends RecyclerView.ViewHolder {
private TextView test_name;
private TextView test_price;
public CheckBox chkSelected;
public TestListModel testLists;
public ViewHolder(View itemView) {
super(itemView);
test_name = (TextView)itemView.findViewById(R.id.test_name);
test_price = (TextView)itemView.findViewById(R.id.price_name);
chkSelected = (CheckBox) itemView.findViewById(R.id.check_box);
}
}
// method to access in activity after updating selection
public List<TestListModel> getTestList() {
return android;
}
}
HealthActivity
public class HealthServicesActivity extends AppCompatActivity implements View.OnClickListener {
SharePreferenceManager<LoginModel> sharePreferenceManager;
/*
*Api call
* */
private RecyclerView recyclerView;
private ArrayList<TestListModel> data;
private RecyclerAdapter madapter;
private Button submitButton;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_health_services);
ButterKnife.bind(this);
sharePreferenceManager = new SharePreferenceManager<>(getApplicationContext());
submitButton = (Button) findViewById(R.id.submit_button);
}
/*
* On Click Listner
* */
#Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.submit_button:
String serialNo="";
int serialNum=1;
String testListId = "";
int totalPrice = 0;
String testName = "";
String testPrice="";
List<TestListModel> stList = ((RecyclerAdapter) madapter)
.getTestList();
for (int i = 0; i < stList.size(); i++) {
TestListModel singleStudent = stList.get(i);
if (singleStudent.isSelected() == true) {
testListId = testListId+ "," + singleStudent.getTestlist_id().toString();
testName = testName + "\n" + "\n" + singleStudent.getTest_name().toString();
testPrice= testPrice+"\n" + "\n" + singleStudent.getTest_price().toString();
serialNo=serialNo + "\n" + "\n"+ Integer.parseInt(String.valueOf(serialNum));
serialNum++;
totalPrice= totalPrice+ Integer.parseInt(stList.get(i).getTest_price());
Intent in= new Intent(HealthServicesActivity.this, AmountCartActivity.class);
in.putExtra("test_id",testListId);
in.putExtra("test_name", testName);
in.putExtra("test_price", testPrice);
in.putExtra("total_price",totalPrice);
in.putExtra("serial_number",serialNo);
in.putExtra("patient_id",patientID);
startActivity(in);
}
else
Toasty.error(getApplicationContext(), "Please Select Test Lists", Toast.LENGTH_SHORT, true).show();
}
break;
/* Toast.makeText(HealthServicesActivity.this,
"Selected Lists: \n" + testName+""+testPrice, Toast.LENGTH_LONG)
.show();*/
/** back Button Click
* */
case R.id.back_to_add_patient:
startActivity(new Intent(getApplicationContext(), PatientActivity.class));
finish();
break;
default:
break;
}
}
/*
* Api Call For Displaying Test Lists
* */
private void loadJSON() {
String centerID=(sharePreferenceManager.getUserLoginData(LoginModel.class).getResult().getCenterId());
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(" http://192.168.1.80/aoplnew/api/")
// .baseUrl("https://earthquake.usgs.gov/fdsnws/event/1/query?")
.addConverterFactory(GsonConverterFactory.create())
.build();
ApiInterface request = retrofit.create(ApiInterface.class);
Call<JSONResponse> call = request.getTestLists("http://192.168.1.80/aoplnew/api/users/gettestlist/"+centerID);
call.enqueue(new Callback<JSONResponse>() {
#Override
public void onResponse(Call<JSONResponse> call, Response<JSONResponse> response) {
JSONResponse jsonResponse = response.body();
data = new ArrayList<>(Arrays.asList(jsonResponse.getResult()));
madapter = new RecyclerAdapter(data);
recyclerView.setAdapter(madapter);
Toast.makeText(HealthServicesActivity.this, "APi Call Back", Toast.LENGTH_SHORT).show();
}
#Override
public void onFailure(Call<JSONResponse> call, Throwable t) {
Log.d("Error",t.getMessage());
}
});
}
#Override
public void onBackPressed() {
super.onBackPressed();
startActivity(new Intent(getApplicationContext(), PatientActivity.class));
finish();
}
}
AmountCartActivity
public class AmountCartActivity extends AppCompatActivity implements View.OnClickListener , PaymentResultListener {
SharePreferenceManager<LoginModel> sharePreferenceManager;
/*
*Setting Recycler View
* */
private RecyclerView recyclerView;
List<AmountCartModel> mydataList ;
private MyAdapter madapter;
/*
* Getting Bundle Values
* */
Bundle extras ;
String testId="";
String testName="";
String testPrice="";
String totalPrice="";
String serialNumber="";
private Button backButton;
/*
* Api Call For DashBoard
* */
String st;
Api webService = ServiceGenerator.getApi();
ProgressDialog progressDialog;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_amount_cart);
ButterKnife.bind(this);
progressDialog = new ProgressDialog(AmountCartActivity.this);
progressDialog.setMessage("Please Wait...");
progressDialog.setCanceledOnTouchOutside(false);
backButton=(Button) findViewById(R.id.back_button);
showcenterid(sharePreferenceManager.getUserLoginData(LoginModel.class));
backButton.setOnClickListener(this);
gettingValues();
}
#Override
public void onClick(View v) {
switch (v.getId()) {
/*
* back Button Click
* */
case R.id.back_button:
startActivity(new Intent(getApplicationContext(), HealthServicesActivity.class));
//finish();
break;
default:
break;
}
}
/*
* Getting Bundle Values and Setting Recycler View
* */
private void gettingValues() {
mydataList = new ArrayList<>();
/*
* Getting Values From BUNDLE
* */
bundle = getIntent().getExtras();
if (bundle != null) {
testId=bundle.getString("test_id");
testName = bundle.getString("test_name");
testPrice = bundle.getString("test_price");
totalPrice= String.valueOf(bundle.getInt("total_price"));
serialNumber=bundle.getString("serial_number");
//Just add your data in list
AmountCartModel mydata = new AmountCartModel(); // object of Model Class
mydata.setTestId(testId);
mydata.setTestName(testName );
mydata.setTestPrice(testPrice);
mydata.setSerialNumber(serialNumber);
mydataList.add(mydata);
totalPriceDisplay.setText("Total Amount : "+totalPrice);
}
madapter=new MyAdapter(mydataList);
madapter.setMyDataList(mydataList);
recyclerView = (RecyclerView)findViewById(R.id.recyler_amount_cart);
recyclerView.setHasFixedSize(true);
RecyclerView.LayoutManager layoutManager = new LinearLayoutManager(getApplicationContext());
recyclerView.setLayoutManager(layoutManager);
recyclerView.setAdapter(madapter);
}
Recycler Adapter for AmountCart
/*
* Recycler Adapter
*/
public class MyAdapter extends RecyclerView.Adapter<MyAdapter.ViewHolder> {
private List<AmountCartModel> context;
private List<AmountCartModel> myDataList;
public MyAdapter(List<AmountCartModel> context) {
this.context = context;
myDataList = new ArrayList<>();
}
#Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
// Replace with your layout
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.amount_cart_row, parent, false);
return new ViewHolder(view);
}
#Override
public void onBindViewHolder(ViewHolder holder, int position) {
// Set Your Data here to yout Layout Components..
// to get Amount
/* myDataList.get(position).getTestName();
myDataList.get(position).getTestPrice();*/
holder.testName.setText(myDataList.get(position).getTestName());
holder.testPrice.setText(myDataList.get(position).getTestPrice());
holder.textView2.setText(myDataList.get(position).getSerialNumber());
}
#Override
public int getItemCount() {
/*if (myDataList.size() != 0) {
// return Size of List if not empty!
return myDataList.size();
}
return 0;*/
return myDataList.size();
}
public void setMyDataList(List<AmountCartModel> myDataList) {
// getting list from Fragment.
this.myDataList = myDataList;
notifyDataSetChanged();
}
public class ViewHolder extends RecyclerView.ViewHolder {
TextView testName,testPrice,textView2;
public ViewHolder(View itemView) {
super(itemView);
// itemView.findViewById
testName=itemView.findViewById(R.id.test_name_one);
testPrice=itemView.findViewById(R.id.test_price);
textView2=itemView.findViewById(R.id.textView2);
}
}
}
How to maintain the checkbox state across the activities. I am displaying checkbox using recycler view in rest api call. I am selecting checkboxes from HealthActivity and clicking on submit button then the whole list is displaying in AmountCartActivity but when I m clicking on back button then i m not getting those selected checkboxes. And when I add or remove any checkbox then it should give the result as per selection only. How to maintain the state of the selected checkboxes?
In your AmountCartActivity when you listen for back button clicks you do this:
#Override
public void onClick(View v) {
switch (v.getId()) {
/*
* back Button Click
* */
case R.id.back_button:
startActivity(new Intent(getApplicationContext(), HealthServicesActivity.class));
//finish();
break;
default:
break;
}
}
You are opening a brand new HealthServicesActivity and you don't persist the data anywhere. (When you open a new HealthServicesActivity it does not know anything about your old list). So I think what you aim to do is finishing the AmountCartActivity and resuming the previous HealthServicesActivity like this:
#Override
public void onClick(View v) {
switch (v.getId()) {
/*
* back Button Click
* */
case R.id.back_button:
finish(); //JUST FINISH THE ACTIVITY AND RETURN TO THE PREVIOUS ACTIVITY
break;
default:
break;
}
}
EDIT: (added item click listener logic)
As you will be using the same HealthServiceActivity every time you submit and go back, I think you should implement an interface to keep your checkbox states updated. Make below changes in your respective methods (Please see my comments)
RecylerAdapter:
public class RecyclerAdapter extends RecyclerView.Adapter<RecyclerAdapter.ViewHolder> {
private ArrayList<TestListModel> android;
private OnItemClickListener onItemClickListener; //ADD THIS GLOBAL FIELD
/** THIS METHOD IS TO BIND YOUR NEW ITEM CLICK LISTENER **/
public void setOnItemClickListener(OnItemClickListener onItemClickListener)
{
this.onItemClickListener = onItemClickListener;
}
#Override
public void onBindViewHolder(RecyclerAdapter.ViewHolder holder, final int position) {
holder.test_name.setText(android.get(position).getTest_name());
holder.test_price.setText(android.get(position).getTest_price());
holder.chkSelected.setChecked(android.get(position).isSelected());
//YOU DON'T HAVE TO DEAL WITH TAGS, JUST USE BELOW CODE TO SET YOUR
// ITEM CLICK LISTENER TO EACH CHECKBOX
holder.chkSelected.setOnClickListener(v ->
onItemClickListener.onClickItem(position);
}
// THIS METHOD WILL SWITCH YOUR SELECT STATES AND UPDATE ITEMS ACCORDINGLY
public void updateCheckboxState(int position){
TestListModel listItem = android.get(position);
listItem.setSelected(!listItem.isSelected());
notifyDataSetChanged();
}
// ADD THIS INTERFACE
public interface OnItemClickListener {
void onClickItem(int position);
}
}
HealthServicesActivity:
//DON'T FORGET TO IMPLEMENT RecylcerAdapter.OnItemClickListener
public class HealthServicesActivity extends AppCompatActivity implements View.OnClickListener, RecyclerAdapter.OnItemClickListener {
/*
* Api Call For Displaying Test Lists
* */
private void loadJSON() {
{ ... }
#Override
public void onResponse(Call<JSONResponse> call, Response<JSONResponse> response) {
JSONResponse jsonResponse = response.body();
data = new ArrayList<>(Arrays.asList(jsonResponse.getResult()));
madapter = new RecyclerAdapter(data);
madapter.setOnItemClickListener(this); // SET YOUR LISTENER HERE
recyclerView.setAdapter(madapter);
Toast.makeText(HealthServicesActivity.this, "APi Call Back", Toast.LENGTH_SHORT).show();
}
// UPDATE CHECKBOX STATES WHEN AN ITEM IS CLICKED
#Override
public void onClickItem(int position) {
madapter.updateCheckboxState(position);
}
}
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.