1. 自动获取绑定 ViewID 的插件库
1.1 Application module 中 build.gradle中 添加
- apply plugin: 'org.jetbrains.kotlin.android'
- apply plugin: 'org.jetbrains.kotlin.android.extensions'
1.2 项目 build.gradle 中添加
- plugins {
- id "org.jetbrains.kotlin.android.extensions" version '1.7.10' apply false
- id "org.jetbrains.kotlin.kapt" version '1.7.10' apply false
- }
2. dependencies 中引用的库
- implementation 'androidx.lifecycle:lifecycle-livedata:2.5.1'
- implementation 'androidx.lifecycle:lifecycle-livedata-ktx:2.5.1'
- kapt "androidx.lifecycle:lifecycle-common-java8:2.5.1"
3. 示例代码
3.1 activity_live_data.xml 布局文件
- <androidx.core.widget.NestedScrollView xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="match_parent"
- android:layout_height="match_parent">
-
- <androidx.appcompat.widget.LinearLayoutCompat
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:gravity="center_horizontal"
- android:orientation="vertical"
- android:padding="10dp">
-
- <androidx.appcompat.widget.AppCompatTextView
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="LiveData使用演示" />
-
- <androidx.appcompat.widget.AppCompatTextView
- android:id="@+id/tv_live_data_activity"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="当前liveData的值: " />
-
- <androidx.appcompat.widget.AppCompatTextView
- android:id="@+id/tv_mapped_data_activity"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="Map后liveData值: "
- android:textColor="@color/teal_700" />
-
- <FrameLayout
- android:id="@+id/fl_container_live"
- android:layout_width="match_parent"
- android:layout_height="300dp"
- android:layout_marginTop="20dp"
- android:background="@android:color/darker_gray" />
-
- <androidx.appcompat.widget.AppCompatButton
- android:id="@+id/btn_create_fg_live"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_marginTop="10dp"
- android:padding="5dp"
- android:text="显fragment" />
-
- <androidx.appcompat.widget.AppCompatButton
- android:id="@+id/btn_destroy_fg_live"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_marginTop="20dp"
- android:padding="5dp"
- android:text="隐fragment" />
-
- <LinearLayout
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_marginTop="20dp"
- android:orientation="horizontal">
-
- <Button
- android:id="@+id/btn_change_live"
- android:layout_width="0dp"
- android:layout_height="wrap_content"
- android:layout_weight="1"
- android:padding="5dp"
- android:text="变LiveData" />
-
- <Button
- android:id="@+id/btn_change1_live"
- android:layout_width="0dp"
- android:layout_height="wrap_content"
- android:layout_weight="1"
- android:padding="5dp"
- android:text="变LiveOne" />
-
- <Button
- android:id="@+id/btn_change2_live"
- android:layout_width="0dp"
- android:layout_height="wrap_content"
- android:layout_weight="1"
- android:padding="5dp"
- android:text="变LiveTwo" />
- LinearLayout>
- androidx.appcompat.widget.LinearLayoutCompat>
- androidx.core.widget.NestedScrollView>
3.2 LiveActivity.kt
- /**
- * LiveData 的示例
- */
- class LiveActivity : AppCompatActivity() {
- private val TAG: String = "LiveActivity"
-
- //声明变量live data
- val liveAppleData = MutableLiveData
() -
- private val liveMappedData = liveAppleData.map {
- Pair<Int, String>(it.hashCode(), it)
- }
-
- val liveOne = MutableLiveData
() - val liveTwo = MutableLiveData
() - val mediatorLive = MediatorLiveData
>() -
- override fun onCreate(savedInstanceState: Bundle?) {
- super.onCreate(savedInstanceState)
- setContentView(R.layout.activity_live_data)
-
- val appleFragment = AppleFragment()
- supportFragmentManager.beginTransaction().add(R.id.fl_container_live, appleFragment)
- .commit()
- //TODO hide 和 show 不会改变 fragment 的生命周期状态,所以用 attach detach
- //显示 fragment attach
- btn_create_fg_live.setOnClickListener {
- supportFragmentManager.beginTransaction().attach(appleFragment).commit()
- Log.i(TAG, "onCreate: 显示fg ${appleFragment.isVisible}")
- }
- //隐藏 fragment detach
- btn_destroy_fg_live.setOnClickListener {
- supportFragmentManager.beginTransaction().detach(appleFragment).commit()
- Log.w(TAG, "onCreate 隐藏 fg ${appleFragment.isVisible}")
- }
- //变更livedata的值
- btn_change_live.setOnClickListener {
- liveAppleData.value = "当前 liveData 的值: ${System.currentTimeMillis()}"
- }
-
- btn_change1_live.setOnClickListener {
- liveOne.value = "one: ${System.currentTimeMillis().toString().takeLast(6)}"
- }
- btn_change2_live.setOnClickListener {
- liveTwo.value = "two ${System.currentTimeMillis().toString().takeLast(6)}"
- }
-
- //观察者
- liveAppleData.observe(this, Observer {
- tv_live_data_activity.text = it
- Log.i(TAG, "LiveData在LiveActivity中 $it")
- })
- //map转换后的数值
- liveMappedData.observe(this, Observer {
- tv_mapped_data_activity.text = it.toString()
- Log.i(TAG, "LiveData在LiveActivity 中 map 后 $it")
- })
-
- //中介者
- mediatorLive.addSource(liveOne) {
- Log.i(TAG, "LiveActivity中 LiveOne ---> $it")
- mediatorLive.value = "one >>" to it
- }
- mediatorLive.addSource(liveTwo) {
- Log.i(TAG, "LiveActivity中 LiveTwo ---> $it")
- mediatorLive.value = "two >>>>> " to it
- }
- mediatorLive.observe(this, Observer {
- Log.w(TAG, "LiveActivity中 mediatorLive ---> $it")
- })
- }
- }
4. 内部Fragment
4.1 fg_apple.xml 布局文件
- <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">
-
- <androidx.appcompat.widget.AppCompatTextView
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="Apple Fragment"
- android:textColor="@color/red"
- app:layout_constraintBottom_toBottomOf="parent"
- app:layout_constraintEnd_toEndOf="parent"
- app:layout_constraintStart_toStartOf="parent"
- app:layout_constraintTop_toTopOf="parent"
- app:layout_constraintVertical_bias="0.3" />
-
- <androidx.appcompat.widget.AppCompatTextView
- android:id="@+id/tv_live_apple"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:textSize="20sp"
- app:layout_constraintBottom_toBottomOf="parent"
- app:layout_constraintEnd_toEndOf="parent"
- app:layout_constraintStart_toStartOf="parent"
- app:layout_constraintTop_toTopOf="parent"
- tools:text="Apple Data" />
-
- <androidx.appcompat.widget.AppCompatTextView
- android:id="@+id/tv_mapped_live_apple"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:textColor="@android:color/holo_green_light"
- android:textSize="14sp"
- app:layout_constraintBottom_toBottomOf="parent"
- app:layout_constraintEnd_toEndOf="parent"
- app:layout_constraintStart_toStartOf="parent"
- app:layout_constraintTop_toTopOf="parent"
- app:layout_constraintVertical_bias="0.6"
- tools:text="Mapped Apple Data" />
-
- <androidx.appcompat.widget.AppCompatTextView
- android:id="@+id/tv_media_live_apple"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:textColor="@android:color/holo_blue_light"
- android:textSize="14sp"
- app:layout_constraintBottom_toBottomOf="parent"
- app:layout_constraintEnd_toEndOf="parent"
- app:layout_constraintStart_toStartOf="parent"
- app:layout_constraintTop_toTopOf="parent"
- app:layout_constraintVertical_bias="0.7"
- tools:text="mediator Apple Data" />
-
- <androidx.appcompat.widget.AppCompatTextView
- android:id="@+id/tv_switch_live_apple"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:textColor="@android:color/holo_red_dark"
- android:textSize="14sp"
- app:layout_constraintBottom_toBottomOf="parent"
- app:layout_constraintEnd_toEndOf="parent"
- app:layout_constraintStart_toStartOf="parent"
- app:layout_constraintTop_toTopOf="parent"
- app:layout_constraintVertical_bias="0.8"
- tools:text="Switch Apple Data" />
- androidx.constraintlayout.widget.ConstraintLayout>
4.2 AppleFragment.kt
- class AppleFragment : Fragment() {
- private val TAG: String = "AppleFragment"
- override fun onCreateView(
- inflater: LayoutInflater,
- container: ViewGroup?,
- savedInstanceState: Bundle?
- ): View? {
- return inflater.inflate(R.layout.fg_apple, container, false)
- }
-
- override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
- super.onViewCreated(view, savedInstanceState)
- }
-
- override fun onResume() {
- super.onResume()
- Log.i(TAG, "onResume()")
- (requireActivity() as LiveActivity).apply {
- liveAppleData.observe(viewLifecycleOwner, Observer {
- tv_live_apple.text = it
- Log.i(TAG, "tv_live_apple 显示 ${tv_live_apple.isVisible}")
- Log.i(TAG, "LiveData 在 AppleFragment中: $it")
- })
- val liveMapApple = liveAppleData.map {
- Log.i(TAG, "LiveData 在 AppleFragment中 map: $it")
- "it mapped it ${it.takeLast(4)}"
- }
- //在inActive状态下,是不会感知数据的,但是一旦resume,就会得到最新的数据
- liveMapApple.observe(viewLifecycleOwner, Observer {
- val s = "mapped it: $it"
- tv_mapped_live_apple.text = s
- Log.w(TAG, "LiveData 在 AppleFragment中 map 后的数据 $it")
- })
-
- //mediator
- mediatorLive.observe(viewLifecycleOwner, Observer {
- //如果在inactive状态下,one two都变化了,它 resume 后只接受最新的
- val s = "mediator it $it"
- tv_media_live_apple.text = s
- Log.w(TAG, "AppleFragment中 mediatorLive ---> $it")
- })
-
- //switch map 结合 mediator, 通过条件,控制选择数据源,这里模拟的是,it的数字奇偶,控制最终输出
- val swLive = mediatorLive.switchMap {
- if (it.second.takeLast(1).toInt() % 2 == 0) liveOne else liveTwo
- }
-
- //UI可以看出,不论是 One,还是 Two,改变的话,只有满足条件,才会生效
- swLive.observe(viewLifecycleOwner, Observer {
- tv_switch_live_apple.text = it
- Log.w(TAG, "AppleFragment中 switchMap ---> $it")
- })
- }
- }
- }