四篇文章带你快速入门Jetpck(上)之Lifecycle,Li

2021-01-05  本文已影响0人  Cache技术分享

四篇文章带你快速入门Jetpck(上)之Lifecycle,LiveData

Jetpack

Jetpack 是一个由多个库组成的套件,可帮助开发者遵循最佳做法,减少样板代码并编写可在各种 Android 版本和设备中一致运行的代码,让开发者精力集中编写重要的代码。

image.png

官方推荐架构

img

请注意,每个组件仅依赖于其下一级的组件。例如,Activity 和 Fragment 仅依赖于视图模型。存储区是唯一依赖于其他多个类的类;在本例中,存储区依赖于持久性数据模型和远程后端数据源。

Lifecycle

感知Activity的生命周期并不复杂,但问题在于,在一个Activity中去感知它的生命周期非常简单,而如果要在一个非Activity的类中去感知Activity的生命周期,应该怎么办呢?

Lifecycles组件就是为了解决这个问题而出现的,它可以让任何一个类都能轻松感知到Activity的生命周期,同时又不需要在Activity中编写大量的逻辑处理。

UI的生命周期

activity&fragment生命周期图

Lifecycles的基本用法

新建一个MyObserver类,并让它实现LifecycleObserver接口,然后使用方法注解就能感知到Activity的生命周期了:

class MyObserver : LifecycleObserver {

    @OnLifecycleEvent(Lifecycle.Event.ON_START)
    fun activityStart() {
        Log.d("MyObserver", "activityStart")
    }

    @OnLifecycleEvent(Lifecycle.Event.ON_STOP)
    fun activityStop() {
        Log.d("MyObserver", "activityStop")
    }

}

另外一种方式:实现LifecycleEventObserver接口。

lifecycle.addObserver(object : LifecycleEventObserver {
            override fun onStateChanged(source: LifecycleOwner, event: Lifecycle.Event) {
                when (event) {
                    Lifecycle.Event.ON_CREATE -> {
                    }
                    Lifecycle.Event.ON_START -> {
                    }
                    Lifecycle.Event.ON_RESUME -> {
                    }
                    Lifecycle.Event.ON_PAUSE -> {
                    }
                    Lifecycle.Event.ON_STOP -> {
                    }
                    Lifecycle.Event.ON_DESTROY -> {
                    }
                }
            }
        })

最后,在Activity中调用addObserver()方法来观察LifecycleOwner的生命周期:

class MainActivity : AppCompatActivity() {
    …
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        …
        lifecycle.addObserver(MyObserver())
    }
    …
}

Lifecycle状态图

image.png

示例

LifecycleActivity

class LifecycleActivity : AppCompatActivity() {

    private val lifecycleObject = LifecycleObject()
    val TAG = this.javaClass.simpleName
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_lifecycle)
        Log.d(TAG, "onCreate")
        //lifecycleObject.onCreate()

        //LifecycleObject1(this)
        LifecycleObject2(this)
    }

//    override fun onResume() {
//        super.onResume()
//        lifecycleObject.onResume()
//        Log.d(TAG, "onResume")
//    }
//
//    override fun onPause() {
//        super.onPause()
//        lifecycleObject.onPause()
//        Log.d(TAG, "onPause")
//    }
//
//    override fun onDestroy() {
//        super.onDestroy()
//        lifecycleObject.onDestroy()
//        Log.d(TAG, "onDestroy")
//    }
}

LifecycleObject.kt

class LifecycleObject {
    val TAG = this.javaClass.simpleName
    private lateinit var player: MediaPlayer

    fun onCreate() {
        player = MediaPlayer()
        Log.d(TAG, "onCreate")
    }

    fun onResume() {
        thread {
            SystemClock.sleep(3000)
            player.start()
            Log.d(TAG, "onResume")
        }
    }

    fun onPause() {
        player.stop()
        Log.d(TAG, "onPause")
    }

    fun onDestroy() {
        player.release()
        Log.d(TAG, "onDestroy")
    }
}

class LifecycleObject1(private val owner: LifecycleOwner) : LifecycleObserver {
    private lateinit var player: MediaPlayer
    val TAG = this.javaClass.simpleName

    init {
        owner.lifecycle.addObserver(this)
    }

    @OnLifecycleEvent(Lifecycle.Event.ON_CREATE)
    fun onCreate() {
        player = MediaPlayer()
        Log.d(TAG, "onCreate")
    }

    @OnLifecycleEvent(Lifecycle.Event.ON_RESUME)
    fun onResume() {
        thread {
            SystemClock.sleep(3000)
            if (owner.lifecycle.currentState.isAtLeast(Lifecycle.State.STARTED)) {
                player.start()
                Log.d(TAG, "onResume")
            }
        }
    }

    @OnLifecycleEvent(Lifecycle.Event.ON_PAUSE)
    fun onPause() {
        player.stop()
        Log.d(TAG, "onPause")
    }

