samedi 9 mai 2020

How to handle interface in adapter properly?

I have a RecyclerView that displays tasks and contains checkboxes. When user will click the checkbox, I want to check if the time ending of the task is less than the current time and if it is true, then the checkbox will remain checked, otherwise it should be unchecked. Let me clarify my problem with the help of the code.

In my adapter I created an interface:

private OnItemClickedListener listener;

public void setOnItemClickedListener(OnItemClickedListener listener){
    this.listener = listener;
}
interface OnItemClickedListener {
    void onItemClick(View v, int position, boolean isChecked, int time);
}

Then, in OnBindViewHolder I set onClickListener to checkbox:

@Override
public void onBindViewHolder(@NonNull final SortedViewHolder holder, final int position) {
    final Sorted data = list.get(position);
    holder.title.setText(data.getSortedName());
    holder.date.setText(data.getSortedDate());
    holder.category.setText(String.valueOf(data.getSortedCategory()));
    holder.attach.setText(String.valueOf(data.isSortedAttach()));
    holder.to.setText(String.valueOf(toTime(data.getSortedDuration() + data.getSortedTimeBegin())));
    holder.from.setText(String.valueOf(toTime(data.getSortedTimeBegin())));
    holder.checkBox.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            if (listener != null){
                boolean isChecked = holder.checkBox.isChecked();
                listener.onItemClick(v, position, isChecked, data.getSortedDuration() + data.getSortedTimeBegin());
            }
        }
    });
}

(Note: I store time of the tasks in minutes, so later I will split them seperately into minutes and hours).

After that, in my activity I get this method and check the time:

//in OnCreate: 
final SortedAdapter adapter = new SortedAdapter();
adapter.setOnItemClickedListener(this);

@Override
public void onItemClick(View v, int position, boolean isChecked, int time) {
    if (isChecked){
        //String currentTime = new SimpleDateFormat("HH:mm:ss", Locale.getDefault()).format(new Date());
        //get current day time
        int hour = Calendar.getInstance().get(Calendar.HOUR_OF_DAY);
        int minute = Calendar.getInstance().get(Calendar.MINUTE);
        //compare to the given
        if (hour > time/60){
            //save state
            Toast.makeText(this, "check1", Toast.LENGTH_SHORT).show();
        }
        else if (hour == time/60){
            if (minute > time % 60){
                //save state
                Toast.makeText(this, "check2", Toast.LENGTH_SHORT).show();
            }
            else{
                //set the checkbox to false
                Toast.makeText(this, "uncheck1", Toast.LENGTH_SHORT).show();
                listener.onCheckBoxOff(v);
            }
        }
        else{
            Toast.makeText(this, "uncheck2", Toast.LENGTH_SHORT).show();
            listener.onCheckBoxOff(v);
        }
    }
}

All the Toasts work fine. Now I want somehow to access my checkbox variable and change it's state. And this is my problem. I don't really understand how to do it. I've tried to make another interface in my activity:

 //outside activity class
 interface CheckBoxOff {
    void onCheckBoxOff(View v);
 }

//in activity class before onCreate
private CheckBoxOff listener;

void setCheckboxOffListener(CheckBoxOff listener){
    this.listener = listener;
}

So then I implemented it in my adapter:

@Override
public void onCheckBoxOff(View v) {
    SortedViewHolder holder = new SortedViewHolder(v);
    holder.checkBox.setChecked(false);
}

And in BindViewHolder I wrote(maybe here is the mistake?):

ShowSortedActivity activity = new ShowSortedActivity();
activity.setCheckboxOffListener(this);

After starting my app I got error:

java.lang.NullPointerException: Attempt to invoke interface method 'void com.example.tryalgorithm.ui.CheckBoxOff.onCheckBoxOff(android.view.View)' on a null object reference
    at com.example.tryalgorithm.ui.ShowSortedActivity.onItemClick(ShowSortedActivity.java:104)
    at com.example.tryalgorithm.ui.SortedAdapter$1.onClick(SortedAdapter.java:66)
    at android.view.View.performClick(View.java:6304)
    at android.widget.CompoundButton.performClick(CompoundButton.java:134)
    at android.view.View$PerformClick.run(View.java:24803)
    at android.os.Handler.handleCallback(Handler.java:794)
    at android.os.Handler.dispatchMessage(Handler.java:99)
    at android.os.Looper.loop(Looper.java:176)
    at android.app.ActivityThread.main(ActivityThread.java:6635)
    at java.lang.reflect.Method.invoke(Native Method)
    at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:547)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:823)

Could you please explain what am I doing wrong here? Maybe there is another way to set the checkbox to false, not with the help of interface or this way is fine? Thanks for any help.




Aucun commentaire:

Enregistrer un commentaire