LiveData概述

LiveData 是一個可觀察的數據持有者類。
與常規observable不同,LiveData是生命週期感知的,這意味着它尊重其他應用程序組件的生命週期,例如活動,片段或服務。
此感知確保LiveData僅更新處於活動生命週期狀態的應用程序組件觀察者

注意:要將LiveData組件導入Android項目

LiveData將一個由Observer類表示的觀察者視爲生命週期處於STARTED或處於狀態時處於活RESUMED狀態。LiveData僅通知活動觀察者有關更新的信息。註冊觀察LiveData對象的非活動觀察者不會收到有關更改的通知

您可以註冊與實現該LifecycleOwner接口的對象配對的觀察者。此關係允許在相應Lifecycle對象的狀態更改爲時刪除觀察者DESTROYED。這對於活動和片段特別有用,因爲它們可以安全地觀察LiveData對象而不用擔心泄漏 - 活動和片段在其生命週期被破壞時立即取消訂閱。

一 使用LiveData的優點
使用LiveData具有以下優勢:
1.確保您的UI符合您的數據狀態LiveData遵循觀察者模式。Observer生命週期狀態更改時,LiveData會通知對象。您可以合代碼以更新這些Observer對象中的UI。每次應用程序數據更改時,您的觀察者都可以在每次更改時更新UI,而不是更新UI。
2..沒有內存泄漏觀察者綁定Lifecycle對象並在其相關生命週期被破壞後自行清理。
3..由於停止活動而沒有崩潰如果觀察者的生命週期處於非活動狀態(例如,在後端堆棧中的活動的情況下),則它不會接收任何LiveData事件。
4.不再需要手動生命週期處理UI組件只是觀察相關數據,不會停止或恢復觀察。LiveData自動管理所有這些,因爲它在觀察時意識到相關的生命週期狀態變化。
5.始終保持最新數據如果生命週期變爲非活動狀態,則會在再次變爲活動狀態時接收最新數據。例如,後臺活動在返回前臺後立即收到最新數據。
6.適當的配置更改如果由於配置更改(例如設備輪換)而重新創建活動或片段,則會立即接收最新的可用數據。
7.共享資源您可以LiveData使用單例模式擴展對象以包裝系統服務,以便可以在應用程序中共享它們。該LiveData對象連接到系統服務一次,然後任何需要該資源的觀察者只能觀察該LiveData對象。
二 使用LiveData對象
請按照以下步驟處理LiveData對象:
1.創建一個LiveData用於保存特定類型數據的實例。這通常在您的ViewModel班級內完成。
2.創建一個Observer定義onChanged()方法的對象,該對象控制LiveData對象保持數據更改時發生的情況。您通常Observer在UI控制器中創建一個對象,例如活動或片段。
3.使用該方法將Observer對象附加到對象。該方法採用一個對象。這會將對象訂閱到對象,以便通知其更改。您通常將對象附加到UI控制器中,例如活動或片段。LiveDataobserve()observe()LifecycleOwnerObserverLiveDataObserver
注意:您可以LifecycleOwner使用該observeForever(Observer)方法註冊沒有關聯對象的觀察者。在這種情況下,觀察者被認爲始終處於活動狀態,因此始終會收到有關修改的通知。您可以刪除調用該removeObserver(Observer)方法的這些觀察者。
更新存儲在LiveData對象中的值時,只要附加LifecycleOwner的處於活動狀態,它就會觸發所有已註冊的觀察者。LiveData允許UI控制器觀察者訂閱更新。當LiveData對象保存的數據發生更改時,UI會自動更新響應。
2.1創建LiveData對象
LiveData是一個包裝器,可以與任何數據一起使用,包括實現的對象Collections,例如List。甲LiveData對象通常存儲一個內ViewModel對象,並且經由吸氣劑的方法被訪問,如下面的示例所示:

public class NameViewModel extends ViewModel {

// Create a LiveData with a String
private MutableLiveData<String> mCurrentName;

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

// Rest of the ViewModel...
}

