首页
学习
活动
专区
工具
TVP
发布
精选内容/技术社群/优惠产品,尽在小程序
立即前往

如何在android中用子回收视图制作回收视图

在Android开发中,RecyclerView是一种高效的列表展示控件,它通过重用已经滑出屏幕的视图来减少内存消耗和提高渲染效率。使用子回收视图(也称为嵌套的RecyclerView)可以进一步优化复杂列表的展示,例如在一个列表项中包含另一个列表。

基础概念

RecyclerView通过以下几个关键组件实现高效的数据展示:

  1. Adapter:负责将数据绑定到视图上。
  2. LayoutManager:负责决定列表项的布局方式。
  3. ViewHolder:用于缓存视图,减少findViewById的调用次数。

相关优势

  • 高效性:通过视图重用机制,减少内存消耗和提高渲染速度。
  • 灵活性:支持多种布局管理器,如线性布局、网格布局等。
  • 可扩展性:可以嵌套使用,适用于复杂的数据结构。

类型

  • 线性布局:LinearLayoutManager
  • 网格布局:GridLayoutManager
  • 瀑布流布局:StaggeredGridLayoutManager

应用场景

  • 列表展示,如新闻列表、商品列表等。
  • 嵌套列表,如在一个列表项中展示另一个列表。

实现步骤

  1. 添加依赖:在build.gradle文件中添加RecyclerView的依赖。
代码语言:txt
复制
dependencies {
    implementation 'androidx.recyclerview:recyclerview:1.2.1'
}
  1. 创建布局文件:为RecyclerView和子RecyclerView创建布局文件。
代码语言:txt
复制
<!-- activity_main.xml -->
<androidx.recyclerview.widget.RecyclerView
    android:id="@+id/recyclerView"
    android:layout_width="match_parent"
    android:layout_height="match_parent" />

<!-- item_layout.xml -->
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:orientation="vertical">

    <TextView
        android:id="@+id/textView"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />

    <androidx.recyclerview.widget.RecyclerView
        android:id="@+id/nestedRecyclerView"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />
</LinearLayout>
  1. 创建数据模型:定义用于展示的数据模型。
代码语言:txt
复制
public class Item {
    private String title;
    private List<NestedItem> nestedItems;

    // Getters and setters
}
  1. 创建Adapter:为外层RecyclerView和内层RecyclerView创建Adapter。
代码语言:txt
复制
public class MainAdapter extends RecyclerView.Adapter<MainAdapter.ViewHolder> {
    private List<Item> items;

    public MainAdapter(List<Item> items) {
        this.items = items;
    }

    @Override
    public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_layout, parent, false);
        return new ViewHolder(view);
    }

    @Override
    public void onBindViewHolder(ViewHolder holder, int position) {
        Item item = items.get(position);
        holder.textView.setText(item.getTitle());
        NestedAdapter nestedAdapter = new NestedAdapter(item.getNestedItems());
        holder.nestedRecyclerView.setLayoutManager(new LinearLayoutManager(holder.itemView.getContext()));
        holder.nestedRecyclerView.setAdapter(nestedAdapter);
    }

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

    public static class ViewHolder extends RecyclerView.ViewHolder {
        public TextView textView;
        public RecyclerView nestedRecyclerView;

        public ViewHolder(View itemView) {
            super(itemView);
            textView = itemView.findViewById(R.id.textView);
            nestedRecyclerView = itemView.findViewById(R.id.nestedRecyclerView);
        }
    }
}

public class NestedAdapter extends RecyclerView.Adapter<NestedAdapter.ViewHolder> {
    private List<NestedItem> nestedItems;

    public NestedAdapter(List<NestedItem> nestedItems) {
        this.nestedItems = nestedItems;
    }

    @Override
    public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.nested_item_layout, parent, false);
        return new ViewHolder(view);
    }

    @Override
    public void onBindViewHolder(ViewHolder holder, int position) {
        NestedItem nestedItem = nestedItems.get(position);
        holder.textView.setText(nestedItem.getTitle());
    }

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

    public static class ViewHolder extends RecyclerView.ViewHolder {
        public TextView textView;

        public ViewHolder(View itemView) {
            super(itemView);
            textView = itemView.findViewById(R.id.textView);
        }
    }
}
  1. 设置LayoutManager:在Activity或Fragment中设置RecyclerView的LayoutManager。
