RecyclerView messes up when scrolling - android

I never asked any question before but hope you'll get my point.
I am making a chat app in which I am using a RecyclerView to show messages. The problem is when I scroll the RecyclerView some of the items disappear from the top and the whole items messes up when I try to add a message it doesn't even scroll to bottom nor added in the ListView.
Here is my RecyclerView:
<android.support.v7.widget.RecyclerView
android:id="#+id/conversation_recyclerView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:clipToPadding="false"
android:layout_above="#id/typingConversationLayout"
android:layout_below="#id/topLayout_conversation_activity"
android:layout_marginBottom="-5dp"
android:paddingBottom="7dp" />
Initializing and setting the RecycerView:
linearLayoutManager = new LinearLayoutManager(this);
adapter = new ConversationRecyclerViewAdapter();
conversationRecyclerView.setAdapter(adapter);
conversationRecyclerView.setLayoutManager(linearLayoutManager);
linearLayoutManager.setStackFromEnd(true);
conversationRecyclerView.setHasFixedSize(true);
conversationRecyclerView.setNestedScrollingEnabled(false);
Here is my Adapter class:
private class ConversationRecyclerViewAdapter
extends RecyclerView.Adapter<ConversationRecyclerViewAdapter.ConversationViewHolder> {
#NonNull
#Override
public ConversationViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int i) {
Log.d(TAG, "onCreateViewHolder: Users Find started");
View conversationsView = LayoutInflater.from(parent.getContext()).inflate(
R.layout.layout_message_received, parent, false);
return new ConversationViewHolder(conversationsView);
}
#Override
public void onBindViewHolder(#NonNull final ConversationViewHolder holderConversation, int i) {
Log.d(TAG, "onBindViewHolder: Users Find started at position is " + i);
final int position = holderConversation.getAdapterPosition();
if (mOwnUser_1.get(position)) {
holderConversation.receivedMsgLayout.setVisibility(View.GONE);
holderConversation.sentProfileImg.setImageResource(mUserProfileImg_2.get(position));
holderConversation.sentMsg.setText(mUserText_3.get(position));
} else {
holderConversation.sentMsgLayout.setVisibility(View.GONE);
holderConversation.receivedProfileImg.setImageResource(mUserProfileImg_2.get(position));
holderConversation.receivedMsg.setText(mUserText_3.get(position));
}
Log.d(TAG, "onBindViewHolder: completed at " + position);
}
#Override
public int getItemCount() {
return mOwnUser_1.size();
}
public class ConversationViewHolder extends RecyclerView.ViewHolder {
RelativeLayout receivedMsgLayout, sentMsgLayout;
EmojiTextView receivedMsg, sentMsg;
CircleImageView receivedProfileImg, sentProfileImg;
public ConversationViewHolder(#NonNull View v) {
super(v);
receivedMsgLayout = v.findViewById(R.id.received_message_layout);
sentMsgLayout = v.findViewById(R.id.sent_message_layout);
receivedMsg = v.findViewById(R.id.received_message_text);
sentMsg = v.findViewById(R.id.sent_message_text);
receivedProfileImg = v.findViewById(R.id.received_message_user__profile_image);
sentProfileImg = v.findViewById(R.id.sent_message_user__profile_image);
}
}
}
Here I am adding data to ListView and displaying to the RecyclerView:
sendBtn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
String msg = editText.getText().toString().trim();
if (TextUtils.isEmpty(msg)) {
editText.setError("Please add a message");
editText.requestFocus();
} else {
Log.d(TAG, "onClick: send Btn ADDED TEXT.. ");
mOwnUser_1.add(user);
mUserProfileImg_2.add(image);
mUserText_3.add(message);
editText.setText("");
editText.requestFocus();
adapter.notifyItemInserted(mOwnUser_1.size());
conversationRecyclerView.scrollToPosition(mOwnUser_1.size() - 1);
}
}
});
I don't know what i am doing wrong but it does not seem to work as i wanted.
Update Code:
The three listviews:
private ArrayList<Boolean> mOwnUser_1 = new ArrayList<>();
private ArrayList<Integer> mUserProfileImg_2 = new ArrayList<>();
private ArrayList<String> mUserText_3 = new ArrayList<>();
And the way of adding data to adapter:
mOwnUser_1.add(true);
mUserProfileImg_2.add(R.drawable.boy);
mUserText_3.add(edittext.getText().toString().trim());
adapter.notifyItemInserted(mOwnUser_1.size());
conversationRecyclerView.scrollToPosition(mOwnUser_1.size() - 1);
My Whole Conversation Activity Class:
public class ConversationActivity extends AppCompatActivity {
private static final String TAG = "ConversationActivity";
private EditText editText;
private LinearLayout linearLayout;
private LinearLayoutManager linearLayoutManager;
private ImageView sendBtn;
private ImageView emojiImage;
private View rootView;
private Boolean popUpShown = false;
private Boolean micShown = false;
private ImageView micBtn;
private RelativeLayout micLayout;
private RecyclerView conversationRecyclerView;
// Array Lists for Find USERS
private ArrayList<Boolean> mOwnUser_1 = new ArrayList<>();
private ArrayList<Integer> mUserProfileImg_2 = new ArrayList<>();
private ArrayList<String> mUserText_3 = new ArrayList<>();
private ConversationRecyclerViewAdapter adapter;
#Override
protected void onCreate(Bundle savedInstanceState) {
Log.d(TAG, "onCreate: started");
super.onCreate(savedInstanceState);
EmojiManager.install(new TwitterEmojiProvider());
setContentView(R.layout.activity_conversation);
editText = findViewById(R.id.conversationEditText);
linearLayout = findViewById(R.id.optionsOther);
emojiImage = findViewById(R.id.emojiIconOther);
rootView = findViewById(R.id.root_view_conversation);
micBtn = findViewById(R.id.microphoneBtn);
micLayout = findViewById(R.id.microphoneLayout);
conversationRecyclerView = findViewById(R.id.conversation_recyclerView);
sendBtn = findViewById(R.id.sendBtnConversation);
if (!(Build.VERSION.SDK_INT >= 21))
findViewById(R.id.typingConversationLayout).setBackgroundResource(R.drawable.edit_text_conversation_background_below_api);
sendBtn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
String msg = editText.getText().toString().trim();
if (TextUtils.isEmpty(msg)) {
editText.setError("Please add a message");
editText.requestFocus();
} else {
Log.d(TAG, "onClick: send Btn ADDED TEXT.. ");
addData(true, R.drawable.boy0, msg);
}
}
});
initConversationArrayList();
}
private void addData(Boolean user, int image, String message) {
mOwnUser_1.add(user);
mUserProfileImg_2.add(image);
mUserText_3.add(message);
editText.setText("");
editText.requestFocus();
adapter.notifyItemInserted(mOwnUser_1.size());
conversationRecyclerView.scrollToPosition(mOwnUser_1.size() - 1);
}
private void initConversationArrayList() {
Log.d(TAG, "initConversationArrayList: created");
mOwnUser_1.add(true);
mUserProfileImg_2.add(R.drawable.boy0);
mUserText_3.add("Hello How are you?");
Log.d(TAG, "initConversationArrayList: completed");
initConversationRecyclerView();
}
private void initConversationRecyclerView() {
Log.d(TAG, "initConversationRecyclerView: started");
linearLayoutManager = new LinearLayoutManager(this);
adapter = new ConversationRecyclerViewAdapter();
conversationRecyclerView.setAdapter(adapter);
conversationRecyclerView.setLayoutManager(linearLayoutManager);
linearLayoutManager.setStackFromEnd(true);
conversationRecyclerView.setHasFixedSize(true);
conversationRecyclerView.setNestedScrollingEnabled(false);
Log.d(TAG, "initConversationRecyclerView: completed");
}

