java—在回收器视图的适配器中删除项时索引越界

wyyhbhjk  于 2021-07-06  发布在  Java
关注(0)|答案(1)|浏览(268)

我正在尝试创建一个注重色彩变化的笔记应用程序。在其中一个活动中,我试图实现对注解的项添加和删除
活动的图片。
项目添加显然按预期工作。问题是删除,它是非常不一致的:当我删除所有的项目开始从最后一个向上,一切工作正常;如果我按另一个顺序删除项目,适配器就会出错,不要总是删除正确的项目,并在删除最后一个项目时崩溃。
我查了一下,找到了一些可能的解决方案(在这里或其他网站),但找不到解决方案,或者,我想。
我在适配器additem()和removItem()中创建了方法,以便在类中完成任何更改。也许我误解了一个概念或者遗漏了什么?提前谢谢!
因为我还没有实现一些特性,所以缺少一些接口或代码保护
活动代码

package com.example.colornoteplus;

import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.widget.Toolbar;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;

import android.os.Bundle;
import android.text.Editable;
import android.text.TextWatcher;

import android.util.Log;
import android.view.Menu;
import android.view.MenuInflater;
import android.widget.EditText;
import android.widget.ImageButton;
import android.widget.TextView;
import android.widget.Toast;

import com.google.android.material.floatingactionbutton.FloatingActionButton;

import java.text.DateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.Objects;

public class CheckListNoteActivity extends AppCompatActivity{

    // note editable views
    private EditText titleView;
    private TextView titleCharacterCount;
    private ImageButton colorView;
    private RecyclerView contentView;
    private FloatingActionButton fab;

    CheckListAdapter adapter;

    // toolbar
    private Toolbar toolbar;

    // Current note
    private CheckListNote note;

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

        getNoteFromIntent();

        note.getContent().add(new CheckListItem("ONE"));
        note.getContent().add(new CheckListItem("TWO"));
        note.getContent().add(new CheckListItem("THREE"));
        note.getContent().add(new CheckListItem("FOUR"));
        note.getContent().add(new CheckListItem("FIVE"));

