从数组适配器中删除数据时更新列表视图

问题描述 投票:0回答:2

我正在创建一个 listView 并在我的主要活动中为其设置一个自定义 arrayAdapter 。在适配器的 getView 方法中使用 onClickListener 来尝试删除单击的项目。它已从适配器中的数组中删除,但我无法刷新列表视图以显示使用notifyDataSetChanged。 我尝试在主活动中使用 onItemClickListener,但我只能通过将对象视图中的项目设置为不可单击来使其工作,但由于复选框而无法工作。 我尝试在 getView 本身的末尾调用 getView 的 onClickListener 中的 notificationDataSetChanged 但两者都没有执行任何操作。 我改变列表视图的唯一方法是创建适配器的新实例并再次设置列表视图,我在主要活动中执行此操作以添加新项目,但我不知道是否可以从适配器执行此操作,并且无法设置由于上述原因,主要活动中的列表视图的 onClick 。 我知道数据正在从阵列中删除,因为日志行 ADAPTER ONCLICK START 和 END 显示删除,但我当时找不到更新屏幕的方法。

这是主要活动

public class MainActivity extends AppCompatActivity {
    CustomAdapter adapter;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        ArrayList<TaskModel> tasks = read();
        //listview
        ListView listView = findViewById(R.id.task_list);
        adapter = new CustomAdapter(this, tasks);
        listView.setAdapter(adapter);
        //add button
        Button addButton = findViewById(R.id.add_button);
        addButton.setOnClickListener(v -> {
            AlertDialog.Builder builder = new AlertDialog.Builder(this);
            View mView = getLayoutInflater().inflate(R.layout.add_dialog,null);
            final EditText txt_inputText = mView.findViewById(R.id.editText);
            builder.setView(mView);
            builder.setMessage("add a new item").setPositiveButton("Add", (dialog, which) -> {
                //do the add here
                Log.d("NEW START", String.valueOf(tasks.size()));
                tasks.add(new TaskModel(txt_inputText.getText().toString(), false));
                write(tasks);
                adapter = new CustomAdapter(this, tasks);
                listView.setAdapter(adapter);
                Toast.makeText(getApplicationContext(),"new item added",Toast.LENGTH_SHORT).show();
                Log.d("NEW END", String.valueOf(tasks.size()));
            }).setNegativeButton("Cancel", (dialog, which) -> Toast.makeText(getApplicationContext(),"new item cancelled",Toast.LENGTH_SHORT).show());
            AlertDialog alert = builder.create();
            alert.show();
        });
    }
}

和适配器

public class CustomAdapter extends ArrayAdapter{
    Context mContext;
    ArrayList<TaskModel> data;
    public CustomAdapter(Context context, ArrayList<TaskModel> data) {
        super(context, R.layout.list_item, data);
        this.mContext = context;
        this.data = data;
    }

    public static class ViewHolder{
        TextView txtName;
        CheckBox chkBox;
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent){
        Log.d("ADAPTER START", String.valueOf(data.size()));
        TaskModel model = (TaskModel) getItem(position);
        ViewHolder viewHolder;
        if(convertView == null){
            viewHolder = new ViewHolder();
            LayoutInflater inflater = LayoutInflater.from(getContext());
            convertView = inflater.inflate(R.layout.list_item, parent, false);
            viewHolder.txtName = convertView.findViewById(R.id.textView);
            viewHolder.chkBox = convertView.findViewById(R.id.checkBox);
            convertView.setTag(viewHolder);
        }else{
            viewHolder = (ViewHolder) convertView.getTag();
        }
            viewHolder.txtName.setOnClickListener(v -> {
                Log.d("ADAPTER ONCLICK START", String.valueOf(data.size()));
                for(int i =0; i < data.size(); i++){
                    if(viewHolder.txtName.getText().equals(data.get(i).name)){
                        data.remove(i);
                    }
                }
                write(data);
                refresh();
                Log.d("ADAPTER ONCLICK END", String.valueOf(data.size()));
            });
        viewHolder.chkBox.setOnCheckedChangeListener((buttonView, isChecked)->{
            if(isChecked){
                //do checked

            }else{
                //do unchecked

            }
        });

        viewHolder.txtName.setText(model.name);
        viewHolder.chkBox.setChecked(model.done);
        return convertView;
    }
}

这些是读取和写入数据的方法,他们使用 bufferedstreams 在内部存储中编辑 json 数组

public class FileController {
public static ArrayList<TaskModel> read(){
    ArrayList<TaskModel> tasks = new ArrayList<>();
    try{
        FileInputStream inputstream = MyApplication.getAppContext().openFileInput("hello.json");
        InputStreamReader streamreader = new InputStreamReader(inputstream);
        BufferedReader bufferedReader = new BufferedReader(streamreader);
        StringBuilder b = new StringBuilder();
        String line;
        while ((line = bufferedReader.readLine()) != null) {
            b.append(line);
        }
        JSONArray jsonArray = new JSONArray(b.toString());
        for(int i=0; i < jsonArray.length(); i++){
            tasks.add(new TaskModel(jsonArray.getJSONObject(i)));
        }
        bufferedReader.close();
    }catch (Exception e){
        e.printStackTrace();
    }
    return tasks;
}
public static void write(ArrayList<TaskModel> tasks){
    try {
        FileOutputStream outputStream = MyApplication.getAppContext().openFileOutput("hello.json", MODE_PRIVATE);
        JSONArray jsonArray = new JSONArray();
        for(int i =0; i < tasks.size(); i++){
            JSONObject jsonObject = new JSONObject();
            jsonObject.put("name", tasks.get(i).name);
            jsonObject.put("done", tasks.get(i).done);
            jsonArray.put(jsonObject);
        }
        outputStream.write(jsonArray.toString().getBytes());
        outputStream.close();
    } catch (Exception e) {
        e.printStackTrace();
    }
}

}

