Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Android WorkManager - Can I pass input data to a Worker that runs periodically?

In my app I start a WebSocketWorker tasks that runs periodically every 15 minutes. As the name implies, it contains a WebSocket for listening to a socket in the background:

// MainApplication.kt
override fun onCreate() {
        super.onCreate()
        if (BuildConfig.DEBUG) {
            Timber.plant(DebugTree())
        }

        val work = PeriodicWorkRequestBuilder<WebSocketWorker>(15, TimeUnit.MINUTES).build()
        workManager.enqueueUniquePeriodicWork("UniqueWebSocketWorker", ExistingPeriodicWorkPolicy.KEEP, work)
    }

The WebSocketWorker contains the following logic:

@HiltWorker
class WebSocketWorker  @AssistedInject constructor(
    @Assisted appContext: Context,
    @Assisted workerParams: WorkerParameters
) : CoroutineWorker(appContext, workerParams) {

    inner class MyWebSocketListener : WebSocketListener() {
        override fun onMessage(webSocket: WebSocket, text: String) {
            Timber.d("The message sent is %s", text)
            // do sth. with the message 
        }

        override fun onFailure(webSocket: WebSocket, t: Throwable, response: Response?) {
            t.localizedMessage?.let { Timber.e("onFailure: %s", it) }
            response?.message?.let { Timber.e("onFailure: %s", it) }
        }
    }


    override suspend fun doWork(): Result {
        try{
            // code to be executed
            val request = Request.Builder().url("ws://***.***.**.***:8000/ws/chat/lobby/").build()
            val myWebSocketListener = MyWebSocketListener()
            val client = OkHttpClient()
            client.newWebSocket(request, myWebSocketListener)
            return Result.success()
        }
        catch (throwable:Throwable){
            Timber.e("There is a failure")
            Timber.e("throwable.localizedMessage: %s", throwable.localizedMessage)
            // clean up and log
            return Result.failure()
        }
    }

}

As you can see, in the Worker class I set the WebSocket and everything is fine. Listening to the socket works.

Now, I also want to add the "sending of messages" functionality to my app. How can I reuse the websocket created in WebSocketWorker? Can I pass input data to the WebSocketWorker that runs in the background ?

Let's say I have a EditText for typing the message and a Button to send the message with a setOnClickListener attached like this:

binding.sendButton.setOnClickListener {
            // get message
            val message = binding.chatMessageEditText.text.toString()
            // check if not empty
            if(message.isNotEmpty()) {
                
                // HOW CAN I REUSE THE WEBSOCKET RUNNING PERIODICALLY IN THE BACKGROUND?
                // CAN I PASS THE MESSAGE TO THAT WEBSOCKET ?
                // OR SHOULD I CREATE A DIFFERENT WORKER FOR SENDING MESSAGES (e.g.: a OneTimeRequest<SendMessageWorker> for sending messages ? 
            
            }
        }

From the documentation, I know that you need to build Data objects for passing inputs and so on but there was no example which showcased how to pass input to a worker running periodically in the background.

like image 417
abdullah celik Avatar asked Jan 21 '26 11:01

abdullah celik


1 Answers

My experience is saying that you can. Basically you "can't" interact with the worker object via the API. It is really annoying.

For example, with the JS you have the option to get a job and check the parameters of the job. There is no such option with the work. For example, I want to check what is the current state of the restrictions - what is satisfied, what is not. Nothing like this. You can just check states, cancel and that is almost all.

My suggestions is that it is because the WorkManager is a "facade/adapter" over other libraries like JS. It has it's own DB to restore JS jobs on device restart and stuff like this, but beside that if you want to interact with the internals I guess it was just too complicated for them to do so they just skipped.

You can just inject some other object and every time the work can ask it for it's data. I don't see other option.

like image 76
Yavor Mitev Avatar answered Jan 24 '26 03:01

Yavor Mitev



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!