2024 在项目中使用 MVVM正确姿势,你用对了吗?,2024年最新安卓面试题最新2024

先自我介绍一下,小编浙江大学毕业,去过华为、字节跳动等大厂,目前阿里P7

深知大多数程序员,想要提升技能,往往是自己摸索成长,但自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

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

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

由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新

如果你需要这些资料,可以添加V获取:vip204888 (备注Android)
img

正文

override fun doCreateView(savedInstanceState: Bundle?) {

// 通过 binding 获取控件

setSupportActionBar(binding.toolbar)

}

}

假如你不想在项目中使用 Databinding,那么你可以像下面的类这样继承 BaseActivity,然后通过传统的 findViewById 来获取控件并使用:

class ContainerActivity : BaseActivity {

override fun getLayoutResId(): Int = R.layout.vmlib_activity_container

override fun doCreateView(savedInstanceState: Bundle?) {

// 通过 findViewById 来获取控件

// 或者,引入 kotlin-android-extensions 之后直接通过 id 使用控件

}

}

也许你看到了,我在使用 Databinding 的时候更多地将当作 ButterKinfe 来使用。我专门提供了不包含 Databinding 的能力,也是出于另一个考虑——使用 kotlin-android-extensions 之后,可以直接在代码中通过控件的 id 来使用它。如果只是想通过 Databinding 来获取控件的话,那么就没有必要使用 Databinding 的必要了。而对于确实喜欢 Databinding 的数据绑定功能的同学可以在 Android-VMLib 之上个性化封装一层。当然了,我并不是排斥 Databinding。Databinding 是一个很好的设计理念,只是对于将其大范围应用到项目中,我还是持观望态度的。

2.3 统一数据交互格式

有过后端开发经验的同学可能会知道,在后端代码中,我们通常会将代码按照层次分为 DAO、Service 和 Controler 层,各个层之间进行数据交互的时候就需要对数据交互格式做统一的封装。后端和前端之间的交互的时候也要对数据格式进行封装。我们将其推广到 MVVM 中,显然,ViewModel 层和 View 层之间进行交互的时候也应该进行一层数据包装。下面是我看到的一段代码,

final private SingleLiveEvent toast;

final private SingleLiveEvent loading;

public ApartmentProjectViewModel() {

toast = new SingleLiveEvent<>();

loading = new SingleLiveEvent<>();

}

public SingleLiveEvent getToast() {

return toast;

}

public SingleLiveEvent getLoading() {

return loading;

}

public void requestData() {

loading.setValue(true);

ApartmentProjectRepository.getInstance().requestDetail(projectId, new Business.ResultListener() {

@Override

public void onFailure(BusinessResponse businessResponse, ProjectDetailBean projectDetailBean, String s) {

toast.setValue(s);

loading.setValue(false);

}

@Override

public void onSuccess(BusinessResponse businessResponse, ProjectDetailBean projectDetailBean, String s) {

data.postValue(dealProjectBean(projectDetailBean));

loading.setValue(false);

}

});

}

这里为了通知 View 层数据的加载状态定义了一个 Boolean 类型的 LiveData 进行交互。这样你需要多维护一个变量,显得代码不够简洁。实际上,通过对数据交互格式的规范,我们可以更优雅地完成这个任务。

在 Android-VMLib 当中,我们通过自定义枚举来表示数据的状态,

public enum Status {

// 成功

SUCCESS(0),

// 失败

FAILED(1),

// 加载中

LOADING(2);

public final int id;

Status(int id) {

this.id = id;

}

}

然后,将错误信息、数据结果、数据状态以及预留字段包装成一个 Resource 对象,来作为固定的数据交互格式,

public final class Resources {

// 状态

public final Status status;

// 数据

public final T data;

// 状态,成功或者错误的 code 以及 message

public final String code;

public final String message;

// 预留字段

public final Long udf1;

public final Double udf2;

public final Boolean udf3;

public final String udf4;

public final Object udf5;

// …

}

解释下这里的预留字段的作用:它们主要用来作为数据补充说明。比如进行分页的时候,如果 View 层不仅想获取真实的数据,还想得到当前的页码,那么你可以将页码信息塞到 udf1 字段上面。以上,我对各种不同类型的基础数据类型只提供了一个通用的选择,比如整型的只提供了 Long 类型,浮点型的只提供了 Double 类型。另外,我们还提供了一个无约束的类型 udf5.

除了数据交互格式的封装,Android-VMLib 还提供了交互格式的快捷操作方法。如下图所示:

那么,使用了 Resource 之后,代码会变成什么样呢?

// View 层代码

class MainActivity : CommonActivity<MainViewModel, ActivityMainBinding>() {

override fun getLayoutResId(): Int = R.layout.activity_main

override fun doCreateView(savedInstanceState: Bundle?) {

addSubscriptions()

vm.startLoad()

}

private fun addSubscriptions() {

vm.getObservable(String::class.java).observe(this, Observer {

when(it!!.status) {

Status.SUCCESS -> { ToastUtils.showShort(it.data) }

Status.FAILED -> { ToastUtils.showShort(it.message) }

Status.LOADING -> {/* temp do nothing */ }

else -> {/* temp do nothing */ }

}

})

}

}

