从 ListView 到 RecyclerView 的用法浅析

文章目录

要走好明天的路,必须记住昨天走过的路,思索今天正在走着的路。

ListView,一种在垂直滚动列表中显示条目的视图;RecyclerView,一种在局限的窗口呈现大数据集合的灵活视图。RecyclerView 部件是 ListView 的一种更高级且更灵活的版本。

以上描述来自官网。

移动设备屏幕空间有限,导致在屏幕上一次性显示的内容也是有限的。当需要显示大量的数据时,设想有这样的控件,可以帮助用户只通过手指上下滑动,就可以让屏幕外的数据滚动到屏幕内,同时,屏幕上原有的数据会滚动出屏幕。如此,便可以优雅地解决在局限的屏幕上显示大量数据的问题。ListView 和 RecyclerView 便适用于此。

不过,自 Android 5.0 推出以来,RecyclerView 在很多地方都在逐步取代 ListView,这也是官方推崇的。“江山代有才人出,各领风骚数百年”。如今,已要来到 Android 7.0 的时代,RecyclerView 的使用也很普遍了,或许,ListView 正逐步从 Android 的大舞台退出,RecyclerView 即将独领风骚。

下面浅析从 ListView 到 RecyclerView 的用法。

ListView 的用法

ListViewDemo 地址: ListViewDemo,学习总结自郭霖的《第一行代码》。

新建一个 ListViewDemo 项目,默认持续下一步直至完成。然后,删掉 activity_main.xml 中默认建好的 TextView,建立一个 ListView 如下:

12345
<ListView    android:id="@+id/list_view"    android:layout_width="match_parent"    android:layout_height="match_parent"></ListView>

接着,新建一个实体类 Fruit,作为 ListView 适配器的适配类型:

123456789101112131415161718
public class  {

    private String name;    private int imageId;

    public (String name, int imageId) {        this.name = name;        this.imageId = imageId;    }

    public String getName() {        return name;    }

    public int getImageId() {        return imageId;    }}

name 是水果的名字,imageId 是水果对应图片的资源 id。然后,为 ListView 的子项自定义一个布局,在 layout 目录下新建 fruit_item.xml 如下:

1234567891011
<ImageView    android:id="@+id/fruit_image"    android:layout_width="wrap_content"    android:layout_height="wrap_content"/>

<TextView    android:id="@+id/fruit_name"    android:layout_width="wrap_content"    android:layout_height="wrap_content"    android:layout_gravity="center"    android:layout_marginLeft="10dp"/>

ImageView 用于显示水果的图片,TextView 用于显示水果的名称。

由于数据无法直接传递给 ListView,需要借助适配器完成。Android 中提供了很多适配器的实现类,这里使用 ArrayAdapter,通过泛型指定适配的数据类型,再在构造函数中传入适配的数据。自定义一个适配器 FruitAdapter,继承自 ArrayAdapter,泛型指定为 Fruit 类。

同时,优化 ListView 的使用效率:

一. FruitAdapter 中的 getView() 方法每次都将布局加载一遍,这样,快速滚动的话会影响性能。故利用好 convertView 参数,缓存之前加载好的布局,再重用。

二. 使用 ViewHolder 模式,其充分利用 ListView 的视图缓存机制,避免每次调用 getView() 时通过 findViewById() 实例化控件。

代码如下:

12345678910111213141516171819202122232425262728293031323334
public class FruitAdapter extends ArrayAdapter<Fruit> {

    private int resourceId;

    public FruitAdapter(Context context, int textViewResourceId, List<Fruit> objects) {        super(context, textViewResourceId, objects);        resourceId = textViewResourceId;    }

