Android 系统架构组件--LiveData

简介:

      LiveData 数据观察者持有类  拥有生命周期感应的特性  所以他实在对应组件的生命周期内(例如 activity  fragment service 等等)完成数据活动 

        liveDate 也可以理解成一个观察者 在被观察者(生命活动持有者)的生命周期处在onstart 或者onResume 的状态下 也就是active的状态下 可以接受到liveData的事件通知  再非active 的状态下 将无法接收到liveData的任何事件  那么这样就可以完全避免内存泄漏的风险了  

       那么下面的问题就是liveData怎么知道被观察者的生命状态呢  我们这里就要结合上篇文章中的lifecycle-aware来实现 不知道的小伙伴可以去翻下  这里就不给链接了   再上一篇中我们知道 只要你实现的lifecycleOwener 接口 那么就可以注册生命周期观察者 来感知被观察者生命周期的变化了 (PS: 对于activity和fragment 系统已经帮我们实现了lifecycleowner接口 ) 下面就简单了 我们只需要把我们的liveData 当做观察者注册到生命活动持有者(activity、fragment中就可以了 ) 是不是很简单  看不懂没关系 继续往下走就好了

 我们先看下liveData的优点:

使用LiveData提供以下优点:

  • 保证用户界面与数据状态匹配
    LiveData遵循观察者模式。在生命周期状态更改时LiveData会通知Observer对象。您可以升级代码在observer对象中更新UI,不必每次数据改变时手动更新UI,观察者可以在每次更改时更新UI。

  • 没有内存泄漏
    观察者与Lifecycle对象绑定,并在具有生命周期的对象被destroyed后自行清理。

  • 停止activities不会导致崩溃
    如果观察者的生命周期处于非活动状态,例如在后退堆栈中的活动,则不会收到任何LiveData事件。

  • 无需手动处理生命周期
    UI组件只是观察相关数据,不会停止或恢复观察。LiveData自动管理所有这些操作,因为在观察时它实时响应相关的生命周期状态的变化。

    扫描二维码关注公众号,回复: 1645187 查看本文章
  • 始终保持最新的数据
    如果生命周期变为非活动状态,它将在再次变为活动状态时接收到最新的数据。例如,后台活动在返回到前台后立即收到最新数据。

  • 正确的配置更改
    如果由于配置更改(如设备旋转)而重新创建活动或片段,则会立即收到最新的可用数据。

  • 共享资源
    可以使用单例模式来扩展LiveData对象来包装系统服务,以便它们可以在应用程序中共享。LiveData对象一旦连接到系统服务,然后其他任何需要系统资源的观察者只需要观看该LiveData 对象就可以。

看到这里是不是有些激动了  那我们写几个demo看下 是不是真的这么好用 :

 我们看下liveData的用法:

   1.在project build.gradle中添加google()仓库引用

repositories {
    google()
    jcenter()
}

2. 在app build.gradle中添加插件引用

// ViewModel and LiveData
implementation "android.arch.lifecycle:extensions:1.1.1"
// alternatively, just ViewModel
implementation "android.arch.lifecycle:viewmodel:1.1.1"
// alternatively, just LiveData
implementation "android.arch.lifecycle:livedata:1.1.1"

3.下面我们开始码代码

 PS:一般liveData 对象一般存储在VIewModel中  关于ViewModel 我们下一章中会具体介绍 

那么首先我们先创建 ViewModel 来保存 LiveData对象 

public class MyViewModel extends ViewModel {

    /**
     * liveData 对象MutableLiveData LiveData(抽象类)的子类
     */
    private MutableLiveData<String> mutableLiveData;

    public MutableLiveData<String> getCurrentName() {
        if (mutableLiveData == null) {
            mutableLiveData = new MutableLiveData<>();
        }
        return mutableLiveData;
    }

}

PS:这里我们使用了系统提供的MutableLiveData 创建liveData实例  这里我要说下 所谓liveData对象 只需要继承LiveData的类创建出来的都是LiveData 再后面我们会自己定义LiveData对象 这里不多说

 创建了LiveData对象 并存储在ViewModel中 之后我们需要一个被观察者(生命周期持有者) 这里我们使用Activity当demo