        changeViewsColor(0);
    }

    // Method used to add menus and configure button action
    // like OnClickListeners ...
    @Override
    public boolean onCreateOptionsMenu(Menu menu) {

        // Create a submenu for sorting purpose
        MenuInflater inflater = getMenuInflater();
        inflater.inflate(R.menu.menu_check_list_activity,menu);

        return super.onCreateOptionsMenu(menu);
    }

    // get note from the intent
    private void getNoteFromIntent(){

        if (!getIntent().getStringExtra(Statics.KEY_NOTE_ACTIVITY).equals(Statics.NOTE_DEFAULT_UID)){
            note = MySharedPreferences.LoadCheckListNoteFromSharedPreferences(getIntent().getStringExtra(Statics.KEY_NOTE_ACTIVITY),getApplicationContext());
        } else {
            note = new CheckListNote();
        }
    }

    private void changeViewsColor(int color){

        // set the global theme
        setTheme(StyleManager.getTheme(color));

        // set the appropriate layout
        setContentView(R.layout.activity_check_list_note);

        // change status bar color
        getWindow().setStatusBarColor(getResources().getColor(StyleManager.getThemeColor(color)));

        // set up FAB action
        fab = findViewById(R.id.fab_add_item);
        fab.setOnClickListener(view -> onFabClickListener());

        // setting the toolbar
        toolbar = findViewById(R.id.toolbar);
        setSupportActionBar(toolbar);
        toolbar.setBackgroundColor(getResources().getColor(StyleManager.getThemeColor(color)));
        Objects.requireNonNull(getSupportActionBar()).setDisplayHomeAsUpEnabled(true);

        // setting the note title
        titleView = findViewById(R.id.note_title_view);
        titleView.setText("");
        titleView.setTextColor(getResources().getColor(StyleManager.getThemeColorDark(color)));
        titleView.setHintTextColor(getResources().getColor(StyleManager.getThemeColorLight(color)));

        // setting the character counter for the note title
        titleCharacterCount = findViewById(R.id.note_title_characters);
        String m = titleView.getText().toString().trim().length()+ getString(R.string.text_divider)+ getResources().getInteger(R.integer.title_max_length);
        titleCharacterCount.setText(m);
        titleCharacterCount.setTextColor(getResources().getColor(StyleManager.getThemeColor(color)));

        titleView.addTextChangedListener(new TextWatcher()
        {
            @Override
            public void onTextChanged(CharSequence s, int start, int before, int count)
            {
            }

            @Override
            public void beforeTextChanged(CharSequence s, int start, int count, int aft)
            {
            }

            @Override
            public void afterTextChanged(Editable s)
            {
                // this will show characters remaining
                String msg = titleView.getText().toString().length()+ getString(R.string.text_divider)+ getResources().getInteger(R.integer.title_max_length);
                titleCharacterCount.setText(msg);
            }
        });

        // setting the color view
        colorView = findViewById(R.id.note_color_view);
        colorView.setOnClickListener(view -> buildColorPickDialog());
        colorView.setBackgroundResource(StyleManager.getBackground(color));

        adapter = new CheckListAdapter(getApplicationContext(),note.getContent(),color);
        adapter.setOnItemClickListener(new CheckListAdapter.OnItemClickListener() {
            @Override
            public void onChecked(int position) {
                Toast.makeText(CheckListNoteActivity.this, "Checked item: " +position, Toast.LENGTH_SHORT).show();
            }

            @Override
            public void onUnchecked(int position) {
                Toast.makeText(CheckListNoteActivity.this, "Unchecked item: " +position, Toast.LENGTH_SHORT).show();
            }

            @Override
            public void onSetPriority(int position) {

            }

            @Override
            public void onSetReminder(int position) {

            }

            @Override
            public void onDelete(int position) {
                adapter.removeItem(position);
                Toast.makeText(CheckListNoteActivity.this, "List has "+note.getContent().size()+" elements", Toast.LENGTH_SHORT).show();
            }
        });

        contentView = findViewById(R.id.note_content_view);
        contentView.setLayoutManager(new LinearLayoutManager(getApplicationContext()));
        contentView.setAdapter(adapter);

    }

    private void switchColor(int color){

        String tempTitle = titleView.getText().toString().trim();
        changeViewsColor(color);
        titleView.setText(tempTitle);

    }

    // build the color picker dialog
    private void buildColorPickDialog(){

        FragmentPickColor fragment = new FragmentPickColor(new ColorAdapter(),5,note.getColor());

        fragment.show(getSupportFragmentManager(),Statics.TAG_FRAGMENT_COLOR_PICK);

        fragment.setOnItemClickListener(new ColorAdapter.OnItemClickListener() {
            @Override
            public void OnClickListener(int position) {
                note.setColor(position);
                switchColor(position);
                fragment.dismiss();
            }

            @Override
            public void OnLongClickListener(int position) {

            }
        });

    }

    private void onFabClickListener(){
        FragmentAddCheckListItem fragment = new FragmentAddCheckListItem(note.getColor());
        fragment.show(getSupportFragmentManager(),Statics.TAG_FRAGMENT_ADD_CHECK_LIST_ITEM);
        fragment.setOnClickListener(new FragmentAddCheckListItem.OnClickListener() {
            @Override
            public void onConfirmClickListener() {
                fragment.getItem().setDescription(fragment.getInputText());
                adapter.addItem(fragment.getItem(),0);
                fragment.dismiss();
            }

            @Override
            public void onSetPriorityClickListener() {
            }

            @Override
            public void onSetDueTimeClickListener() {
                FragmentDatePicker datePicker = new FragmentDatePicker();
                datePicker.show(getSupportFragmentManager(),Statics.TAG_FRAGMENT_DATE_PICKER);
                datePicker.setOnDateSet((year, month, day) -> {
                    Calendar c = Calendar.getInstance();
                    c.set(Calendar.YEAR,year);
                    c.set(Calendar.MONTH,month);
                    c.set(Calendar.DAY_OF_MONTH,day);
                    fragment.getItem().setDueDate(c.getTime().getTime());
                    fragment.setDueTimeText(DateFormat.getDateInstance().format(new Date(fragment.getItem().getDueDate())));
                });
            }
        });
    }

}

适配器

package com.example.colornoteplus;

import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.CheckBox;
import android.widget.EditText;
import android.widget.ImageButton;
import android.widget.TextView;