最初,LiveData未設置對象中的數據。
注意:確保存儲在LiveData對象中更新UI的ViewModel對象,而不是活動或片段,原因如下:

  • 避免臃腫的活動和碎片。現在,這些UI控制器負責顯示數據但不保持數據狀態。
  • 將LiveData實例與特定活動或片段實例分離,並允許LiveData對象在配置更改後繼續存在。您可以ViewModel在ViewModel指南中閱讀有關該類的好處和用法的更多信息。
    2.2觀察LiveData對象
    .在大多數情況下,app組件的onCreate()方法是開始觀察LiveData對象的正確位置,原因如下:
  • 確保系統不會從活動或片段的onResume()方法進行冗餘調用。
  • 確保活動或片段具有可在其變爲活動狀態時立即顯示的數據。只要應用程序組件處於該STARTED狀態,它就會從LiveData它正在觀察的對象中接收最新值。
    只有LiveData在設置了要觀察的對象時纔會出現這種情況。
    通常,LiveData僅在數據更改時才提供更新,並且僅在活動觀察者時提供更新。此行爲的一個例外是觀察者在從非活動狀態更改爲活動狀態時也會收到更新。此外,如果觀察者第二次從非活動狀態更改爲活動狀態,則只有在自上次活動狀態以來該值發生更改時纔會收到更新。以下示例代碼說明了如何開始觀察LiveData對象:

    public class NameActivity extends AppCompatActivity {
    
    private NameViewModel mModel;
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
    
        // Other code to setup the activity...
    
        // Get the ViewModel.
        mModel = ViewModelProviders.of(this).get(NameViewModel.class);
    
        // Create the observer which updates the UI.
        final Observer<String> nameObserver = new Observer<String>() {
            @Override
            public void onChanged(@Nullable final String newName) {
                // Update the UI, in this case, a TextView.
                mNameTextView.setText(newName);
            }
        };
    
        // Observe the LiveData, passing in this activity as the LifecycleOwner and the observer.
        mModel.getCurrentName().observe(this, nameObserver);
    }
    }

    observe()調用nameObserverafter作爲參數傳遞後,onChanged()立即調用,提供存儲的最新值mCurrentName。如果LiveData對象未設置值mCurrentName,onChanged()則不調用。
    2.3更新LiveData對象
    LiveData沒有公開的方法來更新存儲的數據。本MutableLiveData類公開setValue(T)和postValue(T)方法公開,如果你需要編輯存儲在一個值,你必須使用這些LiveData對象。通常MutableLiveData用於ViewModel然後將ViewModel唯一的不可變LiveData對象暴露給觀察者。
    設置觀察者關係後,您可以更新LiveData對象的值,如以下示例所示,當用戶點擊按鈕時觸發所有觀察者:

    mButton.setOnClickListener(new OnClickListener() {
    @Override
    public void onClick(View v) {
        String anotherName = "John Doe";
        mModel.getCurrentName().setValue(anotherName);
    }
    });

    調用setValue(T)示例會導致觀察onChanged()使用值調用其方法John Doe。該示例示出了按鈕下,但setValue()還是postValue()可以被調用以更新mName爲各種各樣的原因,包括響應於網絡請求或數據庫負荷完成;在所有情況下,調用setValue(或postValue()觸發觀察者並更新UI。
    注意:您必須調用setValue(T)方法以LiveData從主線程更新對象。如果代碼在工作線程中行,則可以使用該postValue(T)方法來更新LiveData對象。
    2.3與房間一起使用LiveData
    該廳持久庫支持可觀察到的查詢,這回LiveData對象。可觀察查詢作爲數據庫訪問對象(DAO)的一部分編寫。
    在更新LiveData數據庫時,Room會生成更新對象所需的所有代碼。生成的代碼在需要時在後臺線程上異步運行查詢。此模式對於使UI中顯示的數據與存儲在數據庫中的數據保持同步非常有用。您可以在Room持久性庫指南中閱讀有關Room和DAO的更多信息。
    三 擴展LiveData
    如果觀察者的生命週期處於STARTED或RESUMED狀態,LiveData會將觀察者視爲處於活動狀態。以下示例代碼說明了如何擴展LiveData該類:

    public class StockLiveData extends LiveData<BigDecimal> {
    private StockManager mStockManager;
    
    private SimplePriceListener mListener = new SimplePriceListener() {
        @Override
        public void onPriceChanged(BigDecimal price) {
            setValue(price);
        }
    };
    
    public StockLiveData(String symbol) {
        mStockManager = new StockManager(symbol);
    }
    
    @Override
    protected void onActive() {
        mStockManager.requestPriceUpdates(mListener);
    }
    
    @Override
    protected void onInactive() {
        mStockManager.removeUpdates(mListener);
    }
    }

    此示例中價格監聽器的實現包括以下重要方法:onActive()當LiveData對象具有活動觀察者時調用該方法。這意味着您需要從此方法開始觀察股票價格更新。onInactive()當LiveData對象沒有任何活動觀察者時調用該方法。由於沒有觀察者正在傾聽,因此沒有理由保持與StockManager服務的連接。該setValue(T)方法更新LiveData實例的值,並通知任何活動的觀察者有關更改的信息。您可以StockLiveData按如下方式使用該類:

public class MyFragment extends Fragment {
    @Override
    public void onActivityCreated(Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);
        LiveData<BigDecimal> myPriceListener = ...;
        myPriceListener.observe(this, price -> {
            // Update the UI.
        });
    }
}

