Android架构组件-LiveData扩展使用

前言

LiveData的优势以及实现原理已经在上一篇中介绍,那么接下来接触一些扩展用法,从而更能体会该组件的设计意图,方便在业务中进行相应的扩展。

扩展LiveData

以下为股票价格监听StockLiveData,只有观察者生命周期处于STARTED或者RESUMED状态,则LiveData会认为观察者处于活跃状态,再进行相关连接操作,更新股价信息。这种实现规则与MediatorLiveData类似。

    public class StockLiveData extends LiveData<BigDecimal> {
        private StockManager stockManager;

        private SimplePriceListener listener = new SimplePriceListener() {
            @Override
            public void onPriceChanged(BigDecimal price) {
                //更新值,并将更改通知给任何活跃观察者
                setValue(price);
            }
        };

        public StockLiveData(String symbol) {
            stockManager = new StockManager(symbol);
        }

        //当StockLiveData有活跃对象时,会调用该方法。从而开始观察股价更新
        @Override
        protected void onActive() {
            stockManager.requestPriceUpdates(listener);
        }
        
        //当StockLiveData没有任何活跃观察者时,会调用该方法。由于没有观察者在监听,因此没有理由与StockManager服务保持连接
        @Override
        protected void onInactive() {
            stockManager.removeUpdates(listener);
        }
    }

可在UI控制器中进行如下调用:

    public class MyFragment extends Fragment {
        @Override
        public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
            super.onViewCreated(view, savedInstanceState);
            LiveData<BigDecimal> myPriceListener = ...;
            myPriceListener.observe(getViewLifeycleOwner(), price -> {
                // Update the UI.
            });
        }
    }

LiveData对象具有生命周期感知能力,意味着可以在多个Activity和Fragment之间共享这些对象,从而保证各个Activity或者Fragment随时拿到的值都是最新的值。为了达到共享,可以将LiveData设置为单一实例,如下所示:

    public class StockLiveData extends LiveData<BigDecimal> {
        private static StockLiveData sInstance;
        private StockManager stockManager;

        private SimplePriceListener listener = new SimplePriceListener() {
            @Override
            public void onPriceChanged(BigDecimal price) {
                setValue(price);
            }
        };

        @MainThread
        public static StockLiveData get(String symbol) {
            if (sInstance == null) {
                sInstance = new StockLiveData(symbol);
            }
            return sInstance;
        }

        private StockLiveData(String symbol) {
            stockManager = new StockManager(symbol);
        }

        @Override
        protected void onActive() {
            stockManager.requestPriceUpdates(listener);
        }

        @Override
        protected void onInactive() {
            stockManager.removeUpdates(listener);
        }
    }

可在不同的Fragment中使用,如下所示:

    public class MyFragment extends Fragment {
        @Override
        public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
            super.onViewCreated(view, savedInstanceState);
            StockLiveData.get(symbol).observe(getViewLifecycleOwner(), price -> {
                // Update the UI.
            });
        }
    }
    
    public class PriceFragment extends Fragment {
        @Override
        public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
            super.onViewCreated(view, savedInstanceState);
            StockLiveData.get(symbol).observe(getViewLifecycleOwner(), price -> {
                // Update the UI.
            });
        }
    }    
    

多个 Fragment 和 Activity 可以观察 MyPriceListener 实例。仅当一个或多个系统服务可见且处于活跃状态时,LiveData 才会连接到该服务。

LiveData-MediatorLiveData

MediatorLiveData,LiveData的子类,可观察指定LiveData对象,当其数据发生变化时,有且只有该MediatorLiveData有活跃观察者时,才会通知onChanged方法。接下来分析其实现原理:

public class MediatorLiveData<T> extends MutableLiveData<T> {
    //一个LiveData 对一个Source对象。
    private SafeIterableMap<LiveData<?>, Source<?>> mSources = new SafeIterableMap<>();
    
    
    
    //为目标LiveData添加Observer,当LiveData数据发生变化时,回调指定的Observer方法
    private static class Source<V> implements Observer<V> {
        final LiveData<V> mLiveData;
        final Observer<? super V> mObserver;
        int mVersion = START_VERSION;

        Source(LiveData<V> liveData, final Observer<? super V> observer) {
            mLiveData = liveData;
            mObserver = observer;
        }

        //添加Observer
        void plug() {
            mLiveData.observeForever(this);
        }

        //移除Observer
        void unplug() {
            mLiveData.removeObserver(this);
        }

        @Override
        public void onChanged(@Nullable V v) {
            if (mVersion != mLiveData.getVersion()) {
                mVersion = mLiveData.getVersion();
                mObserver.onChanged(v);
            }
        }
    }
    
    //添加source对象以及观察则Observer
    @MainThread
    public <S> void addSource(@NonNull LiveData<S> source, @NonNull Observer<? super S> onChanged) {
        Source<S> e = new Source<>(source, onChanged);
        Source<?> existing = mSources.putIfAbsent(source, e);
        if (existing != null && existing.mObserver != onChanged) {
            throw new IllegalArgumentException(
                    "This source was already added with the different observer");
        }
        if (existing != null) {
            return;
        }
        if (hasActiveObservers()) {
            e.plug();
        }
    }
    
    
    //下面这个两个方法非常重要,只有当前MediatorLiveData有活跃观察者时,LiveData的数据变化,addSource添加的onChanged 才会执行。
    @CallSuper
    @Override
    protected void onActive() {
        for (Map.Entry<LiveData<?>, Source<?>> source : mSources) {
            source.getValue().plug();
        }
    }

