1

I have a simple worker thread class that has a function called execute that adds tasks to a ConcurrentLinkedQueue object.

package com.bignerdranch.android.handler
import android.util.Log
import java.util.concurrent.ConcurrentLinkedQueue
import java.util.concurrent.atomic.AtomicBoolean

class SimpleWorker : Thread(TAG) {

    lateinit var taskQueue: ConcurrentLinkedQueue<Runnable>
    lateinit var alive: AtomicBoolean

    companion object {
        val TAG = "SimpleWorker"
    }

    init {
        start() // call start method of thread
    }

    override fun run() {
        alive = AtomicBoolean(true)
        taskQueue = ConcurrentLinkedQueue()

        while (alive.get()) { // .get returns the value
            val task: Runnable = taskQueue.poll()
            if(task != null) { // if there is a task in queue
                task.run() // run the task
            }
        }
        Log.i(TAG, "SimpleWorker Terminated")
    }

    fun execute(task: Runnable): SimpleWorker {
        taskQueue.add(task)
        return this
    }

    fun quit() {
        alive.set(false)
    }
}

I am able to run an anonymous part as a lambda in Java, but it isn't working as a Lambda in Kotlin. Here is this main part:

package com.bignerdranch.android.handler

import android.os.Bundle
import android.os.Handler
import android.os.Looper
import android.os.Message
import android.widget.TextView
import androidx.appcompat.app.AppCompatActivity

class MainActivity : AppCompatActivity() {
    private var worker: SimpleWorker? = null
    private var tvMessage: TextView? = null
    private val handler: Handler = object : Handler(Looper.getMainLooper()) {
        // using anonymous class outside of arguments
        override fun handleMessage(msg: Message) {
            super.handleMessage(msg)
            tvMessage!!.text = msg.obj as String
        }
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        tvMessage = findViewById(R.id.tv_message)
        worker = SimpleWorker() // thread starts
        worker.execute({
            try {
                Thread.sleep(1000)
            } catch (e: InterruptedException) {
                e.printStackTrace()
            }
            val message = Message.obtain()
            message.obj = "Task 1 completed"
            handler.sendMessage(message)
        }).execute({
            try {
                Thread.sleep(500)
            } catch (e: InterruptedException) {
                e.printStackTrace()
            }
            val message = Message.obtain()
            message.obj = "Task 2 completed"
            handler.sendMessage(message)
        }).execute({
            try {
                Thread.sleep(1000)
            } catch (e: InterruptedException) {
                e.printStackTrace()
            }
            val message = Message.obtain()
            message.obj = "Task 3 completed"
            handler.sendMessage(message)
        })
    }
}

The execute lambdas are lined out in red and the compiler tells me that its required to return Runnable. That doesn't make any sense to me since those methods return a SimpleWorker.

Thanks for the help everyone.

Lester
  • 357
  • 3
  • 16
  • You aren't creating `Runnable` with this `worker.execute({...})`. Use `worker.execute(Runnable { ... })`. It will probably also crash because of empty taskQueue. – blackr4y Jan 02 '20 at 14:15
  • But in Java, "worker.execute(() -> {" works just fine, sir. – Lester Jan 02 '20 at 14:53

1 Answers1

1

The problem is when you do worker.execute({ }) in Kotlin you're using a Kotlin lambda reference which is not a @FunctionalInterface. The reason why this works in Java and not in Kotlin is that Runnable has the @FunctionalInterface annotation on it so you can substitute Runnable with a Java lambda. Also take a look at this related question.

Adam Arold
  • 29,285
  • 22
  • 112
  • 207
  • May I ask you why it wants to work when writing worker.execute(Runnable {...})? I thought that () -> implies making a Runnable. – Lester Jan 02 '20 at 16:49
  • It is because with `Runnable {}` you create an anonymous instance of `Runnable`. It is a shorthand for that in Kotlin. – Adam Arold Jan 02 '20 at 16:50