RecyclerView losing Checkbox status despite storing it - java

I've read that you have to store the item's state and set it again because it gets cleared from the RAM. For me, If I keep scrolling up and down in a bit longer list (10-15 item) random checks will appear and disappear. Below is how I store it and set it. What should I set apart from these? I'm using this inside a fragment.
#Override
public void onBindViewHolder(#NonNull BettingViewHolder holder, int position) {
BettingItem item = items.get(position);
holder.homeTextView.setText(item.homeTeam);
holder.awayTextView.setText(item.awayTeam);
holder.dateTextView.setText(item.date);
holder.leagueTextView.setText(item.league);
holder.sportsTextView.setText(item.sport);
holder.homeOddsTextView.setText(Double.toString(item.homeOdds));
holder.drawOddsTextView.setText(Double.toString(item.drawOdds));
holder.awayOddsTextView.setText(Double.toString(item.awayOdds));
switch (item.outcome) {
case HOME:
holder.homeCheckBox.setChecked(true);
break;
case DRAW:
holder.drawCheckBox.setChecked(true);
break;
case AWAY:
holder.awayCheckBox.setChecked(true);
break;
default:
holder.homeCheckBox.setChecked(false);
holder.drawCheckBox.setChecked(false);
holder.awayCheckBox.setChecked(false);
break;
}
holder.item = item;
}
//its a part from ViewHolder's constructor
homeCheckBox.setOnCheckedChangeListener(new CheckBox.OnCheckedChangeListener() {
#Override
public void onCheckedChanged(final CompoundButton buttonView, final boolean isChecked) {
if (item != null) {
homeCheckBox.setChecked(isChecked);
if (isChecked) {
item.outcome = BettingItem.Outcome.valueOf("HOME");
drawCheckBox.setChecked(false);
awayCheckBox.setChecked(false);
} else {
if (item.outcome == BettingItem.Outcome.valueOf("HOME"))
item.outcome = BettingItem.Outcome.valueOf("NONE");
}
listener.onEventSelected(item);
}
}
});
drawCheckBox.setOnCheckedChangeListener(new CheckBox.OnCheckedChangeListener() {
#Override
public void onCheckedChanged(final CompoundButton buttonView, final boolean isChecked) {
if (item != null) {
drawCheckBox.setChecked(isChecked);
if (isChecked) {
item.outcome = BettingItem.Outcome.valueOf("DRAW");
homeCheckBox.setChecked(false);
awayCheckBox.setChecked(false);
} else {
if (item.outcome == BettingItem.Outcome.valueOf("DRAW"))
item.outcome = BettingItem.Outcome.valueOf("NONE");
}
listener.onEventSelected(item);
}
}
});
awayCheckBox.setOnCheckedChangeListener(new CheckBox.OnCheckedChangeListener() {
#Override
public void onCheckedChanged(final CompoundButton buttonView, final boolean isChecked) {
if (item != null) {
awayCheckBox.setChecked(isChecked);
if (isChecked) {
item.outcome = BettingItem.Outcome.valueOf("AWAY");
drawCheckBox.setChecked(false);
homeCheckBox.setChecked(false);
} else {
if (item.outcome == BettingItem.Outcome.valueOf("AWAY"))
item.outcome = BettingItem.Outcome.valueOf("NONE");
}
listener.onEventSelected(item);
}
}
});

