原文地址:https://blog.csdn.net/zhanglei5415/article/details/131434931 ## 一、問題 當對含有中文的url字元串,進行NSURL對象包裝時,是不能被識別的。 不會得到期望的NSURL對象,而是返回一個nil 值 ; ```objectiv ...
查詢資料的其中一個場景: 創建一個回調函數,當查詢後臺的時候,後臺有結果了,回調對應的回調函數,並將結果保存到LiveData中。
public class DataModel { ... public MutableLiveData<List<Repo>> searchRepo(String query) { final MutableLiveData<List<Repo>> repos = new MutableLiveData<>(); githubService.searchRepos(query) .enqueue(new Callback<RepoSearchResponse>() { @Override public void onResponse(@NonNull Call<RepoSearchResponse> call, @NonNull Response<RepoSearchResponse> response) { repos.setValue(response.body().getItems()); } ... }); return repos; } }如果 RepoViewModel的部分寫成這樣:
public class RepoViewModel extends ViewModel { ... MutableLiveData<List<Repo>> searchRepo(String query) { // NO! return dataModel.searchRepo(query); } }這種寫法有如下兩個問題: 1.當輸入新的關鍵字的時候,DataModel會返回新的LiveData,這樣View每次都要去observe新的LiveData 2.當View重新創建的時候,會再次調用searchRepo,於是DataModel又再一次查詢,並且返回新的LiveData。 為了避免重覆創建LiveData,只使用固定的一個LiveData,可以使用 Transformations改造上述代碼: 下述代碼repos返回的都是同一個LiveData。Transformations不會使返回的LiveData變成新的對象,因此View一值都是對LiveData做observe的。即解決了上面提到的兩個問題。
public class RepoViewModel extends ViewModel { ... private final MutableLiveData<String> query = new MutableLiveData<>(); private final LiveData<List<Repo>> repos; public RepoViewModel(final DataModel dataModel) { ... repos = Transformations.switchMap(query, new Function<String, LiveData<List<Repo>>>() { @Override public LiveData<List<Repo>> apply(String userInput) { return dataModel.searchRepo(userInput); } }); } ... void searchRepo(String userInput) { query.setValue(userInput); } }如果dataModel查詢結果可能為null,也就是沒有返回值,但是依然需要返回一個backing LiveData,那麼,可以使用 AbsentLiveData
/** * A LiveData class that has {@code null} value. */ public class AbsentLiveData extends LiveData { private AbsentLiveData() { postValue(null); } public static <T> LiveData<T> create() { //noinspection unchecked return new AbsentLiveData(); } }
repos = Transformations.switchMap(query, new Function<String, LiveData<List<Repo>>>() { @Override public LiveData<List<Repo>> apply(String userInput) { if (TextUtils.isEmpty(userInput)) { return AbsentLiveData.create(); } else { return dataModel.searchRepo(userInput); } } });LiveData<Y> switchMap (LiveData<X> trigger,Function<X, LiveData<Y>> func) Creates a LiveData, let's name it swLiveData, which follows next flow: it reacts on changes of trigger LiveData, applies the given function to new value of trigger LiveData and sets resulting LiveData as a "backing" LiveData to swLiveData. "Backing" LiveData means, that all events emitted by it will retransmitted by swLiveData. If the given function returns null, then swLiveData is not "backed" by any other LiveData. The given function func will be executed on the main thread. 創建一個swLiveData,每當triggerLiveData的值發生變化的時候,就使用triggerLiveData的值,應用相應的函數操作,得到的結果,作為swLiveData的值。 Consider the case where you have a LiveData containing a user id. Every time there's a new user id emitted, you want to trigger a request to get the user object corresponding to that id, from a repository that also returns a LiveData. The userIdLiveData is the trigger and the LiveData returned by the repository.getUserById is the "backing" LiveData. In a scenario where the repository contains User(1, "Jane") and User(2, "John"), when the userIdLiveData value is set to "1", the switchMap will call getUser(1), that will return a LiveData containing the value User(1, "Jane"). So now, the userLiveData will emit User(1, "Jane"). When the user in the repository gets updated to User(1, "Sarah"), the userLiveData gets automatically notified and will emit User(1, "Sarah"). When the setUserId method is called with userId = "2", the value of the userIdLiveData changes and automatically triggers a request for getting the user with id "2" from the repository. So, the userLiveData emits User(2, "John"). The LiveData returned by repository.getUserById(1) is removed as a source.
MutableLiveData userIdLiveData = ...; LiveData userLiveData = Transformations.switchMap(userIdLiveData, id -> repository.getUserById(id)); void setUserId(String userId) { this.userIdLiveData.setValue(userId); }
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
LiveData<Y> map (LiveData<X> source, Function<X, Y> func) Applies the given function on the main thread to each value emitted by source LiveData and returns LiveData, which emits resulting values. The given function func will be executed on the main thread. Suppose that you have a LiveData, named userLiveData, that contains user data and you need to display the user name, created by concatenating the first and the last name of the user. You can define a function that handles the name creation, that will be applied to every value emitted by useLiveData. 在主線程上,對源source liveData的每個數值應用函數操作func,返回的一個新的LiveData,包含func操作的結果,比如如下例子代碼, userLiveData作為源,要創建一個新的LiveData,它的每個值是firstname與lastname的合併。LiveData userLiveData = ...; LiveData userName = Transformations.map(userLiveData, user -> { return user.firstName + " " + user.lastName });
版權聲明: 作者:ttylinux 出處:http://www.cnblogs.com/ttylinux/ 本文版權歸作者,歡迎轉載,但未經作者同意必須保留此段聲明,且在文章頁面明顯位置給出原文連接,否則保留追究法律責任的權利。