第十七个项目——使用接口回调实现删除ListView列表中的Item数据

实验目的

  • 掌握如何删除ListView列表中的Item

  • 掌握如何使用接口回调在不同组件进行通信的方式;

实验要求

  • 掌握使用接口回调在不同组件进行通信的方式;

实验内容

第十六个项目中使用SwipeRefreshLayout为新闻列表页面增加了下拉刷新数据功能。实际工程项目中,在列表页面通常提供了删除某一Item数据的功能,本实验中通过在NewsAdapter中自定义名为OnItemDeleteListener接口,并通过接口回调的方式在MainActivity活动中实现删除指定id的新闻Item

实现删除指定 id 的新闻 Item 的逻辑主要为:

  • NewsAdapter中定义声明OnItemDeleteListener接口;

    • NewsAdapter中实例化OnItemDeleteListener接口对象;

    • 通过定义setOnItemDeleteListener()方法将OnItemDeleteListener接口对象给其他组件(本项目中是MainActivity);

  • NewsAdapter.getView()方法中设置ImageView控件(id为iv_ delete) OnClick事件侦听器,并重写onClick()方法,在该方法中调用NewsAdapter中实例化的OnItemDeletedListener接口对象中的onDelete()方法;

  • MainActivity中实现OnItemDeleteListener接口,并重写onDelete()方法,在该方法中实现删除指定id新闻Item的功能;

步骤一,打开第七个项目或第十六个项目

打开第七个项目第十六个项目,在此基础上完成本次实验。

步骤二,更改list_ item.xml布局文件

list_ item.xml布局中,需要加入相应用户点击删除操作的ImageView控件(id为iv_delete),代码如下所示。 其中使用layout_ alignParentEndlayout_ below两个属性将ImageView控件放在布局的右下角。 ImageView控件的图片使用了Vector asset资源,通过右击项目【res】->【Vector Asset】弹出**Vector Asset对话框进行选择,如图1. Vector Asset资源选择对话框所示。

<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.CardView
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    app:cardCornerRadius="8dp">

    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content">
        ...
        <TextView
            android:id="@+id/tv_title"
            style="@style/TextAppearance.AppCompat.Subhead"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_below="@id/iv_image"
            android:paddingTop="8dp"
            android:paddingStart="8dp"
            android:paddingBottom="4dp"
            android:textColor="@color/colorPrimary"
            android:textSize="18sp"
            android:textStyle="bold" />
        ...
        <ImageView
            android:id="@+id/iv_delete"
            android:src="@drawable/ic_close_black_24dp"
            android:layout_alignParentEnd="true"
            android:layout_below="@id/tv_title"
            android:paddingEnd="8dp"
            android:paddingBottom="8dp"
            android:clickable="true"
            android:layout_width="24dp"
            android:layout_height="24dp" />
    </RelativeLayout>
</android.support.v7.widget.CardView>

步骤三,更改NewsAdapter文件

1. 定义OnItemDeleteListener接口

NewsAdapter类内定义OnItemDeleteListener接口类型,接口中声明一个onDelete(int id)抽象方法,其他组件实现接口时必须重写该方法。

2. 实现setOnItemDeleteListener()方法

NewsAdapter需要为其他组件提供设置OnItemDeleteListener接口对象的方法,在NewsAdapter中定义setOnItemDeleteListener()方法,该方法的参数为OnItemDeleteListener接口类型,这从其他组件实例化后传递进来的接口对象。

上述两步的代码如下所示。

public class NewsAdapter extends ArrayAdapter<News> {
    ...
    private OnItemDeleteListener listener = null;

    ...

    public interface OnItemDeleteListener {
        public void onDelete(int id);
    }

    public void setOnItemDeleteListener (
                OnItemDeleteListener listener) {
        this.listener = listener;
    }
  ...
}

3. 更新ViewHolder类声明

如果在第十六个项目的基础上进行实验,则需要更新ViewHolder类声明,添加一个名为ivDeleteImageView控件对象,用于绑定list_ item.xml布局中的iv_ delete控件,具体代码如下所示。

public class NewsAdapter extends ArrayAdapter<News> {
    ...

