diff --git a/jetpack/databinding/src/main/res/layout/fragment_databinding.xml b/jetpack/databinding/src/main/res/layout/fragment_databinding.xml index 9171578..5a1b5a8 100644 --- a/jetpack/databinding/src/main/res/layout/fragment_databinding.xml +++ b/jetpack/databinding/src/main/res/layout/fragment_databinding.xml @@ -6,6 +6,14 @@ android:orientation="vertical" android:padding="8dp"> + + () + + override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) //此界面在AndroidManifest中使用了theme,状态栏和导航栏的透明 @@ -31,5 +41,8 @@ class JetpackActivity : FragmentActivity() { val navController = fcv.findNavController() // val navController = findNavController(R.id.fcv_jetpack)//也可以这么写 bnv.setupWithNavController(navController) + //去掉bottom navigation view的color tint,则就变成了原始的imageView的效果, + //navView.menu.getItem(2).icon 就是ImageView,可以加载gif,webp等icon效果 + bnv.itemIconTintList = null } } \ No newline at end of file diff --git a/jetpack/src/main/java/org/zhiwei/jetpack/components/ui/JetpackFragment.kt b/jetpack/src/main/java/org/zhiwei/jetpack/components/ui/JetpackFragment.kt new file mode 100644 index 0000000..a2dc20a --- /dev/null +++ b/jetpack/src/main/java/org/zhiwei/jetpack/components/ui/JetpackFragment.kt @@ -0,0 +1,58 @@ +package org.zhiwei.jetpack.components.ui + +import android.icu.math.BigDecimal +import android.os.Bundle +import android.util.Log +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.TextView +import androidx.fragment.app.Fragment +import androidx.fragment.app.viewModels +import org.zhiwei.jetpack.components.R + +/** + * 这部分主要演示除dataBinding外的,主要的几个jetpack组件的用法; + * 1. liveData、lifecycle、viewModel,room,paging,work,navigation + * 2. 其实在JetpackActivity中就已经使用了navigation结合bottomNavigationView的简单用法 + */ +class JetpackFragment : Fragment() { + //fragment-ktx提供的扩展函数,便于获取viewModel的实例;该方式获取的vm,不同的fragment对象获取后的vm,不是同一个实例。 + private val vm: JetpackViewModel by viewModels() + + //fragment-ktx提供的扩展函数,便于获取该fragment依附的activity的viewModel的实例。 + // 该方式获取的vm,如果是同一个activity下不同的fragment获取vm,对象是同一个。 +// private val vm2: JetpackViewModel by activityViewModels() + + private val tvLive: TextView by lazy { requireView().findViewById(R.id.tv_live_ret_jetpack) } + + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle?, + ): View? { + //这里注意,第三个参数一定要设置false,否则报错 + return inflater.inflate(R.layout.fragment_jetpack, container, false) + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + testLiveData() + } + + private val TAG = "JetpackFragment" + private fun testLiveData() { + //模拟生成数据 + vm.startSendScore() + //观察live的数据变化,不要关联生命周期的lifecycleOwner,observeForever不需要。 + //viewLifecycleOwner是fragment的,activity就是自身。 + vm.liveScore.observe(viewLifecycleOwner) { + //保留小数点2位 + val num = BigDecimal(it).setScale(2, BigDecimal.ROUND_UP) + Log.d(TAG, "testLiveData:👀到$it ,保留2位:$num") + tvLive.text = "文本$num" + } + } + + +} \ No newline at end of file diff --git a/jetpack/src/main/java/org/zhiwei/jetpack/components/ui/JetpackViewModel.kt b/jetpack/src/main/java/org/zhiwei/jetpack/components/ui/JetpackViewModel.kt new file mode 100644 index 0000000..1eed220 --- /dev/null +++ b/jetpack/src/main/java/org/zhiwei/jetpack/components/ui/JetpackViewModel.kt @@ -0,0 +1,37 @@ +package org.zhiwei.jetpack.components.ui + +import androidx.lifecycle.LiveData +import androidx.lifecycle.MutableLiveData +import androidx.lifecycle.ViewModel +import androidx.lifecycle.viewModelScope +import kotlinx.coroutines.delay +import kotlinx.coroutines.launch +import kotlin.math.nextDown +import kotlin.random.Random + +/** + * 作用于JetpackActivity和JetpackFragment的viewModel; + * viewModel作为数据管理层,可以给多个fragment共用。 + * + */ +class JetpackViewModel : ViewModel() { + //一般使用ViewModel作为基类即可,另有AndroidViewModel,内含application参数,根据业务场景来选择使用与否。 + + //region liveData + private val _liveStudentScore = + MutableLiveData()//一般mutable的都是可修改的,开发习惯,可修改额私有,对外提供不可变的。 + val liveScore: LiveData = _liveStudentScore + + //endregion + + internal fun startSendScore() { + viewModelScope.launch { + repeat(20) { + delay(500) + _liveStudentScore.postValue(Random.nextDouble(20.0, 100.0).nextDown()) + } + } + + } + +} \ No newline at end of file diff --git "a/jetpack/src/main/java/org/zhiwei/jetpack/components/ui/jetpack\347\254\224\350\256\260\351\200\237\350\247\210.md" "b/jetpack/src/main/java/org/zhiwei/jetpack/components/ui/jetpack\347\254\224\350\256\260\351\200\237\350\247\210.md" new file mode 100644 index 0000000..3d287fa --- /dev/null +++ "b/jetpack/src/main/java/org/zhiwei/jetpack/components/ui/jetpack\347\254\224\350\256\260\351\200\237\350\247\210.md" @@ -0,0 +1,60 @@ +#### Jetpack笔记速览 + +##### 一、前言 + +> [Jetpack](https://developer.android.google.cn/jetpack?hl=zh-cn) +> 是Android官方推出的一些列组件库,最早`databinding` +> 也属于官方推荐的工具写法,但是由于其影响编译性能,且`xml` +> 中编写出错的时候IDE不易准确检测和报错,逐步不再使用。且`compose` +> 更为高效的UI编写方式,所以该项目内`dataBinding`有独立module作为代码示例,并有详细注释说明,便于学习。 +> +> 如果不是接手老项目需要,可以跳过,直接学习compose;如果是老项目有databinding,则可以学习了解即可。 + +Jetpack的其他组件则都会共用在同一个项目module内,同时也是使用MVVM的架构设计模式,来简单实现一个组合使用各个库的示例。 + + +以下笔记仅用于初步了解库的使用和简单构成,不太深入基本原理。先知其然,然后自然而然你会探索其所以然。 + +可以在`IDE`的project模式下,`External Libraries`找到想看的库的编译源码。 + +##### 二、Lifecycle + +> 简言之,Lifecycle就是观察者模式,用以感知UI元素的生命周期的。Android中Activity/Fragment级别的实现。 + +简要理解`Lifecycle`库就核心三个类文件:`Lifecycle`、`LifecycleOwner`、`LifecycleObserver` + +1. `Lifecycle`就是表述生命周期的,抽象类,提供观察者的注册/注销。内有生命周期的不同状态`State` + 和`Event`。 +2. `LifecycleOwner`就是上面`lifecycle`的持有者,Android中是`componentActivity/Fragment` + 类实现的。两个`componentActivity`类,一般使用`andriodx.activity`包下的,因为这个实现了`viewModel` + 的结合。开发中多用`AppcompatActivity来作为基类`,直接使用`Activity`作为基类就没有这个实现。 +3. `LifecycleObserver`和子类`LifecycleEventObsever`就可以添加到上面的`lifecycle` + 注册观察,就能感知到生命周期变化的回调。具体你不实现,可参照源码,`LifecycleController`等分析。 + +##### 三、LiveData + +> 又一个观察者模式的实现,数据变化时候可以得到及时的通知。两个核心库`lifecycle-livedata-core` +> 和`lifecycle-livedata` + +1. `core`库就三个文件:`Observer`接口,`LiveData`抽象类和`MutableLiveData` + 的类。LiveData内有观察者的注册/注销,及数据变化的管理和通知等逻辑。 +2. `livedata`库有`MediatorLiveData`,`Transformations`和一些**协程**相关的实现类,扩展函数等。 + +```kotlin +``` + +Worker + 任务的执行者,是一个抽象类,需要继承它实现要执行的任务。 + +WorkRequest +指定让哪个 Worker 执行任务,指定执行的环境,执行的顺序等。 + 要使用它的子类 OneTimeWorkRequest 或 PeriodicWorkRequest。 + +WorkManager + 管理任务请求和任务队列,发起的 WorkRequest 会进入它的任务队列。 + +WorkStatus + 包含有任务的状态和任务的信息,以 LiveData 的形式提供给观察者。 + +WorkManager适用于那些即使应用程序退出,系统也能够保证这个任务正常运行的场景,比如将应用程序数据上传到服务器。 +它不适用于应用进程内的后台工作,如果应用进程消失,就可以安全地终止,对于这种情况,推荐你使用线程池 \ No newline at end of file diff --git a/jetpack/src/main/java/org/zhiwei/jetpack/components/ui/work.txt b/jetpack/src/main/java/org/zhiwei/jetpack/components/ui/work.txt deleted file mode 100644 index 39104d6..0000000 --- a/jetpack/src/main/java/org/zhiwei/jetpack/components/ui/work.txt +++ /dev/null @@ -1,15 +0,0 @@ -Worker - 任务的执行者,是一个抽象类,需要继承它实现要执行的任务。 - -WorkRequest - 指定让哪个 Woker 执行任务,指定执行的环境,执行的顺序等。 - 要使用它的子类 OneTimeWorkRequest 或 PeriodicWorkRequest。 - -WorkManager - 管理任务请求和任务队列,发起的 WorkRequest 会进入它的任务队列。 - -WorkStatus - 包含有任务的状态和任务的信息,以 LiveData 的形式提供给观察者。 - -WorkManager适用于那些即使应用程序退出,系统也能够保证这个任务正常运行的场景,比如将应用程序数据上传到服务器。 -它不适用于应用进程内的后台工作,如果应用进程消失,就可以安全地终止,对于这种情况,推荐你使用线程池 \ No newline at end of file diff --git a/jetpack/src/main/java/org/zhiwei/jetpack/components/ui/MyWorker.java b/jetpack/src/main/java/org/zhiwei/jetpack/components/ui/work/MyWorker.java similarity index 95% rename from jetpack/src/main/java/org/zhiwei/jetpack/components/ui/MyWorker.java rename to jetpack/src/main/java/org/zhiwei/jetpack/components/ui/work/MyWorker.java index 7bd5e19..aa1698e 100644 --- a/jetpack/src/main/java/org/zhiwei/jetpack/components/ui/MyWorker.java +++ b/jetpack/src/main/java/org/zhiwei/jetpack/components/ui/work/MyWorker.java @@ -1,4 +1,4 @@ -package org.zhiwei.jetpack.components.ui; +package org.zhiwei.jetpack.components.ui.work; import android.content.Context; import android.util.Log; diff --git a/jetpack/src/main/java/org/zhiwei/jetpack/components/ui/WorkActivity.kt b/jetpack/src/main/java/org/zhiwei/jetpack/components/ui/work/WorkFragment.kt similarity index 77% rename from jetpack/src/main/java/org/zhiwei/jetpack/components/ui/WorkActivity.kt rename to jetpack/src/main/java/org/zhiwei/jetpack/components/ui/work/WorkFragment.kt index 43a0118..25b2ab4 100644 --- a/jetpack/src/main/java/org/zhiwei/jetpack/components/ui/WorkActivity.kt +++ b/jetpack/src/main/java/org/zhiwei/jetpack/components/ui/work/WorkFragment.kt @@ -1,9 +1,12 @@ -package org.zhiwei.jetpack.components.ui +package org.zhiwei.jetpack.components.ui.work import android.os.Bundle import android.util.Log +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup import android.widget.Toast -import androidx.appcompat.app.AppCompatActivity +import androidx.fragment.app.Fragment import androidx.work.BackoffPolicy import androidx.work.Constraints import androidx.work.Data @@ -31,9 +34,9 @@ import java.util.concurrent.TimeUnit * ---------------------------------------------------------------- * workmanager的演示界面 */ -class WorkActivity : AppCompatActivity() { +class WorkFragment : Fragment() { //todo 这里workmanager的request有个高级用法,就是添加环境约束 ,比如网络、电量等 - var constraints: Constraints = Constraints.Builder() + private var constraints: Constraints = Constraints.Builder() .setRequiredNetworkType(NetworkType.CONNECTED) //联网状态 .setRequiresBatteryNotLow(true) //低电量不操作 // .setRequiresCharging(true) // TODO 充电时候才开始,这个条件开启后,测试机不充电则无演示效果 @@ -41,11 +44,11 @@ class WorkActivity : AppCompatActivity() { .setRequiresStorageNotLow(true) //存储空间不能太小 .build() - private val name = "tmc" + private val name = "Kotlin小娜娜" private val age = 18 //类似于intent的bundle - var data = Data.Builder() + private var data = Data.Builder() .putString("name", name) .putInt("age", age) .build() @@ -62,22 +65,29 @@ class WorkActivity : AppCompatActivity() { .setBackoffCriteria(BackoffPolicy.LINEAR, 20, TimeUnit.MINUTES) .build() - override fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) - setContentView(R.layout.activity_work) + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle?, + ): View? { + return inflater.inflate(R.layout.fragment_work, container, false) + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) //3、加入任务管理,但不是执行,执行的代码稍后 - WorkManager.getInstance(this).enqueue(workRequest) + WorkManager.getInstance(requireContext()).enqueue(workRequest) //4、通过workRequest的唯一标记id,来操作request,并获取返回数据 - //todo 这里因为在oncreate中执行,会先与work执行,toast会弹出未执行work的空结果,work变化后,还会显示出成功后的结果。这是因为observe监测worker的status变化 enqueued、RUNNING、successed、retry、failure等 - WorkManager.getInstance(this).getWorkInfoByIdLiveData(workRequest.id) - .observe(this) { workStatus: WorkInfo -> + //todo 这里toast会弹出未执行work的空结果,work变化后,还会显示出成功后的结果。这是因为observe监测worker的status变化 enqueued、RUNNING、successed、retry、failure等 + WorkManager.getInstance(requireContext()).getWorkInfoByIdLiveData(workRequest.id) + .observe(viewLifecycleOwner) { workStatus: WorkInfo -> //接收从worker中返回的任务结果,最好在这里判断status为success再做具体操作 if (workStatus.state == WorkInfo.State.SUCCEEDED) { val data = workStatus.outputData val result = data.getString("result") val status = data.getInt("status", 0) Toast.makeText( - this@WorkActivity, + requireContext(), "result: $result status: $status", Toast.LENGTH_SHORT ).show() @@ -114,6 +124,6 @@ class WorkActivity : AppCompatActivity() { // override fun onDestroy() { super.onDestroy() - WorkManager.getInstance(this).cancelWorkById(workRequest.id) + WorkManager.getInstance(requireContext()).cancelWorkById(workRequest.id) } } \ No newline at end of file diff --git a/jetpack/src/main/res/layout/fragment_jetpack.xml b/jetpack/src/main/res/layout/fragment_jetpack.xml new file mode 100644 index 0000000..34e0d54 --- /dev/null +++ b/jetpack/src/main/res/layout/fragment_jetpack.xml @@ -0,0 +1,28 @@ + + + + + + + + \ No newline at end of file diff --git a/jetpack/src/main/res/layout/activity_work.xml b/jetpack/src/main/res/layout/fragment_work.xml similarity index 100% rename from jetpack/src/main/res/layout/activity_work.xml rename to jetpack/src/main/res/layout/fragment_work.xml diff --git a/jetpack/src/main/res/navigation/graph_main_jetpack.xml b/jetpack/src/main/res/navigation/graph_main_jetpack.xml index 97baf7e..a9c0f7f 100644 --- a/jetpack/src/main/res/navigation/graph_main_jetpack.xml +++ b/jetpack/src/main/res/navigation/graph_main_jetpack.xml @@ -4,11 +4,16 @@ xmlns:tools="http://schemas.android.com/tools" android:id="@+id/graph_main" app:startDestination="@+id/databinding_item_menu"> - + + \ No newline at end of file diff --git a/jetpack/src/test/java/org/zhiwei/jetpack/components/ExampleUnitTest.kt b/jetpack/src/test/java/org/zhiwei/jetpack/components/ExampleUnitTest.kt index 86f4b2b..d8d129d 100644 --- a/jetpack/src/test/java/org/zhiwei/jetpack/components/ExampleUnitTest.kt +++ b/jetpack/src/test/java/org/zhiwei/jetpack/components/ExampleUnitTest.kt @@ -13,4 +13,5 @@ class ExampleUnitTest { fun addition_isCorrect() { assertEquals(4, 2 + 2) } + } \ No newline at end of file