I am writing a todo list application and, in particular, I want the value of the checkBox to be stored in the database every time it is changed.
I set this feature by adding setOnCheckedChangeListener in onBindViewHolder
#Override
public void onBindViewHolder(#NonNull TodosAdapter.TodoViewHolder holder, int position)
{
Todo todo = todoList.get(position);
holder.todoTV.setText(todo.getText());
holder.todoTV.setChecked(todo.isDone()); //isDone is a boolean that indicates whether the checkBox has been selected or not
holder.todoTV.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
#Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
dbManager.allDao().setTodoIsDone(todo.getTodoId(), isChecked); //sets the isDone attribute of the database
todo.setDone(isChecked);
}
});
}
The problem is that onCheckedChanged is also called when the viewHolder is recycled and in these cases it returns isChecked = false;
I found the solution here:Android setOnCheckedChangeListener calls again when old view comes back.
Just use the buttonView.isShown() method:
#Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
if(buttonView.isShown()) {
dbManager.allDao().setTodoIsDone(todo.getTodoId(), isChecked); //sets the isDone attribute of the database
todo.setDone(isChecked);
}
}
Related
this is my code
ck1.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener(){
#Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
if (buttonView.isChecked()) {
// perform logic
new LikeTask().execute();
ck1.setTag(R.drawable.fill_like);
ck1.setButtonDrawable(R.drawable.fill_like);
} else {
// perform logic
new UnLikeTask().execute();
ck1.setTag(R.drawable.like);
ck1.setButtonDrawable(R.drawable.like);
}
}
});
I want toggle a Switch to false if the user toggles it to true.
In order to avoid firing onCheckChanged again, I remove the listener, then add it back after the switch.
mCheckedChangeListener = new CompoundButton.OnCheckedChangeListener() {
#Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
if(isChecked) {
mMySwitch.setOnCheckedChangeListener(null);
mMySwitch.setChecked(false);
mMySwitch.setOnCheckedChangeListener(mCheckedChangeListener);
}
};
mMySwitch.setOnCheckedChangeListener(mCheckedChangeListener);
This doesn't work, however, and I'm not sure why. When I toggle to true, it stays on true.
/** Update **/
Apparently I don't have to set the listener null, so here's another that still does not set the switch to false:
mMySwitch.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
#Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
if(isChecked) {
mMySwitch.setChecked(false);
}
}
});
return v;
I dug a little more and Looks like this is a known issue: https://code.google.com/p/android/issues/detail?id=57980
This workaround seems to work until someone has a better answer:
mMySwitch.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
#Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
if(isChecked) {
// Not sure why I need a delay here, but it won't fire otherwise.
final Handler handler = new Handler();
handler.postDelayed(new Runnable() {
#Override
public void run() {
mMySwitch.setChecked(false);
}
}, 100);
}
}
});
I have a switch in a recyclerview and data is displayed in the recyclerview after retrieving data from DB. When the recyclerview is opened I read DB and if a field in DB is "Y" I enable the switch or else I disable the switch.
Now the problem is along with it the onCheckedchanged listener is also called, I want the onCheckedChanged to be called only when user sets the switch manually.
On opening the recyclerview below is executed:
holder.enabledisable.setChecked(messengerRecord.get_is_valid().equalsIgnoreCase("Y"));
ViewHolder class:
public class viewHolder extends RecyclerView.ViewHolder implements CompoundButton.OnCheckedChangeListener{
public SwitchCompat enabledisable;
public viewHolder(View v) {
enabledisable = (SwitchCompat) v.findViewById(R.id.enabledisable);
enabledisable.setOnCheckedChangeListener(this);
...................................
...................................
OncheckedChanged method which is called when the recyclerView is just opened:
#Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
Log.v("ranjith","called oncheckedchanged");
MessengerRecord rec;
rec = dbHelper.getRecord(descview.getText().toString());
switch (buttonView.getId()) {
case R.id.enabledisable:
if (isChecked) {
rec.set_is_valid("Y");
dbHelper.updateRecord(rec);
}
}
In Layout file:
<android.support.v7.widget.SwitchCompat
android:layout_marginRight="16dp"
android:layout_marginEnd="16dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:focusable="false"
android:id="#+id/enabledisable"
android:layout_alignRight="#+id/textview_to"
android:layout_alignEnd="#+id/textview_to"
android:layout_alignParentRight="true"
android:layout_alignParentEnd="true"/>
It's weird all of us have this problem but not official Google answer to this simple problem.
The MOST simple it's to check:
buttonView.isPressed()
If true, means the user clicked the view.
No global variables are needed.
Try this
#Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
if (buttonView.isPressed()) {
... //returns true, if user clicks the switch button
}}
I've ended up using this subclass of SwitchCompat to avoid this issue. This way I don't need boilerplate code where I'm using this class.
Whenever you need to change the checked without firing the listener, use setCheckedSilent instead of setChecked:
import android.content.Context;
import android.os.Parcelable;
import android.support.v7.widget.SwitchCompat;
import android.util.AttributeSet;
/**
* Created by emanuel on 30/5/16.
*/
public class Switch extends SwitchCompat {
private OnCheckedChangeListener listener;
public Switch(Context context, AttributeSet attrs) {
super(context, attrs);
}
#Override
public void setOnCheckedChangeListener(OnCheckedChangeListener listener) {
this.listener = listener;
super.setOnCheckedChangeListener(listener);
}
#Override
public void onRestoreInstanceState(Parcelable state) {
super.setOnCheckedChangeListener(null);
super.onRestoreInstanceState(state);
super.setOnCheckedChangeListener(listener);
}
public void setCheckedSilent(boolean checked) {
super.setOnCheckedChangeListener(null);
super.setChecked(checked);
super.setOnCheckedChangeListener(listener);
}
}
onRestoreInstanceState was triggering the listening also, when set in the onViewCreated method and you are going back to a previous fragment.
Hope it works for you!
Since RecyclerView is recycling views, a previously attached OnCheckedChangeListener can be triggered when setting checked value for the Switch of the new item.
When binding new data to an item:
switch.setOnCheckedChangeListener(null) // remove any existing listener from recycled view
switch.isChecked = [true/false] // will no longer trigger any callback to listener
switch.setOnCheckedChangeListener { btnView, isChecked ->
// do exiting stuff
}
This works for me:
boolean selected = preferences.isChecked();
yourCheckBox.setOnCheckedChangeListener(new
CompoundButton.OnCheckedChangeListener() {
#Override
public void onCheckedChanged(CompoundButton buttonView,
boolean isChecked) {
if (buttonView.isPressed()) {
preferences.setChecked(isChecked);
} else {
yourCheckBox.setChecked(selected);
}
}
});
Kotlin Developers:
checkboxXYZ.setOnCheckedChangeListener { btnView, isChecked ->
if (btnView.isPressed) {
}
}
use a global boolean variable and when read a data from DB set it "true" and after check(if) in onCheckChange set it "false" again. in first of onCheckChange method check if this variable is false execute codes else return(default value of this variable must be false ) ;
#Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
if(!isSourceDB){
Log.v("ranjith","called oncheckedchanged");
MessengerRecord rec;
rec = dbHelper.getRecord(descview.getText().toString());
switch (buttonView.getId()) {
case R.id.enabledisable:
if (isChecked) {
rec.set_is_valid("Y");
dbHelper.updateRecord(rec);
}
}//end if
isSourceDB = false; }// end oncheckedchange
If you are changing state in adapter then
holder.rawManageDriverLayoutBinding.rawManageDriverSwitch.setOnCheckedChangeListener(null);
before setOnCheckedChangeListener.
I faced the same problem inside ViewPager screen for fragments. When we switch between fragments, onCheckedChanged Listener is called again and again.
If anyone still looking for this problem, please try it.
#Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
if (buttonView.isInTouchMode()) {
... //Your code will come here.
}
}
Only solution is to use the method isPressed() in the listener
I want to achieve this : user check on a unchecked checkbox, a toast displayed, the checkbox then become disable..
male.setOnCheckedChangeListener(new OnCheckedChangeListener(){
#Override
public void onCheckedChanged(CompoundButton arg0, boolean isChecked) {
// TODO Auto-generated method stub
if (isChecked){
Toast.makeText(CheckBoxTuts.this, "male" , Toast.LENGTH_SHORT).show();
male.setChecked(false);
}
}
});
the output failed, because they execute on the same time, even I put the male.setChecked(false) outside.. I can't recall there's something to run something 1st, then other thing.. is it thread? really cant remember
If you want to achieve: "user check on a unchecked checkbox, a toast displayed, the checkbox then become disable..",you should try this code:
male.setOnCheckedChangeListener(new OnCheckedChangeListener(){
#Override
public void onCheckedChanged(CompoundButton arg0, boolean isChecked) {
if (isChecked){
Toast.makeText(CheckBoxTuts.this, "male" , Toast.LENGTH_SHORT).show();
male.setEnabled(false); // disable checkbox
}
}
});
Try this....
- Use the setEnabled(false) on the CheckBox
male.setOnCheckedChangeListener(new OnCheckedChangeListener(){
#Override
public void onCheckedChanged(CompoundButton arg0, boolean isChecked) {
if (isChecked){
Toast.makeText(CheckBoxTuts.this, "male" , Toast.LENGTH_SHORT).show();
male.setEnabled(false); // Will Disable checkbox
}
}
});
male.setOnCheckedChangeListener(new OnCheckedChangeListener(){
#Override
public void onCheckedChanged(CompoundButton arg0, boolean isChecked) {
// TODO Auto-generated method stub
if (isChecked){
Toast.makeText(CheckBoxTuts.this, "male" , Toast.LENGTH_SHORT).show();
//male.setVisibility(View.GONE);//disappear your check box
male.setEnabled(false);//disable your check box
}
}
});
Try to use .onClickListener(View.OnClickListener) with implemented View.OnClickListener. In body of implemented method you will check if the CheckBox is checked or not and set them.
First , Register Your CheckBox to OnCheckedChangeListener.
chk.setOnCheckedChangeListener(this);
then, Overrides it's Method
#Override
public void onCheckedChanged(CompoundButton compoundButton, boolean b)
{
if (chk.isChecked())
{
chk.setEnabled(false);
}
}
How do you implement this onTouchEvent? It should fire when the user checks or unchecks the CheckBox widget.
CheckBox checkBox = new CheckBox(activity);
checkBox.setText("Don't present me information again.");
checkBox.onTouchEvent(.....);
The CheckBox widget (and any other widget that extends CompoundButton) has a method setOnCheckedChangeListener, which is the bit you're lacking (you probably don't want to use onTouchEvent in this case).
This example should replace the final line of code in your snippet:
checkBox.setOnCheckedChangeListener( new OnCheckedChangeListener() {
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
if ( isChecked ) {
// do some stuff
}
}
});
what you need in your case is this
checkBox.setOnCheckedChangeListener(new OnCheckedChangeListener()
{
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked)
{
if ( isChecked )
{
Toast.makeText(yourActivity.this,"CheckBox is Checked ..",3000).show();
}
else{
Toast.makeText(yourActivity.this,"CheckBox is Unchecked ..",3000).show();
}
}
});