    public View getView(int position, View convertView, ViewGroup parent) {        Fruit fruit = getItem(position);        View view;        ViewHolder viewHolder;        if (convertView == null) {            view = LayoutInflater.from(getContext()).inflate(resourceId, null);            viewHolder = new ViewHolder();            viewHolder.fruitImage = (ImageView) view.findViewById(R.id.fruit_image);            viewHolder.fruitName = (TextView) view.findViewById(R.id.fruit_name);            view.setTag(viewHolder);         } else {            view = convertView;            viewHolder = (ViewHolder) view.getTag(); //重新获取 ViewHolder, 找到缓存的布局.        }        viewHolder.fruitImage.setImageResource(fruit.getImageId());        viewHolder.fruitName.setText(fruit.getName());        return view;    }

    class ViewHolder {        ImageView fruitImage;        TextView fruitName;    }}

FruitAdapter 重写父类的构造函数,将上下文、ListView 子项布局的 id 和数据传递进来。同时,重写了 getView() 方法,每个子项滚动进屏幕内时调用该方法。其中,getItem() 方法获取当前项的 Fruit 实例。

增加判断与一个内部类 ViewHolder,利用视图缓存机制进行缓存。

若 convertView 为空,则创建一个 ViewHolder 对象,将控件的实例存放在 ViewHolder 里。然后,调用 View 的 setTag() 方法,将 ViewHolder 对象存储在 View 中。若 convertView 不为空,则调用 View 的 getTag() 方法,重新取出 ViewHolder。如此,所有控件的实例都缓存在 ViewHolder 里。

最后,修改并完善 MainActivity 中的代码:

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647
public class MainActivity extends AppCompatActivity {

    private List<Fruit> fruitList = new ArrayList<Fruit>();

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

        FruitAdapter adapter = new FruitAdapter(MainActivity.this, R.layout.fruit_item, fruitList);        ListView listView = (ListView) findViewById(R.id.list_view);        listView.setAdapter(adapter);    }

    private void initFruits() {        Fruit apple = new Fruit("Apple", R.mipmap.ic_launcher);        fruitList.add(apple);        Fruit banana = new Fruit("Banana", R.mipmap.ic_launcher);        fruitList.add(banana);        Fruit orange = new Fruit("Orange", R.mipmap.ic_launcher);        fruitList.add(orange);        Fruit watermelon = new Fruit("Watermelon", R.mipmap.ic_launcher);        fruitList.add(watermelon);        Fruit pear = new Fruit("Pear", R.mipmap.ic_launcher);        fruitList.add(pear);        Fruit grape = new Fruit("Grape", R.mipmap.ic_launcher);        fruitList.add(grape);        Fruit pineapple = new Fruit("Pineapple", R.mipmap.ic_launcher);        fruitList.add(pineapple);        Fruit strawberry = new Fruit("Strawberry", R.mipmap.ic_launcher);        fruitList.add(strawberry);        Fruit cherry = new Fruit("Cherry", R.mipmap.ic_launcher);        fruitList.add(cherry);        Fruit mango = new Fruit("Mango", R.mipmap.ic_launcher);        fruitList.add(mango);        Fruit peach = new Fruit("Peach", R.mipmap.ic_launcher);        fruitList.add(peach);        Fruit lemon = new Fruit("Lemon", R.mipmap.ic_launcher);        fruitList.add(lemon);        Fruit pitaya = new Fruit("Pitaya", R.mipmap.ic_launcher);        fruitList.add(pitaya);        Fruit durin = new Fruit("Durin", R.mipmap.ic_launcher);        fruitList.add(durin);    }

}

添加了 initFruits() 方法,初始化所有的水果数据。将水果的名字和对应的图片 id 传入 Fruit 类的构造函数中,再把创建好的对象添加到水果列表中。而后,在 onCreate() 方法里创建了 FruitAdapter 对象,将 FruitAdapter 作为适配器传递给 ListView。

至此,ListView 的简单综合应用浅析完毕,运行程序,如下:

更多如动态修改 ListView、使 ListView 具有弹性、自动显示与隐藏布局 ListView、模仿微信聊天布局 ListView、动态改变点击 Item 布局的 ListView 等,详见 GitHub

RecyclerView 的用法

RecyclerViewDemo 地址: RecyclerViewDemo,学习总结自徐宜生的《 Android 群英传》。

首先,在 gradle 中引入compile 'com.android.support:recyclerview-v7:23.4.0'的依赖。由于 RecyclerView 封装好了 ViewHolder,再实现其功能。新建一个 RecyclerViewDemo 如上所示,同时添加了 Spinner 和按钮:

12345678910111213141516171819202122232425262728293031323334
<android.support.v7.widget.RecyclerView    android:id="@+id/rc_list"    android:layout_width="match_parent"    android:layout_height="0dp"    android:layout_weight="9"    android:scrollbars="vertical"/>

<LinearLayout    android:layout_width="match_parent"    android:layout_height="0dp"    android:layout_weight="1">

    <Spinner        android:id="@+id/spinner"        android:layout_width="0dp"        android:layout_height="wrap_content"        android:layout_weight="1"        android:entries="@array/recycler_list"/>

    <Button        android:layout_width="0dp"        android:layout_height="wrap_content"        android:layout_weight="1"        android:onClick="addRecycler"        android:text="Add"/>