创建ViewModel 对象 然后将注册生命周期持有者   这样我们就将 生命周期持有者 和liveData 关联起来了 

我们再onResume中 模拟了 数据变化的过程 具体运行结果 看你喽 如果还是不懂没关系 继续 

public class MainActivity extends AppCompatActivity {

    private static final String TAG = "lifeCycle";
    private MyViewModel myViewModel;
    private int count = 0;

    @Override

    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        //        获取ModelView对象
        myViewModel = ViewModelProviders.of(this).get(MyViewModel.class);
        addLiveDataObject();
    }
    /**
     * 添加liveData观察对象
     * 一般放在oncreate中执行 为了防止反复执行
     */
    private void addLiveDataObject() {
//        注册观察者(生命周期活动持有者 在这里就是我们的activity) 观察行为(当接收到livedata通知之后的相应行为)
//        完成之后 我们再onResume中更新下数据
        myViewModel.getCurrentName().observe(this, observer);
    }

    Observer<String> observer = new Observer<String>() {
        @Override
        public void onChanged(@Nullable String s) {
//            livedata 通知之后的行为  这里可以进行UI更新 比如 textView.setText(s)啥的 不做了
            Log.d(TAG, "onChanged=" + s);
        }
    };

    @Override
    protected void onResume() {
        super.onResume();
        count++;
        myViewModel.getCurrentName().setValue("dataChangeCount=" + count);
        Log.d(TAG, "onResume");
    }



    @Override
    protected void onStart() {
        super.onStart();
        Log.d(TAG, "onStart");
    }

    @Override
    protected void onPause() {
        super.onPause();
        Log.d(TAG, "onPause");
    }

    @Override
    protected void onStop() {
        super.onStop();
        Log.d(TAG, "onStop");
    }

}

上面的用法 我们都看了一下 关于用法有了大概了解 但是 很懵懂吧  那么下面我们自己定义一个liveData 估计你就很清楚了

1.创建股价波动类模拟真实数据获取

public interface SimplePriceChangeListener {
    void onChange(int price);
}

public class StockManager {
    public void requestPriceUpdate(final SimplePriceChangeListener mListener) {
        new Thread(new Runnable() {
            @Override
            public void run() {
//                模拟股市波动 1股每1s 1块钱 高兴
                for (int i = 0; i < 50; i++) {
                    SystemClock.sleep(1000);
                    if (mListener != null) {
                        mListener.onChange(i + 100);
                    }
                }
            }
        }).start();
    }

    public void removeListener(SimplePriceChangeListener mListener) {
//        随意写
        mListener = null;
    }
}
当请求估计的时候 我们模拟网络请求返回 这里再看不懂 借你我的长发 

2.自定义liveData(这次我们不在使用系统现有的 ) 

刚刚我们说过 需要继承LiveData 那么就不得不说liveData的两个方法 

onActive onInactive 我们上面已经说过 当被观察者处在active状态的时候可以接受liveData的通知 处在inActive 的状态下 接受不到   那么我们这里的onActive onInactive两个方法 大家应该知道是什么鬼了吧  就是对应被观察者的生命周期状态  一般我们再active中完成数据的实时更新 再Inactive中完成监听的移除等等操作(就像onDestory的用处一样)

废话少说 上代码

public class StockLiveData extends LiveData<Integer> {
    private StockManager mStokeManager;

    private SimplePriceChangeListener mListener = new SimplePriceChangeListener() {
        @Override
        public void onChange(int price) {
//            因为onchange我们再子线程里面调用的 这里我们不适用 setValue
            postValue(price);
        }
    };

    public StockLiveData() {
        this.mStokeManager = new StockManager();
    }

    @Override
    protected void onActive() {
        super.onActive();
        mStokeManager.requestPriceUpdate(mListener);
    }

    @Override
    protected void onInactive() {
        super.onInactive();
        mStokeManager.removeListener(mListener);
    }
}
 
 

这里我们出现了postValue()方法 上面我们模拟值得时候用的setValue  这里说下两个方法  都是用来发送值变化事件的  但是 如果你当前线程是主线程 那么就使用setValue 如果是子线程 那么就用postValue 像不像Handler  哈哈~我自己瞎想的