代码语言:txt
复制
public class MainActivity extends AppCompatActivity {
    private RecyclerView recyclerView;
    private MainAdapter adapter;

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

        recyclerView = findViewById(R.id.recyclerView);
        recyclerView.setLayoutManager(new LinearLayoutManager(this));

        List<Item> items = generateData(); // 生成数据
        adapter = new MainAdapter(items);
        recyclerView.setAdapter(adapter);
    }

    private List<Item> generateData() {
        // 生成数据逻辑
        return new ArrayList<>();
    }
}

可能遇到的问题及解决方法

  1. 嵌套RecyclerView滚动冲突
    • 问题:外层RecyclerView和内层RecyclerView滚动时发生冲突。
    • 解决方法:设置内层RecyclerView的setNestedScrollingEnabled(false)
代码语言:txt
复制
holder.nestedRecyclerView.setNestedScrollingEnabled(false);
  1. 性能问题
    • 问题:嵌套RecyclerView导致性能下降。
    • 解决方法:确保内层RecyclerView的Adapter和布局优化良好,避免不必要的视图创建和数据绑定。
  • 布局问题
    • 问题:内层RecyclerView的布局不正确。
    • 解决方法:检查内层RecyclerView的LayoutManager设置和布局文件。

通过以上步骤和解决方法,可以在Android中成功使用子回收视图制作回收视图。更多详细信息和示例代码可以参考Android官方文档

页面内容是否对你有帮助?
有帮助
没帮助

相关·内容

Android开发笔记(一百零一)滑出式菜单

可是LinearLayout作为水平展示时有点逗,因为如果下面有两个子视图的宽度都是match_parent,那么LinearLayout只会显示第一个视图,第二个视图却是怎么拉也死活显示不了。...倘若在外侧加个HorizontalScrollView,由于HorizontalScrollView的宽度只能是wrap_content,因此视图的宽度也只能是wrap_content而不能是match_parent...办法肯定是有的,在《Android开发笔记(三十五)页面布局视图》中,我们提到margin和padding都可用来设置空隙,空隙的数值都是正数,其实空隙值也能是负数,负数表示该视图被隐藏了一部分,仿佛一张纸插了部分纸面到书中...菜单点击时跳回内容页面 菜单点击的交互例子可见demo工程的ResponsiveUIActivity,主要做法步骤如下: 1、定义一个菜单点击接口OnSlidingMenuListener,其内部定义菜单点击方法...,仅仅是做了detach操作,并没有做remove或destroy操作,也就是说,ViewPager页面根本就没被回收;所以点击菜单重新回到替换后的ViewPager时,系统发现头两页没有回收,自然也不会再次

1.2K70

【基本功】Litho的使用及原理剖析

Layout是Litho中的容器组件,类似于Android中的ViewGroup,但是只能使用Flexbox的规范。它可以包含组件节点,是Litho各组件连接的纽带。...下面通过一个简单的例子了解一下如何在组件中定义和使用Props属性: ? 在上面的代码中,共使用了三次Prop注解,分别标注prop1和prop2两个变量,即定义了prop1和prop2两个属性。...限制视图绘出父布局。 有监听焦点变化。 有设置Tag。 有监听触摸事件。 有光影效果。 对于以上场景的使用请仔细考虑,过多的使用会导致Litho的层级优化效果变差。...滑出屏幕的itemType1会被拆分成一个个的视图单元。LithoView容器由Recycler缓存池回收,其他视图单元由Litho的缓存池分类回收。 ?...使用细粒度复用的RecyclerView的缓存池不再需要区分模板类型来缓存大量的视图模板,只需要缓存LithoView容器。细粒度回收视图单元数量要远远小于原来缓存在各个视图模板中的视图单元数量。

