Currently, I need to perform some actions, when
Hence, the following code snippet serve me pretty well so far. I learn such trick from CommonWare's - https://commonsware.com/AndroidArch/previews/other-lifecycle-owners and https://proandroiddev.com/react-to-app-foreground-and-background-events-with-processlifecycleowner-96278e5816fa
public class WeNoteApplication extends Application {
public static class AppLifecycleObserver implements DefaultLifecycleObserver {
@Override
public void onResume(LifecycleOwner owner) {
// Do something when the application launched.
// But not during activity recreation, configuration change, ...
}
@Override
public void onPause(LifecycleOwner owner) {
// Do something when the application quit.
// But not during activity recreation, configuration change, ...
}
}
private static final AppLifecycleObserver appLifecycleObserver = new AppLifecycleObserver();
@Override
public void onCreate() {
super.onCreate();
initLifecycleObserver();
}
private void initLifecycleObserver() {
Lifecycle lifecycle = ProcessLifecycleOwner.get().getLifecycle();
lifecycle.removeObserver(appLifecycleObserver);
lifecycle.addObserver(appLifecycleObserver);
}
}
However, I also need to perform some actions, by using Activity
, Fragment
, ... For instance, showing a DialogFragment
.
For my entry point main Activity
, here's what I had tried.
public class MainActivity extends AppCompatActivity implements DefaultLifecycleObserver {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ProcessLifecycleOwner.get().getLifecycle().removeObserver(this);
ProcessLifecycleOwner.get().getLifecycle().addObserver(this);
setContentView(R.layout.activity_main);
}
@Override
public void onResume(LifecycleOwner owner) {
android.util.Log.i("CHEOK", "onResume LifecycleOwner called");
}
@Override
public void onPause(LifecycleOwner owner) {
android.util.Log.i("CHEOK", "onPause LifecycleOwner called");
}
@Override
public void onCreate(LifecycleOwner owner) {
android.util.Log.i("CHEOK", "onCreate LifecycleOwner called");
}
}
It doesn't work as expected due the following following observations
onCreate LifecycleOwner called
onResume LifecycleOwner called
onResume LifecycleOwner called <-- Why onResume of LifecycleOwner is called twice??
onCreate LifecycleOwner called
onResume LifecycleOwner called <-- Why onCreate and onResume of LifecyclOwner is called during configuration change?
I tried to use LiveData
in order for AppLifecycleObserver
to communicate with Activity
. However, during configuration change, onResumeLiveData
treats re-created Activity
as new lifecycle owner. Hence, it will trigger it again.
public class WeNoteApplication extends Application {
public MutableLiveData<LifecycleOwner> onResumeLiveData = new MutableLiveData<>();
public class AppLifecycleObserver implements DefaultLifecycleObserver {
@Override
public void onResume(LifecycleOwner owner) {
// This will only be called during app launch, not configuration change.
android.util.Log.i("CHEOK", "onResume callback happen in application");
onResumeLiveData.setValue(owner);
...
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
WeNoteApplication.instance().onResumeLiveData.observe(this, new Observer<LifecycleOwner>() {
@Override
public void onChanged(@Nullable LifecycleOwner lifecycleOwner) {
// This will only be called during app launch
// This will also be called during configuration change.
android.util.Log.i("CHEOK", "onResume callback happen in activity");
}
});
So, I'm some how confused. What is a correct way, for an Activitly
(or Fragment
) to observe Lifecycle
event? Meaning, those call back event functions shouldn't be triggered, during configuration change, activity re-creation, ...
Activity-lifecycle concepts To navigate transitions between stages of the activity lifecycle, the Activity class provides a core set of six callbacks: onCreate() , onStart() , onResume() , onPause() , onStop() , and onDestroy() . The system invokes each of these callbacks as an activity enters a new state.
Lifecycle Awareness: ViewModel objects are also lifecycle-aware. They are automatically cleared when the Lifecycle they are observing gets permanently destroyed. Data Sharing: Data can be easily shared between fragments in an activity using ViewModels .
The root of your problem is inside LifecycleRegistry.addObserver
, you see:
void addObserver (LifecycleObserver observer) Adds a LifecycleObserver that will be notified when the LifecycleOwner changes state.
The given observer will be brought to the current state of the LifecycleOwner. For example, if the LifecycleOwner is in STARTED state, the given observer will receive ON_CREATE, ON_START events.
So let's see what's happen when you add a new Observer
to a LifeCycleRegistery
:
@Override
public void addObserver(@NonNull LifecycleObserver observer) {
State initialState = mState == DESTROYED ? DESTROYED : INITIALIZED;
ObserverWithState statefulObserver = new ObserverWithState(observer, initialState);
...
State targetState = calculateTargetState(observer);
while ((statefulObserver.mState.compareTo(targetState) < 0
&& mObserverMap.contains(observer))) {
pushParentState(statefulObserver.mState);
statefulObserver.dispatchEvent(lifecycleOwner, upEvent(statefulObserver.mState));
popParentState();
// mState / subling may have been changed recalculate
targetState = calculateTargetState(observer);
}
...
}
When you add a new observer
, the LifecycleRegistery
tries to bring the observer
state to its own state, in your case iterating through the Activity
state and since the state is starting from INITIALIZED the registry dispatch events all the way to it's current state which is RESUMED:
private State calculateTargetState(LifecycleObserver observer) {
Entry<LifecycleObserver, ObserverWithState> previous = mObserverMap.ceil(observer);
State siblingState = previous != null ? previous.getValue().mState : null;
State parentState = !mParentStates.isEmpty() ? mParentStates.get(mParentStates.size() - 1)
: null;
return min(min(mState, siblingState), parentState);
}
TL,DR: So the duplicate event sequence you see when Activity
is re-created (or the future duplicate events you gonna see when you register a new observer in a second activity) are actually from the observer
lifecycle which is the Activity
lifecycle itself!
A WORKAROUND would be querying the process's state itself instead of relying only on events, so replace this:
public class MainActivity extends AppCompatActivity implements DefaultLifecycleObserver {
...
@Override
public void onResume(LifecycleOwner owner) {
android.util.Log.i("CHEOK", "onResume LifecycleOwner called");
}
@Override
public void onPause(LifecycleOwner owner) {
android.util.Log.i("CHEOK", "onPause LifecycleOwner called");
}
@Override
public void onCreate(LifecycleOwner owner) {
android.util.Log.i("CHEOK", "onCreate LifecycleOwner called");
}
}
with this:
public class MainActivity extends AppCompatActivity implements DefaultLifecycleObserver {
...
@Override
public void onResume(LifecycleOwner owner) {
if(owner.getLifecycle().getCurrentState() == Lifecycle.State.RESUMED)
android.util.Log.i("CHEOK", "onResume LifecycleOwner called");
}
@Override
public void onPause(LifecycleOwner owner) {
if(owner.getLifecycle().getCurrentState() == Lifecycle.State.STARTED)
android.util.Log.i("CHEOK", "onPause LifecycleOwner called");
}
@Override
public void onCreate(LifecycleOwner owner) {
if(owner.getLifecycle().getCurrentState() == Lifecycle.State.CREATED)
android.util.Log.i("CHEOK", "onCreate LifecycleOwner called");
}
}
, the SOLUTION would be using a single source of truth like a ViewModel
or ApplicationClass
like the way you did to receive LifeCycle.Event
;
Now if you plan to do an action only once use a SingleLiveEvent or if you plan to do an action in a limited window when conditions are met use some kind of Bus or Event Broadcast!
Remember that every time a observer
register to a LiveData
the latest value will be delivered to it.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With