Android MVVM框架搭建RecyclerVIew + ViewPager2 + BaseQuickAdapter
Posted 初学者-Study
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android MVVM框架搭建RecyclerVIew + ViewPager2 + BaseQuickAdapter相关的知识,希望对你有一定的参考价值。
android MVVM框架搭建(四)RecyclerVIew + ViewPager2 + BaseQuickAdapter
前言
在日常的开发中,最常用于展示数据的形式就是列表,你会看到各种各样的列表,比如图片列表、视频列表,联系人列表,而在RecyclerView出来之前列表的开发是使用ListView,而现在绝大多数开发者都使用RecyclerVIew了,优势就不说了,都已经用了这么多年了,那么RecyclerView在MVVM中要怎么使用呢?另外它与JetPack的组件Paging之间,有什么联系呢?我们往下看。
正文
在上一篇文章中,我讲述了怎么使用Room和MMKV去管理本地数据,本文将是不一样的介绍方式,因为会和页面打交道比较多,所以会比上一篇更有意思,起码我是这么觉得的。
一、图片列表数据
首先我们要拿到数据才行,拿到数据才能去展示,最好是有图片的数据,我这里找了一个网络上的免费API接口,在我发布文章的时候这个API接口还是能用的。地址如下:
http://service.picasso.adesk.com/v1/vertical/vertical?limit=30&skip=180&adult=false&first=0&order=hot
我在写好天气的时候用过这个接口作为每日壁纸列表的使用。建议用浏览器测试一下找个接口,看有没有数据返回。那么同样的这个接口每天也只需要请求一次即可,后面对这个再做处理,前面先解决列表显示的问题。
我这里是有数据返回的,通过返回的数据构建一个数据实体,命名为WallPaperResponse,放在model包下,代码如下:
public class WallPaperResponse
private String msg;
private ResBean res;
private int code;
public String getMsg()
return msg;
public void setMsg(String msg)
this.msg = msg;
public ResBean getRes()
return res;
public void setRes(ResBean res)
this.res = res;
public int getCode()
return code;
public void setCode(int code)
this.code = code;
public static class ResBean
private List<VerticalBean> vertical;
public List<VerticalBean> getVertical()
return vertical;
public void setVertical(List<VerticalBean> vertical)
this.vertical = vertical;
public static class VerticalBean
private String preview;
private String thumb;
private String img;
private int views;
private String rule;
private int ncos;
private int rank;
private String source_type;
private String wp;
private boolean xr;
private boolean cr;
private int favs;
private double atime;
private String id;
private String store;
private String desc;
private List<String> cid;
private List<?> tag;
private List<?> url;
public String getPreview()
return preview;
public void setPreview(String preview)
this.preview = preview;
public String getThumb()
return thumb;
public void setThumb(String thumb)
this.thumb = thumb;
public String getImg()
return img;
public void setImg(String img)
this.img = img;
public int getViews()
return views;
public void setViews(int views)
this.views = views;
public String getRule()
return rule;
public void setRule(String rule)
this.rule = rule;
public int getNcos()
return ncos;
public void setNcos(int ncos)
this.ncos = ncos;
public int getRank()
return rank;
public void setRank(int rank)
this.rank = rank;
public String getSource_type()
return source_type;
public void setSource_type(String source_type)
this.source_type = source_type;
public String getWp()
return wp;
public void setWp(String wp)
this.wp = wp;
public boolean isXr()
return xr;
public void setXr(boolean xr)
this.xr = xr;
public boolean isCr()
return cr;
public void setCr(boolean cr)
this.cr = cr;
public int getFavs()
return favs;
public void setFavs(int favs)
this.favs = favs;
public double getAtime()
return atime;
public void setAtime(double atime)
this.atime = atime;
public String getId()
return id;
public void setId(String id)
this.id = id;
public String getStore()
return store;
public void setStore(String store)
this.store = store;
public String getDesc()
return desc;
public void setDesc(String desc)
this.desc = desc;
public List<String> getCid()
return cid;
public void setCid(List<String> cid)
this.cid = cid;
public List<?> getTag()
return tag;
public void setTag(List<?> tag)
this.tag = tag;
public List<?> getUrl()
return url;
public void setUrl(List<?> url)
this.url = url;
二、新增访问地址和接口
这个API的地址和必应明显是两个地址,那么我们就需要对第二篇文章中所写的网络框架做一些修改,首先我们修改NetworkApi中的代码。
将BASE_URL的默认值改成null,并去掉final关键字,然后我们在NetworkApi中增加一个方法,代码如下:
/**
* 设置访问Url类型
* @param type 0 必应 1 壁纸列表
*/
private static void setUrlType(int type)
switch (type)
case 0:
//必应
BASE_URL = "https://cn.bing.com";
break;
case 1:
//热门壁纸
BASE_URL = "http://service.picasso.adesk.com";
break;
default:break;
这里根据输入的类型使用不同的网络服务器地址,然后再修改createService方法,修改后如下:
public static <T> T createService(Class<T> serviceClass, int type)
//设置Url类型
setUrlType(type);
return getRetrofit(serviceClass).create(serviceClass);
那么我们就同样需要修改代码中调用了createService方法的地方,在MainRepository中
这样就可以了,这样做的好处就在于我们既增加了访问API的可拓展性,同时易于修改,还不会对你之前的网络请求很影响。
对于之前的内容改动目前就这些了,下面需要增加新的接口了。在ApiService中增加如下接口。
/**
* 热门壁纸
*/
@GET("/v1/vertical/vertical?limit=30&skip=180&adult=false&first=0&order=hot")
Observable<WallPaperResponse> wallPaper();
三、访问接口
接口有了,下面就是访问的事情了,现在主页面有点太空旷了,所以找个接口的数据访问依然可以在MainRepository中进行请求。打开MainRepository,在里面增加如下代码:
/**
* 热门壁纸数据
*/
final MutableLiveData<WallPaperResponse> wallPaper = new MutableLiveData<>();
/**
* 获取壁纸数据
* @return wallPaper
*/
public LiveData<WallPaperResponse> getWallPaper()
NetworkApi.createService(ApiService.class,1).
wallPaper().compose(NetworkApi.applySchedulers(new BaseObserver<WallPaperResponse>()
@Override
public void onSuccess(WallPaperResponse wallPaperResponse)
KLog.e("WallPaper: " + new Gson().toJson(wallPaperResponse));
wallPaper.setValue(wallPaperResponse);
@Override
public void onFailure(Throwable e)
KLog.e("WallPaper Error: " + e.toString());
));
return wallPaper;
然后进入到MainViewModel中,在里面增加如下代码:
public LiveData<WallPaperResponse> wallPaper;
public void getWallPaper() wallPaper = new MainRepository().getWallPaper();
现在访问接口数据这一块就搞定了,下面就是显示出来就可以了。
四、RecyclerView显示数据
因为返回的数据比较多,因此通过RecyclerView来进行显示,作为壁纸显示可以通过更改布局管理器,把列表变成纵向两列的形式去显示,首先我们先修改activity_main.xml的布局代码,如下图所示
这里我去掉了页面的居中布局,然后增加了一个RecyclerView,添加了一个id,同事改了一下CustomImageView的scaleType=“fitXY”,这样可以让我们的壁纸完整呈现出来。
这里我需要修改一下CustomImageView类的代码:
其实就是改它所继承的父类,为什么要这么改呢?现在就来说明一下。下面我们写一个列表适配器的item布局,在layout下新建一个item_wall_paper.xml文件,里面的代码我们先不写,先去写一个样式,在themes.xml文件中(老版本的AS中是styles.xml),增加如下样式代码:
<!-- 圆角图片 -->
<style name="roundedImageStyle">
<item name="cornerFamily">rounded</item>
<item name="cornerSize">24dp</item>
</style>
这里是设置一个圆角图片的样式代码,那么怎么去使用它呢,下面我们修改一下item_wall_paper.xml,代码如下:
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<!--绑定数据-->
<data>
<variable
name="wallPaper"
type="com.llw.mvvm.model.WallPaperResponse.ResBean.VerticalBean" />
</data>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<com.llw.mvvm.view.CustomImageView
networkUrl="@wallPaper.img"
android:layout_width="match_parent"
android:layout_height="300dp"
android:layout_margin="5dp"
android:scaleType="centerCrop"
app:shapeAppearanceOverlay="@style/roundedImageStyle" />
</LinearLayout>
</layout>
这里依然是使用DataBinding,因为我们数据是要显示在列表上的,因此直接绑定item就可以了,然后这里我用的是networkUrl的属性,因为你如果使用了biyingUrl会添加一个前缀,而这个API不需要前缀,同时我把刚才写的样式设置了进来,这里就解释了为什么要更改继承的父类,因为之前的那个父类没有这个属性值,这个属性值可以让你的Image图片做很多的形状上的变化,相当Nice! 这样就不用再去导入其他的依赖库或者使用自定义View了,这得力于Material,关于ShapeableImageView更多的介绍可以看一下这一篇文章:Android Material UI控件之ShapeableImageView,如果你感兴趣的话。
好了回到正题,那就是我们现在布局都已经写好了,下面写一个适配器,在com.llw.mvvm包下新建一个adapter包,adapter包下新建一个WallPaperAdapter类,里面的代码如下:
public class WallPaperAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder>
/**
* 传递过来的数据
*/
private final List<WallPaperResponse.ResBean.VerticalBean> verticalBeans;
public WallPaperAdapter(List<WallPaperResponse.ResBean.VerticalBean> verticalBeans)
this.verticalBeans = verticalBeans;
@NonNull
@NotNull
@Override
public RecyclerView.ViewHolder onCreateViewHolder(@NonNull @NotNull ViewGroup parent, int viewType)
ItemWallPaperBinding binding = DataBindingUtil.inflate(LayoutInflater.from(parent.getContext()), R.layout.item_wall_paper, parent, false);
return new ViewHolderWallPaper(binding);
@Override
public void onBindViewHolder(@NonNull @NotNull RecyclerView.ViewHolder holder, int position)
ItemWallPaperBinding binding = ((ViewHolderWallPaper) holder).getBinding();
binding.setWallPaper(verticalBeans.get(position));
binding.executePendingBindings();
@Override
public int getItemCount()
return verticalBeans.size();
private static class ViewHolderWallPaper extends RecyclerView.ViewHolder
private ItemWallPaperBinding binding;
public ItemWallPaperBinding getBinding()
return binding;
public void setBinding(ItemWallPaperBinding binding)
this.binding = binding;
public ViewHolderWallPaper(ItemWallPaperBinding inflate)
super(inflate.getRoot());
this.binding = inflate;
这就是RecyclerView.Adapter的常规使用而已,很简单,其中要注意的就是DataBinding的使用,这个很关键了,它决定了你的数据与xml绑定。下面我们回到MainActivity中,首先增加一个initView()方法,里面的代码如下:
/**
* 初始化
*/
private void initView()
GridLayoutManager manager = new GridLayoutManager(this, 2);
dataBinding.rv.setLayoutManager(manager以上是关于Android MVVM框架搭建RecyclerVIew + ViewPager2 + BaseQuickAdapter的主要内容,如果未能解决你的问题,请参考以下文章
Android MVVM框架搭建ViewModel + LiveData + DataBinding
Android MVVM框架搭建ViewModel + LiveData + DataBinding
Android MVVM框架搭建高德地图定位天气查询BottomSheetDialog
Android MVVM框架搭建HiltViewBindingActivity Result API
Android MVVM框架搭建HiltViewBindingActivity Result API
Android MVVM框架搭建Navigation + Fragment + BottomNavigationView