// ViewModel 层代码

class MainViewModel(application: Application) : BaseViewModel(application) {

fun startLoad() {

getObservable(String::class.java).value = Resources.loading()

ARouter.getInstance().navigation(MainDataService::class.java)

?.loadData(object : OnGetMainDataListener{

override fun onGetData() {

getObservable(String::class.java).value = Resources.loading()

}

})

}

}

这样对数据交互格式封装之后,代码是不是简洁多了呢?至于让你的代码更加简洁,Android-VMLib 还为你提供了其它的方法,请继续阅读。

2.4 进一步简化代码,优化无处不在的 LiveData

之前在使用 ViewModel+LiveData 的时候,为了进行数据交互,每个变量我都需要定义一个 LiveData,于是代码变成了下面这个样子。甚至我在有的同学那里看到过一个 ViewModel 中定义了 10+ 个 LiveData. 这让代码变得非常得难看,

public class ApartmentProjectViewModel extends ViewModel {

final private MutableLiveData data;

final private SingleLiveEvent toast;

final private SingleLiveEvent submit;

final private SingleLiveEvent loading;

public ApartmentProjectViewModel() {

data = new MutableLiveData<>();

toast = new SingleLiveEvent<>();

submit = new SingleLiveEvent<>();

loading = new SingleLiveEvent<>();

}

// …

}

后来我的一个同事建议我考虑下如何整理一下 LiveData,于是经过不断的推广和演化,如今这个解决方案已经比较完善——即通过 HashMap 统一管理单例的 LiveData。后来为了进一步简化 ViewModel 层的代码,我将这部分工作交给了一个 Holder 来完成。于是如下解决方案就基本成型了,

public class BaseViewModel extends AndroidViewModel {

private LiveDataHolder holder = new LiveDataHolder();

// 通过要传递的数据类型获取一个 LiveData 对象

public MutableLiveData<Resources> getObservable(Class dataType) {

return holder.getLiveData(dataType, false);

}

}

这里的 Holder 实现如下,

public class LiveDataHolder {

private Map<Class, SingleLiveEvent> map = new HashMap<>();

public MutableLiveData<Resources> getLiveData(Class dataType, boolean single) {

SingleLiveEvent<Resources> liveData = map.get(dataType);

if (liveData == null) {

liveData = new SingleLiveEvent<>(single);

map.put(dataType, liveData);

}

return liveData;

}

}

原理很简单吧。使用了这套方案之后你的代码将会变得如下面这般简洁优雅,

// ViewModel 层

class EyepetizerViewModel(application: Application) : BaseViewModel(application) {

private var eyepetizerService: EyepetizerService = ARouter.getInstance().navigation(EyepetizerService::class.java)

private var nextPageUrl: String? = null

fun requestFirstPage() {

getObservable(HomeBean::class.java).value = Resources.loading()

eyepetizerService.getFirstHomePage(null, object : OnGetHomeBeansListener {

override fun onError(errorCode: String, errorMsg: String) {

getObservable(HomeBean::class.java).value = Resources.failed(errorCode, errorMsg)

}

override fun onGetHomeBean(homeBean: HomeBean) {

nextPageUrl = homeBean.nextPageUrl

getObservable(HomeBean::class.java).value = Resources.success(homeBean)

// 再请求一页

requestNextPage()

}

})

}

fun requestNextPage() {

eyepetizerService.getMoreHomePage(nextPageUrl, object : OnGetHomeBeansListener {

override fun onError(errorCode: String, errorMsg: String) {

getObservable(HomeBean::class.java).value = Resources.failed(errorCode, errorMsg)

}

override fun onGetHomeBean(homeBean: HomeBean) {

nextPageUrl = homeBean.nextPageUrl

getObservable(HomeBean::class.java).value = Resources.success(homeBean)

}

})

}

}

// View 层

class EyepetizerActivity : CommonActivity<EyepetizerViewModel, ActivityEyepetizerBinding>() {

private lateinit var adapter: HomeAdapter

private var loading : Boolean = false

override fun getLayoutResId() = R.layout.activity_eyepetizer

override fun doCreateView(savedInstanceState: Bundle?) {

addSubscriptions()

vm.requestFirstPage()

}

private fun addSubscriptions() {

vm.getObservable(HomeBean::class.java).observe(this, Observer { resources ->

loading = false

when (resources!!.status) {

Status.SUCCESS -> {

L.d(resources.data)

val list = mutableListOf()

resources.data.issueList.forEach {

it.itemList.forEach { item ->

if (item.data.cover != null

&& item.data.author != null

) list.add(item)

}

}

文末

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

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

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

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

【算法合集】

【延伸Android必备知识点】

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

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

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化的资料的朋友,可以添加V获取:vip204888 (备注Android)
img

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

g-JgdFEurS-1713710801856)]

【延伸Android必备知识点】

[外链图片转存中…(img-GlSk0Cpk-1713710801856)]

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

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

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化的资料的朋友,可以添加V获取:vip204888 (备注Android)
[外链图片转存中…(img-3a7e3xDp-1713710801856)]

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

  • 9
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值