I am coding a simple Android App using Kotlin and Epson's ePOS SDK for Android to learn more about Android App development and Bluetooth Printing. However, I hit a dead-end, I am struggling to find a way to wait for the printer to finish it's print job before disconnecting, I want to do this because currently if I try connecting and printing, and then try disconnecting afterwards, it gives me an error saying it failed to disconnect, after fiddling around with different methods, I found out this is because the app is attempting to disconnect from the printer too early (while a print job is happening), despite adding those await functions to make sure it finishes each function before disconnecting.
I want to be able to wait for the printer to finish it's print job entirely before executing the disconnect command to prevent this error from happening.
Logcat: Successfully connects and prints for the first time, fails to disconnects, and cannot connect, print, disconnect unless the app restarts.
2023-06-04 21:33:40.954 7338-7409 PrintJob com.dishdasher.orderprintbluetooth D Successfully Printed
2023-06-04 21:33:41.018 7338-7409 PrintJob com.dishdasher.orderprintbluetooth E Failed to disconnect from printer: null, status: 6
2023-06-04 21:33:42.895 7338-7409 PrintJob com.dishdasher.orderprintbluetooth E Failed to connect: null
2023-06-04 21:33:42.898 7338-7409 PrintJob com.dishdasher.orderprintbluetooth E Failed to print: null
2023-06-04 21:33:42.899 7338-7419 PrintJob com.dishdasher.orderprintbluetooth E Failed to disconnect from printer: null, status: 5
Printing.kt:
import android.util.Log
import com.epson.epos2.Epos2Exception
import com.epson.epos2.printer.Printer
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import kotlinx.coroutines.async
import kotlinx.coroutines.withContext
import kotlin.coroutines.CoroutineContext
// The Printing class manages the printing tasks.
// It uses Coroutines to run tasks asynchronously.
class Printing(private val context: Context) : CoroutineScope {
// The printer object.
private lateinit var yourPrinter: Printer
// Flag to track if printer is currently in use.
private var isPrinting: Boolean = false
// Job instance for coroutine.
private val job = Job()
// Queue for storing print jobs.
private val printQueue: MutableList<String> = mutableListOf()
// Defines coroutine context to be main thread.
override val coroutineContext: CoroutineContext
get() = Dispatchers.Main + job
// Adds a print job to the queue.
// If printer isn't currently printing, starts next print job.
suspend fun print(PrintString: String) {
printQueue.add(PrintString)
if (!isPrinting) {
printNextJob()
} else {
Log.d("PrintJob", "Print job added to queue")
}
}
// Prints next job in the queue if available.
private suspend fun printNextJob() {
if (printQueue.isNotEmpty()) {
val nextJob = printQueue.removeAt(0)
isPrinting = true
try {
val connectTask = async { connectPrinter() }
connectTask.await()
val printTask = async { printTask(nextJob) }
printTask.await()
val disconnectTask = async { disconnectPrinter() }
disconnectTask.await()
} finally {
isPrinting = false
if (printQueue.isNotEmpty()) {
printNextJob()
}
}
}
}
// Connects to printer. If connection fails, logs an error message.
private suspend fun connectPrinter() {
withContext(Dispatchers.IO) {
try {
yourPrinter = Printer(Printer.TM_M30, Printer.LANG_EN, context)
yourPrinter.connect("BT:00:01:90:7B:E0:EE", 10000)
Log.d("PrintJob", "Successfully Connected")
} catch (e: Epos2Exception) {
Log.e("PrintJob", "Failed to connect: ${e.message}")
}
}
}
// Prints the receipt. If printing fails, logs an error message.
private suspend fun printTask(receiptString: String) {
withContext(Dispatchers.IO) {
try {
yourPrinter.beginTransaction()
yourPrinter.addText(receiptString)
yourPrinter.addFeedLine(1)
yourPrinter.addCut(Printer.CUT_FEED)
yourPrinter.sendData(Printer.PARAM_DEFAULT)
yourPrinter.endTransaction()
Log.d("PrintJob", "Successfully Printed")
} catch (e: Epos2Exception) {
Log.e("PrintJob", "Failed to print: ${e.message}")
}
}
}
// Disconnects from the printer. If disconnection fails, logs an error message.
private suspend fun disconnectPrinter() {
withContext(Dispatchers.IO) {
try {
if (::yourPrinter.isInitialized) {
yourPrinter.disconnect()
} else {
}
} catch (ex: Epos2Exception) {
Log.e(
"PrintJob",
"Failed to disconnect from printer: ${ex.message}, status: ${ex.errorStatus}"
)
}
}
}
}```