you need to uncheck the old checkboxes, because the viewHolders got recycled (if the old checkBoxes were selected, it'll remain selected).
switch (item.outcome) {
case HOME:
holder.homeCheckBox.setChecked(true);
holder.drawCheckBox.setChecked(false);
holder.awayCheckBox.setChecked(false);
break;
case DRAW:
holder.homeCheckBox.setChecked(false);
holder.drawCheckBox.setChecked(true);
holder.awayCheckBox.setChecked(false);
break;
case AWAY:
holder.homeCheckBox.setChecked(false);
holder.drawCheckBox.setChecked(false);
holder.awayCheckBox.setChecked(true);
break;
default:
holder.homeCheckBox.setChecked(false);
holder.drawCheckBox.setChecked(false);
holder.awayCheckBox.setChecked(false);
break;
}
I would only want this behaviour if the user taps on it. I don't know
yet how to seperate these.
in this case, do something like this in your onCheckedChangedListener
homeCheckBox.setOnCheckedChangedListener(buttonView, isChecked -> {
if(buttonView.isPressed()){
//user pressed the button. (handle user clicks)
} else {
//the program toggled the checkbox (do nothing)
}
});

You can basically create list of objects to store your checkbox status with default status (you can use Boolean) and you need to set your recycler view checkbox status from that list. By the way, your status list need to have same size as your total cell size to avoid index out of range error. Also, when your status change you need to change your list of object in your already created list.

Related

change the background color of three textInputlayouts by using listener

I have three text input layouts in my activity, I apply a listener on them and it changes background color when I click on it .but need to click again if I want to click the other two .my question is that how I implement such type of logic that when it 1st clicked and I click on one of the other two, the first one clickable color disappear and 2nd one or third one clicked and its background color change and same for others
View.OnClickListener listener = new View.OnClickListener() {
#SuppressLint("NonConstantResourceId")
#Override
public void onClick(View v) {
if (v.getId() == R.id.textViewLoseWeightSubtitle) {
if (mStateChanged) {
v.setBackgroundResource(R.drawable.textview_after_click);
// mLoseWgt.setTextColor(Color.WHITE);
mStateChanged = false;
mFittedToned.setClickable(false);
mBuildMuscle.setClickable(false);
} else {
v.setBackgroundResource(R.drawable.textview_outline_style);
//mLoseWgt.setTextColor(Color.parseColor("#363C60"));
mStateChanged = true;
mFittedToned.setClickable(true);
mBuildMuscle.setClickable(true);
}
}
if (v.getId() == R.id.textViewBuildMusclesSubtitle) {
if (mStateChanged) {
v.setBackgroundResource(R.drawable.textview_after_click);
// mLoseWgt.setTextColor(Color.WHITE);
mStateChanged = false;
mLoseWgt.setClickable(false);
mFittedToned.setClickable(false);
} else {
v.setBackgroundResource(R.drawable.textview_outline_style);
//mLoseWgt.setTextColor(Color.parseColor("#363C60"));
mStateChanged = true;
mLoseWgt.setClickable(true);
mFittedToned.setClickable(true);
}
}
if (v.getId() == R.id.textViewFittedAndTonedSubtitle) {
if (mStateChanged) {
v.setBackgroundResource(R.drawable.textview_after_click);
// mLoseWgt.setTextColor(Color.WHITE);
mStateChanged = false;
mLoseWgt.setClickable(false);
mBuildMuscle.setClickable(false);
} else {
v.setBackgroundResource(R.drawable.textview_outline_style);
//mLoseWgt.setTextColor(Color.parseColor("#363C60"));
mStateChanged = true;
mLoseWgt.setClickable(true);
mBuildMuscle.setClickable(true);
}
}
}
};
mLoseWgt.setOnClickListener(listener);
mBuildMuscle.setOnClickListener(listener);
mFittedToned.setOnClickListener(listener);
}
What you need is a onFocusChangedListener(). It gives a callback with a boolean which can be used to identify whether the current view is selected or not.
Declare it as:
View.OnFocusChangeListener listener = new View.OnFocusChangeListener() {
public void onFocusChange(View v, boolean hasFocus) {
if (hasFocus) {
v.setBackgroundResource(R.drawable.textview_after_click);
// mLoseWgt.setTextColor(Color.WHITE);
} else {
v.setBackgroundResource(R.drawable.textview_outline_style);
//mLoseWgt.setTextColor(Color.parseColor("#363C60"));
}
}
});
Set it as:
mLoseWgt.setOnFocusChangeListener(listener);
mBuildMuscle.setOnFocusChangeListener(listener);
mFittedToned.setOnFocusChangeListener(listener);
That's it. Your other code seems redundant. For EditText specific functions, you can typecast the view provided by onFocusChange().

onNavigationItemSelected in Android

