Skip to content

Instantly share code, notes, and snippets.

@Sal7one
Created June 23, 2024 07:58
Show Gist options
  • Save Sal7one/f23e21ead9e0ad9b59cc2ddf45e15a48 to your computer and use it in GitHub Desktop.
Save Sal7one/f23e21ead9e0ad9b59cc2ddf45e15a48 to your computer and use it in GitHub Desktop.
It's the weekend and I miss handlers :]
package com.sal7one.handler
import android.os.Bundle
import android.os.Handler
import android.os.Looper
import android.os.Message
import android.util.Log
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.activity.enableEdgeToEdge
import androidx.activity.viewModels
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.safeDrawingPadding
import androidx.compose.material3.Button
import androidx.compose.material3.Scaffold
import androidx.compose.material3.Text
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.lifecycle.ViewModel
import com.sal7one.handler.ui.theme.HandlerTheme
class MainActivity : ComponentActivity() {
private val viewModel: MainViewModel by viewModels()
private var mMainThreadHandler: Handler? = null
private var myCustomThread1: MyCustomThread? = null
private var myCustomThread2: MyCustomThread? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
mMainThreadHandler = object : Handler(Looper.getMainLooper()) {
override fun handleMessage(msg: Message) {
super.handleMessage(msg)
handleHandlerMessssage(msg)
}
}
myCustomThread1 = MyCustomThread(mMainThreadHandler, 1, 50, 15000)
myCustomThread2 = MyCustomThread(mMainThreadHandler, 2, 10, 100)
myCustomThread1?.start()
myCustomThread2?.start()
enableEdgeToEdge()
setContent {
HandlerTheme {
Scaffold(
modifier = Modifier
.fillMaxSize()
.safeDrawingPadding()
) { padding ->
Column(
modifier = Modifier
.padding(padding)
.fillMaxSize(),
horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.Center
) {
Text(text = "Task 1: " + viewModel.message1)
Text(text = "Task 2: " + viewModel.message2)
Button(onClick = { sendMessageToBackgroundThread(1, "Start Task 1") }) {
Text("Start Task 1")
}
Button(onClick = { sendMessageToBackgroundThread(2, "Start Task 2") }) {
Text("Start Task 2")
}
}
}
}
}
}
fun handleHandlerMessssage(msg: Message): Boolean {
val taskId = msg.arg1
val progress = msg.arg2
val message = msg.obj as String
when (taskId) {
1 -> viewModel.updateMessage1(message)
2 -> viewModel.updateMessage2(message)
}
return true
}
private fun sendMessageToBackgroundThread(taskId: Int, message: String) {
val msg = Message.obtain().apply {
arg1 = taskId
obj = message
}
when (taskId) {
1 -> myCustomThread1?.sendMessageToBackgroundThread(msg)
2 -> myCustomThread2?.sendMessageToBackgroundThread(msg)
}
}
}
class MyCustomThread(
private val mainHandler: Handler?,
private val taskId: Int,
private val iterations: Int,
private val sleepDuration: Long
) : Thread() {
private var mHandler: MyThreadHandler? = null
override fun run() {
Looper.prepare()
mHandler = MyThreadHandler(Looper.myLooper()!!)
Looper.loop()
}
inner class MyThreadHandler(looper: Looper) : Handler(looper) {
override fun handleMessage(msg: Message) {
val taskMessage = msg.obj as String
for (i in 0 until iterations) {
sleep(sleepDuration)
val progressMessage = Message.obtain()
progressMessage.arg1 = taskId
progressMessage.arg2 = i
progressMessage.obj = "$taskMessage: Progress $i"
mainHandler?.sendMessage(progressMessage)
}
}
}
fun sendMessageToBackgroundThread(message: Message) {
mHandler?.sendMessage(message)
}
}
class MainViewModel : ViewModel() {
var message1 by mutableStateOf("")
var message2 by mutableStateOf("")
fun updateMessage1(newMessage: String) {
message1 = newMessage
}
fun updateMessage2(newMessage: String) {
message2 = newMessage
}
}
@Sal7one
Copy link
Author

Sal7one commented Jun 23, 2024

the ability to kill it also

package com.sal7one.handler

