ProcessLifecycleOwner not working after updating app compat to to 1.4.1

Viewed 1518

I'm investigating a weird issue, where we changed the androidx.appcompat:appcompat from 1.3.1 to 1.4.1 and all of a sudden our LifecycleObservers observing process lifecycle stopped emitting any events.

I'm also using "androidx.lifecycle:lifecycle-extensions:2.2.0", I know that this is already deprecated, but it works flawlessly if appcompat is 1.3.1

I have set the correct application name in the Manifest, I have included this provider as required per docs.

        <provider
            android:name="androidx.startup.InitializationProvider"
            android:authorities="${applicationId}.androidx-startup"
            tools:node="remove" />

Example of initialisation, which doesn't work. This object is injected in the Application class and lifecycle observer is getting added, but onStart and onStop are never called.

class AppLifecycle @Inject constructor(
    private val foregroundProxy: AppLifecycleProxy
) : LifecycleObserver {

    init {
        ProcessLifecycleOwner.get().lifecycle.addObserver(this)
    }

    @OnLifecycleEvent(Lifecycle.Event.ON_START)
    fun onStart() {
        foregroundProxy.onStarted()
    }

    @OnLifecycleEvent(Lifecycle.Event.ON_STOP)
    fun onStop() {
        foregroundProxy.onStopped()
    }
}

EDIT: As per @EpicPandaForce comment, changing the the provider block in Manifest to:

 <provider
    android:name="androidx.startup.InitializationProvider"
    android:authorities=\"${applicationId}.androidx-startup"
    android:exported="false"
    tools:node=\"merge">
    <!-- If you are using androidx.startup to initialize other components -->
    <meta-data
        android:name="androidx.lifecycle.ProcessLifecycleInitializer"
        android:value="androidx.startup"
        tools:node="remove" />
 </provider>

And replacing the "androidx.lifecycle:lifecycle-extensions:2.2.0" dependency with "androidx.lifecycle:lifecycle-common:2.4.1" has fixed this problem

2 Answers

There's a good bet that the reason there has been changes on your side is because ProcessLifecycleOwner's initialization was reworked to use the Jetpack Startup library, which relies on a ContentProvider, therefore only does initialization in a process's main process.

In the actual code for ProcessLifecycleOwner, it says:

/**
 * Initializes {@link ProcessLifecycleOwner} using {@code androidx.startup}.
 */
public final class ProcessLifecycleInitializer implements Initializer<LifecycleOwner> {

    @NonNull
    @Override
    public LifecycleOwner create(@NonNull Context context) {
        AppInitializer appInitializer = AppInitializer.getInstance(context);
        if (!appInitializer.isEagerlyInitialized(getClass())) {
            throw new IllegalStateException(
                    "ProcessLifecycleInitializer cannot be initialized lazily. \n"
                            + "Please ensure that you have: \n"
                            + "<meta-data\n"
                            + "    android:name='androidx.lifecycle.ProcessLifecycleInitializer' \n"
                            + "    android:value='androidx.startup' /> \n"
                            + "under InitializationProvider in your AndroidManifest.xml");
        }
        LifecycleDispatcher.init(context);
        ProcessLifecycleOwner.init(context);
        return ProcessLifecycleOwner.get();
    }

    @NonNull
    @Override
    public List<Class<? extends Initializer<?>>> dependencies() {
        return Collections.emptyList();
    }
}

And the commit that made it use androidx.startup in 2021-03 says this:

"lifecycle-process now uses androidx.startup to initialize process lifecycle owner.

Previously, this was being done by androidx.lifecycle.ProcessLifecycleOwnerInitializer.

If you used tools:node="remove" the ContentProvider being used to initialize process lifecycle in the past, then you need to do the following instead.

<provider
 android:name="androidx.startup.InitializationProvider"
 android:authorities=\"${applicationId}.androidx-startup"
 android:exported="false" tools:node=\"merge"> <!-- If you are using
 androidx.startup to initialize other components --> 
        <meta-data
          android:name="androidx.lifecycle.ProcessLifecycleInitializer"
          android:value="androidx.startup" /> 
</provider>

(or)


     <!-- If you want to disable androidx.startup completely. -->
     <provider android:name="androidx.startup.InitializationProvider"
     android:authorities="${applicationId}.androidx-startup"
     tools:node="remove"> 
    </provider>

"

So the snippet you added specifically disables the AndroidX StartUp process and therefore your ProcessLifecycleOwner won't get initialized.


By the way, Google did NOT provide a way to manually install the ProcessLifecycleOwner if you disable the automatic start-up process, but to achieve it, you just need to mimic what they are doing. For example, if you needed to use ProcessLifecycleOwner in a multi-process app, then you'd need to not use the ContentProvider.

In that case, you can create a Java file in a package called androidx/lifecycle:

public class ProcessLifecycleInitializerAccessor {
    public static LifecycleOwner initialize(Application context) {
        LifecycleDispatcher.init(context);
        ProcessLifecycleOwner.init(context);
        return ProcessLifecycleOwner.get();
    }
}

But in your place, you probably just have to remove the snippet that removes your ContentProvider.

There was an upgrade were androidx.lifecycle started using androidx.startup to initialize. So, if this code was in your manifest:

<provider
    android:name="androidx.startup.InitializationProvider"
    android:authorities="${applicationId}.androidx-startup"
    tools:node="remove" />

Then you can completely remove that code, or use tools:node="merge" instead of remove.

You need to verify in the Merged Manifest that androidx.lifecycle.ProcessLifecycleInitializer is being initialized.

Related