Android--Jetpack--Paging详解

news2024/11/29 12:39:51

不尝世间醋与墨,怎知人间酸与苦。

择一业谋食养命,等一运扭转乾坤。

你见过哪些令你膛目结舌的代码技巧?

文章目录

    • 不尝世间醋与墨,怎知人间酸与苦。
    • 择一业谋食养命,等一运扭转乾坤。
    • 你见过哪些令你膛目结舌的代码技巧?
  • 一,定义
  • 二,优点
  • 三,角色
  • 四,PositionalDataSource来源的使用
    • 1,添加依赖
    • 2,创建bean类
    • 3,创建PositionalDataSource来源的数据源
    • 4,创建数据工厂
    • 5,创建ViewModel
    • 6,创建adapter
    • 7,运行效果
  • 五,ItemKeyedDataSource来源的使用
    • 1,创建数据仓库
    • 2,创建ItemKeyedDataSource
    • 3,创建YuanZhenDataSourceFactory
  • 六,PageKeyedDataSource来源的使用
    • 1,创建PageKeyedDataSource
    • 2,创建数据工厂

一,定义

在我们的 Android 项目中使用 RecyclerViews 时,我们会显示一个包含很多项目的列表。有时我们有一些用例,比如从手机中获取联系人列表并将其显示在列表中。在列表中一次加载大量数据并不是一项非常有效的任务。为了克服这个问题,我们在 Android 中进行了分页。 Paging就是google为了分页而推出的一个库。Paging库可以帮助您一次加载和显示多个小的数据块,按需载入部分数据可以减少网络宽带和系统资源的使用量。

二,优点

①:分页库可以更加轻松地在应用程序中的Recyclerview逐步和优雅的加载数据
​②:数据请求消耗的网络带宽更少,系统资源更少
​③:即使在数据更新和刷新期间,应用程序仍会继续快速响应用户输入 ​
④:不过多浪费,显示多少就用多少

三,角色

①:DataSource(数据源,包含了多种形式,例如:Room来源,PositionalDataSource来源,PageKeyedDataSource来源,ItemKeyedDataSource来源)
数据源就是数据的来源,可以有多种来源渠道,例如:“网络数据”,“本地数据”,“数据库数据”

②:PagedList(UIModel数据层,通过Factory的方式拿到数据源)
创建 管理 数据源 的工厂,为什么有一个工厂,除了可以去创建数据源之外,为了后续的扩展

③:PagedAdapter(不再是之前使用RecycleView的那种适配器了,而是和Paging配套的PagedListAdapter)
数据模型其实就是 ViewModel,用来管理数据
PagedList: 数据源获取的数据最终靠PagedList来承载。
对于PagedList,我们可以这样来理解,它就是一页数据的集合。
每请求一页,就是新的一个PagedList对象。

④:RecycleView(我们之前一直用的RecycleView,只不过setAdapter的时候,绑定的适配器是 PagedAdapter)
这个Adapter就是一个RecyclerView的Adapter。
不过我们在使用paging实现RecyclerView的分页加载效果,
不能直接继承RecyclerView的Adapter,而是需要继承PagedListAdapter。
LiveData观察到的数据,把感应到的数据 给 适配器,适配器又绑定了 RecyclerView,那么RecyclerView的列表数据就改变了

四,PositionalDataSource来源的使用

1,添加依赖

implementation 'androidx.paging:paging-runtime:2.1.0'

2,创建bean类

public class YuanZhen {

    private String id;

    private String name;

    private String age;

    public void setId(String id) {
        this.id = id;
    }

    public String getId() {
        return id;
    }

    public void setName(String name) {
        this.name = name;
    }

    public void setAge(String age) {
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public String getAge() {
        return age;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        YuanZhen student = (YuanZhen) o;
        return id.equals(student.id) &&
                name.equals(student.name) &&
                age.equals(student.age);
    }

    // 比较的函数
    @RequiresApi(api = Build.VERSION_CODES.KITKAT)
    @Override
    public int hashCode() {
        return Objects.hash(id, name, age);
    }
}

3,创建PositionalDataSource来源的数据源

public class YuanZhenDataSource extends PositionalDataSource<YuanZhen> {

    /**
     * 加载第一页数据的时候,会执行此函数来完成
     * 加载初始化数据,加载的是第一页的数据。
     * 形象的说,当我们第一次打开页面,需要回调此方法来获取数据。
     */
    @Override
    public void loadInitial(@NonNull LoadInitialParams params, @NonNull LoadInitialCallback<YuanZhen> callback) {
        callback.onResult(getStudents(0, 20), 0, 1000);
    }
    /**
     * 当有了初始化数据之后,滑动的时候如果需要加载数据的话,会调用此方法。
     */
    @Override
    public void loadRange(@NonNull LoadRangeParams params, @NonNull LoadRangeCallback<YuanZhen> callback) {
        callback.onResult(getStudents(params.startPosition, params.loadSize));
    }