import android.os.Bundle
import android.os.Handler
import android.os.Looper
import android.os.Message
import android.util.Log
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.activity.enableEdgeToEdge
import androidx.activity.viewModels
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.safeDrawingPadding
import androidx.compose.material3.Button
import androidx.compose.material3.Scaffold
import androidx.compose.material3.Text
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.lifecycle.ViewModel
import com.sal7one.handler.ui.theme.HandlerTheme

class MainActivity : ComponentActivity() {
    private val viewModel: MainViewModel by viewModels()
    private var mMainThreadHandler: Handler? = null
    private var myCustomThread1: MyCustomThread? = null
    private var myCustomThread2: MyCustomThread? = null

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        mMainThreadHandler = object : Handler(Looper.getMainLooper()) {
            override fun handleMessage(msg: Message) {
                super.handleMessage(msg)
                handleHandlerMessssage(msg)
            }
        }
        myCustomThread1 = MyCustomThread(mMainThreadHandler, 1, 50, 15000)
        myCustomThread2 = MyCustomThread(mMainThreadHandler, 2, 10, 100)

        myCustomThread1?.start()
        myCustomThread2?.start()

        enableEdgeToEdge()
        setContent {
            HandlerTheme {
                Scaffold(
                    modifier = Modifier
                        .fillMaxSize()
                        .safeDrawingPadding()
                ) { padding ->
                    Column(
                        modifier = Modifier
                            .padding(padding)
                            .fillMaxSize(),
                        horizontalAlignment = Alignment.CenterHorizontally,
                        verticalArrangement = Arrangement.SpaceEvenly
                    ) {
                        Text(text = "Task 1: " + viewModel.message1)
                        Text(text = "Task 2: " + viewModel.message2)
                        Button(onClick = { sendMessageToBackgroundThread(1, "Start Task 1") }) {
                            Text("Start Task 1")
                        }
                        Button(onClick = { sendMessageToBackgroundThread(2, "Start Task 2") }) {
                            Text("Start Task 2")
                        }

                        Button(onClick = { sendMessageToBackgroundThread(1, "Kill Thread") }) {
                            Text(text = "Kill Thread 1 ")
                        }
                        
                        Button(onClick = { sendMessageToBackgroundThread(2, "Kill Thread") }) {
                            Text(text = "Kill Thread 2 ")
                        }
                    }
                }
            }
        }
    }

    fun handleHandlerMessssage(msg: Message): Boolean {
        val taskId = msg.arg1
        val progress = msg.arg2
        val message = msg.obj as String
        when (taskId) {
            1 -> viewModel.updateMessage1(message)
            2 -> viewModel.updateMessage2(message)
        }
        return true
    }

    private fun sendMessageToBackgroundThread(taskId: Int, message: String) {
        val msg = Message.obtain().apply {
            arg1 = taskId
            obj = message
        }
        when (taskId) {
            1 -> myCustomThread1?.sendMessageToBackgroundThread(msg)
            2 -> myCustomThread2?.sendMessageToBackgroundThread(msg)
        }
    }
}

class MyCustomThread(
    private val mainHandler: Handler?,
    private val taskId: Int,
    private val iterations: Int,
    private val sleepDuration: Long
) : Thread() {
    private var mHandler: MyThreadHandler? = null

    override fun run() {
        Looper.prepare()
        mHandler = MyThreadHandler(Looper.myLooper()!!)
        Looper.loop()
        Log.e("MyCustomThread", "Thread is quitting...")
    }

    inner class MyThreadHandler(looper: Looper) : Handler(looper) {
        override fun handleMessage(msg: Message) {
            val taskMessage = msg.obj as String
            if (taskMessage.contains("Kill")) {
                looper.quit()
            } else {
                for (i in 0 until iterations) {
                    sleep(sleepDuration)
                    val progressMessage = Message.obtain()
                    progressMessage.arg1 = taskId
                    progressMessage.arg2 = i
                    progressMessage.obj = "$taskMessage: Progress $i"
                    mainHandler?.sendMessage(progressMessage)
                }
            }
        }
    }

    fun sendMessageToBackgroundThread(message: Message) {
        mHandler?.sendMessage(message)
    }
}

class MainViewModel : ViewModel() {
    var message1 by mutableStateOf("")
    var message2 by mutableStateOf("")

    fun updateMessage1(newMessage: String) {
        message1 = newMessage
    }

    fun updateMessage2(newMessage: String) {
        message2 = newMessage
    }
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment