Android跨界面共享數據——LiveData應用

業務場景

ezgif.com-video-to-gif.gif

3個界面中有3個獨立控件,須要同步他們的狀態,即其中任一控件狀態變化,其他兩個隨之而變。git

解決方案

1. 傳遞值:startActivityForResult() + onActivityResult()

這是最容易想到的方案,實現步驟以下:github

  • 在界面A將控件狀態封裝在Intent
  • 在界面A經過startActivityForResult()跳轉到界面B
  • 在界面A返回以前經過setResult()將控件狀態返回給界面A
  • 在界面A的onActivityResult()中獲取控件狀態並更新UI

但該方案有缺點:bash

  1. 代碼可讀性較差,特別是當onActivityResult()中還夾雜着其餘業務邏輯。
  2. 增長了Activity間的耦合(即Activiy B依賴於Activity A的特殊傳值方式,Activity A依賴於Activity B的回傳值)。由於界面間是兩兩耦合的,因此也致使了擴展性較差,若是需求改爲「從Activity A直接跳轉到Activity B」,須要從新出處理Activity AActivity B的跳轉邏輯。

2. 共享值(持久化)

既然經過傳遞值的方式不夠好,那直接「共享值」呢?即將每次狀態改變都持久化(存在本地),每次繪製界面都從本地讀取狀態。服務器

設想界面A中有一個列表,每一個表項都包含一個須要狀態同步的控件,當服務器返回一批新數據後,須要挨個將數據進行存儲,隨着列表不斷刷新,本地存儲的內容就不斷增多,爲控制本地存儲佔用的空間,在 App 退出時需清空本地存儲。dom

3. 共享值(LiveData)

既然在 App 退出時須要清空數據,則代表控件狀態信息的生命週期和 App 的生命週期同步,而持久化解決的問題是生命週期長於 App 生命週期的狀況。因而第三個解決方案就閃亮登場了~~~ide

LiveData是谷歌在Google I/O 2017發佈的Android Architecture Components(Google教你如何寫 App 系列)中的一項內容。post

對於當前這個case,LiveData充當以下角色:ui

  • LiveData是一個數據持有者,但不像通常的數據持有者,它能夠感知系統組件的生命週期。
  • LiveData能夠被觀察,但它不像通常的觀察者模式(一有數據變更就通知全部觀察者)。只有當被觀察者處於激活狀態時才被通知。

因此基於LiveData的解決方案以下:將控件狀態信息保存在LiveData中,三個不一樣的界面分別觀察LiveDatathis

經過觀察者模式將方案1中數據傳遞問題轉換爲數據共享,三個界面沒有絲毫耦合。將LiveData設置爲單例,使其和 App 生命週期相一致,也避免了開闢額外的本地存儲。spa

LiveData應用

1. 建立狀態信息實體類

將要共享的狀態信息封裝成實體類,簡單起見,demo將狀態信息設置爲int值,以下:

public class Status {
    private int level;

    public int getLevel() {
        return level;
    }

    public void setLevel(int level) {
        this.level = level;
    }
}
複製代碼

2. 建立LiveData單例

下面的代碼只是將狀態信息實體類和LiveData關聯,並將LiveData定義爲單例,方便跨界面使用。

public class StatusLiveData extends MutableLiveData<Status> {
    private StatusLiveData() {
    }

    private static class Holder {
        public static final StatusLiveData INSTANCE = new StatusLiveData();
    }

    public static StatusLiveData getInstance() {
        return Holder.INSTANCE;
    }
}

//MutableLiveData在LiveData基礎上暴露兩個設值接口
public class MutableLiveData<T> extends LiveData<T> {
    @Override
    public void postValue(T value) {
        super.postValue(value);
    }

    @Override
    public void setValue(T value) {
        super.setValue(value);
    }
}
複製代碼

3. 爲LiveData添加觀察者

LiveData的觀察者一般是帶有生命週期概念的組件,好比Activity,Fragment等等。觀察者需實現Observer<T>接口,以定義數據變化時作出的響應。

public class ActivityA extends AppCompatActivity implements View.OnClickListener, Observer<Status> {
    private int level;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        ...
        StatusLiveData.getInstance().observe(this, this);
    }
    
    ...
    
    @Override
    public void onChanged(@Nullable Status status) {
        /**
         * get status data when it is changed and update UI
         */
        int level = status.getLevel();
        changeArrowStatus(level);
    }
}
複製代碼

4. 更新LiveData

最後一步就是在狀態值變化時候調用LiveData.setValue()更新數據。這裏的邏輯和具體業務相關,demo中的業務場景是點擊ImageView控件時改變其圖片。

public class ActivityB extends AppCompatActivity implements View.OnClickListener, Observer<Status> {
    private int level;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        ...
        findViewById(R.id.iv_arrow).setOnClickListener(this);
        ...
    }

    @Override
    public void onClick(View v) {
        int id = v.getId();
        switch (id) {
            ...
            case R.id.iv_arrow:
                changeArrowStatus(++level);
                putStatus(level);
                break;
        }
    }

    /**
     * put status data into LiveData when data is changed
     */
    private void putStatus(int level) {
        Status status = new Status();
        status.setLevel(level);
        StatusLiveData.getInstance().setValue(status);
    }

    private void changeArrowStatus(int level) {
        ImageView ivArrow = findViewById(R.id.iv_arrow);
        LevelListDrawable levelListDrawable = ((LevelListDrawable) ivArrow.getDrawable());
        levelListDrawable.setLevel(level % 2);
    }
}
複製代碼

talk is cheap, show me the code

拋磚引玉,若你們有更好的方案,歡迎交流~~

相關文章
相關標籤/搜索