    /**
     * 数据源,数据的来源(数据库,文件,网络服务器响应  等等)
     */
    private List<YuanZhen> getStudents(int startPosition, int pageSize) {
        List<YuanZhen> list = new ArrayList<>();
        for (int i = startPosition; i < startPosition + pageSize; i++) {
            YuanZhen yuanZhen = new YuanZhen();
            yuanZhen.setName("袁震:" + i);
            yuanZhen.setAge("年龄:" + i);
            list.add(yuanZhen);
        }
        return list;
    }
}

4,创建数据工厂

public class YuanZhenDataSourceFactory extends DataSource.Factory<Integer,YuanZhen> {
    @NonNull
    @Override
    public DataSource<Integer, YuanZhen> create() {
        YuanZhenDataSource yuanZhenDataSource =new YuanZhenDataSource();
        return yuanZhenDataSource;
    }
}

5,创建ViewModel

public class YuanZhenViewModel extends ViewModel {

    private final LiveData<PagedList<YuanZhen>> listLiveData;

    public YuanZhenViewModel() {
        YuanZhenDataSourceFactory factory = new YuanZhenDataSourceFactory();

        // 初始化 ViewModel
        this.listLiveData = new LivePagedListBuilder<Integer, YuanZhen>(factory, 20).build();
    }

    public LiveData<PagedList<YuanZhen>> getListLiveData() {
        return listLiveData;
    }
}

6,创建adapter

public class RecyclerPagingAdapter extends PagedListAdapter<YuanZhen,RecyclerPagingAdapter.MyRecyclerViewHolder> {

    private static DiffUtil.ItemCallback<YuanZhen> DIFF_STUDNET = new
            DiffUtil.ItemCallback<YuanZhen>() {

                // 一般是比较 唯一性的内容, ID
                @Override
                public boolean areItemsTheSame(@NonNull YuanZhen oldItem, @NonNull YuanZhen newItem) {
                    return oldItem.getId().equals(newItem.getId());
                }

                // 对象本身的比较
                @Override
                public boolean areContentsTheSame(@NonNull YuanZhen oldItem, @NonNull YuanZhen newItem) {
                    return oldItem.equals(newItem);
                }
            };

    protected RecyclerPagingAdapter() {
        super(DIFF_STUDNET);
    }

    @NonNull
    @Override
    public MyRecyclerViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item, null);
        return new MyRecyclerViewHolder(view);
    }

    @Override
    public void onBindViewHolder(@NonNull MyRecyclerViewHolder holder, int position) {
        YuanZhen yuanzhen = getItem(position);

        // item view 出来了, 分页库还在加载数据中,我就显示 Id加载中
        if (null == yuanzhen) {
            
            holder.tvName.setText("Name加载中");
            holder.tvAge.setText("age加载中");
        } else {
            
            holder.tvName.setText(yuanzhen.getName());
            holder.tvAge.setText(yuanzhen.getAge());
        }
    }

    // Item 优化的 ViewHolder
    public static class MyRecyclerViewHolder extends RecyclerView.ViewHolder {

        TextView tvId;
        TextView tvName;
        TextView tvAge;

        public MyRecyclerViewHolder(View itemView) {
            super(itemView);
            
            tvName = itemView.findViewById(R.id.tv_name); // 名称
            tvAge = itemView.findViewById(R.id.tv_age); // 性别
        }
    }
}

item

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="horizontal"
    android:layout_width="match_parent"
    android:layout_height="wrap_content">


    <TextView
        android:id="@+id/tv_name"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:textSize="20dp"
        android:layout_weight="1"
        android:gravity="center"
        android:layout_marginLeft="5dp"
        />

    <TextView
        android:id="@+id/tv_age"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:textSize="20dp"
        android:textColor="@android:color/black"
        android:layout_weight="1"
        android:gravity="center"
        android:layout_marginLeft="5dp"
        />

</LinearLayout>

7,使用

public class MainActivity extends AppCompatActivity {

    private RecyclerView recyclerView;
    RecyclerPagingAdapter recyclerPagingAdapter;
    YuanZhenViewModel viewModel;

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

