Unable to allow user to check one checkbox at a time - android

I have a sectioned recyclerview implemented which works great. I want to include a checkbox in all my items which show up under a section.The thing I want to implement now is to allow user to check one checkbox at a time. I have tried radiobutton also but the problem stays the same as I am unable to get hold of the listeners.
I have searched for it on stackoverflow but I could not get it work. getTag() gives me a null pointer exception and I have also tried keeping a selectedPosition variable and trying but I could not get the getTag() to work.
public class HeaderRecyclerViewSection extends StatelessSection {
private static final String TAG = HeaderRecyclerViewSection.class.getSimpleName();
private String title;
private List<RestaurauntMenuItemDetail> list;
private List<RestaurauntMenuItemDetail> checkedList;
private int selectedPosition = -1;
public HeaderRecyclerViewSection(String title, List<RestaurauntMenuItemDetail> list) {
super(R.layout.section_ex1_header, R.layout.layout_section_item);
this.title = title;
this.list = list;
}
#Override
public int getContentItemsTotal() {
return list.size();
}
#Override
public RecyclerView.ViewHolder getItemViewHolder(View view) {
return new ItemViewHolder(view);
}
#Override
public void onBindItemViewHolder(RecyclerView.ViewHolder holder, final int position) {
final ItemViewHolder iHolder = (ItemViewHolder)holder;
iHolder.variationItemName.setText(list.get(position).getVariationItemName());
iHolder.variationItemPrice.setText(Double.toString(list.get(position).getVariationItemPrice()));
iHolder.checkBox.setOnCheckedChangeListener(null);
iHolder.checkBox.setChecked(list.get(position).isSelected());
Log.i("EXECUTED AGAIN","AGAIN");
iHolder.checkBox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
#Override
public void onCheckedChanged(CompoundButton compoundButton, boolean b) {
if(selectedPosition == position){
list.get(selectedPosition).setSelected(false);
iHolder.checkBox.setChecked(list.get(selectedPosition).isSelected());
}
list.get(position).setSelected(b);
Log.i("POSITION is",Integer.toString(position));
Log.i("B Is",Boolean.toString(b));
selectedPosition = position;
}
});
}
#Override
public RecyclerView.ViewHolder getHeaderViewHolder(View view) {
return new HeaderViewHolder(view);
}
#Override
public void onBindHeaderViewHolder(RecyclerView.ViewHolder holder) {
HeaderViewHolder hHolder = (HeaderViewHolder)holder;
hHolder.headerTitle.setText(title);
}
}
My ItemHolder class:
public class ItemViewHolder extends RecyclerView.ViewHolder{
public TextView variationItemName;
public TextView variationItemPrice;
CheckBox checkBox;
public ItemViewHolder(View itemView) {
super(itemView);
variationItemName = (TextView) itemView.findViewById(R.id.variationItemName);
variationItemPrice = (TextView) itemView.findViewById(R.id.variationItemPrice);
checkBox = itemView.findViewById(R.id.checkBox2);
}
}
What i am trying to achieve is to allow user to be able to select one checkbox under a certain section.
EDIT 1:
This is how currently my screen looks either with radiobutton or checkbox.
EDIT 2:
I changed my code as follows which lets me to check one radiobutton at a time. The thing is that when you click on the last item in the recycler view list , the radiobutton does not get checked and if it does then when you scroll up , it vanishes.
#Override
public void onBindItemViewHolder(final RecyclerView.ViewHolder holder, final int position) {
final ItemViewHolder iHolder = (ItemViewHolder)holder;
iHolder.variationItemName.setText(list.get(position).getVariationItemName());
iHolder.variationItemPrice.setText(Double.toString(list.get(position).getVariationItemPrice()));
iHolder.variationItemPrice.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Log.i("I WAS CLICKED","ITEM PRICE WAS CLICKED");
}
});
iHolder.radioButton.setChecked(list.get(position).isSelected());
iHolder.radioButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Log.i("I was pressed","BUtton");
RadioButton rb = (RadioButton) view;
if(rb.isChecked()){
Log.i("CONTAINS",Boolean.toString(radioButtonList.contains(rb)));
if(position >= radioButtonList.size()){
radioButtonList.add(rb);
rb.setChecked(true);
list.get(position).setSelected(true);
}else{
}
//list.get(position).setSelected(true);
}
for (int i = 0; i < radioButtonList.size(); i++) {
RadioButton nrb = radioButtonList.get(i);
if(i != position){
if(nrb.isChecked()){
nrb.setChecked(false);
list.get(i).setSelected(false);
}
}
}
Log.i("RADIO LIST",Integer.toString(radioButtonList.size()));
for (int i = 0; i < radioButtonList.size(); i++) {
Log.i("RADIO CHECKED",Boolean.toString(radioButtonList.get(i).isChecked()));
}
Log.i("CURRENT POST",Integer.toString(position));
for (int i = 0; i < list.size() ; i++) {
Log.i("POST",Boolean.toString(list.get(i).isSelected()));
}
}
});
}
My Activity Class:
public class RestaurauntMenuItemDetailActivity extends AppCompatActivity implements RestaurauntMenuItemDetailInterfaceHandler{
private static List<RestaurauntMenuItemDetail> restaurauntMenuItemDetailList = new LinkedList<>();
RestaurauntMenuItemDetailFetchAPI restaurauntMenuItemDetailFetchAPI;
String restaurauntSlug;
String menuSlug;
int menuId;
int variationCount;
List<String> variationNamesList;
private RecyclerView sectionHeader;
private SectionedRecyclerViewAdapter sectionAdapter;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_restauraunt_menu_item_detail);
//
// sectionAdapter = new SectionedRecyclerViewAdapter();
restaurauntMenuItemDetailFetchAPI = new RestaurauntMenuItemDetailFetchAPI(this,this);
restaurauntSlug = getIntent().getExtras().getString("restaurauntSlug");
menuSlug = getIntent().getExtras().getString("menuSlug");
menuId = getIntent().getExtras().getInt("menuId");
restaurauntMenuItemDetailFetchAPI.prepareURL(restaurauntSlug,menuSlug,menuId);
restaurauntMenuItemDetailFetchAPI.fetchMenuItemDetail();
}
#Override
public void restaurauntMenuItemDetailListDownloadTaskCompleted(List<RestaurauntMenuItemDetail> result,int variationCount,List<String> variationNames) {
restaurauntMenuItemDetailList = result;
this.variationCount = variationCount;
variationNamesList = variationNames;
sectionHeader = (RecyclerView)findViewById(R.id.menuItemDetailRecyclerView);
LinearLayoutManager linearLayoutManager = new LinearLayoutManager(RestaurauntMenuItemDetailActivity.this);
sectionHeader.setLayoutManager(linearLayoutManager);
sectionHeader.setHasFixedSize(true);
// HeaderRecyclerViewSection secondSection = new HeaderRecyclerViewSection("Second Section", restaurauntMenuItemDetailList);
// HeaderRecyclerViewSection thirdSection = new HeaderRecyclerViewSection("Third Section", restaurauntMenuItemDetailList);
sectionAdapter = new SectionedRecyclerViewAdapter();
for(int i=0; i < variationNamesList.size(); i++){
String variationName = variationNames.get(i);
addSectionToAdapter(variationName,sectionAdapter);
sectionHeader.setAdapter(sectionAdapter);
}
// sectionAdapter.addSection(secondSection);
// sectionAdapter.addSection(thirdSection);
// initRecyclerView();
}
private void addSectionToAdapter(String variationName, SectionedRecyclerViewAdapter sectionAdapter){
List<RestaurauntMenuItemDetail> l1 = new ArrayList<>();
for (int i = 0; i < restaurauntMenuItemDetailList.size() ; i++) {
if(restaurauntMenuItemDetailList.get(i).getVariationCategory().equals(variationName)){
l1.add(restaurauntMenuItemDetailList.get(i));
}
}
HeaderRecyclerViewSection firstSection = new HeaderRecyclerViewSection(variationName, l1,sectionAdapter);
sectionAdapter.addSection(firstSection);
}
}

