0

I am trying to start two work request, one worker sends a request to the server for generating excel file and obtains URL for download. Another work starts after previous and must to download that file. First work starts and returns Result.SUCCESS. Problem is another WorkRequest just not execute. LoadInvoiceFileWorker do nothing. What I need to do or what I do wrong?

Here is my code: InvoiceDetailsViewModel:

class InvoiceDetailsViewModel : ViewModel() {
    private val mWorkManager: WorkManager = WorkManager.getInstance()

    fun generateAndLoadExcel(invoiceId: Int, invoiceName: String, enterpriseId: Int) {
        val genInvoiceWorkerBuilder = OneTimeWorkRequest.Builder(GenerateExcelWorker::class.java)
        genInvoiceWorkerBuilder.setInputData(createInputDataForGenerateExcel(invoiceId, invoiceName, enterpriseId))

        val constraintBuilder = Constraints.Builder()
        //constraintBuilder.setRequiredNetworkType(NetworkType.CONNECTED)
        genInvoiceWorkerBuilder.setConstraints(constraintBuilder.build())

        val continuation = mWorkManager.beginWith(
                genInvoiceWorkerBuilder.build()
        )

        val loadFileWorkerBuilder = OneTimeWorkRequest.Builder(LoadInvoiceFileWorker::class.java)
        //loadFileWorkerBuilder.setConstraints(Constraints.NONE)
        continuation.then(loadFileWorkerBuilder.build())

        continuation.enqueue()
    }

    private fun createInputDataForGenerateExcel(invoiceId: Int, invoiceName: String, enterpriseId: Int): Data {
        val builder = Data.Builder()
        builder.putInt(WorkerConstants.INVOICE_ID, invoiceId)
        builder.putString(WorkerConstants.INVOICE_NAME, invoiceName)
        builder.putInt(WorkerConstants.ENTERPRISE_ID, enterpriseId)
        return builder.build()
    }
}

GenerateExcelWorker:

class GenerateExcelWorker : Worker() {
    companion object {
        private val TAG = GenerateExcelWorker::class.java.simpleName
    }

    override fun doWork(): Result {
        val appCont = applicationContext
        val tokenType = PreferenceUtil.getString(TOKEN_TYPE, appCont, R.string.shared_pref_name)
        val accessToken = PreferenceUtil.getString(ACCESS_TOKEN, appCont, R.string.shared_pref_name)
        val enterpriseId = inputData.getInt(WorkerConstants.ENTERPRISE_ID, 0)
        val invoiceId = inputData.getInt(WorkerConstants.INVOICE_ID, 0)
        val invoiceName = inputData.getString(WorkerConstants.INVOICE_NAME)

        makeStatusNotification(applicationContext, invoiceId, invoiceName
                ?: ("Invoice ${invoiceId.str()}"))
        try {
            val rd = RequestData()
            rd.putValue("authorization", "$tokenType $accessToken", RequestData.TYPE_HEADER)
            rd.putValue(FTUrls.SendingParameters.ENTERPRISE_ID, enterpriseId, RequestData.TYPE_PATH)
            rd.putValue(FTUrls.SendingParameters.INVOICE_ID, invoiceId, RequestData.TYPE_PATH)
            val excelUrl = InvoiceManager().generateIncomeInvoiceExcel(rd)
            outputData = Data.Builder().putString(WorkerConstants.FILE_URL, excelUrl).build()
            return Result.SUCCESS
        } catch (t: Throwable) {
            Log.e(TAG, "Error generating excel file for invoice $invoiceName ($invoiceId)", t)
            if (t is UnauthenticatedException) {
                outputData = Data.Builder().putBoolean(WorkerConstants.FILE_URL, true).build()
            } else {
                ExceptionLogger.logException(t)
                Toast.makeText(applicationContext, t.message, Toast.LENGTH_SHORT).show()
            }
            return Result.FAILURE
        }
    }

    private fun makeStatusNotification(context: Context, invoiceId: Int, invoiceTitle: String) {
        // Make a channel if necessary
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            // Create the NotificationChannel, but only on API 26+ because
            // the NotificationChannel class is new and not in the support library
            val name = WorkerConstants.NOTIFICATION_CHANNEL_NAME
            val description = WorkerConstants.NOTIFICATION_CHANNEL_DESCRIPTION
            val importance = NotificationManager.IMPORTANCE_HIGH
            val channel = NotificationChannel(WorkerConstants.CHANNEL_ID, name, importance)
            channel.description = description

            // Add the channel
            val notificationManager = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
            notificationManager.createNotificationChannel(channel)
        }

