banner
jzman

jzman

Coding、思考、自觉。
github

Android Jetpack元件之LiveData篇

PS:時間管理真的很重要,你管理得越好,你的自律能力就越高,共勉。

LiveData 是一個可觀察的數據持有者類,與常規 observable 不同,LiveData 是生命週期感知的,LiveData 也是 Android Jetpack 組件的一部分,本文將從如下幾個方面學習 LiveData:

  1. 什麼是 LiveData
  2. LiveData 的優點
  3. LiveData 的使用
  4. 自定義 Livedata
  5. LiveData 轉換

什麼是 LiveData#

LiveData 是一個可觀察的數據持有者類,與常規的 Observable 不同,LiveData 可感知 Activity、Fragment、Service 的生命週期,確保 LiveData 僅更新處於活動生命週期狀態的組件觀察者。

如果應用程序組件觀察者所處的狀態是 STARTED 或 RESUMED,則 LiveData 認為該組件處於活躍狀態,該組件會收到 LiveData 的數據更新,而其他註冊的組件觀察者將不會收到任何數據更新。

LiveData 的優點#

  • 保持 UI 與數據的一致性:LiveData 遵循觀察者設計模式,生命週期發生變化時,LiveData 會通知對應的應用程序組件 (Observer),數據發生變化時也會通知更新 UI.
  • 避免內存泄漏:這個 Observer 綁定了 Lifecycle 對象,當 Lifecycle 對象生命週期 destory 之後,這些 Observer 也會被自動清理。
  • 避免 Activity 處於不活躍狀態的時候產生崩潰:如果觀察者 (Observer) 處於不活躍狀態,則 Observer 不會接收任何 LiveData 事件。
  • 不在手動處理生命週期:UI 組件只是觀察相關數據,而不會停止或恢復觀察,LiveData 會根據具體生命週期的變化而自動管理。
  • 始終保持最新數據:如果生命週期為非活躍狀態,則會在由非活躍狀態轉為活躍狀態時接收最新數據,如從後台切換到前台自動接收最新數據。
  • 正確處理配置更改:如果 Activity 或 Fragment 因為設備配置發生變化而重新創建,比如螢幕旋轉等,也將會立即重新接收最新數據。
  • 共享服務:可以借助 LiveData 數據的觀察能力,根據 Livecycle 的生命週期狀態隨時連接或斷開服務。

LiveData 的使用#

在某個具體的 ViewModel 類中定義 LiveData 數據,然後在對應的 Activity 或 Fragment 中觀察 LiveData 數據的變化,LiveData 的使用使得我們不再將數據保存在 Activity 或 Fragment 中,而是將 LiveData 對象中存儲的數據保存在 ViewModel 中,減輕了 Activity 和 Fragment 的工作量,使得 Activity 和 Fragment 只負責界面管理和顯示,而不再保存數據,且在配置更改時數據不受影響。

LiceData 使用方式總結:

  1. 在 ViewModel 創建具體的 LiveData 實例來存儲數據,如下:
public class MViewModel extends ViewModel {
    private MutableLiveData<String> data;
    public LiveData<String> getData(){
        if (data == null){
            data = new MutableLiveData<>();
            data.postValue(DataUtil.getData());
        }
        return data;
    }
}
  1. 使用 LiveData 對象的 observe 或 observeForever 方法將對應的 Activity 或 Fragment 等添加為該 LiveData 對象的觀察者,如下:
@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    binding = DataBindingUtil.setContentView(this,R.layout.activity_main);
    MViewModel mViewModel = ViewModelProviders.of(this).get(MViewModel.class);
    mViewModel.getData().observe(this, new Observer<String>() {
        @Override
        public void onChanged(String msg) {
            binding.setData(msg);
        }
    });
}
  1. 使用 LiveData 的 setValue 或 postValue 更新數據,然後在觀察者,也就是 Activity 或 Fragment 中就獲取更新數據了,如下:
public void setData(String data) {
    mData.setValue(data);
}