Try this. It worked for me. Might work for you as well. Just replace your OnCheckedChangeListener code with this one:
iHolder.checkBox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener(){
#Override
public void onCheckedChanged(CompoundButton compoundButton,boolean b){
if(compoundButton.isPressed()){
// click is performed
for(RestaurauntMenuItemDetail item:list){
item.setSelected(false);
}
list.get(holder.getAdapterPosition()).setSelected(b);
notifyDataSetChanged();
}
}
});

I looked at a lot of other questions posted by users and got a little help by the comments provided here. What i actually wanted was to able to check one radio box at a time and secondly, when we scroll down in our recycler view either check box from the radio button vanished or it was wrong.
We need to keep a boolean variable in our class which holds our object and we can set it to false by default. Generate the getters and setters. The code is as follows:
The list goes at the top, just in case.
List<RadioButton> radioButtonList = new ArrayList<>();
private int selectedPosition = -1;
#Override
public void onBindItemViewHolder(final RecyclerView.ViewHolder holder, final int position) {
final ItemViewHolder iHolder = (ItemViewHolder)holder;
final RestaurauntMenuItemDetail r = list.get(position);
iHolder.radioButton.setTag(position);
iHolder.radioButton.setOnCheckedChangeListener(null);
iHolder.radioButton.setChecked(r.getSelected());
iHolder.radioButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Integer pos = (Integer) iHolder.radioButton.getTag();
RadioButton rb = (RadioButton) v;
if(radioButtonList.isEmpty()){
radioButtonList.add(rb);
rb.setChecked(true);
list.get(pos).setSelected(true);
selectedPosition = pos;
}else{
RadioButton nrb = radioButtonList.get(0);
if(nrb.isChecked()){
Log.i("NEW RB BUTTON WAS CHECKED", "CHECKED NRB");
nrb.setChecked(false);
list.get(selectedPosition).setSelected(false);
}
radioButtonList.remove(0);
radioButtonList.add(rb);
rb.setChecked(true);
list.get(pos).setSelected(true);
selectedPosition = pos;
}
}
});