    @OnLifecycleEvent(Lifecycle.Event.ON_DESTROY)
    fun onDestroy() {
        player.release()
        Log.d(TAG, "onDestroy")
    }
}

class LifecycleObject2(private val owner: LifecycleOwner) : LifecycleEventObserver {
    private lateinit var player: MediaPlayer
    val TAG = this.javaClass.simpleName

    init {
        owner.lifecycle.addObserver(this)
    }

    override fun onStateChanged(source: LifecycleOwner, event: Lifecycle.Event) {
        when (event) {
            Lifecycle.Event.ON_CREATE -> {
                player = MediaPlayer()
                Log.d(TAG, "onCreate")
            }
            Lifecycle.Event.ON_START, Lifecycle.Event.ON_RESUME -> {
                thread {
                    SystemClock.sleep(3000)
                    if (owner.lifecycle.currentState.isAtLeast(Lifecycle.State.STARTED)) {
                        player.start()
                        Log.d(TAG, "onResume")
                    }
                }

            }
            Lifecycle.Event.ON_PAUSE, Lifecycle.Event.ON_STOP -> {
                player.stop()
                Log.d(TAG, "onPause")
            }
            Lifecycle.Event.ON_DESTROY -> {
                player.release()
                Log.d(TAG, "onDestroy")
            }
            Lifecycle.Event.ON_ANY -> Log.d(TAG, "onAny")
        }
    }
}

LiveData

添加依赖库

implementation 'androidx.lifecycle:lifecycle-livedata-ktx:2.3.0-beta01'

简介

LiveData 是可被观察的数据持有类。具有生命周期(Activity/Fragment/Service)感知的(确保active状态下接受data更新)。

LiveData是Jetpack提供的一种响应式编程组件,它可以包含任何类型的数据,并在数据发生变化的时候通知给观察者。

LiveData特别适合与ViewModel结合在一起使用,虽然它也可以单独用在别的地方,但是绝大多数情况下,它都是使用在ViewModel当中的。

  1. 背景 原文

    img

    Android开发中 MVX的开发架构设计,生命周期的感知对于Controller/Presenter/ViewModel不是天然可知。数据资源与泄露的问题。

    MVX的生命周期传递
  2. 2018年 google的AAC(Android Architecture Components)。一套组合的Jetpack组件库,使得ViewModel具有生命周期感知能力。同时也有了数据的感知能力(LiveData)

    img

使用LiveData

LiveData是抽象类

MutableLiveData

//声明一个liveData
val liveA = mutableLiveData<String>()
//在需要的时候赋值
liveA.value = "some value of liveA"

//在UI中,观察,在active状态下可以感知变化
val liveAObserver = Observer<String>{
    value?.let{
        //do something
    }
}
liveA.observe(vivewLifeCycleOwner,liveAObserver)

Transformations.map

//数据的来源多样,赋值于UI需要转换
liveA.map{
    //转换规则
}
img

==liveData的数据,不会通知inActive的观察者刷新数据,但是当observer恢复Resume的active后,也会得到最新的data==

img

MediatorLiveData

中介者,媒介,将多个liveData的数据,合并处理成一个LiveData

img

mediator的liveData可以监听A,B两个数据源的变化,通过addSource后,并响应A/B的变化,转化为mediator的变化。

SwitchMap

用于数据源的转化,多数据源的切换和控制

img

配合mediator的liveData使用,根据条件,选择数据源

示例

LiveDataActivity

class LiveDataActivity : AppCompatActivity() {
    val TAG = this.javaClass.simpleName

    // 步骤1
    val testLiveData = MutableLiveData<String>()

    //步骤2
    val liveMappedData = testLiveData.map {
        it.hashCode()
    }


    //步骤3
    val liveData1 = MutableLiveData<Int>()
    val liveData2 = MutableLiveData<Int>()
    val mediatorLive = MediatorLiveData<Pair<String, String>>()

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_live_data)

        val liveDataFragment = LiveDataFragment()
        supportFragmentManager.beginTransaction()
            .add(R.id.fl_container_live, liveDataFragment)
            .commit()

        btn_create_fg_live.setOnClickListener {
            supportFragmentManager.beginTransaction()
                .attach(liveDataFragment)
                .commit()
            Log.d(TAG, "onCreate 显示 ${liveDataFragment.isVisible}")
        }
        btn_destroy_fg_live.setOnClickListener {
            supportFragmentManager.beginTransaction()
                .detach(liveDataFragment)
                .commit()
            Log.d(TAG, "onCreate 隐藏 ${liveDataFragment.isVisible}")
        }
        btn_change_live.setOnClickListener {
            testLiveData.value = "当前liveData的值为:${(10000..99999).random()}"
        }
        // 步骤1
        testLiveData.observe(this, {
            tv_live_data_activity.text = it
            Log.d(TAG, "LiveData在LiveDataActivity中 $it")
        })
        liveMappedData.observe(this, {
            tv_mapped_data_activity.text = it.toString()
            Log.d(TAG, "LiveData在LiveDataActivity中 map 后 $it")
        })


        btn_change_live1.setOnClickListener {
            Log.d(TAG, "liveData1 = ${liveData1.value}")
            liveData1.value = (10000..99999).random()
        }
        btn_change_live2.setOnClickListener {
            Log.d(TAG, "liveData2 = ${liveData2.value}")
            liveData2.value = (10000..99999).random()
        }
        mediatorLive.addSource(liveData1) {
            Log.d(TAG, "live1 = $it")
            mediatorLive.value = "live1 = " to it.toString()
        }
        mediatorLive.addSource(liveData2) {
            Log.d(TAG, "live2 = $it")
            mediatorLive.value = "live2 = " to it.toString()
        }

    }
}