I want to update my UI based on the ongoing Selected Item from the BottomNavigationView. The problem is that the item ID will be changed after the whole method inside the listener is executed, and method getSelectedItemId() will refer to the item that was selected before when I called it inside updateUI() method.
How I can work around this?
Here is the code:
mBottomNavigationView.setOnNavigationItemSelectedListener(new BottomNavigationView.OnNavigationItemSelectedListener() {
#Override
public boolean onNavigationItemSelected(#NonNull MenuItem item) {
switch (item.getItemId()) {
case R.id.navigation_baby:
case R.id.navigation_you:
case R.id.navigation_partner: {
updateUI();
return true;
}
default:
return false;
}
}
});
Update Method:
The value of mBottomNavigationView.getSelectedItemId() refer to the previous selection
private void updateUI() {
mBagListAdapter.setList(mPregnancyLab.getBagList(mBottomNavigationView.getSelectedItemId()));
mBagListAdapter.notifyDataSetChanged();
}
Try this
mBottomNavigationView.setOnNavigationItemSelectedListener(new BottomNavigationView.OnNavigationItemSelectedListener() {
#Override
public boolean onNavigationItemSelected(#NonNull MenuItem item) {
mBagListAdapter.setList(mPregnancyLab.getBagList(item.getItemId()));
BagListAdapter.notifyDataSetChanged();
}
});
Hope this helps. Feel free to ask for clarifications...

Global value becomes null in method

I have created a private member of the whole class called Member curMbr;
The activity (rather the fragment, since this is in a frament class) has a listview
with some contributions from members.
I also have a context menu on that list. When clicking on a contribution, I want a (customized) dialog box to show details about the member. (Member ID is part of the contribution objet. )
#Override
public void onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) {
Log.d("FRGCOTIZ02", "create ctxt menu");
AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo) menuInfo;
String[] menuItems = getResources().getStringArray(R.array.ar_menu_ctxt_participant);
// Get selected member
Contribution curCotis = (Contribution) (((ListView)v).getItemAtPosition(info.position));
Participant p = new Participant(helper.getDBItem(DBHelper.TABLE_PARTICIPANT,
DBHelper.COL_ID, curCotis.getParticipant()));
curMbr = new Member(helper.getDBItem(DBHelper.TABLE_MEMBER, DBHelper.COL_ID, p.getMember()));
for (int i = 0; i < menuItems.length; i++) {
menu.add(Menu.NONE, i, i, menuItems[i]);
}
Log.d("FRGCOTIZ01", curMbr.getId_());
}
#Override
public boolean onContextItemSelected(MenuItem item) {
return ( applyContextMenuSelection(item) || super.onContextItemSelected(item) );
}
private boolean applyContextMenuSelection(MenuItem item) {
switch (item.getItemId()) {
case 0: // Summary
final Dialog dlg = new Dialog(this.getContext());
final String sessID;
try {
sessID = KUtil.DATE_FORMAT.format(curSess.getDate());
dlg.setContentView(R.layout.alert_show_charges);
Button btnOK = dlg.findViewById(R.id.btn_alertOK);
btnOK.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
setupAlertDialogCharges(dlg, sessID, curMbr.getId_());
}
});
Button btnCancel = dlg.findViewById(R.id.btn_alertCancel);
btnCancel.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
dlg.dismiss();
}
});
dlg.show();
} catch (Exception e){
Log.d("FRAGMENT Contribution", e.getMessage());
}
break;
case 1: // Collect
break;
case 2: // Cancel
break;
default:
break;
}
return true;
}
In method onCreateContextMenu, I can get the member and display his ID.
But in method applyContextMenuSelection, there is an exception, saying the meber is null!
Funny enough there is another variable that I am using in that method, and it works fine. Difference is, that variable has been set at creation of the fragment.
How do I solve this?
I have been studying the code for a while and the only thing I could figure was that the issue is somehow linked to the use of contextmenu. It seems to me that variables are set back to their original when the menu action is supposed to be executed. Again, I am not too sure about that.
So, the only solution I found so far was to keep that vale in a "higher" context:
When I can still read the value,
getActivity().getIntent().putExtra(HomeActivity.ID_ENTRY, curMbr.getId_());
When I want to use it,
final String mbrID = getActivity().getIntent().getStringExtra(HomeActivity.ID_ENTRY);

Controlling state of checkbox based on state of other checkboxes in android