import androidx.annotation.NonNull;
import androidx.constraintlayout.widget.ConstraintLayout;
import androidx.recyclerview.widget.RecyclerView;

import java.text.DateFormat;
import java.util.ArrayList;
import java.util.Date;

public class CheckListAdapter extends RecyclerView.Adapter<CheckListAdapter.MyViewHolder> {

    public CheckListAdapter(Context context,ArrayList<CheckListItem> list, int color) {
        this.list = list;
        this.color = color;
        this.context = context;
    }

    final private ArrayList<CheckListItem> list;
    final private int color;
    final private Context context;
    private OnItemClickListener listener;

    @NonNull
    @Override
    public CheckListAdapter.MyViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {

        return new CheckListAdapter.MyViewHolder(LayoutInflater.
                from(parent.getContext()).
                inflate(R.layout.item_check_list,parent,false));
    }

    @Override
    public void onBindViewHolder(@NonNull CheckListAdapter.MyViewHolder holder, int position) {

        CheckListItem currentItem = list.get(position);

        holder.background.setBackgroundResource(StyleManager.getBackgroundLight(color));

        holder.checkBox.setOnCheckedChangeListener((compoundButton, b) -> {
            if (b) listener.onChecked(position);
            else listener.onUnchecked(position);
        });

        holder.title.setTextColor(context.getResources().getColor(StyleManager.getThemeColorDark(color)));
        holder.title.setHintTextColor(context.getResources().getColor(StyleManager.getThemeColor(color)));
        assert currentItem != null;
        holder.title.setText(currentItem.getDescription().trim());

        holder.dueTimeText.setTextColor(context.getResources().getColor(StyleManager.getThemeColor(color)));
        holder.dueTimeText.setText(currentItem.getDoneDate() != -1 ? DateFormat.getDateInstance().format(new Date(currentItem.getDueDate())) : context.getString(R.string.set_reminder));
        holder.dueTimeText.setOnClickListener(view -> listener.onSetReminder(position));

        holder.priorityText.setTextColor(context.getResources().getColor(StyleManager.getThemeColor(color)));
        holder.priorityText.setText(currentItem.priorityToString(context));
        holder.priorityText.setOnClickListener(view -> listener.onSetPriority(position));

        holder.delete.setBackgroundResource(StyleManager.getBackground(color));
        holder.delete.setOnClickListener(view -> {
            // listener.onDelete(position);
            removeItem(position);
        });
    }

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

    public static class MyViewHolder extends RecyclerView.ViewHolder{

        CheckBox checkBox;
        ConstraintLayout background;
        EditText title;
        ImageButton delete;
        TextView priorityText,dueTimeText;

        public MyViewHolder(@NonNull View itemView) {
            super(itemView);

            checkBox = itemView.findViewById(R.id.item_check_box);
            title = itemView.findViewById(R.id.item_title);
            dueTimeText = itemView.findViewById(R.id.item_due_time_text);
            priorityText = itemView.findViewById(R.id.item_priority_text);
            delete = itemView.findViewById(R.id.item_delete);
            background = itemView.findViewById(R.id.item_background);

        }
    }

    public void addItem(CheckListItem item,int position){
        if (position < 0){
            list.add(item);
            notifyItemInserted(list.size()-1);
        }
        else {
            list.add(position,item);
            notifyItemInserted(position);
        }
    }

    public void removeItem(int position){
        list.remove(position);
        notifyItemRemoved(position);
    }

    public void setOnItemClickListener(OnItemClickListener listener){
        this.listener = listener;
    }

    public interface OnItemClickListener{
        void onChecked(int position);
        void onUnchecked(int position);
        void onSetPriority(int position);
        void onSetReminder(int position);
        void onDelete(int position);
    }
}
1u4esq0p

1u4esq0p1#

public void addItem(CheckListItem item, int position) {
    if (position >= 0) {
        list.add(position, item);
        notifyItemInserted(position);
    }  
}

public void removeItem(int position) {
    if (position >= 0) {
        list.remove(position);
        notifyItemRemoved(position);
    }
}

而且在 onBindViewHolder 使用 holder.getAdapterPosition() 而不是 position 在你的听众中:

holder.delete.setOnClickListener(view -> {
    // listener.onDelete(position);
    removeItem(holder.getAdapterPosition());
});

相关问题