天天看点

Android Jetpack 之 LiveData1. LiveData 是什么2. LiveData 的优点3. LiveData 的使用

1. LiveData 是什么

LiveData is an observable data holder class. Unlike a regular observable, LiveData is lifecycle-aware, meaning it respects the lifecycle of other app components, such as activities, fragments, or services. This awareness ensures LiveData only updates app component observers that are in an active lifecycle state.

LiveData是一个可观察的数据持有者类。与可观察的常规程序不同,LiveData 是生命周期感知的,这意味着它遵循其他应用程序组件的生命周期,例如 Activity、fragments 或 services。确保 LiveData 只更新处于活动生命周期状态的应用程序组件观察者。

2. LiveData 的优点

2.1 确保 UI 和数据的统一

LiveData采用了观察者设计模式。当生命周期状态改变时,LiveData会通知Observer对象。

2.2 没有内存泄漏

观察者绑定到生命周期对象,并在其相关生命周期被破坏后自行清理。

2.3 当 Activity 停止时不会引起崩溃

当 Activity 处于非激活状态时,不会收到LiveData中数据变化的通知。

2.4 不需要额外的手动处理来响应生命周期的变化

LiveData 能够感知组件的生命周期,不需要在代码中告诉 LiveData 组件的生命周期状态。

2.5 组件和数据实时更新

如果一个对象的生命周期变到非活跃状态,它将在再次变为活跃状态时接收最新的数据。

2.6 配置更改

如果一个Activity或Fragment由于配置更改(如设备旋转)而重新创建,它会立即收到最新的可用数据。

2.7 资源共享

使用单例模式扩展LiveData对象并包装成系统服务,以便在应用程序中进行共享。LiveData对象一旦连接到系统服务,任何需要该资源的Observer都只需观察这个LiveData对象。

3. LiveData 的使用

在官方的例子中,LiveData对象通常存储在ViewModel对象中,并通过 get 方法访问:

package cn.zzw.livedatademo.viewmodel;

import androidx.lifecycle.MutableLiveData;
import androidx.lifecycle.ViewModel;

public class UserViewModel extends ViewModel {
    private MutableLiveData<String> name;

    public MutableLiveData<String> getUserName() {
        if (null == name) {
            name = new MutableLiveData<>();
        }
        return name;
    }

    public void setTask() {
        new Thread() {
            @Override
            public void run() {
                try {
                    Thread.sleep(3000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                getUserName().postValue("zuowei.zhang");
            }
        }.start();
    }

}
           

这里的 setTask 方法是模拟子线程请求数据,而 LiveData保存的数据和组件分离。LiveData提供了两种改变数据的方法:setValue()和postValue()。区别是setValue()要在主线程中调用,而postValue()既可在主线程也可在子线程中调用。

页面的布局文件:

<?xml version="1.0" encoding="utf-8"?>
<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"
    tools:context=".MainActivity">

    <TextView
        android:id="@+id/textview"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Hello World!"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintVertical_bias="0.120000005" />

    <Button
        android:id="@+id/button"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Button"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

</androidx.constraintlayout.widget.ConstraintLayout>
           

Activity 中进行调用:

package cn.zzw.livedatademo;

import androidx.appcompat.app.AppCompatActivity;
import androidx.lifecycle.Observer;
import androidx.lifecycle.ViewModelProviders;

import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;

import cn.zzw.livedatademo.viewmodel.UserViewModel;

public class MainActivity extends AppCompatActivity {
    TextView mTv;
    Button mBtn;
    UserViewModel mUser;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mTv = findViewById(R.id.textview);
        mBtn = findViewById(R.id.button);
        mUser = ViewModelProviders.of(this).get(UserViewModel.class);
        mUser.getUserName().observe(this, new Observer<String>() {
            @Override
            public void onChanged(String s) {
                mTv.setText(s);
            }
        });
        mBtn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                mUser.setTask();
            }
        });

    }
}
           

在 Activity 中通过 Observer 去观察数据的变换,当数据变换后且 Activity 处于活跃状态时候,就会通知 Activity。

如果给 Activity 加上打印生命周期的 log,以及点击获取数据的时候跳转到其他 Activity,会发现:当 Activity 生命周期处于 onStop() 状态的时候,Activity 是接收不到数据的变化,一旦重新进入 onResume(),则立马接收到消息。

2019-11-01 15:05:34.252 11896-11896/cn.zzw.livedatademo E/zzw: onResume()
2019-11-01 15:05:37.733 11896-11896/cn.zzw.livedatademo E/zzw: onPause()
2019-11-01 15:05:38.217 11896-11896/cn.zzw.livedatademo E/zzw: onStop()
2019-11-01 15:07:56.020 11896-11896/cn.zzw.livedatademo E/zzw: onChanged()
2019-11-01 15:07:56.022 11896-11896/cn.zzw.livedatademo E/zzw: onResume()
           

新的 Activity 代码如下所示:

package cn.zzw.livedatademo;

import androidx.appcompat.app.AppCompatActivity;
import androidx.lifecycle.Observer;
import androidx.lifecycle.ViewModelProviders;

import android.content.Intent;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;

import cn.zzw.livedatademo.viewmodel.UserViewModel;

public class MainActivity extends AppCompatActivity {
    TextView mTv;
    Button mBtn;
    UserViewModel mUser;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mTv = findViewById(R.id.textview);
        mBtn = findViewById(R.id.button);
        mUser = ViewModelProviders.of(this).get(UserViewModel.class);
        mUser.getUserName().observe(this, new Observer<String>() {
            @Override
            public void onChanged(String s) {
                Log.e("zzw", "onChanged()");
                mTv.setText(s);
            }
        });
        mBtn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                mUser.setTask();
                Intent intent = new Intent(MainActivity.this, SecondActivity.class);
                startActivity(intent);
            }
        });

    }

    @Override
    protected void onResume() {
        super.onResume();
        Log.e("zzw", "onResume()");
    }

    @Override
    protected void onPause() {
        super.onPause();
        Log.e("zzw", "onPause()");
    }

    @Override
    protected void onStop() {
        super.onStop();
        Log.e("zzw", "onStop()");
    }
}