   //当前MediatorLiveData没有任何活跃观察者,会移除对对sourc LiveData的监听
    @CallSuper
    @Override
    protected void onInactive() {
        for (Map.Entry<LiveData<?>, Source<?>> source : mSources) {
            source.getValue().unplug();
        }
    }


    

MediatorLiveData也是一个LiveData,在使用的时候,需要调用observe或者observeForever添加观察者,这样当input LiveData的数据发生变化是,onChanged方法才会执行。

下面测试他的使用:

   public void onClick(View view) {
        if (view.getId() == R.id.btn_first) {
            liveData1.setValue(100+random.nextInt(10));
        } else if (view.getId() == R.id.btn_second) {
            liveData2.setValue(200+random.nextInt(10));
        }
    }

    // new liveData
    MediatorLiveData<Integer> liveDataMerger = new MediatorLiveData<>();
    //input liveData
    MutableLiveData<Integer> liveData1 = new MutableLiveData<>();
    MutableLiveData<Integer> liveData2 = new MutableLiveData<>();
    private void initMediator(){
      liveDataMerger.addSource(liveData1, new Observer<Integer>() {
            int count;
            @Override
            public void onChanged(Integer integer) {
                count++;
                liveDataMerger.setValue(integer);
                //大于10次后移除对liveData1的监听
                if(count > 10){
                    liveDataMerger.removeSource(liveData1);
                }
            }
        });
        liveDataMerger.addSource(liveData2, new Observer<Integer>() {
            @Override
            public void onChanged(Integer integer) {
                liveDataMerger.setValue(integer);
            }
        });
        //如果不为liveDataMerger添加观察者,即使liveData1或者liveData2的数据发生改变,addSource()方法的onChanged观察不会受到回调,以为不处于当前liveDataMerger不处于active状态,不会调用Source的plug()方法,为liveData1或者liveData2添加观察者
        liveDataMerger.observe(this, new Observer<Integer>() {
            @Override
            public void onChanged(Integer integer) {
                showToast("liveDataMerger data changed:"+integer.toString());
            }
        });

    }

    private void showToast(String msg){
        Toast.makeText(getApplicationContext(),msg,Toast.LENGTH_SHORT).show();
    }

Transformations 对LiveData进行转换处理

1,map

map对inputData的数据通过mapFunction处理,得到新的类型数据,并返回一个对应的LiveData。功能和RxJava的map操作符类似。其实现主要是借助MediatorLiveData实现的中转;

    @MainThread
    public static <X, Y> LiveData<Y> map(
            @NonNull LiveData<X> source,
            @NonNull final Function<X, Y> mapFunction) {
        //返回的新LiveData对象    
        final MediatorLiveData<Y> result = new MediatorLiveData<>();
        //添加观察,当source数据发生变化时,调用onChaged方法,再调用mapFunction对数据按照要求进行映射处理
        result.addSource(source, new Observer<X>() {
            @Override
            public void onChanged(@Nullable X x) {
                result.setValue(mapFunction.apply(x));
            }
        });
        return result;
    }

使用示例:

    private MutableLiveData<Integer> source = new MutableLiveData<Integer>();
    private void testMap(){
        Transformations.map(source, new Function<Integer, String>() {
            @Override
            public String apply(Integer input) {
                return "changed data "+input.toString();
            }
        }).observe(this, new Observer<String>() {
            @Override
            public void onChanged(String s) {
                showToast(s);
            }
        });
    }

1,switchMap

switchMap也是拿来做数据转换处理的,当source数据变化时,回调onChagned方法,再执行switchMapFunction,这里返回的是LiveData对象,再次监听新的LiveData数据变化,最后将值设置给result;

    @MainThread
    public static <X, Y> LiveData<Y> switchMap(
            @NonNull LiveData<X> source,
            @NonNull final Function<X, LiveData<Y>> switchMapFunction) {
        final MediatorLiveData<Y> result = new MediatorLiveData<>();
        //监听srouce数据变化
        result.addSource(source, new Observer<X>() {
            LiveData<Y> mSource;

            @Override
            public void onChanged(@Nullable X x) {
                //当source数据变化时,拿到对应的值,再由switchMapFunction进行处理
                LiveData<Y> newLiveData = switchMapFunction.apply(x);
                if (mSource == newLiveData) {
                    return;
                }
                if (mSource != null) {
                    result.removeSource(mSource);
                }
                mSource = newLiveData;
                if (mSource != null) {
                   //对switchMapFunction返回的LiveData对象进行数据监听
                    result.addSource(mSource, new Observer<Y>() {
                        @Override
                        public void onChanged(@Nullable Y y) {
                            //最终将值设置给result
                            result.setValue(y);
                        }
                    });
                }
            }
        });
        return result;
    }

使用示例:

  class UserViewModel extends AndroidViewModel {
      MutableLiveData<String> nameQueryLiveData = new MutableLiveData<>();
      
      public LiveData<List<String>> getUsersWithNameLiveData() {
          return Transformations.switchMap(
              nameQueryLiveData,
                  name -> myDataSource.getUsersWithNameLiveData(name));
      }
 
      public void setNameQuery(String name) {
          this.nameQueryLiveData.setValue(name);
      }
  }

switchMap的使用场景在ViewModel中经常使用,比如当调用myDataSource从网络或者room返回LiveData数据时,需要结合switchMap进行处理,最终将值回调给Fragment或者Activity进行处理。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值