Currently I am also working on chat module, let me show you how am I doing this. I am going to show you in steps.
Step 1: make two separate layout for recyclerview items, one for message that has been sent from your side and one for message received from another side.
Step 2 : make two view holders to populate different layout according to your scenario, made in above step, like this:
public class ChatNewAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
private List<Chat> chats;
public ChatNewAdapter(List<Chat> chats) {
this.chats = chats;
}
#Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
if (viewType == 0) {
View viewSend = (View) LayoutInflater.from(parent.getContext()).inflate(R.layout.item_message_send, parent, false);
return new ViewHolderSend(viewSend);
} else {
View viewReceive = (View) LayoutInflater.from(parent.getContext()).inflate(R.layout.item_message_received, parent, false);
return new ViewHolderReceive(viewReceive);
}
}
#Override
public void onBindViewHolder(final RecyclerView.ViewHolder holder, int position) {
switch (holder.getItemViewType()) {
case 0:
ViewHolderSend viewHolderSend = (ViewHolderSend) holder;
viewHolderSend.messageSend.setText(chats.get(position).getMessage());
break;
case 1:
ViewHolderReceive viewHolderReceive = (ViewHolderReceive) holder;
viewHolderReceive.messageReceived.setText(chats.get(position).getMessage());
break;
}
}
#Override
public int getItemCount() {
return chats.size();
}
#Override
public int getItemViewType(int position) {
if (chats != null && !chats.get(position).fromAdmin) {
return 0;
} else
return 1;
}
class ViewHolderSend extends RecyclerView.ViewHolder {
TextView messageSend;
public ViewHolderSend(View itemView) {
super(itemView);
messageSend = (TextView) itemView.findViewById(R.id.messageSend);
}
}
class ViewHolderReceive extends RecyclerView.ViewHolder {
TextView messageReceived;
public ViewHolderReceive(View itemView) {
super(itemView);
messageReceived = (TextView) itemView.findViewById(R.id.messageReceived);
}
}
public int addMessages(Chat chat) {
chats.add(chat);
notifyDataSetChanged();
return chats.size();
}
Step 3 : now in your activity:
public class Test extends AppCompatActivity {
RecyclerView chatList;
RecyclerView.LayoutManager mLayoutManager;
ChatNewAdapter adapter;
ImageView sendButton;
EditText messageEditText;
boolean keyboardUp = false;
boolean isRunning = false;
ArrayList<Chat> chats;
#Override
protected void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_chat);
getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_PAN);
isRunning = true;
setUpComponents();
}
public void setUpComponents() {
chatList = (RecyclerView) findViewById(R.id.chat_list);
chatList.setHasFixedSize(true);
mLayoutManager = new LinearLayoutManager(this);
chatList.setLayoutManager(mLayoutManager);
messageEditText = (EditText) findViewById(R.id.messageText);
getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_HIDDEN);
sendButton = (ImageView) findViewById(R.id.send);
adapter = new ChatNewAdapter(chats);
chatList.setAdapter(adapter);
chatList.scrollToPosition(chatList.getAdapter().getItemCount() - 1);
messageEditText.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
#Override
public void onGlobalLayout() {
if (keyboardShown(messageEditText.getRootView())) {
Log.d("keyboard", "keyboard UP");
if (keyboardUp == false) {
if (chats.size() > 0)
chatList.smoothScrollToPosition(chats.size() + 1);
keyboardUp = true;
}
} else {
Log.d("keyboard", "keyboard Down");
keyboardUp = false;
}
}
});
sendButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
final String message = messageEditText.getText().toString().trim();
if (!message.equals("")) {
Chat chat = new Chat();
String name = message;
chat.setMessage(name);
messageEditText.setText("");
adapter.addMessages(chat);
chatList.scrollToPosition(chatList.getAdapter().getItemCount() - 1);
} else {
Log.d("sending message Error", "error fetching dates");
}
}
});
}
private boolean keyboardShown(View rootView) {
final int softKeyboardHeight = 100;
Rect r = new Rect();
rootView.getWindowVisibleDisplayFrame(r);
DisplayMetrics dm = rootView.getResources().getDisplayMetrics();
int heightDiff = rootView.getBottom() - r.bottom;
return heightDiff > softKeyboardHeight * dm.density;
}
And this is my model class, ignore #PrimaryKey and #Required annotation it just because I am using Realm for local DB. In your case you wont required these annotation.
public class Chat extends RealmObject {
#PrimaryKey
#Required
public Long id;
public boolean fromAdmin;
#Required
public String message;
public int type;
public boolean isRead;
public boolean isSent;
public Date date;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public boolean isFromAdmin() {
return fromAdmin;
}
public void setFromAdmin(boolean fromAdmin) {
this.fromAdmin = fromAdmin;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
public int getType() {
return type;
}
public void setType(int type) {
this.type = type;
}
public boolean isRead() {
return isRead;
}
public void setRead(boolean read) {
isRead = read;
}
public boolean isSent() {
return isSent;
}
public void setSent(boolean sent) {
isSent = sent;
}
public Date getDate() {
return date;
}
public void setDate(Date date) {
this.date = date;
}
I hope it will be helpful for you, you can ask further if you want to know anything else related to code.

RecyclerView as the name stands recycles the views. When binding data to a view, you need to ensure you set or reset all views that are touched in the adapter. Messups typically occur when there's data that is set only conditionally for some but not all items.
In particular:
if (mOwnUser_1.get(position)) {
holderConversation.receivedMsgLayout.setVisibility(View.GONE);
holderConversation.sentProfileImg.setImageResource(mUserProfileImg_2.get(position));
holderConversation.sentMsg.setText(mUserText_3.get(position));
} else {
holderConversation.sentMsgLayout.setVisibility(View.GONE);
holderConversation.receivedProfileImg.setImageResource(mUserProfileImg_2.get(position));
holderConversation.receivedMsg.setText(mUserText_3.get(position));
}
Both of these branches will need to reset the other layout back to visible.
Anyway with this kind of two-layout approach you are likely better off by having them as separate view types in your adapter. See How to create RecyclerView with multiple view type?

Related

RecyclerView filled with Objects from SharedPreferences is slow and laggy

I am building an app which has a RecyclerView which holds Objects that are retrieved from SharedPreferences.
Unfortunately the RecyclerView is lagging when it is binded.
This is my Adapter
public class ShiftAdapter extends RecyclerView.Adapter<ShiftAdapter.ViewHolder>{
private List<Shift> mDataSet;
private Context mContext;
private static final String TAG = "ShiftAdapter";
public int previousExpandedPosition = -1;
public int mExpandedPosition = -1;
private static SharedPreferences mPrefs;
private LinearLayout mShiftIn;
private LinearLayout mShiftOut;
private Boolean isStart;
private Date shiftIn;
private Date shiftOut;
private Date mDate;
public EditText mshiftInText;
public EditText mshiftOutText;
public Date date;
public ShiftAdapter(Context context, List<Shift> list) {
mDataSet = list;
mContext = context;
}
public static class ViewHolder extends RecyclerView.ViewHolder {
public TextView mDate;
public TextView mTime;
public TextView mPay;
public RelativeLayout mRelativeLayout;
public LinearLayout mExepandableLayout;
public Date mshiftIn;
public Date mshiftOut;
public EditText mshiftInText;
public EditText mshiftOutText;
public Button mUpdateButton;
public Button mDeleteButton;
public ViewHolder(View v) {
super(v);
mDate = (TextView) v.findViewById(R.id.date_TV);
mTime = (TextView) v.findViewById(R.id.time_TV);
mPay = (TextView) v.findViewById(R.id.pay_TV);
mRelativeLayout = (RelativeLayout) v.findViewById(R.id.rel_layout);
mExepandableLayout = (LinearLayout) v.findViewById(R.id.expandableLayout);
mshiftInText = (EditText) v.findViewById(R.id.setShiftIn);
mshiftOutText = (EditText) v.findViewById(R.id.setShiftOut);
mUpdateButton = (Button) v.findViewById(R.id.updateButton);
mDeleteButton = (Button) v.findViewById(R.id.deleteButton);
}
}
#Override
public ShiftAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View itemView = LayoutInflater.from(mContext)
.inflate(R.layout.shift, parent, false);
ViewHolder vh = new ViewHolder(itemView);
return vh;
}
//TODO:Bind all the view elements to Shift Properties
#Override
public void onBindViewHolder(#NonNull ViewHolder holder, int i) {
// Format double
String hours = new DecimalFormat("##.##").format(mDataSet.get(i).getHours());
String pay = new DecimalFormat("##.##").format(mDataSet.get(i).getPay());
//set the Text
holder.mTime.setText(hours);
holder.mDate.setText(mDataSet.get(i).dateToString());
holder.mPay.setText(pay);
Log.d(TAG, "onBindViewHolder: called");
// new AsyncTask<>().ex
//Expand mExapndableLayout
final int position = i;
final boolean isExpanded = position ==mExpandedPosition;
holder.mExepandableLayout.setVisibility(isExpanded?View.VISIBLE:View.GONE);
holder.itemView.setActivated(isExpanded);
// //set shift Times
// shiftIn = mDataSet.get(position).getInDate();
// shiftOut = mDataSet.get(position).getInDate();
if (isExpanded)
previousExpandedPosition = position;
holder.itemView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
mExpandedPosition = isExpanded ? -1:position;
notifyItemChanged(previousExpandedPosition);
notifyItemChanged(position);
}
});
//fill expandable layout
holder.mshiftInText.setText(mDataSet.get(position).fullTimeToString(0));
final EditText in = holder.mshiftInText;
final EditText out = holder.mshiftOutText;
//edit mShiftIn Text
holder.mshiftInText.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
isStart =true;
timePickerDialog(in,out);
}
});
holder.mshiftOutText.setText(mDataSet.get(position).fullTimeToString(1));
//edit MshiftOut Text
holder.mshiftOutText.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
isStart =false;
timePickerDialog(in,out);
}
});
//updateButton onClick
holder.mUpdateButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
try {
shiftIn = mDataSet.get(position).getInDate();
shiftOut = mDataSet.get(position).getOutDate();
if(Validate.getValidate().isDateValid(shiftIn,shiftOut)) {
SharedPrefs.getInstance(mContext).editShift(newShift(shiftIn, shiftOut),Integer.toString(position));
int length = SharedPrefs.getInstance(mContext).getLength() - 1;
if (SharedPrefs.getInstance(mContext).getShift(length) != null) {
Log.d(TAG, "Edit Shift onClick: Success");
SharedPrefs.getInstance(mContext).saveShiftList(SharedPrefs.getInstance(mContext).sortList(SharedPrefs.getInstance(mContext).getShiftList()));
ShiftsFragment.updateUI();
Toast.makeText(mContext, "success", Toast.LENGTH_SHORT).show();
}
} else {
mShiftOut.setBackgroundResource(R.drawable.red_border);
Toast.makeText(mContext, "error", Toast.LENGTH_SHORT).show(); }
} catch(Exception e){
Log.d(TAG, "onDateSelected: "+e.toString());
Toast.makeText(mContext,"update FAIL", Toast.LENGTH_SHORT).show();
}
// update the Shift
}
});
holder.mDeleteButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
areYouSure(mExpandedPosition);
}
});
}
#Override
public int getItemCount() {
return mDataSet.size();
}
public Date timePickerDialog(EditText in,EditText out) {
mshiftInText = in;
mshiftOutText = out;
new SingleDateAndTimePickerDialog.Builder(mContext)
.title(mContext.getResources().getString(R.string.choose_time))
.displayListener(new SingleDateAndTimePickerDialog.DisplayListener() {
#Override
public void onDisplayed(SingleDateAndTimePicker picker) {
if(!isStart) {
date = mDate;
}
}
}).defaultDate(returnDate(date))
.listener(new SingleDateAndTimePickerDialog.Listener() {
#Override
public void onDateSelected(Date date) {
mDate = date;
if (isStart) {
updateShiftIn(mDate);
mshiftInText.setText(dateToString(mDate));
} else {
updateShiftOut(mDate);
mshiftOutText.setText(dateToString(mDate));
}
}
}).display();
return mDate;
}
public String dateToString(Date date)
{
DateFormat df = new SimpleDateFormat("dd-MM-yyyy HH:mm");
String string = df.format(date);
return string;
}
private void updateShiftIn(Date date) {
shiftIn = date;
}
private void updateShiftOut(Date date) {
shiftOut = date;
}
private Date returnDate(Date date)
{
if(date!=null)
{
return date;
}
else return mDate;
}
private void areYouSure(int i)
{
final String position = Integer.toString(i);
DialogInterface.OnClickListener dialogClickListener = new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
switch (which){
case DialogInterface.BUTTON_POSITIVE:
Log.d(TAG, "onClick: isSure=true;");
SharedPrefs.getInstance(mContext).removeShift(position);
ShiftsFragment.updateUI();
case DialogInterface.BUTTON_NEGATIVE:
Log.d(TAG, "onClick: isSure= false");
}
}
};
AlertDialog.Builder builder = new AlertDialog.Builder(mContext);
builder.setMessage(mContext.getResources().getString(R.string.are_you_sure)).setPositiveButton(mContext.getResources().getString(R.string.confirm), dialogClickListener)
.setNegativeButton(mContext.getResources().getString(R.string.cancel), dialogClickListener).show();
}
private Shift newShift(Date start,Date stop)
{
int id = SharedPrefs.getInstance(mContext).getLength();
Shift shift = new Shift(dateToCalendar(start),dateToCalendar(stop),id);
return shift;
}
and this is the Fragment that has the RecyclerView
public class ShiftsFragment extends Fragment {
private Toolbar mToolbar;
private TimePicker timePicker1;
private List<Shift> shiftList = new ArrayList<>();
private RecyclerView recyclerView;
private RelativeLayout relativeLayout;
private RecyclerView.LayoutManager layoutManager;
private LinearLayout mShiftIn;
private LinearLayout mShiftOut;
private Context mContext;
private ShiftAdapter mAdapter;
private MenuItem mAdd;
private Menu optionsMenu;
private LinearLayout mShiftAddLL;
private SharedPreferences mPrefs;
private static FragmentManager mFragmentManager;
private static final String TAG = "ShiftsFragment";
public View onCreateView(#NonNull LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
Log.d(TAG,"Clicked");
final View view = inflater.inflate(R.layout.shifts_layout,container,false);
mToolbar = view.findViewById(R.id.topbar);
mToolbar.inflateMenu(R.menu.toolbarmenu);
mShiftAddLL = view.findViewById(R.id.add_shiftLayout);
mAdd = mToolbar.getMenu().getItem(0);
timePicker1 = (TimePicker) view.findViewById(R.id.timePicker);
mFragmentManager = getFragmentManager();
//TODO:Add a summary bar on the bottom.
//get the context
mContext = getContext();
recyclerView = (RecyclerView) view.findViewById(R.id.shift_list);
// Define a layout for RecyclerView
layoutManager = new GridLayoutManager(mContext,1);
recyclerView.setLayoutManager(layoutManager);
// Initialize a new Shift array
List<Shift> shiftList = initShifts();
Log.d(TAG,"shift array initiated");
// Initialize an array list from array
// Initialize a new instance of RecyclerView Adapter instance
mAdapter = new ShiftAdapter(mContext,shiftList);
// Set the adapter for RecyclerView
recyclerView.setAdapter(mAdapter);
recyclerView.setNestedScrollingEnabled(false);
recyclerView.setHasFixedSize(true);
//Menu add button onClick
//Opens Add_Shift_Fragment
mAdd.setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() {
#Override
public boolean onMenuItemClick(MenuItem menuItem) {
Fragment selectedFragment = new Add_Shift_Fragment();
getFragmentManager().beginTransaction().replace(R.id.fragment_container,
selectedFragment).commit();
return false;
}
});
return view;
}
//Initializes the Shift list from SharedPreferences and returns it.
private List<Shift> initShifts() {
return SharedPrefs.getInstance(mContext).getShiftList();
}
public static void updateUI()
{
Fragment selectedFragment = new ShiftsFragment();
mFragmentManager.beginTransaction().replace(R.id.fragment_container,
selectedFragment).commit();
}
}
Everytime i launch the ShiftsFragment there are some frame skips, and the scrolling is choppy and laggy.
Maybe my SharedPreferences handling is what is slowing things down?
public class SharedPrefs {
private static SharedPrefs mSharedPrefs;
private SharedPreferences mPrefs;
private SharedPreferences.Editor mPrefsEditor;
protected Context mContext;
public static final String ID = "shiftList";
private SharedPrefs(Context context) {
mContext = context;
mPrefs = context.getSharedPreferences(ID, Context.MODE_PRIVATE);
mPrefsEditor = mPrefs.edit();
}
public static SharedPrefs getInstance(Context context) {
if (mSharedPrefs == null) {
mSharedPrefs = new SharedPrefs(context.getApplicationContext());
}
return mSharedPrefs;
}
public void saveShiftList(List<Shift> shiftList) {
Gson gson = new Gson();
String json = gson.toJson(shiftList);
mPrefsEditor.putString(ID, json);
mPrefsEditor.apply();
}
public void addShift (Shift shift)
{
List<Shift> shiftList= getShiftList();
shiftList.add(shift);
saveShiftList(shiftList);
}
//Replaced the shift#id with shift
public void editShift(Shift shift,String id)
{
removeShift(id);
addShift(shift);
}
public void removeShift(String id) {
List<Shift> shiftList = getShiftList();
int pos = Integer.parseInt(id);
shiftList.remove(pos);
saveShiftList(shiftList);
}
public void removeShift(int id) {
List<Shift> shiftList = getShiftList();
shiftList.remove(id);
saveShiftList(shiftList);
}
public Shift getShift(int id) {
Gson gson = new Gson();
List<Shift> shiftList;
String json = mPrefs.getString(ID, null);
Type type = new TypeToken<List<Shift>>() {
}.getType();
shiftList = gson.fromJson(json, type);
Shift shift = shiftList.get(id);
return shift;
}
public List<Shift> getShiftList() {
Gson gson = new Gson();
List<Shift> shiftList;
String json = mPrefs.getString(ID, null);
Type type = new TypeToken<List<Shift>>() {
}.getType();
shiftList = gson.fromJson(json, type);
if (shiftList!=null) {
return shiftList;
} else{
shiftList = new ArrayList<>();
return shiftList;
}
}
public List<Shift> sortList(List<Shift> shiftList)
{
Collections.sort(shiftList, new Comparator<Shift>() {
public int compare(Shift shift1, Shift shift2) {
if (shift1.getShiftStart() == null || shift2.getShiftStart() == null)
return 0;
return shift1.getShiftStart().compareTo(shift2.getShiftStart());
}
});
return shiftList;
}
public int getLength()
{
return getShiftList().size();
}
}
I have only found this problem with image loading, not just Strings from Object from SharedPrefs.

