Android MVVM框架搭建(四)RecyclerVIew + ViewPager2 + BaseQuickAdapter

在这里插入图片描述

我这里是有数据返回的,通过返回的数据构建一个数据实体,命名为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 vertical;

public List getVertical() {

return vertical;

}

public void setVertical(List 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 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 getCid() {

return cid;

}

public void setCid(List 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 createService(Class 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 wallPaper();

三、访问接口


接口有了,下面就是访问的事情了,现在主页面有点太空旷了,所以找个接口的数据访问依然可以在MainRepository中进行请求。打开MainRepository,在里面增加如下代码:

/**

  • 热门壁纸数据

*/

final MutableLiveData wallPaper = new MutableLiveData<>();

/**

  • 获取壁纸数据

  • @return wallPaper

*/

public LiveData getWallPaper() {

NetworkApi.createService(ApiService.class,1).

wallPaper().compose(NetworkApi.applySchedulers(new BaseObserver() {

@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 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),增加如下样式代码:

这里是设置一个圆角图片的样式代码,那么怎么去使用它呢,下面我们修改一下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”>

<variable

name=“wallPaper”

type=“com.llw.mvvm.model.WallPaperResponse.ResBean.VerticalBean” />

<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” />

这里依然是使用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);

}

然后在onCreate方法中调用它并且实现数据更新的回调监听。

initView();

//热门壁纸 网络请求

mainViewModel.getWallPaper();

mainViewModel.wallPaper.observe(this, wallPaperResponse -> dataBinding.rv.setAdapter(new WallPaperAdapter(wallPaperResponse.getRes().getVertical())));

下面我们可以开始运行了,效果图如下:

在这里插入图片描述

由于这个平台的限制,所以这个动图是标清,建议读者可以直接安装APK去体验,这样会更舒服一些。这个图片展示的效果就很不错,现在我们已经掌握了怎么在MVVM中使用RecyclerView。

五、绑定点击事件


当我们需要点击查看图片的时候,就需要先绑定点击事件,然后查看图片,在适配器WallPaperAdapter中增加一个ClickBinding内部类,里面的代码如下:

public static class ClickBinding {

public void itemClick(WallPaperResponse.ResBean.VerticalBean verticalBean, View view) {

Intent intent = new Intent(view.getContext(), PictureViewActivity.class);

intent.putExtra(“img”, verticalBean.getImg());

view.getContext().startActivity(intent);

}

}

这里点击之后是跳转到PictureViewActivity,等会去创建它。

然后修改一下布局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”>

<variable

name=“wallPaper”

type=“com.llw.mvvm.model.WallPaperResponse.ResBean.VerticalBean” />

<variable

name=“onClick”

type=“com.llw.mvvm.adapter.WallPaperAdapter.ClickBinding” />

<LinearLayout

android:layout_width=“match_parent”

android:layout_height=“wrap_content”

android:orientation=“vertical”>

<com.llw.mvvm.view.CustomImageView

android:id=“@+id/image”

networkUrl=“@{wallPaper.img}”

android:layout_width=“match_parent”

android:layout_height=“300dp”

android:layout_margin=“5dp”

android:onClick=“@{() -> onClick.itemClick(wallPaper,image)}”

android:scaleType=“centerCrop”

app:shapeAppearanceOverlay=“@style/roundedImageStyle” />

适配器布局修改好了之后,再回到WallPaperAdapter中,在onBindViewHolder方法中添加对点击事件的绑定,修改代码如下图如下:

在这里插入图片描述

然后新增一个PictureViewActivity,对应的布局activity_picture_view.xml代码如下:

<?xml version="1.0" encoding="utf-8"?>

<androidx.constraintlayout.widget.ConstraintLayout xmlns:android=“http://schemas.android.com/apk/res/android”

xmlns:app=“http://schemas.android.com/apk/res-auto”

xmlns:tools=“http://schemas.android.com/tools”

android:layout_width=“match_parent”

android:layout_height=“match_parent”

tools:context=“.PictureViewActivity”>

<ImageView

android:id=“@+id/image”

android:layout_width=“match_parent”

android:layout_height=“match_parent”

app:layout_constraintBottom_toBottomOf=“parent”

app:layout_constraintLeft_toLeftOf=“parent”

app:layout_constraintRight_toRightOf=“parent”

app:layout_constraintTop_toTopOf=“parent” />

</androidx.constraintlayout.widget.ConstraintLayout>

然后修改一下PictureViewActivity的代码,在onCreate方法中增加如下代码。

String img = getIntent().getStringExtra(“img”);

if (img != null) {

ImageView imageView = findViewById(R.id.image);

Glide.with(this).load(img).into(imageView);

}

运行效果如下所示:

在这里插入图片描述

好的,下面对主页面进行一下美化,现在这个样子确实不好看。

六、协调布局使用


在页面中默认的ActionBar占了无用的控件,我们可以自定义一个样式去替换当前页面的样式,在themes.xml下增加如下代码:

然后修改AndroidManifest.xml中的代码:

在这里插入图片描述

设置theme,然后修改activity_main.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”

xmlns:tools=“http://schemas.android.com/tools”>

<variable

name=“viewModel”

type=“com.llw.mvvm.viewmodels.MainViewModel” />

<androidx.coordinatorlayout.widget.CoordinatorLayout

android:layout_width=“match_parent”

android:layout_height=“match_parent”

android:fitsSystemWindows=“true”

tools:context=“.MainActivity”>

<com.google.android.material.appbar.AppBarLayout

android:id=“@+id/appbar_layout”

android:layout_width=“match_parent”

android:layout_height=“200dp”

android:fitsSystemWindows=“true”

android:theme=“@style/ThemeOverlay.AppCompat.Dark.ActionBar”>

<com.google.android.material.appbar.CollapsingToolbarLayout

android:id=“@+id/toolbar_layout”

android:layout_width=“match_parent”

android:layout_height=“match_parent”

android:fitsSystemWindows=“true”

app:collapsedTitleGravity=“center_horizontal”

app:contentScrim=“@color/purple_500”

app:layout_scrollFlags=“scroll|exitUntilCollapsed”

app:title=“MVVM”

app:toolbarId=“@+id/toolbar”>

<com.llw.mvvm.view.CustomImageView

android:id=“@+id/image”

biyingUrl=“@{viewModel.biying.images.get(0).url}”

android:layout_width=“match_parent”

android:layout_height=“match_parent”

android:fitsSystemWindows=“true”

android:scaleType=“fitXY” />

<androidx.appcompat.widget.Toolbar

android:id=“@+id/toolbar”

android:layout_width=“match_parent”

android:layout_height=“?attr/actionBarSize”

app:contentInsetEnd=“0dp”

app:contentInsetStart=“0dp”

app:layout_collapseMode=“pin”

app:layout_scrollFlags=“scroll|snap” />

</com.google.android.material.appbar.CollapsingToolbarLayout>

</com.google.android.material.appbar.AppBarLayout>

<androidx.core.widget.NestedScrollView

android:layout_width=“match_parent”

android:layout_height=“match_parent”

android:fillViewport=“true”

android:orientation=“vertical”

android:overScrollMode=“never”

app:layout_behavior=“@string/appbar_scrolling_view_behavior”>

<androidx.recyclerview.widget.RecyclerView

android:id=“@+id/rv”

android:layout_width=“match_parent”

android:layout_height=“wrap_content”

android:padding=“5dp” />

</androidx.core.widget.NestedScrollView>

</androidx.coordinatorlayout.widget.CoordinatorLayout>

然后修改MainActivity中的代码,在initView中增加如下代码:

//伸缩偏移量监听

dataBinding.appbarLayout.addOnOffsetChangedListener(new AppBarLayout.OnOffsetChangedListener() {

boolean isShow = true;

int scrollRange = -1;

@Override

public void onOffsetChanged(AppBarLayout appBarLayout, int verticalOffset) {

if (scrollRange == -1) {

scrollRange = appBarLayout.getTotalScrollRange();

}

if (scrollRange + verticalOffset == 0) {//收缩时

dataBinding.toolbarLayout.setTitle(“MVVM-Demo”);

isShow = true;

} else if (isShow) {//展开时

dataBinding.toolbarLayout.setTitle(“”);

isShow = false;

}

}

});

运行效果如下:

在这里插入图片描述

这样的效果如何呢?不管怎么说比之前的页面好看吧,而且这个用户体验会比较的好。

七、保存本地数据库


这里我们依然可以保存热门壁纸的数据,这样可以再第二次打开当前页面的时候使我们的加载效率提高很多,这里我们需要对数据库进行一次升级迁移。

1. Entity

在bean包下新增一个WallPaper类,里面的代码如下:

@Entity(tableName = “wallpaper”)

public class WallPaper {

@PrimaryKey(autoGenerate = true)

private int uid = 0;

private String img;

public int getUid() {

return uid;

}

public void setUid(int uid) {

this.uid = uid;

}

public String getImg() {

return img;

}

public void setImg(String img) {

this.img = img;

}

public WallPaper() {}

@Ignore

public WallPaper(String img) {

this.img = img;

}

}

这里我设置了id字段自增,同时我设置了表名为:wallpaper。

2. Dao

在dao包下新建一个WallPaperDao接口,里面的代码如下:

@Dao

public interface WallPaperDao {

@Query(“SELECT * FROM wallpaper”)

Flowable<List> getAll();

@Insert(onConflict = OnConflictStrategy.REPLACE)

Completable insertAll(List wallPapers);
自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数初中级Android工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则近万的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年Android移动开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。

img

img

img

img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Android开发知识点,真正体系化!

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!

如果你觉得这些内容对你有帮助,可以扫码获取!!(备注:Android)

最后

今天关于面试的分享就到这里,还是那句话,有些东西你不仅要懂,而且要能够很好地表达出来,能够让面试官认可你的理解,例如Handler机制,这个是面试必问之题。有些晦涩的点,或许它只活在面试当中,实际工作当中你压根不会用到它,但是你要知道它是什么东西。

最后在这里小编分享一份自己收录整理上述技术体系图相关的几十套腾讯、头条、阿里、美团等公司2021年的面试题,把技术点整理成了视频和PDF(实际上比预期多花了不少精力),包含知识脉络 + 诸多细节,由于篇幅有限,这里以图片的形式给大家展示一部分。

还有 高级架构技术进阶脑图、Android开发面试专题资料,高级进阶架构资料 帮助大家学习提升进阶,也节省大家在网上搜索资料的时间来学习,也可以分享给身边好友一起学习。

【Android核心高级技术PDF文档,BAT大厂面试真题解析】

【算法合集】

【延伸Android必备知识点】

【Android部分高级架构视频学习资源】

Android精讲视频领取学习后更加是如虎添翼!进军BATJ大厂等(备战)!现在都说互联网寒冬,其实无非就是你上错了车,且穿的少(技能),要是你上对车,自身技术能力够强,公司换掉的代价大,怎么可能会被裁掉,都是淘汰末端的业务Curd而已!现如今市场上初级程序员泛滥,这套教程针对Android开发工程师1-6年的人员、正处于瓶颈期,想要年后突破自己涨薪的,进阶Android中高级、架构师对你更是如鱼得水,赶快领取吧!

《Android学习笔记总结+移动架构视频+大厂面试真题+项目实战源码》,点击传送门即可获取!

则近万的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!**

因此收集整理了一份《2024年Android移动开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。

[外链图片转存中…(img-9Kan4Tkp-1712143575397)]

[外链图片转存中…(img-9lbJ88Ly-1712143575398)]

[外链图片转存中…(img-qGXlsgiv-1712143575398)]

[外链图片转存中…(img-LnjTKRlK-1712143575399)]

[外链图片转存中…(img-6CIVItwb-1712143575399)]

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Android开发知识点,真正体系化!

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!

如果你觉得这些内容对你有帮助,可以扫码获取!!(备注:Android)

最后

今天关于面试的分享就到这里,还是那句话,有些东西你不仅要懂,而且要能够很好地表达出来,能够让面试官认可你的理解,例如Handler机制,这个是面试必问之题。有些晦涩的点,或许它只活在面试当中,实际工作当中你压根不会用到它,但是你要知道它是什么东西。

最后在这里小编分享一份自己收录整理上述技术体系图相关的几十套腾讯、头条、阿里、美团等公司2021年的面试题,把技术点整理成了视频和PDF(实际上比预期多花了不少精力),包含知识脉络 + 诸多细节,由于篇幅有限,这里以图片的形式给大家展示一部分。

还有 高级架构技术进阶脑图、Android开发面试专题资料,高级进阶架构资料 帮助大家学习提升进阶,也节省大家在网上搜索资料的时间来学习,也可以分享给身边好友一起学习。

【Android核心高级技术PDF文档,BAT大厂面试真题解析】

[外链图片转存中…(img-a1aISF5g-1712143575399)]

【算法合集】

[外链图片转存中…(img-ZHFHPpWN-1712143575400)]

【延伸Android必备知识点】

[外链图片转存中…(img-faxVv6X8-1712143575400)]

【Android部分高级架构视频学习资源】

Android精讲视频领取学习后更加是如虎添翼!进军BATJ大厂等(备战)!现在都说互联网寒冬,其实无非就是你上错了车,且穿的少(技能),要是你上对车,自身技术能力够强,公司换掉的代价大,怎么可能会被裁掉,都是淘汰末端的业务Curd而已!现如今市场上初级程序员泛滥,这套教程针对Android开发工程师1-6年的人员、正处于瓶颈期,想要年后突破自己涨薪的,进阶Android中高级、架构师对你更是如鱼得水,赶快领取吧!

《Android学习笔记总结+移动架构视频+大厂面试真题+项目实战源码》,点击传送门即可获取!
  • 9
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值