    class ViewHolder {
        TextView tvTitle;
        TextView tvAuthor;
        ImageView ivImage;

        ImageView ivDelete;
    }
}

4. 更新getView()方法

NewsAdapter.getView()方法中,首先绑定iv_ delete控件至ViewHolderivDelete成员变量。并通过viewHolder.ivDelete.setTag(position)方法将当前Item的索引值保存起来,以便在该ivDelete控件对象OnClick事件触发时取出。

最后通过viewHolder.ivDelete.setOnClickListener()方法设置ivDelete控件对象的OnClick事件侦听器,在onClick方法中,首先判断listener对象(为OnItemDeleteListener接口对象)是否为空,如果不为空则直接调用其onDelete()方法。当其他组件通过调用NewsAdapter.setOnItemDeleteListener()方法设置了OnItemDelete侦听器时,相应的侦听器对象的onDelete()方法将被执行,从而实现删除指定id新闻Item的操作,具体代码如下所示。

public class NewsAdapter extends ArrayAdapter<News> {
    @Override
    public View getView(final int position, View convertView,
                    ViewGroup parent) {
        ...
        if (convertView == null) {
            view = LayoutInflater.from(getContext())
                        .inflate(resourceId, parent, false);

            ...
            viewHolder.ivDelete = view.findViewById(R.id.iv_delete);
            view.setTag(viewHolder);
        } else {
            view = convertView;
            viewHolder = (ViewHolder) view.getTag();
        }

        ...
        viewHolder.ivDelete.setTag(position);
        viewHolder.ivDelete.setOnClickListener(
                  new View.OnClickListener(){
            @Override
            public void onClick(View view) {
                /*最简单的删除方式*/
                /*
                int i = (int) view.getTag();
                mNewsData.remove(i);
                notifyDataSetChanged();
                */

                /*使用interface接口回调进行删除*/
                if (listener != null) {
                    int id =  (int) view.getTag();
                    listener.onDelete(id);
                }
            }
        });

        return view;
     }
  }

步骤四,在MainActivity中设置NewsAdapter的OnItemDelete事件侦听器

1. 设置NewsAdapter对象的OnItemDelete事件侦听器

MainActivity活动的onCreate()方法中,实例化NewsAdapter对象后,通过setOnItemDeleteListener()方法设置OnItemDelete事件侦听器,传递的参数为匿名类接口。在重写匿名类接口的onDelete(int id)方法时,调用MainActivity类定义的私有方法removeData(int id),实际删除功能由该方法实现。

2. 定义removeData()方法实现删除指定 id 新闻Item

在本次实验中,删除指定id新闻的Item功能放在removeDta()方法中。在该方法中,通过调用newsList.remove(int id)方法删除指定id下标的数据,并调用NewsAdapternotifyDataSetChanged()方法通知绑定适配器的ListView控件刷新数据,从而完成删除指定id新闻Item操作。

上述两步的代码具体如下所示。

 public class MainActivity extends AppCompatActivity {
    ...
    private List<News> newsList = new ArrayList<>();
    private NewsAdapter newsAdapter = null;
    private ListView lvNewsList;

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

        ...
        lvNewsList = findViewById(R.id.lv_news_list);
        initData();
        newsAdapter.setOnItemDeletedListener(
                new NewsAdapter.OnItemDeleteListener() {
            @Override
            public void onDelete(int id) {
                removeData(id);
            }
        });

        lvNewsList.setAdapter(newsAdapter);
        ...
    }

    private void removeData(int id) {
      newsList.remove(id);
      newsAdapter.notifyDataSetChanged();
    }
    ...
 }

步骤五,编译并运行App

编译本项目,成功后在AVD上或物理机上运行App,初始化时,ListView显示近20条新闻列表,你可通过下拉刷新新增新闻(该功能在第十六个项目中实现),通过点击每条新闻右下方的删除图标可删除当前新闻Item,运行效果如图2. 在ListView中删除新闻Item所示。

实验小结

通过本次实验,你应该掌握了如下知识内容:

  • 使用接口回调实现组件间通信;

  • 使用接口回调实现删除ListView指定id新闻Item

Last updated

Was this helpful?