Jetpack学习与实践
目录
一、Jetpack学习
1.1lifecycle
1.1.1简介
1.1.2 使用方法
1.1.3 原理
1.2 databinding
1.2.1简介
1.2.2使用方法
二、Jetpack实践
2.1实现登录功能的demo
一、Jetpack学习
1.1lifecycle
1.1.1简介
在使用MVP模式编写代码时,常常需要在View(如Activity或Fragment)的onCreate()函数中进行Presenter的初始化操作,在onDestroy()的函数中进行Presenter的销毁工作,当Presenter很多时,View各个生命周期函数中的代码将变得非常多。
而lifecycle能够监听Activity或者Fragment的生命周期,并在生命周期改变时通知Presenter执行相应的函数,因此使用lifecycle能减少View中的代码量。
1.1.2 使用方法
假设有一个Activity类和一个Presenter类,下面将介绍lifecycle使用方法。
(1)添加lifecycle的依赖
(2)Present继承LifeCycleObserver接口
class Presenter : LifecycleObserver {@OnLifecycleEvent(Lifecycle.Event.ON_CREATE)fun onResume() {Log.d("Presenter", "onCreate")}@OnLifecycleEvent(Lifecycle.Event.ON_DESTROY)fun onPause() {Log.d("Presenter", "onDestroy")}
}
(3)在Activity的onCreate()方法中注册Presenter
class MainActivity : AppCompatActivity() {override fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)setContentView(R.layout.activity_main)getLifecycle().addObserver(Presenter())}override fun onDestroy() {super.onDestroy()}
}
这样,当Activity生命周期变化后,Presenter中重写的方法也会被重写。
1.1.3 原理
lifecycle使用了观察者模式,在上边的例子中,继承了LifecycleObserver的Presenter是观察者,Activity是被观察者,当Activity的生命周期变化时,Activity会通知已经注册的观察者自己的生命周期发生改变,从而使Presenter作出相应的操作。
(1)注册观察者的原理
那么Presenter是如何被Activity注册的呢?在1.1.2小节中,Activity通过getLifecycle().addObserver(Presenter())方法注册观察者Presenter,getLifecycle()实际是接口LifecycleOwner的一个方法,Activity继承的ComponentActivity实现了该接口并通过该方法返回了LifecycleRegistry类的一个实例,LifecycleRegistry类继承了抽象类Lifecycle,是实现lifecycle监听生命周期功能的核心类,LifecycleRegistry实例和Activity(LifecycleOwner)互相持有对方的引用。我认为该LifecycleRegistry实例为lifecycle中被观察者监听自身生命周期并通知注册的观察者的核心。
而LifecycleRegistry中存有一个FastSafeIterableMap类的实例mObserverMap,FastSafeIterableMap类的底层实现原理还是HashMap,当Acitivity调用addObserver(Presenter())方法后,实际上是调用了LifecycleRegistry的addObserver(observer:LifecycleObserver)方法,在该方法中,LifecycleRegistry将Presenter和它对应的状态STATE存入mObserverMap中,这样就完成了观察者的注册。
(2)被观察者监听生命周期并通知观察者的原理。
被观察者(Activity)又是如何监听自己的生命周期变化并通知已经注册的观察者(Presenter)们呢?实际上,被观察者可以在自己的每个生命周期函数中都调用函数去通知观察者自己的生命周期改变了,但lifecycle没有这么做,继承LifeCycleOwner类的ComponentActivity在onCreate()函数中注册了一个继承自Fragment类的ReportFragment 。
protected void onCreate(@Nullable Bundle savedInstanceState) {super.onCreate(savedInstanceState);mSavedStateRegistryController.performRestore(savedInstanceState);ReportFragment.injectIfNeededIn(this);if (mContentLayoutId != 0) {setContentView(mContentLayoutId);}}
因为Fragment依赖于创建它的Activity,所以ReportFragment的生命周期和Activity生命周期同步,ReportFragment中在生命周期函数中调用了dispatch()函数,从而通知所有注册的观察者Activity的生命周期发生改变。
@Overridepublic void onPause() {super.onPause();dispatch(Lifecycle.Event.ON_PAUSE);}@Overridepublic void onStop() {super.onStop();dispatch(Lifecycle.Event.ON_STOP);}
在dispatch()函数中,ReportFragment调用了与它绑定的Activity内部的LifecycleRegistry实例的handleLifecycleEvent(event)方法,来处理通知观察者的事项。
private void dispatch(Lifecycle.Event event) {Activity activity = getActivity();if (activity instanceof LifecycleRegistryOwner) {((LifecycleRegistryOwner) activity).getLifecycle().handleLifecycleEvent(event);return;}if (activity instanceof LifecycleOwner) {Lifecycle lifecycle = ((LifecycleOwner) activity).getLifecycle();if (lifecycle instanceof LifecycleRegistry) {((LifecycleRegistry) lifecycle).handleLifecycleEvent(event);}}}
在handleLifecycleEvent()方法中,LifecycleRegistry又依次调用moveToState()->sync()方法。
public void handleLifecycleEvent(@NonNull Lifecycle.Event event) {State next = getStateAfter(event);moveToState(next);}private void moveToState(State next) {if (mState == next) {return;}mState = next;if (mHandlingEvent || mAddingObserverCounter != 0) {mNewEventOccurred = true;// we will figure out what to do on upper level.return;}mHandlingEvent = true;sync();mHandlingEvent = false;}
在sync()方法中,LifecycleRegistry通过判断mObserverMap中存储的第一个注册的观察者和最后一个注册的观察者的状态是否相同来判断是否需要进行同步,并根据fordwardPass()和backwardPass()方法进行同步。
private void sync() {LifecycleOwner lifecycleOwner = mLifecycleOwner.get();if (lifecycleOwner == null) {throw new IllegalStateException("LifecycleOwner of this LifecycleRegistry is already"+ "garbage collected. It is too late to change lifecycle state.");}while (!isSynced()) {mNewEventOccurred = false;// no need to check eldest for nullability, because isSynced does it for us.if (mState.compareTo(mObserverMap.eldest().getValue().mState) < 0) {backwardPass(lifecycleOwner);}Entry<LifecycleObserver, ObserverWithState> newest = mObserverMap.newest();if (!mNewEventOccurred && newest != null&& mState.compareTo(newest.getValue().mState) > 0) {forwardPass(lifecycleOwner);}}mNewEventOccurred = false;}
而在fordwardPass()中,LifecycleRegistry调用需要同步的观察者(Presenter)的dispatcherEvent()方法进行同步,并最终执根据Activity生命周期的当前状态执行Presenter中我们写的方法。
private void backwardPass(LifecycleOwner lifecycleOwner) {Iterator<Entry<LifecycleObserver, ObserverWithState>> descendingIterator =mObserverMap.descendingIterator();while (descendingIterator.hasNext() && !mNewEventOccurred) {Entry<LifecycleObserver, ObserverWithState> entry = descendingIterator.next();ObserverWithState observer = entry.getValue();while ((observer.mState.compareTo(mState) > 0 && !mNewEventOccurred&& mObserverMap.contains(entry.getKey()))) {Event event = downEvent(observer.mState);pushParentState(getStateAfter(event));observer.dispatchEvent(lifecycleOwner, event);popParentState();}}}
1.2 databinding
1.2.1简介
databinding能实现数据和UI绑定,即当数据改变后自动更新UI,或通过UI直接更新绑定的数据,这将大大减少程序员在更新UI或获取UI数据方便代码的编写量。
1.2.2使用方法
(1)添加依赖
在module的build.gradle文件中添加如下代码,开启databinding功能。
buildFeatures{dataBinding true}
(2)新建数据类
新建一个类,将想要和UI进行绑定的数据声明为ObservableField()类型。
class LoginMessageModel{var username= ObservableField<String>(name)var password = ObservableField<String>(word)
}
(3)更改布局文件
右键点击布局文件的根(最外层)布局,点击"Convert to data binding layout"选项,即可将布局文件转换成符合databinding要求的布局文件,修改后发现,该布局文件的最外层增加了一层<layout>标签,且在<layout>标签内增加了<data>标签。
<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"><data><variablename="model"type="com.example.testjetpack.login.LoginMessageModel" /></data><LinearLayoutandroid:layout_width="match_parent"android:layout_height="match_parent"android:orientation="vertical"tools:context=".login.MainActivity">
当我们想要让数据类和布局绑定时,需要如上图所示将数据类写入<data>标签中的<variable>标签中,其中type参数表示数据类的全限定名,name参数表示数据类的在布局文件中的别名。
之后,当想要某个布局文件的内容与数据类中的数据绑定时,可通过@={类名.参数名}的方式进行绑定,如下图所示。
android:padding="10dp"android:src="@drawable/ic_baseline_account_circle_24"></ImageView><EditTextandroid:layout_width="match_parent"android:layout_height="100dp"android:text="@={model.username}"android:padding="10dp"></EditText></LinearLayout>
注意这里的参数名必须是声明为ObservableField()类型的参数。
(4)生成绑定类
在执行完上述操作后,点击Make Project,Android Studio就会自动生成绑定类,下图中绑定类的名字是ActivityMainBinding.java。
(5)进行绑定
在Activity的onCreate()中,通过DataBindingUtil.setContentView()方法获取绑定类实例,并指定绑定类实例的model(在布局文件的<data>标签中声明过)参数所对应的实例,这样就完成了数据和UI的绑定。
class MainActivity : AppCompatActivity(), View.OnClickListener {var loginModel: LoginMessageModel?=nulloverride fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)setContentView(R.layout.activity_main)val dataBinder: ActivityMainBinding = DataBindingUtil.setContentView(this, R.layout.activity_main)loginModel= LoginMessageModel("", "", this)dataBinder.model = loginModelfindViewById<Button>(R.id.login).setOnClickListener(this)}
二、Jetpack实践
2.1实现登录功能的demo
使用kotlin编写实现登录功能的demo,demo依据MVVM架构进行编写,使用databinding获取用户通过界面输入的账号和密码数据,并根据登录是否成功修改界面的UI。Demo的工作流程如下图所示:
Demo客户端代码上传到gitee仓库中,仓库地址为:logindemo: 自学demohttps://gitee.com/teslgw/logindemo。
Jetpack学习与实践相关推荐
- Sunflower——Google官方的Jetpack学习项目笔记(Java版)
由于Google官网给出的该项目是Kotlin版本,我将其改造成Java版本,供大家学习参考,文末给出下载链接,里面包含了详细的注释说明. 该项目虽然简单,但是用到的知识很多,正所谓麻雀虽小五脏俱全, ...
- 八大深度学习最佳实践
翻译 | AI科技大本营 参与 | 刘畅 [AI 科技大本营导读] 2017年,许多的人工智能算法得到了实践和应用.名博Hack Noon作者 Brian Muhia 认为想要玩转人工智能,不仅要拥有 ...
- 深度学习算法实践(基于Theano和TensorFlow)
深度学习算法实践(基于Theano和TensorFlow) 闫涛 周琦 著 ISBN:9787121337932 包装:平装 开本:16开 用纸:胶版纸 正文语种:中文 出版社:电子工业出版社 出版时 ...
- 【PWA学习与实践】(3) 让你的WebApp离线可用
<PWA学习与实践>系列文章已整理至gitbook - PWA学习手册,文字内容已同步至learning-pwa-ebook.转载请注明作者与出处. 本文是<PWA学习与实践> ...
- Google App Engine 学习和实践
这个周末玩了玩Google App Engine,随手写点东西,算是学习笔记吧.不当之处,请多多指正. 作者:liigo,2009/04/26夜,大连 原创链接:http://blog.csdn.ne ...
- 人工神经网络理论、设计及应用_TensorFlow深度学习应用实践:教你如何掌握深度学习模型及应用...
前言 通过TensorFlow图像处理,全面掌握深度学习模型及应用. 全面深入讲解反馈神经网络和卷积神经网络理论体系. 结合深度学习实际案例的实现,掌握TensorFlow程序设计方法和技巧. 着重深 ...
- 深度学习笔记第二门课 改善深层神经网络 第一周:深度学习的实践层面
本文是吴恩达老师的深度学习课程[1]笔记部分. 作者:黄海广[2] 主要编写人员:黄海广.林兴木(第四所有底稿,第五课第一二周,第三周前三节).祝彦森:(第三课所有底稿).贺志尧(第五课第三周底稿). ...
- .NET Core 微服务学习与实践系列文章目录索引(2019版)
Photo :.NET Core 文 | Edison Zhou 2018年,我开始学习和实践.NET Core,并开始了微服务的学习,以及通过各种开源组件搭建服务治理技术方案,并在学习过程中总结了一 ...
- .NET Core on K8S 学习与实践系列文章索引 (更新至20191126)
更新记录: -- 2019-11-26 增加Docker容器日志系列文章 近期在学习Kubernetes,基于之前做笔记的习惯,已经写了一部分文章,因此给自己立一个flag:完成这个<.NET ...
最新文章
- 判断objcet是否是map类型_57、递归+树的深度+map-二叉搜索树的平衡性
- vue-router基本使用
- Tomcat 部署项目的三种方法
- [网络安全自学篇] 五十八.Windows安全缺陷利用之再看CVE-2019-0708及反弹shell防御措施
- Android开发之RecyclerView滑动到底部的监听方法
- mysql 优化 修复原理_mysql下表的修复与优化
- 将一个包含汉字的字符串逐个转化为数字,并得出该字符串的十进制和
- MyBatis查询,返回值Map或ListMap
- acm c 和java如何取舍,ACM中使用JAVA语言的优缺点介绍
- 【manjaro安装最新的搜狗输入法】2022年1月4号有效测试
- linux下载tftpd服务,Linux tftpd服务安装与配置
- Deprecated: Function eregi() is deprecated in D:\Apache24\htdocs\processfeedback.php on line 21
- LINUX编译xcb/xcb-proto
- 《学会提问》——价值观假设和描述性假设
- java代码编写的文本特征提取_文本特征词提取算法
- 网上最全的系统服务,让PF降到50以下(转)
- 特征选择之Relief算法与Relief-F算法
- glut 配置,解决“gl/glut.h”: No such file or directory
- 用友NC65查询凭证明细方法
- OpenCV4Android学习笔记一