activity_live_data.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context=".fourth.LiveDataActivity">

    <TextView
        android:id="@+id/tv_live_data_activity"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:gravity="center"
        android:text="当前liveData的值:"
        android:textColor="#000000"
        android:textSize="20dp"
        tools:text="当前liveData的值:" />

    <TextView
        android:id="@+id/tv_mapped_data_activity"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:gravity="center"
        android:text="Map后liveData值:"
        android:textColor="#000000"
        android:textSize="20dp"
        tools:text="Map后liveData值:" />


    <FrameLayout
        android:id="@+id/fl_container_live"
        android:layout_width="match_parent"
        android:layout_height="300dp"
        android:background="@color/colorAccent" />


    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content">

        <Button
            android:id="@+id/btn_create_fg_live"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:text="显示Fragment" />

        <Button
            android:id="@+id/btn_destroy_fg_live"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:text="隐藏Fragment" />

    </LinearLayout>

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content">

        <Button
            android:id="@+id/btn_change_live"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:text="改变Live值" />

        <Button
            android:id="@+id/btn_change_live1"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:text="改变Live1值" />

        <Button
            android:id="@+id/btn_change_live2"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:text="改变Live2值" />


    </LinearLayout>
</LinearLayout>

LiveDataFragment

class LiveDataFragment : Fragment() {
    val TAG = this.javaClass.simpleName
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        Log.d(TAG, "onCreate")
    }

    override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        return inflater.inflate(R.layout.fragment_live_data, container, false)
    }

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        (requireActivity() as LiveDataActivity).apply {
            // 步骤1
            testLiveData.observe(viewLifecycleOwner, {
                tv_live_fg.text = it
                Log.i(TAG, "LiveData在LiveDataFragment中 $it")
                Log.d(TAG, "LiveData在LiveDataFragment中 map 后 ${tv_live_fg.isVisible}")
            })
            // 如果这里用this的话就有问题
            liveMappedData.observe(viewLifecycleOwner, {
                tv_mapped_live_fg.text = it.toString()
                Log.d(
                    TAG,
                    "LiveData在LiveDataFragment中 map 后 $it  +   ${tv_mapped_live_fg.isVisible}"
                )
            })
            mediatorLive.observe(viewLifecycleOwner, {
                tv_media_live_fg.text = it.toString()
                Log.d(
                    TAG,
                    "LiveData在LiveDataFragment中 mediatorLive 后 $it  +   ${tv_media_live_fg.isVisible}"
                )
            })
            // 4
            val swLive = mediatorLive.switchMap {
                if (it.second.toInt() % 2 == 0) liveData1 else liveData2
            }
            swLive.observe(viewLifecycleOwner, {
                tv_switch_live_fg.text = it.toString()
            })
        }
        Log.d(TAG, "onViewCreated")
    }

    // 步骤1
    override fun onAttach(context: Context) {
        super.onAttach(context)
        Log.d(TAG, "onAttach")
    }

    override fun onPause() {
        super.onPause()
        Log.d(TAG, "onPause")
    }

    override fun onStop() {
        super.onStop()
        Log.d(TAG, "onStop")
    }

    override fun onDestroy() {
        super.onDestroy()
        Log.d(TAG, "onDestroy")
    }
}

fragment_live_data.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context=".fourth.LiveDataFragment">


    <TextView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:gravity="center"
        android:text="This is fragment"
        android:textColor="#000000"
        android:textSize="20sp" />

    <TextView
        android:id="@+id/tv_live_fg"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:gravity="center"
        android:text="tv_live_fg"
        android:textColor="#000000"
        android:textSize="20sp" />

    <TextView
        android:id="@+id/tv_mapped_live_fg"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:gravity="center"
        android:text="tv_mapped_live_fg1"
        android:textColor="#000000"
        android:textSize="20sp" />

    <TextView
        android:id="@+id/tv_media_live_fg"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:gravity="center"
        android:text="tv_media_live_fg"
        android:textColor="#000000"
        android:textSize="20sp" />

    <TextView
        android:id="@+id/tv_switch_live_fg"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:gravity="center"

        android:textColor="#000000"
        android:textSize="20sp" />
</LinearLayout>
上一篇下一篇

猜你喜欢

热点阅读