java android android-listview android-arrayadapter
2个回答
0
投票

不要在单击事件中重复创建适配器对象

adapter = new CustomAdapter(this, tasks); 
List<CustomAdapter> adapterList = new ArrayList<CustomAdapter>()
for ( ... ){
    adapterList.add(new CustomAdapter(this, tasks));
}


// In your click event...
CustomAdapter adapter = list.get(index)
listView.setAdapter(adapter);
// 

0
投票

尝试像这样改变结构:

  • 在适配器中创建事件监听器接口
  • 让您的活动实现该侦听器
  • 通过适配器中的侦听器将单击或触摸事件传播到活动
  • 仅让您的活动处理数据而不是适配器

解决方案代码原型

对代码进行一些快速更改,您将拥有如下所示的适配器类:

public class CustomAdapter extends ArrayAdapter {

    public interface CustomAdapterEventListener {
        void onItemDelete(int index);
        void onItemCheck(int index, boolean checked);
    }

    Context mContext;
    ArrayList<TaskModel> data;
    CustomAdapterEventListener listener;

    public CustomAdapter(Context context, ArrayList<TaskModel> data, CustomAdapterEventListener listener) {
        super(context, R.layout.list_item, data);
        this.mContext = context;
        this.data = data;
        this.listener = listener;
    }

    public static class ViewHolder{
        TextView txtName;
        CheckBox chkBox;
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        TaskModel model = (TaskModel) getItem(position);
        ViewHolder viewHolder;
        if(convertView == null) {
            viewHolder = new ViewHolder();
            LayoutInflater inflater = LayoutInflater.from(getContext());
            convertView = inflater.inflate(R.layout.list_item, parent, false);
            viewHolder.txtName = convertView.findViewById(R.id.textView);
            viewHolder.chkBox = convertView.findViewById(R.id.checkBox);
            convertView.setTag(viewHolder);

            // You wanna setup the listeners only once when view binding
            // Notify the listener (the activity in this case) that an item delete request has been made
            viewHolder.txtName.setOnClickListener(v -> listener.onItemDelete(position));
            // Notify the listener (the activity in this case) that item check has changed
            viewHolder.chkBox.setOnCheckedChangeListener((buttonView, isChecked)->
                listener.onItemCheck(position, isChecked));
        }
        else {
            viewHolder = (ViewHolder) convertView.getTag();
        }

        // Always execute the data filling code
        viewHolder.txtName.setText(model.name);
        viewHolder.chkBox.setChecked(model.done);
        return convertView;
    }

    public void setDataList(ArrayList<TaskModel> dataList) {
        this.data.clear();
        this.data.addAll(dataList); // Mind here that we don't change the list's reference
        notifyDataSetChanged();
    }
}

然后,您可以在活动中实现

CustomAdapterEventListener
,以便您可以在用户与列表项中的按钮或复选框交互时处理数据:

public class MainActivity extends AppCompatActivity implements CustomAdapterEventListener {

    private final ArrayList<TaskModel> tasks = new ArrayList<>(); // Make tasks list global
    CustomAdapter adapter;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        tasks.addAll(read()); // Read tasks from file, repo or database etc.
        //listview
        ListView listView = findViewById(R.id.task_list);
        adapter = new CustomAdapter(this, tasks, this); // Added the listener
        listView.setAdapter(adapter); // Set adapter once during the activitiy's lifecycle
                                      // unless you need to manage multiple adapters
        //add button
        Button addButton = findViewById(R.id.add_button);
        addButton.setOnClickListener(v -> {
            AlertDialog.Builder builder = new AlertDialog.Builder(this);
            View mView = getLayoutInflater().inflate(R.layout.add_dialog,null);
            final EditText txt_inputText = mView.findViewById(R.id.editText);
            builder.setView(mView);
            builder.setMessage("add a new item").setPositiveButton("Add", (dialog, which) -> {
                //do the add here
                Log.d("NEW START", String.valueOf(tasks.size()));
                tasks.add(new TaskModel(txt_inputText.getText().toString(), false));
                write(tasks);
                adapter.setDataList(tasks);
                Toast.makeText(getApplicationContext(),"new item added",Toast.LENGTH_SHORT).show();
                Log.d("NEW END", String.valueOf(tasks.size()));
            }).setNegativeButton("Cancel", (dialog, which) -> Toast.makeText(getApplicationContext(),"new item cancelled",Toast.LENGTH_SHORT).show());
            AlertDialog alert = builder.create();
            alert.show();
        });
    }


    @Override
    public void onItemDelete(int index) {
        // Delete the data item here
        if(index < tasks.size) {
            // Make sure the index valid
            tasks.remove(index);
            // Update the data in adapter
            adapter.setDataList(tasks);
            write(tasks); // Save data in file
        }
    }

    @Override
    public void onItemCheck(int index, boolean checked) {
        // Update the data item's done state here
        if(index < tasks.size) {
            // Make sure the index valid
            tasks.get(index).done = checked;
            // Update the data in adapter
            adapter.setDataList(tasks);
            write(tasks); // Save data in file
        }
    }
}

试一试,按照上面的方式重构你的代码,看看它是如何工作的。
注意:我没有测试代码。

© www.soinside.com 2019 - 2024. All rights reserved.