Related

Issue with RecyclerView item selection

I am designing a live quiz app that fetches data from server and question are displayed in a RecyclerView that contains a question and four options. Now when I select one option for a given question, it is selected properly but at the same time, the corresponding option for other question is selected automatically.
Screenshot of the item selection issue is the following.
I have designed Data Model Class and RecylerView Adapter (with the help of #Reaz Murshed) but have been stuck with the code
My Data Model Class is :
//DmLiveQuiz
public class DmLiveQuiz {
String testId;
int questionId;
String question;
String optA;
String optB;
String optC;
String optD;
String answer;
String explain;
...
}
My Adapter Class is //LiveTestAdapter
public class LiveTestAdapter extends RecyclerView.Adapter<LiveTestAdapter.CustomViewHolder> {
private List<DmLiveQuiz> questionList;
private int[] answerList; // Get a list of your answers here.
private DmLiveQuiz questionsList;
private Context context;
public List<Integer> myResponse = new ArrayList<Integer>();
public int qno;
public LiveTestAdapter(List<DmLiveQuiz> questionList, Context context) {
this.questionList = questionList;
this.context = context;
}
#NonNull
#Override
public CustomViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View itemView = LayoutInflater.from(parent.getContext()).inflate(R.layout.live_quiz_display_format, parent, false);
return new CustomViewHolder(itemView);
}
#Override
public void onBindViewHolder(#NonNull final CustomViewHolder holder, int position) {
questionsList = questionList.get(holder.getAdapterPosition());
holder.tvQNo.setText(questionsList.getQuestionId() + "");
holder.tvquestion.getLayoutParams().width = LinearLayout.LayoutParams.WRAP_CONTENT;
holder.tvquestion.setText(questionsList.getQuestion());
holder.optA.setText(questionsList.getOptA());
holder.optB.setText(questionsList.getOptB());
holder.optC.setText(questionsList.getOptC());
holder.optD.setText(questionsList.getOptD());
// Now you need to modify the backgrounds of your option buttons like the following.
if (answerList[position] == 1) holder.optA.setBackgroundResource(R.drawable.button_border);
else holder.optA.setBackgroundResource(R.drawable.button_question_style);
if (answerList[position] == 2) holder.optB.setBackgroundResource(R.drawable.button_border);
else holder.optB.setBackgroundResource(R.drawable.button_question_style);
if (answerList[position] == 3) holder.optC.setBackgroundResource(R.drawable.button_border);
else holder.optC.setBackgroundResource(R.drawable.button_question_style);
if (answerList[position] == 4) holder.optD.setBackgroundResource(R.drawable.button_border);
else holder.optD.setBackgroundResource(R.drawable.button_question_style);
holder.optA.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
holder.optA.setBackgroundResource(R.drawable.button_border);
answerList[position] = 1; // Selected first option which is A
});
holder.optB.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
holder.optB.setBackgroundResource(R.drawable.button_border);
answerList[position] = 2; // Selected second option which is B
Toast.makeText(context, "Position :" + holder.getAdapterPosition(), Toast.LENGTH_SHORT).show();
}
});
holder.optC.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
holder.optC.setBackgroundResource(R.drawable.button_border);
answerList[position] = 3; // Selected third option which is C
Toast.makeText(context, "Position :" + holder.getAdapterPosition(), Toast.LENGTH_SHORT).show();
}
});
holder.optD.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
holder.optD.setBackgroundResource(R.drawable.button_border);
answerList[position] = 4; // Selected fourth option which is D
Toast.makeText(context, "Position :" + holder.getAdapterPosition(), Toast.LENGTH_SHORT).show();
}
});
holder.tvClear.setOnClickListener(new View.OnClickListener() {
public void onClick(View view) {
holder.optA.setBackgroundResource(R.drawable.button_question_style);
holder.optB.setBackgroundResource(R.drawable.button_question_style);
holder.optC.setBackgroundResource(R.drawable.button_question_style);
holder.optD.setBackgroundResource(R.drawable.button_question_style);
answerList[position] = 0; // Clear the value in the answerList
}
});
}
// Use this function to set the question list in the adapter
public void setQuestionList(List<DmLiveQuiz> questionList) {
this.questionList = questionList;
this.answerList = new int[questionList.size()]; // This initializes the answer list having the same size as the question list
notifyDataSetChanged();
}
#Override
public int getItemCount() {
return questionList.size();
}
public class CustomViewHolder extends RecyclerView.ViewHolder {
TextView tvquestion, tvClear, tvQNo;
Button optA, optB, optC, optD;
public CustomViewHolder(View itemView) {
super(itemView);
tvQNo = (TextView) itemView.findViewById(R.id.tvLiveQuizQuestionNo);
tvquestion = (TextView) itemView.findViewById(R.id.tvLiveQuizQuestion);
optA = (Button) itemView.findViewById(R.id.buttonOptionA);
...///
}
}
}
And The Activity where Recyclerview is implemented is
recyclerView = (RecyclerView) findViewById(R.id.recyclerViewLiveTest);
recyclerView.setLayoutManager(new LinearLayoutManager(this));
quizList = new ArrayList<>();
adapter = new LiveTestAdapter(quizList, getApplicationContext());
linearLayoutManager = new LinearLayoutManager(this);
linearLayoutManager.setOrientation(LinearLayoutManager.VERTICAL);
dividerItemDecoration = new DividerItemDecoration(recyclerView.getContext(), linearLayoutManager.getOrientation());
recyclerView.setHasFixedSize(true);
recyclerView.setLayoutManager(linearLayoutManager);
// recyclerView.addItemDecoration(dividerItemDecoration);
recyclerView.setAdapter(adapter);
getData();
......
The method for fetching JSON data is getdata() as given below which fetches data from server correctly...
private void getData() {
JsonArrayRequest jsonArrayRequest = new JsonArrayRequest(quiz_url, new Response.Listener<JSONArray>() {
#Override
public void onResponse(JSONArray response) {
for (int i = 0; i < response.length(); i++) {
try {
JSONObject jsonObject = response.getJSONObject(i);
DmLiveQuiz liveQuiz = new DmLiveQuiz();
...
...
quizList.add(liveQuiz);
} catch (JSONException e) {
e.printStackTrace();
progressDialog.dismiss();
}
}
adapter.notifyDataSetChanged();
..........
}
Now When I run App, it shows index=0 i.e. ArrayOutOfIndexException is generated.. I am not able to call public void setQuestionList(List<DmLiveQuiz> questionList) method of LiveQuizAdapter class from my activity.. Please Help
Initially you are setting empty list in the adapter. After getting value from JsonArrayRequest then need to update adapter using new list.
Update onBindViewHolder:
#Override
public void onBindViewHolder(#NonNull final CustomViewHolder holder, int position) {
DmLiveQuiz dmLiveQuiz= questionList.get(position);
if(dmLiveQuiz!=null){
// do whatever you want. put all code here.}
}
Update your adapter:
#Override
public void onResponse(JSONArray response) {
for (int i = 0; i < response.length(); i++) {
// put all code here
quizList.add(liveQuiz);}
adapter.setQuestionList(quizList);
adapter.notifyDataSetChanged();
}
you have to add a boolean value in DmLiveQuiz model class :-
boolean isSelected ;
and then set a check in your adapter while your are showing the answer is selected or not :-
if(DmLiveQuiz.isSelectd){
// this is the selected answer
}else {
// in case don't selected
}
and change the boolean value on adapter item Click

RecyclerView messes up when scrolling

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?

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)

My textView is not receiving the correct value from list.size(), why not?

I have a list that I add Players too and the Player names are based off the size of the list. When I initially set the player list the names are correct but when I add a new Player to the list the name is incorrect. Please help below is the relevant code.
The method that adds the Players to the List:
public static void addNewPlayers(List<Player> playerArrayList, SharedPreferences sharedPreferences,
PlayerScoreCardAdapter playerScoreCardAdapter,
int numberOfPlayersToAdd) {
for (int i = 0; i < numberOfPlayersToAdd; i++) {
// TODO: 2016-03-19 Fix player name not updating
String name = String.format("%s%s",
Keys.KEY_DEFAULT_PLAYER_NAME, playerArrayList.size() + 1);
Player player = new Player(name,
sharedPreferences.getInt(Keys.KEY_PLAYER_SCORE + String.valueOf(i + 1),
Keys.KEY_DEFAULT_PLAYER_SCORE));
playerArrayList.add(i, player);
playerScoreCardAdapter.notifyItemInserted(playerArrayList.size());
}
}
The RecylcerView.Adapter:
public class PlayerScoreCardAdapter extends RecyclerView.Adapter<PlayerScoreCardAdapter.ScoreViewHolder> {
private List<Player> mPlayerList;
public PlayerScoreCardAdapter(List<Player> playerList) {
mPlayerList = playerList;
}
#Override
public ScoreViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext())
.inflate(R.layout.player_score_list_item, parent, false);
return new ScoreViewHolder(view);
}
#Override
public void onBindViewHolder(ScoreViewHolder holder, int position) {
holder.bindPlayers(mPlayerList.get(position));
}
#Override
public int getItemCount() {
return mPlayerList.size();
}
public class ScoreViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener, View.OnLongClickListener {
public TextView mPlayerName;
public EditText mPlayerScore;
public Button mMinusButton, mAddButton;
public ScoreViewHolder(View itemView) {
super(itemView);
mPlayerName = (TextView) itemView.findViewById(R.id.textView_player_name);
mPlayerScore = (EditText) itemView.findViewById(R.id.editText_player_score);
mMinusButton = (Button) itemView.findViewById(R.id.button_minus);
mAddButton = (Button) itemView.findViewById(R.id.button_add);
mMinusButton.setOnClickListener(this);
mAddButton.setOnClickListener(this);
mPlayerName.setOnLongClickListener(this);
}
/**
* Binds the data from the player to the appropriate views.
*
* #param player The player data to be bound.
*/
public void bindPlayers(Player player) {
mPlayerName.setText(player.getName());
mPlayerScore.setText(String.valueOf(player.getScore()));
}
#Override
public void onClick(View v) {
int id = v.getId();
int updatedScoreCount = mPlayerList.get(getAdapterPosition()).getScore();
switch (id) {
case R.id.button_minus:
updatedScoreCount--;
if (updatedScoreCount < 0) {
Toast.makeText(itemView.getContext(), R.string.toast_text_score_to_low, Toast.LENGTH_LONG).show();
return;
} else {
updatePlayerScore(updatedScoreCount);
notifyItemChanged(getAdapterPosition());
}
break;
case R.id.button_add:
updatedScoreCount++;
if (updatedScoreCount >= 9999) {
Toast.makeText(itemView.getContext(), R.string.toast_text_score_to_high, Toast.LENGTH_LONG).show();
return;
} else {
updatePlayerScore(updatedScoreCount);
notifyItemChanged(getAdapterPosition());
}
break;
default:
}
}
#Override
public boolean onLongClick(View v) {
removePlayer(getAdapterPosition());
return true;
}
public void removePlayer(int positionInArrayList) {
mPlayerList.remove(positionInArrayList);
notifyItemRemoved(positionInArrayList);
}
private void updatePlayerScore(int updatedScoreCount) {
mPlayerList.get(getAdapterPosition()).setScore(updatedScoreCount);
}
}
}
The base number of Players in the list starts as two and their names show up as
Player 1 and Player 2. But when 1 is passed into numberOfPlayers in addNewPlayers the players all show up as Player 2.
Screen captures of the list before and after addNewPlayer().
try this: override the getItemCount in the adapter to reflect the size of the list it is using, and call that method instead to get the number of items in your list.
The problem was that I was adding the new Player to the beginning of the list and not the end of the list. To be honest I'm sure why this worked but it does. the new code looks like this.
public static void addNewPlayers(List<Player> playerArrayList, SharedPreferences sharedPreferences,
PlayerScoreCardAdapter playerScoreCardAdapter,
int numberOfPlayersToAdd) {
for (int i = 0; i < numberOfPlayersToAdd; i++) {
String name = String.format("%s%s", Keys.KEY_DEFAULT_PLAYER_NAME, playerArrayList.size() + 1);
Player player = new Player(name, sharedPreferences.getInt(Keys.KEY_PLAYER_SCORE + String.valueOf(i + 1),
Keys.KEY_DEFAULT_PLAYER_SCORE));
playerArrayList.add(playerArrayList.size(), player);
playerScoreCardAdapter.notifyItemInserted(playerArrayList.size());
}
}

ArrayList loses data

On my app I have a ListView with Checkboxes and have an adapter that extends BaseAdapterto populate the ListView. The basic function of the list is to show debts and the user can choose which ones to pay by checking the boxes, you have the total at the bottom of the list that gets updated when the user adds/removes an item. Now, some debts are related to another and if the user checks one, any other related debt should be marked as well and same if you uncheck a debt. I also have a button that should clear all the selected debts on the list, and that's where my problem is.
I keep record of the selected debts on an ArrayList and it seems to work for all the program but the clear button. When the button is pressed the selected debts list seems to be always empty. Any idea on what could be happening?
Here is my adapter:
public class ServicesFinancialStatusAdapter extends BaseAdapter implements CompoundButton.OnCheckedChangeListener{
private Context context;
private List<Debts> debtsList;
private List<Debts> selectedDebts;
private LayoutInflater inflater;
private int tabPosition;
private float total;
private OnTotalChangedListener listener;
public ServicesFinancialStatusAdapter(Context context, List<Debts> debtsList, int tabPosition) {
this.context = context;
this.debtsList = debtsList;
this.tabPosition = tabPosition;
this.total = 0;
this.inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
this.selectedDebts = new ArrayList<Debts>();
}
#Override
public int getCount() {
return debtsList.size();
}
#Override
public Object getItem(int i) {
return debtsList.get(i);
}
#Override
public long getItemId(int i) {
return i;
}
#Override
public View getView(int i, View view, ViewGroup viewGroup) {
ViewHolder holder;
if (view == null) {
holder = new ViewHolder();
view = inflater.inflate(R.layout.item_services_financial_status, viewGroup, false);
holder.concept = (TextView) view.findViewById(R.id.payment_concept);
holder.descriptionOrDate = (TextView) view.findViewById(R.id.payment_description_date);
holder.amount = (TextView) view.findViewById(R.id.payment_amount);
holder.expirationDate = (TextView) view.findViewById(R.id.payment_expiration_date);
if (tabPosition > 4) {
holder.checkBox = (CheckBox) view.findViewById(R.id.check_box);
holder.checkBox.setOnCheckedChangeListener(this);
}
view.setTag(holder);
} else
holder = (ViewHolder) view.getTag();
Debts item = debtsList.get(i);
holder.concept.setText(item.getConcept());
holder.amount.setText(item.getAmountToString());
if (item.isExpired())
holder.expirationDate.setText(context.getString(R.string.expired_status_indicator));
else
holder.expirationDate.setText(context.getString(R.string.debts_expiration_date_indicator) + item.getExpirationDate());
if (tabPosition < 3)
holder.descriptionOrDate.setText(item.getDescription());
else if (tabPosition < 5)
holder.descriptionOrDate.setText(item.getDate());
else {
holder.descriptionOrDate.setVisibility(View.GONE);
holder.checkBox.setVisibility(View.VISIBLE);
holder.checkBox.setTag(i);
holder.checkBox.setChecked(item.isSelected());
}
return view;
}
#Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
//Get the position of the item clicked and the data object
Integer position = (Integer) buttonView.getTag();
Debts item = debtsList.get(position);
//Change the status ob the object
item.setSelected(isChecked);
for (Debts debts : debtsList) {
//Check on the list for related objects and marks them as well
if (debts.getConceptId() == item.getRelatedDebt())
debts.setSelected(isChecked);
//Get the amount of the debt and add/remove it from
//the selectedDebts list and update the total
float amount = debts.getAmount();
if (debts.isSelected()) {
if (!selectedDebts.contains(debts)) {
selectedDebts.add(debts);
listener.onTotalChanged(addToTotal(amount), selectedDebts);
}
}
else {
if (selectedDebts.contains(debts)) {
selectedDebts.remove(debts);
listener.onTotalChanged(removeFromTotal(amount), selectedDebts);
}
}
}
//Finally update the UI
notifyDataSetChanged();
}
//Anywhere else in the code selectedDebts has the right data but here
//Here the size of the list is always 0
public void unMarkDebts() {
for (Debts debts : debtsList) {
//Get the amount of the debt and remove it from
//the selectedDebts list, set the data object as unselected
//and update the total
float amount = debts.getAmount();
if (selectedDebts.contains(debts)) {
debts.setSelected(false);
selectedDebts.remove(debts);
listener.onTotalChanged(removeFromTotal(amount), selectedDebts);
}
}
//Update the UI
notifyDataSetChanged();
}
private float addToTotal(float value) {
return total += value;
}
private float removeFromTotal(float value) {
return total -=value;
}
public interface OnTotalChangedListener{
public void onTotalChanged(float total, List<Debts> selectedDebts);
}
public void setOnTotalChangedListener(OnTotalChangedListener listener) {
this.listener = listener;
}
private class ViewHolder {
TextView concept, descriptionOrDate, amount, expirationDate;
CheckBox checkBox;
}
}
And here is my fragment code:
public class CheckoutFragment extends BaseFragment implements View.OnClickListener, ServicesFinancialStatusAdapter.OnTotalChangedListener {
public static final String TAG = CheckoutFragment.class.getSimpleName();
private List<Debts> debtsList;
private List<Debts> selectedDebts;
private ServicesFinancialStatusAdapter adapter;
private TextView totalView, positiveBalanceView;
private View noDebtsView, header, footer;
private LinearLayout mainLayout;
private float total, positiveBalance;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setHasOptionsMenu(true);
debtsList = new ArrayList<Debts>();
adapter = new ServicesFinancialStatusAdapter(getActivity(), debtsList, 5);
adapter.setOnTotalChangedListener(this);
webServices = ((MainActivity) getActivity()).getNetworkInstance();
}
#Nullable
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
//Initialize the views
...
reloadData();
onTotalChanged(0, null);
return view;
}
#Override
public void onClick(View view) {
reloadData();
}
#Override
public void onTotalChanged(float total, List<Debts> selectedDebts) {
this.total = total == 0 ? total : total - positiveBalance;
this.selectedDebts = selectedDebts;
totalView.setText(getString(R.string.total_indicator) + Utilities.formatNumberAsMoney(this.total));
getActivity().invalidateOptionsMenu();
}
private void reloadData() {
debtsList.clear();
adapter = new ServicesFinancialStatusAdapter(getActivity(), debtsList, 5);
adapter.setOnTotalChangedListener(this);
loadData();
}
private void loadData() {
//Load debts from server
...
}
private void saveSelectedDebts() {
for (Debts selectedDebt : selectedDebts) {
long id = Debts.insert(getActivity(), selectedDebt);
//Log.d(TAG, "Inserted " + selectedDebt.getConcept() + " with ID " + id);
}
}
#Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
super.onCreateOptionsMenu(menu, inflater);
if (!((MainActivity) getActivity()).drawerIsOpen) {
inflater.inflate(R.menu.checkout, menu);
}
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.clear:
adapter.unMarkDebts();
break;
case R.id.checkout:
selectPaymentMode();
break;
}
return super.onOptionsItemSelected(item);
}
private void selectPaymentMode() {
...
}
}
The chat broke. I think one investigation could be:
Everytime you call reload, you are initiating from scracth the adapter with a new object, (call method new). Remove that line and just use the previous adapter (taking care of initiating the adapteer on onCreate). Notice that the vairable selectedDebts is local to the adapter and you are not passing it in the constructor.

Categories

Resources