        val builder = NotificationCompat.Builder(context, WorkerConstants.CHANNEL_ID)
                .setSmallIcon(R.drawable.ic_autorenew_blue)
                .setContentTitle(WorkerConstants.NOTIFICATION_TITLE)
                .setContentText(String.format(WorkerConstants.NOTIFICATION_TEXT, invoiceTitle))
                .setPriority(NotificationCompat.PRIORITY_HIGH)
                .setVibrate(LongArray(0))

        NotificationManagerCompat.from(context).notify(invoiceId, builder.build())
    }
}

LoadInvoiceFileWorker:

class LoadInvoiceFileWorker : Worker() {
    companion object {
        private val TAG = LoadInvoiceFileWorker::class.java.simpleName
    }

    override fun doWork(): Result {
        try {
            val fileUrl = inputData.getString(WorkerConstants.FILE_URL)
            val invoiceId = inputData.getInt(WorkerConstants.INVOICE_ID, 0)
            val invoiceName = inputData.getString(WorkerConstants.INVOICE_NAME)
            val r = DownloadManager.Request(Uri.parse(fileUrl))
            // This put the download in the same Download dir the browser uses
            r.setDestinationInExternalPublicDir(Environment.DIRECTORY_DOWNLOADS, invoiceName
                    ?: ("Invoice ${invoiceId.str()}"))
            // Notify user when download is completed
            r.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED)
            // Start download
            val dm = applicationContext.getSystemService(Context.DOWNLOAD_SERVICE) as DownloadManager?
            if (dm != null) {
                dm.enqueue(r)
            } else {
                Log.w(TAG, "Download manager not exists for load invoice excel file")
                ToastError(applicationContext, R.string.download_manager_not_found, Toast.LENGTH_SHORT)
                val intent = Intent(Intent.ACTION_VIEW, Uri.parse(fileUrl))
                try {
                    applicationContext.startActivity(intent)
                } catch (e: ActivityNotFoundException) {
                    Log.e(TAG, "Error open browser for view invoice excel file", e)
                    ToastError(applicationContext, R.string.browser_not_found, Toast.LENGTH_SHORT)
                }
            }
            clearGenerateFileNotification(invoiceId)
            return Result.SUCCESS
        } catch (t: Throwable) {
            Log.e(TAG, "Error loading excel generated file", t)
            ExceptionLogger.logException(t)
            ToastError(applicationContext, R.string.error_during_loading_file, Toast.LENGTH_SHORT)
            return Result.FAILURE
        }
    }

    private fun clearGenerateFileNotification(invoiceId: Int) {
        val notificationManager = applicationContext.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
        notificationManager.cancel(invoiceId)
    }
}

WorkerConstants:

object WorkerConstants {
    const val ENTERPRISE_ID = "enterprise_id"
    const val INVOICE_ID = "invoice_id"
    const val INVOICE_NAME = "invoice_name"
    const val FILE_URL = "file_url"

    const val UNIQUE_WORK_NAME_FOR_INVOICE = "generate_and_load_excel_for_invoice"

    const val NOTIFICATION_CHANNEL_NAME = "GenerateExcelWorker Notifications"
    const val NOTIFICATION_CHANNEL_DESCRIPTION = "Shows notifications whenever work starts"
    const val NOTIFICATION_TITLE = "Генерація ексель файла"
    const val NOTIFICATION_TEXT = "Генерація ексель файла накладної %s"
    const val CHANNEL_ID = "GENERATE_INVOICE_NOTIFICATION"
}
InsaneCat
  • 2,115
  • 5
  • 21
  • 40

1 Answers1

2

Ok, I found my mistake. Instead of this: ...

continuation.then(loadFileWorkerBuilder.build())
continuation.enqueue()

I need make this: ...

continuation = continuation.then(loadFileWorkerBuilder.build())
continuation.enqueue()

I was apllying enqueue() for first continuation of one request. Method WorkContinuation.then() returns new object which contains old continuation with new added request.