add integer values selected by checkbox

TestListModel.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 void setSelected(boolean isSelected) {
this.isSelected = isSelected;
}
}
JsonResponse.java
public class JSONResponse {
private TestListModel[] result;
public TestListModel[] getResult() {
return result;
}
public void setResult(TestListModel[] result) {
this.result = result;
}
}
HealthActivity.java
public class HealthServicesActivity extends AppCompatActivity implements View.OnClickListener {
/*
*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);
showcenterid(sharePreferenceManager.getUserLoginData(LoginModel.class));
initViews();
submitButton.setOnClickListener(this);
/*
* On Click Listner
* */
#Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.submit_button:
int totalAmount = 0;
int totalPrice = 0;
String testName = "";
String testPrice="";
int count = 0;
List<TestListModel> stList = ((RecyclerAdapter) madapter)
.getTestList();
for (int i = 0; i < stList.size(); i++) {
TestListModel singleStudent = stList.get(i);
//AmountCartModel serialNumber = stList.get(i);
if (singleStudent.isSelected() == true) {
testName = testName + "\n" + singleStudent.getTest_name().toString();
testPrice = testPrice+"\n" + singleStudent.getTest_price().toString();
count++;
totalAmount = Integer.parseInt(stList.get(i).getTest_price());
totalPrice = totalPrice + totalAmount;
}
}
Toast.makeText(HealthServicesActivity.this,
"Selected Lists: \n" + testName+ "" + testPrice, Toast.LENGTH_LONG)
.show();
Intent in= new Intent(HealthServicesActivity.this, AmountCartActivity.class);
in.putExtra("test_name", testName);
in.putExtra("test_price", testPrice);
//in.putExtra("total_price",totalPrice);
in.putExtra("total_price", totalPrice);
in.putExtra("serialNumber", count);
startActivity(in);
finish();
break;
/** back Button Click
* */
case R.id.back_to_add_patient:
startActivity(new Intent(getApplicationContext(), PatientActivity.class));
finish();
break;
default:
break;
}
}
/** show center Id in action bar
* */
#Override
protected void onResume() {
super.onResume();
showcenterid(sharePreferenceManager.getUserLoginData(LoginModel.class));
}
private void showcenterid(LoginModel userLoginData) {
centerId.setText(userLoginData.getResult().getGenCenterId());
centerId.setText(userLoginData.getResult().getGenCenterId().toUpperCase());
deviceModeName.setText(userLoginData.getResult().getDeviceModeName());
}
private void initViews() {
recyclerView = (RecyclerView)findViewById(R.id.test_list_recycler_view);
recyclerView.setHasFixedSize(true);
RecyclerView.LayoutManager layoutManager = new LinearLayoutManager(getApplicationContext());
recyclerView.setLayoutManager(layoutManager);
loadJSON();
}
private void loadJSON() {
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();
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);
}
#Override
public void onFailure(Call<JSONResponse> call, Throwable t) {
Log.d("Error",t.getMessage());
}
});
}
HealthRecyclerAdapter.java
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;
}
AmountCartModel.java
public class AmountCartModel {
private String testName;
private String testPrice;
private Integer serialNumber;
private Integer totalPrice;
public AmountCartModel() {
this.testName = testName;
this.testPrice = testPrice;
this.serialNumber = serialNumber;
this.totalPrice = totalPrice;
}
public String getTestName() {
return testName;
}
public void setTestName(String testName) {
this.testName = testName;
}
public String getTestPrice() {
return testPrice;
}
public void setTestPrice(String testPrice) {
this.testPrice = testPrice;
}
public Integer getSerialNumber() {
return serialNumber;
}
public void setSerialNumber(Integer serialNumber) {
this.serialNumber = serialNumber;
}
public Integer getTotalPrice() {
return totalPrice;
}
public void setTotalPrice(Integer totalPrice) {
this.totalPrice = totalPrice;
}
}
AmountCartActivity.java
public class AmountCartActivity extends AppCompatActivity implements View.OnClickListener {
#BindView(R.id.total_price)
TextView totalPriceDisplay;
SharePreferenceManager<LoginModel> sharePreferenceManager;
private RecyclerView recyclerView;
List<AmountCartModel> mydataList ;
private MyAdapter madapter;
Bundle extras ;
String testName="";
String testPrice="";
String totalPrice= "";
int counting = 0;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_amount_cart);
ButterKnife.bind(this);
sharePreferenceManager = new SharePreferenceManager<>(getApplicationContext());
showcenterid(sharePreferenceManager.getUserLoginData(LoginModel.class));
mydataList = new ArrayList<>();
/*
* Getting Values From BUNDLE
* */
extras = getIntent().getExtras();
if (extras != null) {
testName = extras.getString("test_name");
testPrice = extras.getString("test_price");
totalPrice = String.valueOf(extras.getInt("total_price"));
counting = extras.getInt("serialNumber");
//Just add your data in list
AmountCartModel mydata = new AmountCartModel(); // object of Model Class
mydata.setTestName(testName );
mydata.setTestPrice(testPrice);
mydata.setTotalPrice(Integer.valueOf(totalPrice));
mydata.setSerialNumber(counting);
mydataList.add(mydata);
//totalPriceDisplay.setText(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);
RecyclerAdapter.java //RecyclerAdapter for AmountCart
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);
}
}
}
#Override
public void onBackPressed() {
super.onBackPressed();
startActivity(new
Intent(AmountCartActivity.this,HealthServicesActivity.class));
finish();
}
}
This is my code.
Here I am taking HealthActivity and in this class by using recycler view I have displayed testList in recycler view. I am passing testList whichever I am selecting through checkbox to AmountCartActivity of recycler View, And, I am calculating total amount of the selected testList and I am getting the result and that result I am passing to the AmountCart Activity through bundle and I am getting correct result in bundle, but, when I am trying to display total amount in a textView its showing me nothing.
And, my second problem is,
I am trying to display serial number to to my AmountCartActivity of recycler view whichever I am selecting from previous HealthCartActivity using checkbox. And, I have implemented some code but I am not getting how to solve it. please help me.
For Issue#1
Data should be passed onto the Adapter through constructor. The issue could simply be adding another parameter to the constructor:
public MyAdapter(List<AmountCartModel> context, List<AmountCartModel> myDataList) {
this.context = context;
myDataList = this.myDataList;
}
Or,
To add selection support to a RecyclerView instance:
Determine which selection key type to use, then build a ItemKeyProvider.
Implement ItemDetailsLookup: it enables the selection library to access information about RecyclerView items given a MotionEvent.
Update item Views in RecyclerView to reflect that the user has selected or unselected it.
The selection library does not provide a default visual decoration for the selected items. You must provide this when you implement onBindViewHolder() like,
In onBindViewHolder(), call setActivated() (not setSelected()) on the View object with true or false (depending on if the item is selected).
Update the styling of the view to represent the activated status.
For Issue #2
Try using passing data through intents.
The easiest way to do this would be to pass the serial num to the activity in the Intent you're using to start the activity:
Intent intent = new Intent(getBaseContext(), HealthServicesActivity.class);
intent.putExtra("EXTRA_SERIAL_NUM", serialNum);
startActivity(intent);
Access that intent on next activity
String sessionId= getIntent().getStringExtra("EXTRA_SERIAL_NUM");

