Livedata
LiveData
is one for holding data and supporting data can be monitored (observed). Unlike the observed in the traditional observer pattern, Livedata is a 生命周期感知
component, so the observer can designate one LifeCycle
to Livedata and listen to the data.
If the Observer specifies LifeCycle
in Started
or RESUMED
state, Livedata treats the observer as active and notifies them of changes in the data.
Let's look at a piece of code:
Public classLocationlivedataextendsLivedata<location> { PrivateLocationmanager Locationmanager; PrivateSimplelocationlistener listener =NewSimplelocationlistener () {@Override Public voidonlocationchanged (location) {setValue); } }; PublicLocationlivedata (Context context) {Locationmanager=(Locationmanager) Context.getsystemservice (Context.location_service); } @Overrideprotected voidonactive () {locationmanager.requestlocationupdates (Locationmanager.gps_provider,0, 0, listener); } @Overrideprotected voidoninactive () {locationmanager.removeupdates (listener); }}
There are three noteworthy places:
When this method is called, the number of observers representing Livedata has changed from 0 to 1, and for our position monitoring, we should register our time monitoring.
When this method is called, the number of observers representing Livedata becomes 0, and since there is no observer, there is no reason to listen again, so we should remove the location listener.
This method is called to update the Livedata data and to notify the active observer.
Then we can use the Locationlivedata as follows.
public class myfragment extends lifecyclefragment { public void onactivitycreated (Bundle savedinstancestate) {livedata <Location> myloc Ationlistener = ...; Util.checkuserstatus (Result -> if< /span> (Result) {Mylocationlistener.addobserver ( this , location-> { / / update UI }); } }); }}
Note the above addObserver
method, which we will LifeCycleOwner
pass in as the first parameter, which means that our locationlivedata will follow the lifecycle of this fragment.
- If lifecycle is not in either started or resumed, then the observer will not be able to accept the callback for the data update, even if the data has changed.
- If the lifecycle is destroyed, that is, the end of the life cycle, the observer will be automatically removed from the Livedata.
Since Locationlivedata is life-cycle aware, we can change its code slightly so that it can be shared by multiple activity or fragment:
Public classLocationlivedataextendsLivedata<location> { Private StaticLocationlivedata sinstance; PrivateLocationmanager Locationmanager; @MainThread Public StaticLocationlivedata Get (Context context) {if(Sinstance = =NULL) {sinstance=NewLocationlivedata (Context.getapplicationcontext ()); } returnsinstance; } PrivateSimplelocationlistener listener =NewSimplelocationlistener () {@Override Public voidonlocationchanged (location) {setValue); } }; PrivateLocationlivedata (Context context) {Locationmanager=(Locationmanager) Context.getsystemservice (Context.location_service); } @Overrideprotected voidonactive () {locationmanager.requestlocationupdates (Locationmanager.gps_provider,0, 0, listener); } @Overrideprotected voidoninactive () {locationmanager.removeupdates (listener); }}
The reason for using a singleton here is to have multiple activity or fragment share a Locationlivedata instance.
Then we can use this:
public class myfragment extends lifecyclefragment { public void onactivitycreated (Bundle savedinstancestate) {util.checkuserstatus (Result -& Gt { if (res Ult) {Mylocationlistener.get (Getactivity ()). Addobserver ( this , L ocation-> { // update UI }); } }); }}
With this change, it can now be managed gracefully even with multiple activity or fragment using Locationlivedata. Don't bother about page destruction.
Summarize some of the livedata a bit:
When the viewer is bound to their corresponding lifecycle, they are automatically overrun when the page is destroyed, without causing a memory overflow.
- does not cause crash due to the invisible activity
When activity is not visible, Livedata does not notify the observer even if there are data changes. Because at this time the Observer's Lifecyele is not in the started or resumed state.
When the current activity configuration changes (such as the screen orientation), it causes the oncreate to go through again, which is the latest data that the viewer will receive immediately before the configuration changes.
We only need a locationlivadata, connect the system service once, can support all observers.
- No more human life cycle processing
As you can see from the code above, our activity or fragment as long as we need to observe the data to observe the data, do not need to ignore the life cycle changes. All of this is given to Livedata for automatic management.
Conversion of Livedata
Sometimes there is a need to change the type of data before Livedata notifies the observer of the changed data, or to return a different livedata.
Here is a class Transformations
that can help with these operations.
Before the change of the Livedata data is passed to the observer, a method is applied on the data:
livedata<user> userlivedata = ...; Livedata<String> userName = Transformations.map (userlivedata, user, { + "" + User.lastname});
If we just need to know the name of the changing user, we can just observe the Livedata object of username. It extracts the user name from the Userlivedata data and passes it to its own observer.
- Transformations.switchmap ()
Similar to Transformations.map (), except that the method of passing a switchmap () must return a Livedata object.
Private Livedata<user> GetUser (String id) { ...;} Livedata<String> userId = ...; Livedata<User> User = Transformations.switchmap (userid, ID, getUser (ID));
When you consider using Lifecycle objects in ViewModel, this conversion is an optional solution.
If there is a demand, the user input an address, we update the address on the screen of the ZIP code, the simple wording as follows:
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); }}
This is obviously a serious problem, and when the Getpostalcode method is called, the UI code needs to perform a registered observer operation on the return value of the Getpostalcode and remove the previous observer, which is obviously inefficient. Also, if the UI is rebuilt because of a change in configuration (screen rotation), it triggers a call to Getpostalcode again instead of using the previous invocation result.
So we can do the following conversions:
classMyviewmodelextendsViewModel {Private Finalpostalcoderepository repository; Private FinalMutablelivedata<string> Addressinput =NewMutablelivedata (); Public FinalLivedata<string> PostalCode =Transformations.switchmap (addressinput, address)- { returnRepository.getpostcode (address); }); PublicMyviewmodel (postalcoderepository repository) { This. Repository =Repository}Private voidSetInput (String address) {Addressinput.setvalue (address); }}
Note that here we write the PostalCode access limiter as public final because it will always be the same, and the UI simply registers the observer with PostalCode when it is needed. This is when the user calls SetInput, and if there is an active observer on the PostalCode, then Repository.getpostcode (address) is called, and if there are no active observers at this time, Then Repository.getpostcode (address) is not called.
Custom transformations
In your application, you may need to convert more livedata than the above two, you can use the class to implement these transformations, MediatorLiveData
which can be used to correctly handle the changes of events in many other livedata and to handle these events. Mediatorlivedata will active/inactive
pass its state changes correctly to the Livedata it handles, such as MEDIATORLIVEDATA without the observer.
This article turns from https://www.cnblogs.com/zqlxtt/p/6887940.htm
Android Official architecture Components introduction of Livedata (ii)