該observe()方法將片段(它是一個實例LifecycleOwner)作爲第一個參數傳遞。這樣做表示此觀察者綁定到Lifecycle與所有者關聯的對象,這意味着:

  • 如果Lifecycle對象未處於活動狀態,則即使值發生更改,也不會調用觀察者。
  • 在之後Lifecycle的對象被破壞,觀察者被自動刪除。
    LiveData對象具有生命週期感知這一事實意味着您可以在多個活動,片段和服務之間共享它們。爲了使示例簡單,您可以將LiveData類實現爲單例,如下所示:

    public class StockLiveData extends LiveData<BigDecimal> {
    private static StockLiveData sInstance;
    private StockManager mStockManager;
    
    private SimplePriceListener mListener = 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) {
        mStockManager = new StockManager(symbol);
    }
    
    @Override
    protected void onActive() {
        mStockManager.requestPriceUpdates(mListener);
    }
    
    @Override
    protected void onInactive() {
        mStockManager.removeUpdates(mListener);
    }
    }

    您可以在片段中使用它,如下所示:

    public class MyFragment extends Fragment {
    @Override
    public void onActivityCreated(Bundle savedInstanceState) {
        StockLiveData.get(symbol).observe(this, price -> {
            // Update the UI.
        });
    }
    }

    多個片段和活動可以觀察MyPriceListener實例。LiveData僅在系統服務中的一個或多個可見且處於活動狀態時才連接到系統服務。
    四 轉換LiveData
    您可能希望在將LiveData對象分發給觀察者之前對其中存儲的值進行更改,或者您可能需要
    LiveData根據另一個實例的值返回其他實例。該Lifecycle包提供了Transformations包含支持這些方案的輔助方法的類。 
    對存儲在LiveData對象中的值應用函數,並將結果傳播到下游。

LiveData<User> userLiveData = ...;
LiveData<String> userName = Transformations.map(userLiveData, user -> {
    user.name + " " + user.lastName
});

Transformations.switchMap()
類似於map(),將函數應用於存儲在LiveData對象中的值,並向下遊解包和調度結果。傳遞給的函數switchMap()必須返回一個LiveData對象,如下例所示

private LiveData<User> getUser(String id) {
  ...;
}

LiveData<String> userId = ...;
LiveData<User> user = Transformations.switchMap(userId, id -> getUser(id) );

您可以使用轉換方法在觀察者的生命週期中傳遞信息。除非觀察者正在觀察返回的LiveData對象,否則不會計算變換。因爲轉換是懶惰地計算的,所以與生命週期相關的行爲被隱式傳遞而不需要額外的顯式調用或依賴。
如果您認爲Lifecycle對象內部需要ViewModel對象,則轉換可能是更好的解決方案。例如,假設您有一個接受地址的UI組件並返回該地址的郵政編碼。您可以ViewModel爲此組件實現naive,如以下示例代碼所示:

class MyViewModel extends ViewModel {
    private final PostalCodeRepository repository;
    public MyViewModel(PostalCodeRepository repository) {
       this.repository = repository;
    }

    private LiveData<String> getPostalCode(String address) {
       // DON'T DO THIS
       return repository.getPostCode(address);
    }
}

然後,UI組件需要從前一個LiveData對象取消註冊,並在每次調用時註冊到新getPostalCode()。此外,如果重新創建UI組件,它將觸發對repository.getPostCode()方法的另一次調用,而不是使用先前調用的結果。相反,您可以將郵政編碼查找實現爲地址輸入的轉換,如以下示例所示:

class MyViewModel extends ViewModel {
    private final PostalCodeRepository repository;
    private final MutableLiveData<String> addressInput = new MutableLiveData();
    public final LiveData<String> postalCode =
            Transformations.switchMap(addressInput, (address) -> {
                return repository.getPostCode(address);
             });

  public MyViewModel(PostalCodeRepository repository) {
      this.repository = repository
  }

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

在這種情況下,postalCode字段是public和final,因爲字段永遠不會更改。該postalCode字段被定義爲轉換addressInput,這意味着repository.getPostCode()在addressInput更改時調用該方法。如果有一個活動的觀察者,如果當時沒有活動的觀察者repository.getPostCode()被調用,則這是真的,在添加觀察者之前不進行任何計算。
此機制允許較低級別的應用程序創建LiveData根據需要延遲計算的對象。甲ViewModel對象可以容易地獲得以引用LiveData的對象,然後在它們的頂部限定的變換規則。
4.1創建新的轉換
.在您的應用中有十幾種不同的特定轉換可能很有用,但默認情況下不提供它們。要實現自己的轉換,您可以使用MediatorLiveData該類,該類偵聽其他LiveData對象並處理它們發出的事件。MediatorLiveData正確地將其狀態傳播到源LiveData對象。要了解有關此模式的更多信息,請參閱Transformations該類的參考文檔。
五 合併多個LiveData源
MediatorLiveData是一個子類LiveData,允許您合併多個LiveData源。MediatorLiveData
只要任何原始LiveData源對象發生更改,就會觸發對象的觀察者。
例如,如果LiveDataUI中有一個可以從本地數據庫或網絡更新的對象,則可以將以下源添加到該MediatorLiveData對象:

  • LiveData與存儲在數據庫中的數據關聯的對象。
  • LiveData與從網絡訪問的數據關聯的對象。
    您的活動只需要觀察MediatorLiveData對象以從兩個來源接收更新手寫事件通信方案LiveDataBushttps://pan.baidu.com/s/1S4Xjdw_cwYNsPL4SbP6tbA
    手寫事件通信方案LiveDataBus

https://pan.baidu.com/s/1S4Xjdw_cwYNsPL4SbP6tbA

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章