While searching using EditText, the items in Recyclerview is duplicating, if i am searching fast

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)

Deleting all items in a page one by one in Android recyclerview does not load the next set of data

I have implemented recyclerview and it loads 10 tasks at a time. Once every task is completed, I am removing the task with a completed button. It loads the 11th item if I scroll to the bottom at one condition there has to be atleast one uncompleted task present on the page. If I clear all 10 items it just shows me loading animation and nothing happens. I have to close the app and open again to load the tasks again.
I have implemented a PaginationActivity, PaginationAdapter and scroll listener for the page. It loads data from a local database whenever you have reached the end of the page and you have got more tasks to load.
PaginationActivity.java
public class PaginationActivity extends AppCompatActivity {
private static final String TAG = "MainActivity";
PaginationAdapter adapter;
LinearLayoutManager linearLayoutManager;
public static ArrayList<String> reasonsdata = new ArrayList<String>();
public static String rslt="";
public static String[] reasons;
public static boolean chk = true;
public static String payTypeSelected;
public static String reasonSelected;
public static HashMap<String, EditText> drivernotesMap = new HashMap<String, EditText>();
public static HashMap<String, EditText> paynoteMap = new HashMap<String, EditText>();
public static HashMap<String, String> paytypeMap = new HashMap<String, String>();
RecyclerView rv;
ProgressBar progressBar;
private static final int PAGE_START = 0;
private boolean isLoading = false;
private boolean isLastPage = false;
private int TOTAL_PAGES;
private int currentPage = PAGE_START;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.pagination_main);
fillspinner();
rv = (RecyclerView) findViewById(R.id.main_recycler);
progressBar = (ProgressBar) findViewById(R.id.main_progress);
adapter = new PaginationAdapter(this);
linearLayoutManager = new LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false);
rv.setLayoutManager(linearLayoutManager);
rv.setItemAnimator(new DefaultItemAnimator());
rv.setAdapter(adapter);
rv.addOnScrollListener(new PaginationScrollListener(linearLayoutManager) {
#Override
protected void loadMoreItems() {
isLoading = true;
currentPage += 1;
// mocking network delay for API call
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
loadNextPage();
}
}, 1000);
}
#Override
public int getTotalPageCount() {
return TOTAL_PAGES;
}
#Override
public boolean isLastPage() {
return isLastPage;
}
#Override
public boolean isLoading() {
return isLoading;
}
});
// mocking network delay for API call
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
loadFirstPage();
}
}, 1000);
}
private void fillspinner() {
reasonsdata.clear();
try
{
rslt="START";
CallReasons cr = new CallReasons();
cr.join();
cr.start();
while(rslt=="START") {
try {
Thread.sleep(10);
}catch(Exception ex) {
}
}
}
catch (Exception ex) {
ex.printStackTrace();
}
if(rslt == "Success"){
reasonsdata.add("<--- Select Reason --->");
for(int i =0; i< reasons.length;i++){
reasonsdata.add(reasons[i]);
}
}
}
public void loadFirstPage() {
Log.d(TAG, "loadFirstPage: ");
TOTAL_PAGES = Run.getTotalPages();
//List<Run> runs = Run.createRuns(adapter.getItemCount());
List<Run> runs = Run.createRuns(adapter.getMaxID());
progressBar.setVisibility(View.GONE);
adapter.addAll(runs);
if (currentPage <= TOTAL_PAGES) adapter.addLoadingFooter();
else isLastPage = true;
}
public void loadNextPage() {
Log.d(TAG, "loadNextPage: " + currentPage);
//List<Run> runs = Run.createRuns(adapter.getItemCount());
List<Run> runs = Run.createRuns(adapter.getMaxID());
adapter.removeLoadingFooter();
isLoading = false;
adapter.addAll(runs);
if (currentPage != TOTAL_PAGES) adapter.addLoadingFooter();
else isLastPage = true;
}
}
PaginationAdapter.java
public class PaginationAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
private static final int ITEM = 0;
private static final int LOADING = 1;
private List<Run> runs = new ArrayList<>();
private Context context;
private boolean isLoadingAdded = false;
private String cash = "CASH";
private String cheque = "CHEQUE";
SQLiteDatabase db;
//PaginationActivity func_call;
public PaginationAdapter(Context context) {
this.context = context;
runs = new ArrayList<>();
//func_call = new PaginationActivity();
}
public List<Run> getRuns() {
return runs;
}
public void setRuns(List<Run> runs) {
this.runs = runs;
}
#Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
RecyclerView.ViewHolder viewHolder = null;
LayoutInflater inflater = LayoutInflater.from(parent.getContext());
switch (viewType) {
case ITEM:
viewHolder = getViewHolder(parent, inflater);
break;
case LOADING:
View v2 = inflater.inflate(R.layout.item_progress, parent, false);
viewHolder = new LoadingVH(v2);
//viewHolder = getViewHolder(parent, inflater);
//func_call.loadNextPage();
break;
}
return viewHolder;
}
#NonNull
private RecyclerView.ViewHolder getViewHolder(ViewGroup parent, LayoutInflater inflater) {
RecyclerView.ViewHolder viewHolder;
View v1 = inflater.inflate(R.layout.activity_main, parent, false);
viewHolder = new RunVH(v1);
return viewHolder;
}
#Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
final Run run = runs.get(position);
switch (getItemViewType(position)) {
case ITEM:
final RunVH runVH = (RunVH) holder;
//adding text areas to show data
//Completed task button
runVH.btnSave.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
Toast.makeText(context, "Mark as Completed", Toast.LENGTH_LONG).show();
remove(run);
}
}
} catch (Exception ex) {
//pbbar.setVisibility(View.GONE);
ex.printStackTrace();
}
}
});
break;
case LOADING:
break;
}
}
#Override
public int getItemCount() {
return runs == null ? 0 : runs.size();
}
//#Override
public int getMaxID() {
if(runs == null || runs.size() == 0){
return 0;
}else{
Run test = runs.get(runs.size()-2);
int maxid = (int) test.getProperty(0);
return maxid;
}
}
#Override
public int getItemViewType(int position) {
return (position == runs.size() - 1 && isLoadingAdded) ? LOADING : ITEM;
}
public void add(Run run) {
runs.add(run);
notifyItemInserted(runs.size() - 1);
}
public void addAll(List<Run> runList) {
for (Run run : runList) {
add(run);
}
}
public void remove(Run run) {
int position = runs.indexOf(run);
if (position > -1) {
runs.remove(position);
notifyItemRemoved(position);
notifyItemRangeChanged(position, runs.size());
}
/*if(runs.size() < 0){
clear();
func_call.loadNextPage();
}*/
}
public void clear() {
isLoadingAdded = false;
while (getItemCount() > 0) {
remove(getItem(0));
}
}
public boolean isEmpty() {
return getItemCount() == 0;
}
public void addLoadingFooter() {
isLoadingAdded = true;
add(new Run());
}
public void removeLoadingFooter() {
isLoadingAdded = false;
int position = runs.size() - 1;
Run item = getItem(position);
if (item != null) {
runs.remove(position);
notifyItemRemoved(position);
}
}
public Run getItem(int position) {
return runs.get(position);
}
protected class RunVH extends RecyclerView.ViewHolder {
private TextView textEsky;
private TextView textAdjusted;
private TextView textAddress;
private TextView textNew;
private TextView textTrusted;
private TextView textName;
private TextView textMobile;
private TextView textHome;
private TextView textWork;
private TextView payType;
private EditText textPayNote;
private EditText textDeliveryInst;
private EditText textDriverNotes;
private final Spinner reasons;
private RadioGroup rg;
private Button btnSave;
private CheckBox IsDriverData;
public RunVH(View itemView) {
super(itemView);
textEsky = (TextView) itemView.findViewById(R.id.idEsky);
textAdjusted = (TextView) itemView.findViewById(R.id.idAdjusted);
textAddress = (TextView) itemView.findViewById(R.id.idAddress);
textNew = (TextView) itemView.findViewById(R.id.idNew);
textTrusted = (TextView) itemView.findViewById(R.id.idTrusted);
textName = (TextView) itemView.findViewById(R.id.idName);
textMobile = (TextView) itemView.findViewById(R.id.idMobile);
textHome = (TextView) itemView.findViewById(R.id.idHome);
textWork = (TextView) itemView.findViewById(R.id.idWork);
payType = (TextView) itemView.findViewById(R.id.idPayType);
textPayNote = (EditText) itemView.findViewById(R.id.idPayNoteText);
textDeliveryInst = (EditText) itemView.findViewById(R.id.idDeliInsText);
textDriverNotes = (EditText) itemView.findViewById(R.id.idDriverNotesText);
IsDriverData = (CheckBox) itemView.findViewById(R.id.idCheckBox);
reasons = (Spinner) itemView.findViewById(R.id.idReason);
rg = (RadioGroup) itemView.findViewById(R.id.Radiogroup);
btnSave = (Button) itemView.findViewById(R.id.button);
}
}
protected class LoadingVH extends RecyclerView.ViewHolder {
public LoadingVH(View itemView) {
super(itemView);
}
}
}
PaginationScrollListener.java
public abstract class PaginationScrollListener extends RecyclerView.OnScrollListener {
LinearLayoutManager layoutManager;
public PaginationScrollListener(LinearLayoutManager layoutManager) {
this.layoutManager = layoutManager;
}
#Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);
int visibleItemCount = layoutManager.getChildCount();
int totalItemCount = layoutManager.getItemCount();
int firstVisibleItemPosition = layoutManager.findFirstVisibleItemPosition();
if (!isLoading() && !isLastPage()) {
if ((visibleItemCount + firstVisibleItemPosition) >= totalItemCount
&& firstVisibleItemPosition >= 0) {
loadMoreItems();
}
}
}
protected abstract void loadMoreItems();
public abstract int getTotalPageCount();
public abstract boolean isLastPage();
public abstract boolean isLoading();
}
I could be wrong, but it looks to me like the only time you call loadNextPage() is when the RecyclerView gets a scroll event. Removing ViewHolders doesn't cause scroll events iirc.
If you register an AdapterDataObserver on the PaginationAdapter, you can listen in on removal/add events and trigger loads when there aren't any tasks left. You could probably do the same thing with some small changes to that commented-out code in remove(Run):
if (runs.isEmpty()) {
func_call.loadNextPage();
}
EDIT:
Btw, you see where you called adapter = new PaginationAdapter(this); in the PaginationActivity.onCreate method? The this here is your PaginationActivity, which means you can assign it to a PaginationAdapter field like so:
/**
* #param context the activity this adapter will appear in
*/
public PaginationAdapter(Context context) {
this.context = context;
runs = new ArrayList<>();
func_call = (PaginationActivity)context;
}
That should be enough to prevent crashes. For better separation of concerns, you'll probably want to switch over to AdapterDataObserver-based logic (I think this is called the open/closed principle? Maybe?).

