Ошибка интерфейса флажка и адаптера recyclerview - PullRequest
0 голосов
/ 09 мая 2020

У меня есть RecyclerView, который отображает задачи и содержит флажки. Когда пользователь установит флажок, я хочу проверить, меньше ли время завершения задачи, чем текущее время, и если это правда, то флажок останется установленным, в противном случае его следует снять. Позвольте мне прояснить мою проблему с помощью кода.

В моем адаптере я создал интерфейс:

private OnItemClickedListener listener;

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

Затем в OnBindViewHolder я установил onClickListener для флажка:

@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());
            }
        }
    });
}

(Примечание: я храню время задач в минутах, поэтому позже я разделю их на минуты и часы).

После этого в своей деятельности я использую этот метод и проверяю время:

//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);
        }
    }
}

Все тосты работают нормально. Теперь я хочу каким-то образом получить доступ к моей переменной флажка и изменить ее состояние. И это моя проблема. Я не очень понимаю, как это сделать. Я попытался сделать другой интерфейс в своей деятельности:

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

//in activity class before onCreate
private CheckBoxOff listener;

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

Итак, я реализовал его в своем адаптере:

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

И в BindViewHolder я написал (возможно, это ошибка ?):

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

После запуска моего приложения я получил ошибку:

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)

Не могли бы вы объяснить, что я здесь делаю не так? Может быть, есть другой способ установить флажок в false, не с помощью интерфейса или это нормально? Спасибо за любую помощь.

Код активности:

public class ShowSortedActivity extends AppCompatActivity {

SortedViewModel viewModel;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_show_sorted);

    final SortedAdapter adapter = new SortedAdapter();
    RecyclerView showSorted = findViewById(R.id.show_sorted);
    showSorted.setLayoutManager(new LinearLayoutManager(this));
    showSorted.setHasFixedSize(true);
    showSorted.setAdapter(adapter);

    getSupportActionBar().setHomeAsUpIndicator(R.drawable.ic_close);
    setTitle(R.string.Sorted);

    Intent intent = getIntent();
    String currentDate = intent.getStringExtra("value");

    viewModel = new ViewModelProvider(this, ViewModelProvider.AndroidViewModelFactory.getInstance(this.getApplication())).get(SortedViewModel.class);
    try {
        viewModel.getSortedWhereDateIs(currentDate).observe(this, new Observer<List<Sorted>>() {
            @Override
            public void onChanged(List<Sorted> sorteds) {
                adapter.setSortedData(sorteds);
            }
        });
    } catch (ExecutionException e) {
        e.printStackTrace();
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
}

@Override
public void onItemClick(View v, int position, boolean isChecked, int time) {
    if (isChecked){
        //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();
            }
        }
        else{
            //set the checkbox to false
            Toast.makeText(this, "uncheck2", Toast.LENGTH_SHORT).show();
        }
    }
}
}

1 Ответ

1 голос
/ 09 мая 2020
@Override
public void onCheckBoxOff(View v) {
    SortedViewHolder holder = new SortedViewHolder(v);
    holder.checkBox.setChecked(false);
}

Ваша проблема в том, что вы не можете самостоятельно создать держатель представления, он должен управляться адаптером через onCreateViewHolder. Измените свой код на

@Override
public void onCheckBoxOff(View v) {
    ((CheckBox)v).setChecked(false);
}

Но это только исправляет пользовательский интерфейс, вы должны сохранять значение каждого держателя, чтобы оставаться в состоянии флажка при его прокрутке. Выполните следующие действия:

  1. Добавить isChecked в Sorted модель

  2. onBindViewHolder должно обновиться checkBox с помощью isChecked с data

  3. внутренний метод onItemClick должен обновить isChecked модель в списке данных базы адаптера на позиции

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...