2

I'm trying to use androidx.work:work-multiprocess:2.5.0 to run work in a process specified using Configuration.setDefaultProcessName(), but no matter which process I enqueue the work from, the doWork() method is called in main application process.

As stated in documentation RemoteWorkManager always reaches out to the designated process. The in-process scheduler also runs in the designated process.

My full test project is here: https://github.com/padreMateo88/multiprocessWorkManagerTest

I use the following dependencies:

implementation 'androidx.work:work-runtime-ktx:2.5.0'
implementation 'androidx.work:work-multiprocess:2.5.0'

I removed the default WorkManagerInitialiser in manifest:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    package="com.example.workmanagertest">

    <application
        android:name=".MyApplication"
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">

        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>

        <receiver
            android:name="com.example.workmanagertest.SecondProcessBroadcastReceiver"
            android:process=":second_process" />

        <provider
            android:name="androidx.work.impl.WorkManagerInitializer"
            android:authorities="${applicationId}.workmanager-init"
            tools:node="remove" />
    </application>

</manifest>

implemented Configuration.Provider in Application class:

 class MyApplication : Application(), Configuration.Provider {
   
   override fun getWorkManagerConfiguration(): Configuration = WorkConfigurationProvider().get()
   
}

class WorkConfigurationProvider {
    fun get() = Configuration.Builder().setDefaultProcessName(processName).build()

    companion object {
        private const val processName = "com.example.workmanagertest:second_process"
    }
} 

And use RemoteWorkManager.getInstance() to enqueue my work:

 class SampleWorker(context: Context, workerParams: WorkerParameters) : Worker(context, workerParams) {

    override fun doWork(): Result {
        Util.d(applicationContext, "SampleWorker.doWork()")
        return Result.success()
    }

    companion object {
        @JvmStatic
        fun enqueueWork(context: Context) {
            Util.d(context,"SampleWorker.enqueueWork()")
            try {
                val rwm = RemoteWorkManager.getInstance(context)
                Util.d(context,"RemoteWorkManager hash ${rwm.hashCode()}")
                rwm.enqueueUniqueWork(
                        "SampleWorker",
                        ExistingWorkPolicy.REPLACE,
                        OneTimeWorkRequest.from(SampleWorker::class.java)
                )
            } catch (ex: Throwable) {
                Util.d(context,"SampleWorker, WorkManager is not initialized properly, reason: " + ex.message)
            }
        }
    }
} 

What am I doing wrong?

  • 1
    Is it mandatory to create an Application class? I want to implement WorkManager in a multi-process android library. – Rahul Patidar Mar 04 '21 at 10:57
  • @Rahul Patidar You can call _WorkManager.initialize(this, Configuration.Builder().setDefaultProcessName(processName).build())_ in _Application.onCreate()_ instead of implementing the _Configuration.Provider_ interface. I've tested it and it works fine.You could do it in an initialization method that the user of our library would call in _Application.onCreate()_ like e.g. _FirebaseApp.initializeApp()_, but you still have to impose your initialization of WorkManager on the app using your library. – Mateusz Piotrowski Mar 04 '21 at 16:09
  • Thanks for the reply @Mateusz Piotrowski, but my concern is that I can not create the Application class in my library. – Rahul Patidar Mar 05 '21 at 06:23
  • @Rahul Patidar yes, I understand this (I develop a multiprocess library myself, and I want to leave an option for the developer to extend e.g. _MultidexApplication_). Instead of creating an Application class in your library you can create an initialization method, that users of your library will call in their own _Application.onCreate()_ This is why I gave the exapmle of _FirebaseApp.initializeApp()_ another example is _Fabric.with()_. Alternatively you can do the initialization in a content provider. – Mateusz Piotrowski Mar 05 '21 at 11:22
  • Thanks. I Will vote up the que/answer. – Rahul Patidar Mar 08 '21 at 14:38

1 Answers1

3

In order for the doWork() method to be called in the designated process you also need to set the designated process name for RemoteWorkerManagerService and SystemJobService in your manifest:

<service
    android:name="androidx.work.multiprocess.RemoteWorkManagerService"
    tools:replace="android:process"
    android:process=":second_process"/>

<service
    android:name="androidx.work.impl.background.systemjob.SystemJobService"
    tools:replace="android:process"
    android:process=":second_process"/>

You can find a working example here: https://github.com/padreMateo88/multiprocessWorkManagerTest

This implementation is based on clues I got from Google Issue Tracker: https://issuetracker.google.com/issues/180255558