        recyclerView =  findViewById(R.id.recycle_view);
        recyclerPagingAdapter = new RecyclerPagingAdapter();

        
        viewModel = new ViewModelProvider(this, new ViewModelProvider.NewInstanceFactory())
                .get(YuanZhenViewModel.class);

        // LiveData 观察者 感应更新
        viewModel.getListLiveData().observe(this, new Observer<PagedList<YuanZhen>>() {
            @Override
            public void onChanged(PagedList<YuanZhen> students) {
                // 再这里更新适配器数据
                recyclerPagingAdapter.submitList(students);
            }
        });

        recyclerView.setAdapter(recyclerPagingAdapter);
        recyclerView.setLayoutManager(new LinearLayoutManager(this));
    }
}
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity"
    android:orientation="vertical">

    <androidx.recyclerview.widget.RecyclerView
        android:id="@+id/recycle_view"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

</LinearLayout>

7,运行效果

在这里插入图片描述

五,ItemKeyedDataSource来源的使用

1,创建数据仓库

public class DataRepository {

    private List<YuanZhen> dataList = new ArrayList<>();

    public DataRepository() {
        for (int i = 0; i < 1000; i++) {
            YuanZhen person = new YuanZhen();
            person.setName("袁震:" + i);
            person.setAge("年龄:" + i);
            dataList.add(person);
        }
    }

    public List<YuanZhen> initData(int size) {
        return dataList.subList(0, size);
    }

    public List<YuanZhen> loadPageData(int page, int size) {
        int totalPage;
        if (dataList.size() % size == 0) {
            totalPage = dataList.size() / size;
        } else {
            totalPage = dataList.size() / size + 1;
        }

        if (page > totalPage || page < 1) {
            return null;
        }
        if (page == totalPage) {
            return dataList.subList((page - 1) * size, dataList.size());
        }
        return dataList.subList((page - 1) * size, page * size);
    }
}

2,创建ItemKeyedDataSource

public class CustomItemDataSource extends ItemKeyedDataSource<Integer, YuanZhen> {

    private DataRepository dataRepository;

    CustomItemDataSource(DataRepository dataRepository) {
        this.dataRepository = dataRepository;
    }

    // loadInitial 初始加载数据
    @Override
    public void loadInitial(@NonNull LoadInitialParams<Integer> params, @NonNull LoadInitialCallback<YuanZhen> callback) {
        List<YuanZhen> dataList = dataRepository.initData(params.requestedLoadSize);
        callback.onResult(dataList);
    }

    @NonNull
    @Override
    public Integer getKey(@NonNull YuanZhen item) {
        return (int) System.currentTimeMillis();
    }

    // loadBefore 向前分页加载数据
    @Override
    public void loadBefore(@NonNull LoadParams<Integer> params, @NonNull LoadCallback<YuanZhen> callback) {
        List<YuanZhen> dataList = dataRepository.loadPageData(params.key, params.requestedLoadSize);
        if (dataList != null) {
            callback.onResult(dataList);
        }
    }

    // loadAfter 向后分页加载数据
    @Override
    public void loadAfter(@NonNull LoadParams<Integer> params, @NonNull LoadCallback<YuanZhen> callback) {
        List<YuanZhen> dataList = dataRepository.loadPageData(params.key, params.requestedLoadSize);
        if (dataList != null) {
            callback.onResult(dataList);
        }
    }

}

3,创建YuanZhenDataSourceFactory

public class YuanZhenDataSourceFactory extends DataSource.Factory<Integer,YuanZhen> {
   

    @NonNull
    @Override
    public DataSource<Integer, YuanZhen> create() {
        return new CustomItemDataSource(new DataRepository());
    }
}

六,PageKeyedDataSource来源的使用

1,创建PageKeyedDataSource

public class CustomPageDataSource extends PageKeyedDataSource<Integer, YuanZhen> {

    private DataRepository dataRepository;

    CustomPageDataSource(DataRepository dataRepository) {
        this.dataRepository = dataRepository;
    }

    // loadInitial 初始加载数据
    @Override
    public void loadInitial(@NonNull LoadInitialParams<Integer> params, @NonNull LoadInitialCallback<Integer, YuanZhen> callback) {
        List<YuanZhen> dataList = dataRepository.initData(params.requestedLoadSize);
        callback.onResult(dataList, null, 2);
    }

    // loadBefore 向前分页加载数据
    @Override
    public void loadBefore(@NonNull LoadParams<Integer> params, @NonNull LoadCallback<Integer, YuanZhen> callback) {
        List<YuanZhen> dataList = dataRepository.loadPageData(params.key, params.requestedLoadSize);
        if (dataList != null) {
            callback.onResult(dataList, params.key - 1);
        }
    }

    // loadAfter 向后分页加载数据
    @Override
    public void loadAfter(@NonNull LoadParams<Integer> params, @NonNull LoadCallback<Integer, YuanZhen> callback) {
        List<YuanZhen> dataList = dataRepository.loadPageData(params.key, params.requestedLoadSize);
        if (dataList != null) {
            callback.onResult(dataList, params.key + 1);
        }
    }
}

2,创建数据工厂

public class YuanZhenDataSourceFactory extends DataSource.Factory<Integer,YuanZhen> {
  
    @NonNull
    @Override
    public DataSource<Integer, YuanZhen> create() {
        return new CustomPageDataSource(new DataRepository());
    }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1348559.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

03.QT命名规范及快捷键(部分)

一、命名规范 1.类名 大驼峰规则&#xff1a;首字母大写&#xff0c;单词和单词之间首字母大写。 2.变量名 小驼峰规则&#xff1a;首字母小写&#xff0c;单词和单词之间首字母大写。 二、快捷键 1.代码操作相关 注释&#xff1a;ctrl / 运行&#xff1a;ctrl r 编译…

GPT4-AIl本地部署-chat AI本地使用

文章目录 GPT4-AIl本地部署GPT4客户端下载地址&#xff1a;对应的下载下载后的文件点击安装&#xff0c;改一下文件存放路径&#xff0c;下面都是默认下一步进度条100%后&#xff0c;点击完成 安装完桌面生成图标&#xff0c;点击选择都是NO&#xff0c;不进行数据上传点击后&a…

开源数据集的获取不该成为你的阻塞项

B站&#xff1a;啥都会一点的研究生公众号&#xff1a;啥都会一点的研究生 当可获取的数据有限&#xff0c;公共的开源数据集将是不错的选择 很多人并不知道该如何获取最权威的官方数据&#xff0c;亦或是不清楚有哪些数据集能为之所用&#xff0c;最适合自己的任务场景 不用…

js遍历后端返回的集合将条件相同的放入同一个数组内

项目场景&#xff1a; echarts折线图需要根据条件动态展示多条不同曲线 解决方案&#xff1a; 后端直接将使用sql将数据查询出来返回即可,因为我这里不是Java使用的C#不是很熟练后台不好写逻辑,所以在前端js完成的 代码如下: function createline(villagename, buildingname…

构建安全的SSH服务体系

1、配置OpenSSH服务端 在CentOS7.3系统中&#xff0c;OpenSSH服务由openssh、openssh-server等软件包提供&#xff08;默认已安装&#xff09;&#xff0c;并已将sshd添加为标准的系统服务。执行"systemctl start sshd"命令即可启动sshd服务。ssh服务的配置文件默认位…

前端:html+css+js实现CSDN首页

提前说一下&#xff0c;只实现了部分片段哈&#xff01;如下&#xff1a; 前端&#xff1a;htmlcssjs实现CSDN首页 1. 实现效果2. 需要了解的前端知识3. 固定定位的使用4. js 监听的使用4. 参考代码和运行结果 1. 实现效果 我的实现效果为&#xff1a; 原界面如下,网址为&…

按照故障码类型分类的API接口

随着汽车的普及&#xff0c;车辆故障也成为了一个不可忽视的问题。对于车主来说&#xff0c;及时了解故障码的含义以及解决方案十分重要。挖数据平台为解决这一问题&#xff0c;提供了一套按照故障码类型分类的API接口&#xff0c;用于查询车辆故障、故障码适用品牌以及提供相应…

托管在亚马逊云科技的向量数据库MyScale如何借助AWS基础设施构建稳定高效的云数据库

MyScale是一款完全托管于亚马逊云科技&#xff0c;支持SQL的高效向量数据库。MyScale的优势在于&#xff0c;它在提供与专用向量数据库相匹敌甚至优于的性能的同时&#xff0c;还支持完整的SQL语法。以下内容&#xff0c;将阐述MyScale是如何借助亚马逊云科技的基础设施&#x…

打破数据孤岛:ChatGPT如何打通金融大数据的任督二脉?

文章目录 一、引言二、ChatGPT与金融大数据分析的融合三、实践应用&#xff1a;ChatGPT在金融大数据分析中的优势与挑战四、案例分析&#xff1a;ChatGPT在金融大数据分析中的应用案例五、前景展望&#xff1a;ChatGPT在金融大数据分析领域的未来发展《AI时代Python金融大数据分…

git上传代码到github远程仓库

1、添加SSH公钥 为了把本地的仓库传到github&#xff0c;还需要配置ssh key&#xff0c;说白了就是为了把本地的代码上传到github。 1、前置准备 本地需要安装git&#xff1a;Git - Downloads。安装成功后本地右键鼠标会多出一些git选项。 2、添加SSH Key 首先在本地创建s…

DVWA靶场中的xss-反射型xss、存储型xss的low、medium、high的详细通关方法

目录 1.DVWA反射型xss &#xff08;1&#xff09;Low&#xff1a; &#xff08;2&#xff09;Medium&#xff1a; &#xff08;3&#xff09;Heigh 2.xss存储型 &#xff08;1&#xff09;Low&#xff1a; &#xff08;2&#xff09;Medium &#xff08;3&#xff09;He…

2024年【黑龙江省安全员C证】考试及黑龙江省安全员C证找解析

题库来源&#xff1a;安全生产模拟考试一点通公众号小程序 2024年黑龙江省安全员C证考试为正在备考黑龙江省安全员C证操作证的学员准备的理论考试专题&#xff0c;每个月更新的黑龙江省安全员C证找解析祝您顺利通过黑龙江省安全员C证考试。 1、【多选题】下列属于编制安全检查…

Docker 从入门到实践:Docker介绍

前言 在当今的软件开发和部署领域&#xff0c;Docker已经成为了一个不可或缺的工具。Docker以其轻量级、可移植性和标准化等特点&#xff0c;使得应用程序的部署和管理变得前所未有的简单。无论您是一名开发者、系统管理员&#xff0c;还是IT架构师&#xff0c;理解并掌握Dock…

论文阅读:神经 MCMC 的深度内卷生成模型 Deep Involutive Generative Models for Neural MCMC

文章总结&#xff1a;本文提出了使用一种生成式的模型作为MCMC算法中的建议方式&#xff0c;并通过GAN进行优化。 原文&#xff1a;Deep Involutive Generative Models for Neural MCMC 我们引入了深度内卷生成模型&#xff08;一种深度生成建模的新架构&#xff09;&#xff…

PHP特性知识点扫盲 - 下篇

概述 在实际的生产环境中遇到了实际需要解决的问题&#xff0c;需要把服务部署的方式梳理出来&#xff0c;在同一个服务器中部署多个PHP环境&#xff0c;架构图如下&#xff1a; 架构方案 在工作实践中遇到的很多问题的普遍性都是相通的&#xff0c;公司运行的可新项目都是版…

第四部分 一维连续型随机变量

目录 温馨提示&#xff1a; 已知fx(X)求概率 方法&#xff1a; 例1 例2 求fx(X)中的未知数 方法&#xff1a; 例3 已知 fx(X)求F 方法&#xff1a; 例4 求F中的未知数 方法&#xff1a; 例5 已知F求f 方法&#xff1a; 例6 已知f求f 方法&#xff1a; 普通求法&#xff1a; 公…

CRM客户关系管理系统

系统开发环境以及版本 操作系统&#xff1a; Windows_7集成开发工具&#xff1a; Eclipse EE_4.7编译环境&#xff1a;JDK_1.8Web服务器&#xff1a;Tomcat_9.0数据库&#xff1a;MySQL_5.7.23 系统框架 spring框架springmvc框架mybatis框架Logback日志框架安全验证框架maven框…

26、web攻防——通用漏洞SQL注入SqlmapOracleMongodbDB2

文章目录 OracleMongoDBsqlmap SQL注入课程体系&#xff1b; 数据库注入&#xff1a;access、mysql、mssql、oracle、mongodb、postgresql等数据类型注入&#xff1a;数字型、字符型、搜索型、加密型&#xff08;base63 json&#xff09;等提交方式注入&#xff1a;get、post、…

VS2019+OpenCV4.7.0+OpenCV_contrib4.7.0+CUDA安装+配置视频硬解码保姆级别教程

在算法开发过程中&#xff0c;涉及基于opencv的rtsp流硬解码&#xff0c;这里设计结合当前所有的资料&#xff0c;实现了现有opengl相关的所有跟视频硬解码相关的功能&#xff0c;下面对opencv4.7.0的编译流程进行说明&#xff1a; 一、准备工作 下载opencv &#xff1a;open…

gem5学习(8):创建一个简单的缓存对象--Creating a simple cache object

目录 一、SimpleCache SimObject 二、Implementing the SimpleCache 1、getSlavePort() 2、handleRequest() 3、AccessEvent() 4、accessTiming() &#xff08;1&#xff09;缓存命中&#xff1a;sendResponse() &#xff08;2&#xff09;缓存未命中&#xff1a; 三、…