那麼如何創建沒有 LifecycleOwner 的觀察者呢? 可以使用 LiveData 對象的 observeForever 方法來將一個沒有 LifecycleOwner 的類添加到觀察者列表中,如下:

public class NoLifecycleOwner {
    public void print(NViewModel viewModel, final TextView tvData){
        //使用observeForever對象創建沒有LifecycleOwner的觀察者
        viewModel.getData().observeForever(new Observer<String>() {
            @Override
            public void onChanged(String s) {
                tvData.setText("我是沒有LifecycleOwner的觀察者:"+s);
            }
        });
    }
}

不過使用 observeForever 獲得觀察者對象會一直處於活躍狀態,此時就需要我們手動調用 removeObserver (Observer) 移除該觀察者。

自定義 Livedata#

可以使用 LiveData 對象具有生命週期感知能力對外提供服務,可以很方便的控制服務的開啟和關閉,如下:

/**
 * 自定義LiveData
 * Powered by jzman.
 * Created on 2018/12/17 0017.
 */
public class CustomLiveData extends LiveData<String> {

    @Override
    protected void onActive() {
        //有活躍觀察者調用該方法
        //開啟服務...
    }

    @Override
    protected void onInactive() {
        //沒有任何活躍觀察者調用該方法
        //結束服務...
    }
}

LiveData 轉換#

Lifecycle 提供了工具類 Transformations 來對 LiveData 的數據類型進行轉換,可以在 LiveData 在數據返回給觀察者之前修改 LiveData 中數據的具體類型,比如 int 型數字 1、2 等轉化為中文大寫壹、贰等,那麼如何使用呢,創建 MapViewModel 如下:


/**
 * LiveData轉換
 * Powered by jzman.
 * Created on 2018/12/17 0017.
 */
public class MapViewModel extends ViewModel {
    private MutableLiveData<Integer> mPrice = new MutableLiveData<>();

    //Map
    private LiveData<String> mMapPrice = Transformations.map(mPrice, new Function<Integer, String>() {
        @Override
        public String apply(Integer input) {
            //返回String
            return Util.getNumberCapital(input);
        }
    });

    //SwitchMap
    private LiveData<String> mSwitchMapPrice = Transformations.switchMap(mPrice, new Function<Integer, LiveData<String>>() {
        @Override
        public LiveData<String> apply(Integer input) {
            //返回LiveData
            MutableLiveData<String> data = new MutableLiveData<>();
            data.postValue(Util.getNumberCapital(input));
            return data;
        }
    });

    public void setPrice(int price) {
        mPrice.setValue(price);
    }

    public LiveData<String> getPrice() {
        //Map
        return mMapPrice;
        //SwitchMap
//        return mSwitchMapPrice;
    }
}

然後,在 Activity 觀察數據的變化即可,如下:

public class MapActivity extends AppCompatActivity {
    private MapViewModel mapViewModel;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        final ActivityMapBinding binding = DataBindingUtil.setContentView(this,R.layout.activity_map);
        mapViewModel = new MapViewModel();
        mapViewModel.getPrice().observe(this, new Observer<String>() {
            @Override
            public void onChanged(String s) {
                //數字轉換為中文大寫
                binding.tvData.setText(s);
            }
        });
    }

    public void btnSetPrice1(View view) {
        mapViewModel.setPrice(1);
    }

    public void btnSetPrice2(View view) {
        mapViewModel.setPrice(2);
    }
}

Transformations 工具類中 map 和 switchMap 方法唯一的區別是 map 將 LiveData 數據轉換為具體的類型,如上述代碼中的 String,而 switchMap 則是 LiveData,上述代碼中 getNumberCapital 方法只是大小寫轉化的一個方法就不貼了,測試效果如下:

jzman-blog

map 方法和 switchMap 方法內部都是由 MediatorLiveData 參與轉換,可以自己使用 MediatorLiveData 來實現更多類似 map 、 switch 這樣的數據類型轉換。

載入中......
此文章數據所有權由區塊鏈加密技術和智能合約保障僅歸創作者所有。