Change the Icon of a Button in a Recycler View in Adapter Class Based off boolean value

I'm trying to change the icon of a button in my recycler view every time the activity starts based off a boolean value in my custom object. I assume this has to be done within the adapter since not every groups button will have the same background.
Below is the code for my recycler view adapter:
public class RecipeListAdapter extends RecyclerView.Adapter<RecipeListAdapter.ViewHolder>{
private List<Recipe> mRecipeSet;
private Button mAddToGroceriesButton;
public RecipeListAdapter(List<Recipe> recipes){
mRecipeSet = recipes;
}
// Provide a reference to the views for each data item
// Complex data items may need more than one view per item, and
// you provide access to all the views for a data item in a view holder
public class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
//This is what will handle what happens when you click a recipe in the recycler view
private TextView mRecipeName;
private TextView mPrepTime;
private TextView mCookTime;
private TextView mServingSize;
private RelativeLayout mRecipeTextSection;
public ViewHolder(View v) {
super(v);
mRecipeName = (TextView) v.findViewById(R.id.recipe_list_recycler_view_recipe_name);
mServingSize = (TextView) v.findViewById(R.id.recipe_list_recycler_view_serving_size);
mPrepTime = (TextView) v.findViewById(R.id.recipe_list_recycler_view_prep_time);
mCookTime = (TextView) v.findViewById(R.id.recipe_list_recycler_view_cook_time);
mRecipeTextSection = (RelativeLayout) v.findViewById(R.id.recycled_item_section_view);
mRecipeTextSection.setOnClickListener(this);
mAddToGroceriesButton = (Button) v.findViewById(R.id.add_to_grocery_list);
mAddToGroceriesButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
int position = getAdapterPosition();
Recipe recipeToGrocery = mRecipeSet.get(position);
//RecipeDB dbHelper = new RecipeDB(v.getContext());
//dbHelper.addGroceryItem(recipeToGrocery);
if(!recipeToGrocery.isInList()) {
RecipeDB dbHelper = new RecipeDB(v.getContext());
dbHelper.addGroceryItem(recipeToGrocery);
recipeToGrocery.setInList(true);
dbHelper.updateRecipe(recipeToGrocery);
mAddToGroceriesButton.setBackgroundResource(R.mipmap.ic_playlist_add_check_black_24dp);
Toast.makeText(v.getContext(), recipeToGrocery.getRecipeName() + " added to grocery list.", Toast.LENGTH_SHORT).show();
}
else {
Toast.makeText(v.getContext(), "That recipe is already in the list.", Toast.LENGTH_SHORT).show();
}
}
});
}
#Override
public void onClick(View v){
int position = getAdapterPosition();
Intent i = new Intent(v.getContext(), RecipeTextView.class);
Recipe selectedRecipe = mRecipeSet.get(position);
i.putExtra("view_recipe_key", selectedRecipe);
v.getContext().startActivity(i);
}
}
public void add(int position, Recipe item) {
mRecipeSet.add(position, item);
notifyItemInserted(position);
}
public void remove(Recipe item) {
int position = mRecipeSet.indexOf(item);
mRecipeSet.remove(position);
notifyItemRemoved(position);
}
public RecipeListAdapter(ArrayList<Recipe> myRecipeset) {
mRecipeSet = myRecipeset;
}
// Create new views (invoked by the layout manager)
#Override
public RecipeListAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
// create a new view
View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.recipe_item_recycled, parent, false);
ViewHolder vh = new ViewHolder(v);
return vh;
}
#Override
public void onBindViewHolder(ViewHolder holder, int position) {
Recipe recipe = mRecipeSet.get(position);
String recipeName = recipe.getRecipeName();
String prepTime = "Prep Time: " + String.valueOf(recipe.getPrepTime()) + " minutes";
String cookTime = "Cook Time: " + String.valueOf(recipe.getCookTime()) + " minutes";
String servingSize = "Servings: " + String.valueOf(recipe.getServings());
holder.mRecipeName.setText(recipeName);
//Only display values if they are not null
if(recipe.getServings() != null) {
holder.mServingSize.setText(servingSize);
}
if (recipe.getPrepTime() != null) {
holder.mPrepTime.setText(prepTime);
}
if(recipe.getCookTime() != null) {
holder.mCookTime.setText(cookTime);
}
}
// Return the size of your dataset (invoked by the layout manager)
#Override
public int getItemCount() {
if(mRecipeSet != null) {
return mRecipeSet.size();
}
return 0;
}
}
I know how to change the background of the button when it's clicked with
mAddToGroceriesButton.setBackgroundResource(R.mipmap.ic_playlist_add_check_black_24dp);
but it's obviously not going to save the state of that button when the activity restarts. I'm just not sure of how to check the boolean value for each group upon activity start up and change the button background accordingly.
I tried using
if(recipe.isInList()){
mAddToGroceriesButton.setBackgroundResource(R.mipmap.ic_playlist_add_check_black_24dp);
}
in the onBindViewHolder method but it didn't do anything, and I'm pretty sure that wouldn't be the correct place for it anyways. I know the boolean is working properly since I use it in other places and it works fine.
Here's the relevant XML code:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/apk/res/android"
android:layout_margin="7dp"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingLeft="10dp"
android:id="#+id/recycled_item_section_view"
android:elevation="30dp"
android:background="#drawable/background_border"
>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
tools:text="Recipe name"
android:textSize="24dp"
android:textColor="#color/black"
android:id="#+id/recipe_list_recycler_view_recipe_name"
android:paddingBottom="3dp"
android:maxWidth="275dip"
android:singleLine="false"/>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textSize="18dp"
android:textColor="#color/black"
android:layout_below="#id/recipe_list_recycler_view_recipe_name"
android:id="#+id/recipe_list_recycler_view_serving_size"
android:paddingBottom="3dp"/>
<Button
android:layout_width="35dp"
android:layout_height="35dp"
android:background="#mipmap/ic_playlist_add_black_24dp"
android:height="36dp"
android:padding="8dp"
android:layout_alignParentRight="true"
android:id="#+id/add_to_grocery_list"
android:layout_alignParentTop="true"
android:layout_alignParentEnd="true"
/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="#id/recipe_list_recycler_view_serving_size"
android:layout_alignParentLeft="true"
android:textSize="18dp"
android:textColor="#color/black"
android:id="#+id/recipe_list_recycler_view_prep_time"
android:paddingBottom="3dp"
/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="#id/recipe_list_recycler_view_prep_time"
android:textSize="18dp"
android:textColor="#color/black"
android:layout_alignParentLeft="true"
android:id="#+id/recipe_list_recycler_view_cook_time"/>
</RelativeLayout>
Recipe class:
public class Recipe implements Parcelable {
//These are all of the qualities a recipe contains, we will create an arraylist of this in the activity
private String mRecipeName;
private int mID;
private String mServings;
private String mPrepTime;
private String mCookTime;
private boolean isInList;
private List<String> mIngredients;
private List<String> mDirections;
public Recipe(){
}
public Recipe(int id, String name, String serving, String prep, String cook, List<String>
ingredientsList, List<String> directionsList, boolean inList){
this.mID = id;
this.mRecipeName = name;
this.mServings = serving;
this.mPrepTime = prep;
this.mCookTime = cook;
this.mIngredients = ingredientsList;
this.mDirections = directionsList;
this.isInList = inList;
}
public Recipe(String name, String serving, String prep, String cook, List<String>
ingredientsList, List<String> directionsList, boolean inList){
this.mRecipeName = name;
this.mServings = serving;
this.mPrepTime = prep;
this.mCookTime = cook;
this.mIngredients = ingredientsList;
this.mDirections = directionsList;
this.isInList = inList;
}
public String getRecipeName() {
return mRecipeName;
}
public int getID() {
return mID;
}
public void setID(int id){
mID = id;
}
public String getServings() {
return mServings;
}
public String getPrepTime() {
return mPrepTime;
}
public void setRecipeName(String recipeName) {
mRecipeName = recipeName;
}
public void setServingSize(String servings) {
mServings = servings;
}
public void setPrepTime(String prepTime) {
mPrepTime = prepTime;
}
public void setServings(String servings) {
mServings = servings;
}
public List<String> getIngredients() {
return mIngredients;
}
public List<String> getDirections() {
return mDirections;
}
public String getCookTime() {
return mCookTime;
}
public void setCookTime(String cookTime) {
mCookTime = cookTime;
}
public void setIngredients(List<String> ingredients) {
mIngredients = ingredients;
}
public void setDirections(List<String> directions) {
mDirections = directions;
}
public boolean isInList() {
return isInList;
}
public void setInList(boolean inList) {
isInList = inList;
}
#Override
public int describeContents() {
return 0;
}
#Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(this.mRecipeName);
dest.writeInt(this.mID);
dest.writeString(this.mServings);
dest.writeString(this.mPrepTime);
dest.writeString(this.mCookTime);
dest.writeByte(this.isInList ? (byte) 1 : (byte) 0);
dest.writeStringList(this.mIngredients);
dest.writeStringList(this.mDirections);
}
protected Recipe(Parcel in) {
this.mRecipeName = in.readString();
this.mID = in.readInt();
this.mServings = in.readString();
this.mPrepTime = in.readString();
this.mCookTime = in.readString();
this.isInList = in.readByte() != 0;
this.mIngredients = in.createStringArrayList();
this.mDirections = in.createStringArrayList();
}
public static final Creator<Recipe> CREATOR = new Creator<Recipe>() {
#Override
public Recipe createFromParcel(Parcel source) {
return new Recipe(source);
}
#Override
public Recipe[] newArray(int size) {
return new Recipe[size];
}
};
}
And main activity class that uses the adapter:
public class RecipeList extends AppCompatActivity{
private RecyclerView mRecyclerView;
private RecyclerView.Adapter mAdapter;
private RecyclerView.LayoutManager mLayoutManager;
private int REQUEST_CODE=1;
private Button mNavigateGroceryButton;
RecipeDB dbHelper = new RecipeDB(this);
List<Recipe> recipes;
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
recipes = dbHelper.getAllRecipes();
setContentView(R.layout.activity_recipe_list);
mRecyclerView = (RecyclerView) findViewById(R.id.list_recycler_view);
mLayoutManager = new LinearLayoutManager(this);
mRecyclerView.setLayoutManager(mLayoutManager);
mAdapter = new RecipeListAdapter(recipes);
mRecyclerView.setAdapter(mAdapter);
mNavigateGroceryButton = (Button) findViewById(R.id.navigate_to_groceries_button_list_view);
mNavigateGroceryButton.setOnClickListener(new View.OnClickListener(){
#Override
public void onClick(View v){
Intent i = new Intent(RecipeList.this, ExpandableListViewActivity.class);
//Log.d("Navigate", "navigate pressed" );
startActivity(i);
}
});
}
#Override
public void onBackPressed() {
}
public boolean onOptionsItemSelected(MenuItem item){
//Handles menu buttons
switch (item.getItemId()){
case R.id.recipe_list_add_recipe_actionbar_button:
//This button creates a new empty Recipe object and passes it to the EditRecipe class
//The Recipe object is passed as a parcelable
Recipe passedRecipe = new Recipe();
Intent i = new Intent(RecipeList.this, EditRecipe.class);
i.putExtra("passed_recipe_key", (Parcelable) passedRecipe);
startActivityForResult(i, REQUEST_CODE);
return true;
default:
Log.d("Name,", "default called");
return super.onOptionsItemSelected(item);
}
}
public void addNewReRecipe(Recipe recipe){
dbHelper.addRecipe(recipe);
recipes = dbHelper.getAllRecipes();
mAdapter = new RecipeListAdapter(recipes);
mRecyclerView.setAdapter(mAdapter);
}
//Makes the menu bar appear as it is in the action_bar_recipe_list_buttons menu layout file
#Override
public boolean onCreateOptionsMenu(Menu menu){
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.action_bar_recipe_list_buttons, menu);
return true;
}
//This code is called after creating a new recipe. This is only for creating, and not editing.
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data){
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == REQUEST_CODE){
if(resultCode == Activity.RESULT_OK) {
Recipe createdRecipe = data.getExtras().getParcelable("recipe_key");
addNewReRecipe(createdRecipe);
}
}
}
}
Looks like you need to declare your button at the top of your ViewHolder with your other views. So move the declaration from the top of your adapter:
private Button mAddToGroceriesButton;
Then in your onBindViewHolder method you can get a reference to your button through the holder and set the background:
if(recipe.isInList()) {
holder.mAddToGroceriesButton.setBackgroundResource(R.mipmap.ic_playlist_add_check_black_24dp);
}
Try this,
public class RecipeListAdapter extends RecyclerView.Adapter<RecipeListAdapter.ViewHolder>{
private List<Recipe> mRecipeSet;
private Button mAddToGroceriesButton;
public RecipeListAdapter(List<Recipe> recipes){
mRecipeSet = recipes;
}
// Provide a reference to the views for each data item
// Complex data items may need more than one view per item, and
// you provide access to all the views for a data item in a view holder
public class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
//This is what will handle what happens when you click a recipe in the recycler view
private TextView mRecipeName;
private TextView mPrepTime;
private TextView mCookTime;
private TextView mServingSize;
private RelativeLayout mRecipeTextSection;
public ViewHolder(View v) {
super(v);
mRecipeName = (TextView) v.findViewById(R.id.recipe_list_recycler_view_recipe_name);
mServingSize = (TextView) v.findViewById(R.id.recipe_list_recycler_view_serving_size);
mPrepTime = (TextView) v.findViewById(R.id.recipe_list_recycler_view_prep_time);
mCookTime = (TextView) v.findViewById(R.id.recipe_list_recycler_view_cook_time);
mRecipeTextSection = (RelativeLayout) v.findViewById(R.id.recycled_item_section_view);
mAddToGroceriesButton = (Button) v.findViewById(R.id.add_to_grocery_list);
}
}
public void add(int position, Recipe item) {
mRecipeSet.add(position, item);
notifyItemInserted(position);
}
public void remove(Recipe item) {
int position = mRecipeSet.indexOf(item);
mRecipeSet.remove(position);
notifyItemRemoved(position);
}
public RecipeListAdapter(ArrayList<Recipe> myRecipeset) {
mRecipeSet = myRecipeset;
}
// Create new views (invoked by the layout manager)
#Override
public RecipeListAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
// create a new view
View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.recipe_item_recycled, parent, false);
ViewHolder vh = new ViewHolder(v);
return vh;
}
#Override
public void onBindViewHolder(ViewHolder holder, int position) {
Recipe recipe = mRecipeSet.get(position);
String recipeName = recipe.getRecipeName();
String prepTime = "Prep Time: " + String.valueOf(recipe.getPrepTime()) + " minutes";
String cookTime = "Cook Time: " + String.valueOf(recipe.getCookTime()) + " minutes";
String servingSize = "Servings: " + String.valueOf(recipe.getServings());
holder.mRecipeName.setText(recipeName);
//Only display values if they are not null
if(recipe.getServings() != null) {
holder.mServingSize.setText(servingSize);
}
if (recipe.getPrepTime() != null) {
holder.mPrepTime.setText(prepTime);
}
if(recipe.getCookTime() != null) {
holder.mCookTime.setText(cookTime);
}
mRecipeTextSection.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
int position = getAdapterPosition();
Intent i = new Intent(v.getContext(), RecipeTextView.class);
Recipe selectedRecipe = mRecipeSet.get(position);
i.putExtra("view_recipe_key", selectedRecipe);
v.getContext().startActivity(i);
});
Recipe recipeToGrocery = mRecipeSet.get(position);
if(!recipeToGrocery.isInList()) {
mAddToGroceriesButton.setBackgroundResource(R.mipmap.ic_playlist_add_check_black_24dp);
}
else{
mAddToGroceriesButton.setBackgroundResource(R.mipmap.ic_playlist_add_check_black_26dp);//set another image
}
mAddToGroceriesButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
int position = getAdapterPosition();
Recipe recipeToGrocery = mRecipeSet.get(position);
//RecipeDB dbHelper = new RecipeDB(v.getContext());
//dbHelper.addGroceryItem(recipeToGrocery);
if(!recipeToGrocery.isInList()) {
RecipeDB dbHelper = new RecipeDB(v.getContext());
dbHelper.addGroceryItem(recipeToGrocery);
recipeToGrocery.setInList(true);
dbHelper.updateRecipe(recipeToGrocery);
notifyDataSetChanged();
}
else {
Toast.makeText(v.getContext(), "That recipe is already in the list.", Toast.LENGTH_SHORT).show();
}
}
});
}
// Return the size of your dataset (invoked by the layout manager)
#Override
public int getItemCount() {
if(mRecipeSet != null) {
return mRecipeSet.size();
}
return 0;
}
}

Categories

Resources