Nassim B
Nassim B

Reputation: 3

How to get checkbox value from Adapter to fragment

I have a cardView custom layout with a checkbox inside, I am using this cardView inside a recyclerView in a fragment (I have 3 fragments and one adapter).

I tried to implement setOnCheckedListener, with different tutorials, for the checkbox because I need to know if all the checkboxes inside the recyclerView are checked and put the boolean value of each checkbox inside a SparseBooleanArray from the fragment.

My Adapter :

public class WarmupProgramAdapter extends RecyclerView.Adapter<WarmupProgramAdapter.ProductViewHolder> {

private Context mCtx;
private List<Program> warmupProgramList;

public WarmupProgramAdapter(Context mCtx, List<Program> warmupProgramList) {
    this.mCtx = mCtx;
    this.warmupProgramList = warmupProgramList;
}

@NonNull
@Override
public ProductViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
    //inflating and returning our view holder
    LayoutInflater inflater = LayoutInflater.from(mCtx);
    View view = inflater.inflate(R.layout.custom_program_card_layout, null);
    ProductViewHolder holder = new ProductViewHolder(view);
    return holder;
}

@Override
public void onBindViewHolder(@NonNull final ProductViewHolder holder, final int position) {
    //getting the program of the specified position
    final Program program = warmupProgramList.get(position);

    //binding the data with the viewholder views
    holder.imageView.setImageDrawable(mCtx.getResources().getDrawable(program.getImage()));
    holder.tvName.setText(program.getName());
    holder.tvHow.setText(program.getHow());
    holder.tvHint.setText(program.getHint());
    holder.checkBox.setChecked(program.getDone());

    holder.checkBox.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            if (program.getDone()) {
                program.setDone(false);
                cbWarmupProgramStateArray.put(position, false);
            } else {
                program.setDone(true);
                cbWarmupProgramStateArray.put(position, true);
            }

            int trueCount = 0;
            for (int i = 0; i < cbWarmupProgramStateArray.size(); i++) {
                if (cbWarmupProgramStateArray.get(i)) {
                    trueCount++;
                }
                if ((trueCount == WarmupFragment.programWarmupList.size())) {
                    Toast.makeText(mCtx, " ## Program done !", Toast.LENGTH_SHORT).show();
                    break;
                }
            }
        }
    });
}

@Override
public int getItemCount() {
    return warmupProgramList.size();
}

static class ProductViewHolder extends RecyclerView.ViewHolder{

    TextView tvName, tvHow, tvHint;
    ImageView imageView;
    CheckBox checkBox;

    ProductViewHolder(View itemView) {
        super(itemView);

        imageView = itemView.findViewById(R.id.iv_type_program);
        tvName = itemView.findViewById(R.id.tv_name_program);
        tvHow = itemView.findViewById(R.id.tv_how_program);
        tvHint = itemView.findViewById(R.id.tv_hint_program);
        checkBox = itemView.findViewById(R.id.cb_program);
    }
}
}

As you can see, I tried with setOnClickListener for the checkbox, I put all the values in my SparseBooleanArray but I don't know if I can get this array in the Fragment and if it's the right method to do that.

My Fragment :

public class WarmupFragment extends Fragment {

RecyclerView recyclerViewWarmup;
RecyclerView.LayoutManager layoutManagerWarmup;
ProgramAdapter programAdapterWarmup;
public static List<Program> programWarmupList;
ArrayList<Program> programWarmupObject;

private OnFragmentInteractionListener mListener;

public WarmupFragment() {
    // Required empty public constructor
}

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
}

@Override
public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container,
                         Bundle savedInstanceState) {
    // Inflate the layout for this fragment
    final View warmupView = inflater.inflate(R.layout.fragment_warmup, container, false);

    programWarmupObject = new ArrayList<>();
    programWarmupObject.clear();

    if (getArguments() != null) {
        programWarmupObject = getArguments().getParcelableArrayList("warmupProgramListForFragment");
    }

    recyclerViewWarmup = warmupView.findViewById(R.id.warmup_recycler_view);
    recyclerViewWarmup.setHasFixedSize(false);
    layoutManagerWarmup = new LinearLayoutManager(getContext());
    recyclerViewWarmup.setLayoutManager(layoutManagerWarmup);

    programWarmupList = new ArrayList<>();

    programWarmupList.addAll(programWarmupObject);

    programAdapterWarmup = new ProgramAdapter(getContext(), programWarmupList);
    recyclerViewWarmup.setAdapter(programAdapterWarmup);

    return warmupView;
}