那么下面我们像上面一样 将liveData添加到ViewModel中 

public class MyViewModel extends ViewModel {

    /**
     * liveData 对象MutableLiveData LiveData(抽象类)的子类
     */
    private MutableLiveData<String> mutableLiveData;
    private StockLiveData mStockLiveData;

    public MutableLiveData<String> getCurrentName() {
        if (mutableLiveData == null) {
            mutableLiveData = new MutableLiveData<>();
        }
        return mutableLiveData;
    }

    public StockLiveData getCustomLiveDataName() {
        if (mStockLiveData == null) {
            mStockLiveData = new StockLiveData();
        }
        return mStockLiveData;
    }

}

这里 大概大家就能大概明白一样 VIewModel 岁LiveData进行统一管理了吧   

下一步 和被观察者关联

public class MainActivity extends AppCompatActivity {

    private static final String TAG = "lifeCycle";
    private MyViewModel myViewModel;
    private int count = 0;

    @Override

    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
//        addLifeCycleObserve();
        //        获取ModelView对象
        myViewModel = ViewModelProviders.of(this).get(MyViewModel.class);
//        addLiveDataObject();
//        按照之前的步骤 搞定
        addCustomLiveDataObject();
    }

    private void addCustomLiveDataObject() {
        myViewModel.getCustomLiveDataName().observe(this, customObserver);
    }

    Observer<Integer> customObserver = new Observer<Integer>() {
        @Override
        public void onChanged(@Nullable Integer integer) {
            Log.d(TAG, "current price=" + integer);
        }
    };

    /**
     * 添加liveData观察对象
     * 一般放在oncreate中执行 为了防止反复执行
     */
    private void addLiveDataObject() {
//        注册观察者(生命周期活动持有者 在这里就是我们的activity) 观察行为(当接收到livedata通知之后的相应行为)
//        完成之后 我们再onResume中更新下数据
        myViewModel.getCurrentName().observe(this, observer);
    }

    Observer<String> observer = new Observer<String>() {
        @Override
        public void onChanged(@Nullable String s) {
//            livedata 通知之后的行为  这里可以进行UI更新 比如 textView.setText(s)啥的 不做了
            Log.d(TAG, "onChanged=" + s);
        }
    };

    @Override
    protected void onResume() {
        super.onResume();
        count++;
        myViewModel.getCurrentName().setValue("dataChangeCount=" + count);
        Log.d(TAG, "onResume");
    }



    @Override
    protected void onStart() {
        super.onStart();
        Log.d(TAG, "onStart");
    }

    @Override
    protected void onPause() {
        super.onPause();
        Log.d(TAG, "onPause");
    }

    @Override
    protected void onStop() {
        super.onStop();
        Log.d(TAG, "onStop");
    }

    /**
     * 注册生命周期观察者
     */
    private void addLifeCycleObserve() {
        MyObserver myObserver = new MyObserver();
        getLifecycle().addObserver(myObserver);
    }

}
 
 

为了做对比我放在了 刚刚的mainActivity中了  和刚刚步骤一样只是这次获取的是自定义LiveData对象 那么我们跑下

03-26 16:12:02.485 27899-27899/com.example.lifeapplication D/lifeCycle: current price=100
03-26 16:12:03.486 27899-27899/com.example.lifeapplication D/lifeCycle: current price=101
03-26 16:12:04.487 27899-27899/com.example.lifeapplication D/lifeCycle: current price=102
03-26 16:12:04.959 27899-27899/com.example.lifeapplication D/lifeCycle: onPause
03-26 16:12:04.982 27899-27899/com.example.lifeapplication D/lifeCycle: onStop
03-26 16:12:07.068 27899-27899/com.example.lifeapplication D/lifeCycle: onStart
03-26 16:12:07.069 27899-27899/com.example.lifeapplication D/lifeCycle: current price=104
03-26 16:12:07.070 27899-27899/com.example.lifeapplication D/lifeCycle: onResume
03-26 16:12:07.487 27899-27899/com.example.lifeapplication D/lifeCycle: current price=105
03-26 16:12:08.070 27899-27899/com.example.lifeapplication D/lifeCycle: current price=100
03-26 16:12:08.488 27899-27899/com.example.lifeapplication D/lifeCycle: current price=106
03-26 16:12:08.534 27899-27899/com.example.lifeapplication D/lifeCycle: onPause
03-26 16:12:08.552 27899-27899/com.example.lifeapplication D/lifeCycle: onStop
03-26 16:12:13.475 27899-27899/com.example.lifeapplication D/lifeCycle: onStart

