onDestroy function completion

I need my app to call and finish a runnable routine the moment my application is being destroyed. I’ve done some code and it seems to partially work.

My goal is to send a small command (consisting of only one character) through a socket opened in a network connection so as to let the server know that the application is closing.

The code seems to be working. I can see the reports of the Log instructions in the debugger window, although in the wrong order:

D/Debug:: On Destroy entered…
D/Debug: And we’re done…
D/Debug: Flushing…
D/Debug: Flushed

As it can be seen, the “And we’re done…” message should be the last one, but it’s not. And also, even though the SendToServer is effectively entered and executed, stringToSend (a single character) is not effectively sent through the socket before the application is killed.

What gives?

    public override fun onDestroy() {
        Log.d("Debug:", "On Destroy entered...")

       if (isDestroyed)
            val cThread = Thread(SendToServer(cmdDisconnect))
            Log.d("Debug:", "Disconnecting...")
            Log.d("Debug", "And we're done...")
    } // onDestroy

    class SendToServer(stringToSend: String) : Runnable {
        private val localStr = stringToSend
        private val localFlag = eolFlag

        override fun run() {
            val output = PrintWriter(valveSocketClient!!.getOutputStream())

            Log.d("Debug", "Flushing...")
            Log.d("Debug", "Flushed")

        } //run
    } //SendToServer

The recommended technique for operations that need to survive the application’s lifetime is using WorkManager. You’ll just need to add a worker that runs when the application closes and yeah it should then work.

1 Like

Thank you very much for your involvement, K.

I’ve done what you’ve suggested. I found an example of how to use thw WorkManager class, and implemented the code shown below (after adding the ‘androidx.work:work-runtime-ktx:2.4.0’ dependency, of course).

The SendToDevice routine works perfectly when used in other parts of the program. And also, the Log.d(“Debug:”, “On Destroy entered…”) in the onDestroy function executes just fine. But the WorkManager enqueue instruction is not executing at all. That is, neither one of the “Disconnecting…” nor “Disconnected…” messages is ever shown.

The code compiles just fine and reports no errors during program execution.

Also, I tried executing SendToDevice(cmdDisconnect, false) without running it as a Thread and the code also compiled just fine… but it didn’t work either.

class MainActivity : AppCompatActivity() {
    private val closeConnectionRequest: WorkRequest =OneTimeWorkRequestBuilder<CloseConnection>().build()


    public override fun onDestroy() {
        if (isDestroyed) {
            Log.d("Debug:", "On Destroy entered...")
    } // onDestroy

    class CloseConnection(appContext: Context, workerParams: WorkerParameters):
        Worker(appContext, workerParams) {
        override fun doWork(): Result {

            val cThread = Thread(SendToDevice(cmdDisconnect, false))
            Log.d("Debug:", "Disconnecting...")
            Log.d("Debug:", "Disconnected...")

            // Indicate whether the work finished successfully with the Result
            return Result.success()
    } //CloseConnection

} // MainActivity
1 Like

The thing with work manager is that AFAIK it gets to decide whenever it runs that request, but as long as the requirements for your worker are met, it should run them ASAP. It also sometimes batches workers together, and so your worker might run after like 5 minutes from when it was enqueued. I’d say that your best bet to test this is to monitor when the server receives the disconnect signal to verify that your worker is actually running to completion (i.e. exit out of your app and then look at your server to see if it received that signal).