@Override
public void onAttach(Context context) {
    super.onAttach(context);
    if (context instanceof OnFragmentInteractionListener) {
        mListener = (OnFragmentInteractionListener) context;
    } else {
        throw new RuntimeException(context.toString()
                + " must implement OnFragmentInteractionListener");
    }
}

@Override
public void onDetach() {
    super.onDetach();
    mListener = null;
}

public interface OnFragmentInteractionListener {
    // TODO: Update argument type and name
    void onFragmentInteraction(Uri uri);
}
}

My program Object :

public class Program implements Parcelable {
private int image;
private String name;
private String how;
private String hint;
private boolean isDone;

public Program(Parcel in) {
    super();
    readFromParcel(in);
}

public static final Parcelable.Creator<Program> CREATOR = new Creator<Program>() {
    @Override
    public Program createFromParcel(Parcel in) {
        return new Program(in);
    }

    @Override
    public Program[] newArray(int size) {
        return new Program[size];
    }
};

public Program(int image, String name, String how, String hint) {
    this.image = image;
    this.name = name;
    this.how = how;
    this.hint = hint;
}

public void readFromParcel(Parcel in) {
    image = in.readInt();
    name = in.readString();
    how = in.readString();
    hint = in.readString();
}

@Override
public void writeToParcel(Parcel dest, int i) {
    dest.writeInt(image);
    dest.writeString(name);
    dest.writeString(how);
    dest.writeString(hint);
}

@Override
public String toString() {
    return image + " , " + name + " , " + how + " , " + hint;
}

public int getImage() {
    return image;
}

public String getName() {
    return name;
}

public String getHow() {
    return how;
}

public String getHint() {
    return hint;
}

public boolean getDone() {
    return isDone;
}

public void setDone(boolean done) {
    isDone = done;
}

@Override
public int describeContents() {
    return 0;
}
}

Thanks in advance.

(sorry for my -not on point- english)

Upvotes: 0

Views: 1324

Answers (1)

4gus71n
4gus71n

Reputation: 4083

Okay, what you need to do is pretty easy.

First I don't know from where the cbWarmupProgramStateArray variable is coming from, I see that you are using it to store boolean values in the Adapter but I don't see it declared as a field anywhere. My guess by the name and the way that you're using that variable is that is some sort of List<Boolean>.

You don't need to have a List<Boolean> and a List<Program>. Program already has a boolean field, you should use that to keep track about if the user checked or not the program.

About the communication with the fragment. You need to declare a callback interface in your adapter, something like:

public class WarmupProgramAdapter ... {

    interface AdapterCallback {
        void isAllChecked();
        void programChecked(Program program);
    }

    ...

}

And you can call the callback like this:

//Do this..

warmupProgramList.get(position).setDone(checkBox.isChecked());
//IDK if your fragment needs to know about individual checks, just added this in case
fragmentCallback.programChecked(warmupProgramList.get(position), checkBox.isChecked());

//Instead of..
//if (checkBox.isChecked()) {
//  checkBox.setChecked(true); //There's no need to programatically set the checkbox checked, the checkbox is check before triggering the View.OnClick listener
//  cbWarmupProgramStateArray.put(position, true);
//} else {
//  checkBox.setChecked(false);
//  cbWarmupProgramStateArray.put(position, false);
//}

//And do this..

Boolean allTrue = true;
for (Program program : warmupProgramList) {
    if (!program.getDone()) {
        allTrue = false;
        break;
    }
}

if (allTrue) {
    fragmentCallback.isAllChecked();
}

//Instead of this...

//int trueCount = 0;
//for (int i = 0; i < cbWarmupProgramStateArray.size(); i++) {
//  if (cbWarmupProgramStateArray.get(i)) {
//      trueCount++;
//  }
//  if ((trueCount == WarmupFragment.programWarmupList.size())) {
//      Toast.makeText(mCtx, " ## Program done !", Toast.LENGTH_SHORT).show();
//      break;
//  }
//}

The fragmentCallback field is the interface, AdapterCallback. It should be implemented by the fragment and you should pass it through the Adapter's constructor.

Upvotes: 1

Related Questions