03-26 16:12:13.476 27899-27899/com.example.lifeapplication D/lifeCycle: current price=105

大家发现了吧 当生命活动是inactive的时候 没有接收到数据变化 但是数据仍然在更新  当active的时候 能够立即获取到数据  怎么样 方便吗? 大概 懂一点了   那我们继续


关于liveData 转换 

很多时候我们会用到 请求到的是一个实体类 我们需要的是String 串 关于liveData 系统给我们提供了转换规则 

1.Transformations.switchMap()

这里我就直接简写了

public class MyViewModel extends ViewModel {

    /**
     * liveData 对象MutableLiveData LiveData(抽象类)的子类
     */
    private MutableLiveData<String> mutableLiveData;
    private StockLiveData mStockLiveData;

    public MutableLiveData<String> getCurrentName() {
        if (mutableLiveData == null) {
            mutableLiveData = new MutableLiveData<>();
        }
        return mutableLiveData;
    }

    public StockLiveData getCustomLiveDataName() {
        if (mStockLiveData == null) {
            mStockLiveData = new StockLiveData();
        }
        return mStockLiveData;
    }

    public LiveData<String> getStringLiveData() {
        return Transformations.map(mStockLiveData, String::valueOf);
    }

}

具体使用方式和之前的是一样的  

2.Transformations.switchMap()

类似于Map(),对存储在LiveData对象中的值应用一个函数,打开并分派结果数据流。传递给switchMap()的方法必须返回一个

关于这个方法的官方说法 我没有看懂  随便写个demo 实现  暂时放着 接下来 我们看下 这个方法的实际意义

public LiveData<User> getSwitchLiveData() {
    MutableLiveData<String> userMutableLiveData = new MutableLiveData<>();
    userMutableLiveData.setValue("Tom");
    return Transformations.switchMap(userMutableLiveData, name -> getUser(name));
}

private LiveData<User> getUser(String name) {
    MutableLiveData<User> userMutableLiveData = new MutableLiveData<>();
    userMutableLiveData.setValue(new User(name, 18));
    return null;
}

PS:这种转化 是惰性的  如果当前生命周期持有者 处于active状态 需要获取当前数据  那么才会进行转换  

我们先写一个 demo

如果我们有一个获取地址返回邮政编码的组件  我们很有可能这样写

 
 
public LiveData<String> getPostalCodeLiveData(String addressName) {
    return PostalCodeResp.getPostalCode(addressName);
}
public static LiveData<String> getPostalCode(String addressName) {
    String postalCode = "邮政编码:" + addressName;
    return new LiveData<String>() {
        @Override
        protected void onActive() {
            super.onActive();
            setValue(postalCode);
        }
    };
}

如果是这样的话 当UI组件销毁重建的时候 我们就会触发 getPostalCode方法 而不是使用先前调用的结果 但是我们的邮政编码是finial的  如果地址一样我们只需要返回之前 回调结果  只有当地址发生变化的时候 我们才需要去调用获取方法  所以  我们队这段代码进行优化 

private  PostalCodeResp repository;
private final MutableLiveData<String> addressInput = new MutableLiveData();
public final LiveData<String> postalCode =
        Transformations.switchMap(addressInput, (address) -> repository.getPostalCode(address));

private void setInput(String address) {
    addressInput.setValue(address);
}

这样的话 只有setInput 被调用重置地址的时候 我们的getPostalCode 方法 才会调用 这样是不是省了一点开销

关于转换规则 我们就整到这   创建新的转化规则以及合并liveData源 我就不在这里进行更多的讲解了  如果有需要可以去develop官网上面继续了解  我们下面继续说ViewModel~ 加油 ~

猜你喜欢

转载自blog.csdn.net/youth_never_go_away/article/details/79655405