    <Button        android:layout_width="0dp"        android:layout_height="wrap_content"        android:layout_weight="1"        android:onClick="delRecycler"        android:text="Delete"/>

</LinearLayout>

在 strings.xml 中新建 Spinner 中用到的 array:

1234
<string-array name="recycler_list">    <item>LinearLayoutManager</item>    <item>GridLayoutManager</item></string-array>

与 ListView 的用法一样,使用一个合适的数据适配器来加载数据,自定义一个适配器 RecyclerAdapter:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
大专栏  从 ListView 到 RecyclerView 的用法浅析pan class="line">21

时间: 2024-11-10 11:31:29

从 ListView 到 RecyclerView 的用法浅析的相关文章

ListView与RecyclerView对比浅析——缓存机制

https://www.jianshu.com/p/193fb966e954 一,背景 RecyclerView是谷歌官方出的一个用于大量数据展示的新控件,可以用来代替传统的ListView,更加强大和灵活. 最近,自己负责的业务,也遇到这样的一个问题,关于是否要将ListView替换为RecyclerView? 秉承着实事求是的作风,弄清楚RecyclerView是否有足够的吸引力替换掉ListView,我从性能这一角度出发,研究RecyclerView和ListView二者的缓存机制,并得到

android listview 替代品recyclerview详解

安卓v7支持包下的ListView替代品————RecyclerView RecyclerView这个控件也出来很久了,相信大家也学习的差不多了,如果还没学习的,或许我可以带领大家体验一把这个艺术般的控件. 据官方介绍,该控件是属于之间用的非常多的ListView和GridView的替代品,既然能替代用的如此普遍的它们,这自然有其该有的优势. 1)相对于ListView而言RecyclerView的优势体现在: ①封装了之前ListView的优化,封装了之前ViewHolder的复用,这样在自定

Android添加图片到ListView或者 RecyclerView显示

先上图 点击+号就去选择图片 实际上这个添加本身就是一个ListView或者 RecyclerView 只是布局有些特殊 item <?xml version="1.0" encoding="utf-8"?> <liu.myrecyleviewchoosephoto.view.SquareRelativeLayout xmlns:android="http://schemas.android.com/apk/res/android&quo

Javascript属性:addEvent()用法浅析

做 web 应用的人,经常会用到 Javascript 来处理页面上的一些事情.表单验证我们不谈,在根据用户使用情况,显示/隐藏,或者执行一段 js function,的时候,我们需要和页面的 DOM 树打交道.看看 Gmail ,发送邮件,按下"发送"钮后,用 Ajax 在后端发送邮件内容,根据返回的状态,在编辑页面的上方直接显示一小段文字"您的邮件已经发送.". 通常的思想,我们会在那个发送按钮里面写上: onclick="javascript:sen

Android长截屏-- ScrollView,ListView及RecyclerView截屏

http://blog.csdn.net/wbwjx/article/details/46674157       Android长截屏-- ScrollView,ListView及RecyclerView截屏 https://github.com/BoBoMEe/AndroidDev/blob/master/common/common/src/main/java/com/bobomee/android/common/util/ScreenUtil.java /* * Copyright (C)

ListView和RecyclerView复用详解

做一家受人尊敬的企业,做一位受人尊敬的老师-动脑学院 前言 我们每一个Android开发人员对ListView的使用肯定是很熟悉的,然而多少人能真正的懂ListView的缓存机制呢,说白了就是ListView为了提高效率,而内部实现的一种优化,牺牲一点内存.而这种优化就需要复用ItemView(也就是item对应的View).那么下面楼主来对ListView和RecyclerView的item复用问题做一个深入的讲解 首先来解答几个问题 1.ListView为什么会存在Item复用问题 答:Li

将替代ListView的RecyclerView 的使用(一)

RecyclerView 是 android-support-v7-21 版本中新增的一个 Widgets, 还有一个 CardView 会在下次介绍使用.官方介绍 RecyclerView 是 ListView 的升级版本,更加先进和灵活.我们写一个简单的实例例,来看一下究竟有多先进和灵活. build.gradle 配置 android { compileSdkVersion 'android-L' buildToolsVersion "20.0.0" defaultConfig

Boost::Asio::Error的用法浅析

一般而言我们创建用于接收error的类型大多声明如下: boost::system::error_code error 我们用这个类型去接受在函数中产生的错误 如 socket.connect( endpoint, error); 如果连接失败,错误类型会保存到error中,比如连接主机失败可能会返回这样的错误 boost::asio::error::host_not_found; 通过if (error)检测到error后,抛出异常 throw boost::system::system_er

ViewSwitcher用法浅析

如果理解了ViewPager的使用方法,使用ViewSwitcher就方便多了.和ViewFlipper一样,ViewSwitcher也是ViewAnimator的子类,并且只能包含两个子视图,每次展示其中一个视图.可以像ViewFlipper一样添加子视图或者通过工厂创建视图. 如果使用类似ViewFlipper用法浅析中的ViewFlipper添加图片的方法: int[] resourses = { R.drawable.one, R.drawable.two }; viewSwitcher