I have three checkboxes and if any two of them are selected I want to disable the third checkbox immediately. I am not getting how to proceed.
Manage your CheckBoxes in a List, so you can iterate over them.
List<CheckBox> boxes = new ArrayList<>();
Assign them like so (in onCreate() of your activity)
boxes.add((CheckBox) findViewById(R.id.checkbox1));
boxes.add((CheckBox) findViewById(R.id.checkbox2));
boxes.add((CheckBox) findViewById(R.id.checkbox3));
Add an onCheckedChangeListener like this:
for(CheckBox box : boxes){
box.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
#Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
manageBoxes();
}
});
}
and finally your manageBoxes()
private void manageBoxes(){
int count = 0;
for(CheckBox box : boxes){
count += box.isChecked()?1:0;
}
if(count>=2){
for(CheckBox box : boxes){
box.setEnabled(box.isChecked());
box.setClickable(box.isChecked()); // not sure if needed
}
}else{
// reset all boxes
for(CheckBox box : boxes){
box.setEnabled(true);
box.setClickable(true);
}
}
}
Just a quick and dirty thought. Hope this works.
Plus: This is scalable, so you could include some more checkboxes if needed.
Try to implement this way :
private ArrayList<Integer> integers = null;
integers = new ArrayList<>();
chkBox.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
try {
int position = (int) yourview.getTag();
if (chkBox.isChecked()) {
integers.add(position);
chkBox.setChecked(true);
} else {
if (integers.size() > 0) {
for (int i=0; i<integers.size(); i++) {
if (integers.get(i) == position) {
integers.remove(i);
}
}
});
if (integers.size() > 2) {
//Disable your third checkbox
}
Add a change handler or a click handler on each of the checkboxes and let it call a small method that is responsible for checking the value of each checkbox: if two of them are true disable the third one.
For example:
checkbox1.setOnCheckedChangeListener(new OnCheckedChangeListener() {
#Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
handleCheckBoxes();
}
});
//Do this for all the checkboxes
private void handleCheckBoxes(){
int checkedCount = 0;
CheckBox uncheckedBox = null;
if(checkBox1.isChecked()){
checkedCount++;
}
else{
uncheckedBox = checkBox1;
}
if(checkBox2.isChecked()){
checkedCount++;
}
else{
uncheckedBox = checkBox2;
}
if(checkBox3.isChecked()){
checkedCount++;
}
else{
uncheckedBox = checkBox3;
}
if(checkedCount == 2){
uncheckedBox .setEnabled(false);
}
else{
//enable all checkboxes
checkBox1.setEnables(true);
checkBox2.setEnables(true);
checkBox3.setEnables(true);
}
In pseudo code this would be:
Create variable to hold the number of checkboxes checked, let's call it amountChecked
When a checkbox gets checked => increment the amountChecked
When a checkbox gets checked => check if the amountChecked is equal or greater than the allowedAmountChecked (in your case this is 2)
=> if it is greater or equal to the allowedAmountChecked then disable the remaining checkboxes

How to prevent second click on radio button if it was already checked in Android?

I want to increase the score by 1, when someone clicks on the right radio button. If someone clicks 2 times, the score is increased by 2. I am trying to prevent that with a boolean but it doesn't work. Were am i wrong?
This is my code:
boolean isChecked;
answer[j].setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
RadioButton checkedRadioButton = ((RadioButton) v);
if (isChecked) {
if (checkedRadioButton.isChecked() & CorrectAnswer == 1) {
score++;
isChecked = false;
}
}
}
});
Thanks!
Assuming you don't need the value outside the OnClickListener, the easiest thing to do is to make it a member variable of that class:
new View.OnClickListener() {
private boolean isChecked = true; // HERE
#Override
public void onClick(View v) {
RadioButton checkedRadioButton = ((RadioButton) v);
if (isChecked) {
if (checkedRadioButton.isChecked() && CorrectAnswer == 1) {
score++;
isChecked = false;
}
}
}
};
You also need to set its value to true initially, since it will otherwise be false and so the conditional's body never runs.
You could also simply use
if (!checkedRadioButton.isChecked())
instead of a dedicated checker
if (isChecked)

Categories