2.1K10
  • Android RecyclerView 缓存机制深度解析与面试题

    引言 RecyclerView 是 Android 开发中用于展示列表和网格的强大组件。它通过高效的缓存机制,优化了滑动性能和内存使用。...它通过多级缓存来复用视图,减少布局的测量和绘制,从而提高滚动的流畅性。 缓存级别 一缓(mAttachedScrap):缓存屏幕中可见范围的 ViewHolder。...缓存:ViewHolder 被回收后,会根据需要被添加到上述缓存中。...ViewHolder 用于缓存视图引用,避免重复调用 findViewById()。 RecyclerView 强制使用 ViewHolder 是为了提高性能和方便管理视图。...6、 如何在 RecyclerView 中实现预加载? 通过 GapWorker 类和 RecyclerView 的预加载机制,提前加载即将显示的视图

    11910

    精选Android中高级面试题:性能优化,JNI,设计模式

    View 如果高度和 RelativeLayout 不同,则会引发效率问题,当 View 很复杂时,这个问题会更加严重。...如何在 JNI 中注册 Native 函数,有几种注册方法 ?...MVC: 视图层 (View) 对应于 xml 布局文件和 java 代码动态 view 部分 控制层 (Controller) MVC 中 Android 的控制层是由 Activity 来承担的,Activity...本来主要是作为初始化页面,展示数据的操作,但是因为 XML 视图功能太弱,所以 Activity 既要负责视图的显示又要加入控制逻辑,承担的功能过多。...MVP:通过引入接口 BaseView,让相应的视图组件 Activity,Fragment 去实现 BaseView,实现了视图层的独立,通过中间层 Preseter 实现了 Model 和 View

    2.7K30

    精选Android中高级面试题 (四):性能优化,JNI,设计模式

    View 如果高度和 RelativeLayout 不同,则会引发效率问题,当 View 很复杂时,这个问题会更加严重。...如何在 JNI 中注册 Native 函数,有几种注册方法 ?...MVC: 视图层 (View) 对应于 xml 布局文件和 java 代码动态 view 部分 控制层 (Controller) MVC 中 Android 的控制层是由 Activity 来承担的,Activity...本来主要是作为初始化页面,展示数据的操作,但是因为 XML 视图功能太弱,所以 Activity 既要负责视图的显示又要加入控制逻辑,承担的功能过多。...MVP:通过引入接口 BaseView,让相应的视图组件 Activity,Fragment 去实现 BaseView,实现了视图层的独立,通过中间层 Preseter 实现了 Model 和 View

    1.1K30

    Android性能优化:这是一份全面&详细的内存优化指南

    储备知识:Android 内存管理机制 3.1 简介 下面,将针对回收 进程、对象 、变量的内存分配 & 回收进行详细讲解 3.2 针对进程的内存策略 a....内存回收策略 步骤1:Application Framework 决定回收的进程类型 Android中的进程 是托管的;当进程空间紧张时,会 按进程优先级低->>高的顺序 自动回收进程 Android...内核 由Linux 内核完成真正的内存回收 此处仅总结流程,这其中的过程复杂,有兴趣的读者可研究系统源码ActivityManagerService.java 3.3 针对对象、变量的内存策略 Android...4.0 后提供的一个API 技巧3:当视图变为隐藏状态时,则释放内存 当用户跳转到不同的应用 & 视图不再显示时, 应释放应用视图所占的资源 注:此时释放所占用的资源能显著的提高系统的缓存处理容量...具体操作:实现当前Activity类的onTrimMemory()后,当用户离开视图时会得到通知;若得到返回的参数 = TRIM_MEMORY_UI_HIDDEN 即代表视图变为隐藏状态,则可释放视图所占用的资源

    1.6K11

    Facebook构建高性能Android视频组件实践之路

    资源回收利用 Android内置的RecyclerView可以基于视图的类型将其保存在不同的缓存池中,这对于创建了很多不同类型视图的用户界面来说可能会是一个问题。...相比之下,Litho的回收系统复用了更小的用户界面构建模块,比如文本或图片,而不是整个视图。通过使用一个核心视频组件,同样的视图可以被循环使用于所有的视频新闻类型。...更有效的回收利用减少了对象的分配,进而提高了滚动性能。 预分配 新闻提要的第一个视频新闻不能循环使用预先存在的视频视图,因为之前没有视图。...当两个视频新闻同时出现在屏幕上时也需要注意:一个视频视图可以从以前的新闻中回收,但是第二个视图需要新建。...当RecyclerView的适配器被更新时,它可以重新绑定所有的视图,并获得所有可见的组件并重新加载(触发onUnmount和onMount)。

    1.6K100

    Android经典面试题之RecycleView 深度解析与面试题梳理

    RecyclerView 是 Android 提供的一个高效且功能强大的列表和网格布局管理器,它不仅提高了滑动的流畅性,还通过回收复用视图的方式提高了内存的利用率。...**LayoutManager**:负责测量和定位项视图,以及决定哪些项可见、哪些项应该被回收复用。 **Adapter**:负责将数据绑定到视图上,以及管理数据集合的变化。...**ItemAnimator**:负责动画效果的播放,添加、删除、移动项时的动画。 2....用户滚动 RecyclerView 时,LayoutManager 会计算哪些项应该显示在屏幕上,并决定哪些项可以被回收复用。...不支持装饰器模式(分割线)。 没有内建的动画支持。 滑动性能较差,因为每个列表项都是独立的视图。 RecyclerView: 支持水平和垂直列表,以及网格布局。

    12710

    资深Android开发的5个经典面试题

    面试题目1:谈谈你对Android中的内存泄漏和内存溢出的理解,以及如何检测和解决它们。 解答: 内存泄漏是指应用程序中的某些对象不再被使用,但仍然被引用,导致垃圾回收器无法回收它们,从而消耗内存。...检测内存泄漏通常可以使用Android Studio的Memory Profiler工具,或者使用第三方库LeakCanary。...面试题目2:描述一下Android中的Binder机制,以及它是如何在不同进程间进行通信的。 解答: Binder是Android中的一种IPC(进程间通信)机制。...解答: MVC(Model-View-Controller)是一种经典的架构模式,它将应用程序分为三个部分:模型(Model)负责数据,视图(View)负责显示,控制器(Controller)负责业务逻辑...面试题目4:描述一下Android中的Handler机制,以及它是如何工作的。 解答: Handler是Android中用于处理线程间通信的类。

    9610

    RecyclerView必知必会

    基本概念 RecyclerView是Android 5.0提出的新UI控件,位于support-v7包中,可以通过在build.gradle中添加compile 'com.android.support...ListView vs RecyclerView ListView相比RecyclerView,有一些优点: addHeaderView(), addFooterView()添加头视图和尾视图。...那么如何在不破坏原有Adapter实现的情况下完成呢? 这里引入装饰器(Decorator)设计模式,该设计模式通过组合的方式,在不破话原有类代码的情况下,对原有类的功能进行扩展。...嵌套滑动机制 Android 5.0推出了嵌套滑动机制,在之前,一旦View处理了触摸事件,父View就没有机会再处理这次的触摸事件,而嵌套滑动机制解决了这个问题,能够实现如下效果: 为了支持嵌套滑动...回顾 回顾整篇文章,发现我们已经实现了RecyclerView的很多扩展功能,包括:打造万能适配器、添加Item事件、添加头视图和尾视图、设置空布局、侧滑拖拽。

    4.7K20

    Android从零单排系列二十九】《Android布局介绍——LinerLayout》

    前言 小伙伴们,在前面的系列文章中,我们重点介绍了Android开发中用到的视图组件,从本文开始我们继续盘点Android中的布局,本文主要介绍一下LinerLayout。...设置布局属性: 可以通过在每个子视图的布局参数中设置不同的属性来控制视图在LinearLayout中的位置和大小,例如android:layout_weight属性可以用来设置视图的权重,实现按比例分配剩余空间...在LinearLayout中添加视图Button、TextView等)作为其元素,并使用布局参数(layout_width和layout_height等)设置每个子视图的大小和对齐方式。...android:gravity:设置LinearLayout内部视图的对齐方式。 android:baselineAligned:设置是否按基线对齐视图。...这个简单的LinearLayout案例展示了如何在垂直方向上排列文本和按钮,并通过android:layout_gravity属性实现水平居中对齐。

    23930

    RecyclerView 必知必会

    ListView vs RecyclerView ListView相比RecyclerView,有一些优点: addHeaderView(), addFooterView()添加头视图和尾视图。...那么如何在不破坏原有Adapter实现的情况下完成呢? 这里引入装饰器(Decorator)设计模式,该设计模式通过组合的方式,在不破话原有类代码的情况下,对原有类的功能进行扩展。...回收机制 ListView回收机制 ListView为了保证Item View的复用,实现了一套回收机制,该回收机制的实现类是RecycleBin,他实现了两级缓存: View[] mActiveViews...嵌套滑动机制 Android 5.0推出了嵌套滑动机制,在之前,一旦View处理了触摸事件,父View就没有机会再处理这次的触摸事件,而嵌套滑动机制解决了这个问题,能够实现如下效果: ?...回顾 回顾整篇文章,发现我们已经实现了RecyclerView的很多扩展功能,包括:打造万能适配器、添加Item事件、添加头视图和尾视图、设置空布局、侧滑拖拽。

    2.6K70

    RecyclerView 必知必会

    基本概念 RecyclerView是Android 5.0提出的新UI控件,位于support-v7包中,可以通过在build.gradle中添加compile 'com.android.support...ListView vs RecyclerView ListView相比RecyclerView,有一些优点: addHeaderView(), addFooterView()添加头视图和尾视图。...那么如何在不破坏原有Adapter实现的情况下完成呢? 这里引入装饰器(Decorator)设计模式,该设计模式通过组合的方式,在不破话原有类代码的情况下,对原有类的功能进行扩展。...嵌套滑动机制 Android 5.0推出了嵌套滑动机制,在之前,一旦View处理了触摸事件,父View就没有机会再处理这次的触摸事件,而嵌套滑动机制解决了这个问题,能够实现如下效果: ?...回顾 回顾整篇文章,发现我们已经实现了RecyclerView的很多扩展功能,包括:打造万能适配器、添加Item事件、添加头视图和尾视图、设置空布局、侧滑拖拽。

    4.2K90

    RecyclerView技术栈参考资料:

    滚出可见区域的条目将被回收,并在下一个条目可见的时候被复用。 我们可以从下图中得到更直观的解释: ? 左边的图是数据初始化后的示例,当向上滚动视图的时候,当条目不可见之后将被回收。...不过,视图回收本身并不是什么新鲜事。但是回想之前我们写的ListView,无论从它的的性能表现着手,还是语法的书写,甚至数据的绑定都未免略显臃肿。...LayoutManager - 负责摆放视图等相关操作 ItemDecoration - 负责绘制Item附近的分割线 ItemAnimator - 为Item的一般操作添加动画效果,,增删条目等...GridLayoutManager 网格Item视图。 StaggeredGridLayoutManager 交错的网格Item视图。...至此,所有与本文章相关的代码都可以从Github上获取到,另外这个仓库中还有一份本人精心制作的PPT,可供参考。

    1.2K10

    Android UI布局优化之ViewStub

    android:layout指定了懒加载的视图android:layout_width和android:layout_height分别指定了懒加载视图的宽和高。...也就是说,在调用inflate方法之前,ViewStub一直存在于视图树中,当调用inflate之后,ViewStub被加载的视图替换,到此,ViewStub的作用完成,之后ViewStub可能被内存回收..., 并把自己所有的layout属性给待加载的视图, 什么是layout属性呢,也就是下面以”android:layout_”打头的属性: android:layout_width以及layout_height...= null) { // 如果引用的视图未被垃圾回收回收,则设置其可见性 view.setVisibility(visibility);...} else { // 如果引用的视图已经被垃圾回收回收,则抛出异常 // 这也就是为什么setVisibility可以调用多次,但是并不推荐这样做的原因

    85120

    Android开发笔记(七十五)内存泄漏的处理

    因为C/C++设计上的原因,手工分配的内存,也要手工来释放,malloc/free是C中分配/释放内存的运算符,而new/delete则是C++中新增的分配/释放内存的运算符。...Java设计之初就是能够自动回收内存,可是有些时候因为某些因素,内存回收机制并不会都奏效。...当列表元素多次处于“展示->隐藏->展示->隐藏……”时,就有必要重用每个元素的视图,如果不重用,那么每次展示可视元素都得重新分配视图对象(从系统服务LAYOUT_INFLATER_SERVICE获取)...适配器的相关介绍参见《Android开发笔记(三十八)列表类视图》。...重用适配可先判断convertView,如果该对象为空,则分配视图对象,并调用setTag方法保存视图持有者;如果该对象非空,则调用getTag方法获取视图持有者。

    1.1K20

    Android常见面试题

    标题栏。 2、继承原有的控件。这种自定义控件在原生控件提供的方法外,可以自己添加一些方法。制作圆角,圆形图片。 3、完全自定义控件:这个View上所展现的内容全部都是我们自己绘制出来的。...比如说制作水波纹进度条。 View的绘制流程:OnMeasure()——>OnLayout()——>OnDraw() 第一步:OnMeasure():测量视图大小。...六个步骤: ①、绘制视图的背景; ②、保存画布的图层(Layer); ③、绘制View的内容; ④、绘制View视图,如果没有就不用; ⑤、还原图层(Layer); ⑥、绘制滚动条。...由于View是保存在ViewGroup中的,多层ViewGroup的节点结构时,上级ViewGroup保存的会是真实处理事件的View所在的ViewGroup对象:ViewGroup0-ViewGroup1...20、Android内存泄露及管理 (1)内存溢出(OOM)和内存泄露(对象无法被回收)的区别。

    1.2K10

    Android界面性能优化必读

    1.4 垃圾回收 垃圾回收器是一个在应用运行期间自动释放那些不再引用的内存的机制,常称 GC 。频繁的 GC 也是导致严重性能问题的罪魁祸首之一。...越接近 16ms ,在垃圾回收事件触发的时候,就越容易导致卡顿。 注意,Android4.4 引进了新的 ART 虚拟机来取代 Dalvik 虚拟机。...因此,尽管垃圾回收Android 5.0 之后不再是耗资源的行为,但也是始终需要尽可能避免的,特别是在执行动画的情况下,可能会导致一些让用户明显感觉的丢帧。...使用包含 layoutweight 属性的线性布局 LinearLayout 每一个组件都需要被测量两次,会消耗过多的系统资源。...在使用 ListView 标签与 GridView 标签的时候,这个问题显的尤其重要,因为组件会重复被创建。

    4.7K10

    Flutter 高性能原理浅析

    Dart 垃圾回收机制 Dart的垃圾回收也采用了多生代算法,新生代在回收内存时采用了“半空间”算法,触发垃圾回收时Dart会将当前半空间中的“活跃”对象拷贝到备用空间,然后整体释放当前空间的所有内存如图...Flutter只关心向 GPU提供视图数据,GPU的 VSync信号同步到 UI线程,UI线程使用 Dart来构建抽象的视图结构,这份数据结构在 GPU线程进行图层合成,视图数据提供给 Skia引擎渲染为..., 但是其树上每个节点的类型没有变化时, element 树和 render 树可以完全重用原来的对象 (因为 element 和 render object 的属性都是可变的) 布局原理 传统布局,Android...对象不存储自己在容器中的位置, 所以在它的位置发生改变时并不需要重新布局或者绘制....对象的位 置信息存储在它自己的 parentData 字段中,但是该字段由它的父对象负责维护,自身并不关心该字段的内容。

    2.3K31

    Android性能优化相关的10个经典面试题

    优化代码:减少onCreate中的初始化代码,使用工具ProGuard来移除无用的代码。...答案: 内存泄漏:长时间持有不需要的对象引用,导致垃圾回收器无法回收这些对象。 检测:使用工具LeakCanary、Profiler来检测内存泄漏。...如何优化Android应用的UI渲染性能? 答案: 布局优化:使用ConstraintLayout减少布局嵌套,避免过度使用复杂的自定义视图。...避免内存泄漏:确保所有视图和回调在不需要时能够被垃圾回收回收。 使用硬件加速:在Activity或View上启用硬件加速,可以提高绘制性能。...减少Overdraw:使用工具Hierarchy Viewer来检测和减少过度绘制。 5. 在Android中,如何优化网络请求的性能?

    10010
    领券