Kotlin协程返回String

时间:2018-12-10 15:25:41

标签: kotlin kotlinx.coroutines

我正在尝试将方法从Java转换为kotlin,并用协程替换AsyncTask,但是我不知道如何从协程返回值

这是我的方法

override fun getCompressedVideo(context:Context ,video: Uri) {

        GlobalScope.launch(Dispatchers.Main) {

            val inputFile = video.getRealPathFromVideoUri(context)
            val loadJNI: LoadJNI = LoadJNI();
            try {

                val workFolder: String = context.filesDir.absolutePath

                val outputFile: String = getFileFullName(
                    FilesConstants.VIDEO_FOLDER,
                    String.format(FilesConstants.VIDEO_NAME_FILE_FORMAT, System.currentTimeMillis())
                );

                val complexCommand = arrayOf (
                    "ffmpeg", "-y"
                    , "-i", inputFile
                    , "-strict", "experimental"
                    , "-s", "320x240"
                    , "-r", "25"
                    , "-aspect", "4:3"
                    , "-ab", "48000"
                    , "-ac", "2"
                    , "-vcodec", "mpeg4"
                    , "-movflags", "+faststart"
                    , "-ar", "22050"
                    , "-b", "2097k"
                    , outputFile);

                loadJNI.run(complexCommand, workFolder, context);
                return outputFile

            } catch (th: Throwable) {
                return@launch
            }
        }
    }

返回outputFile 的行使编译错误,任何人都可以帮忙,这是我第一次使用协程

编辑

这是使用暂停后的方法,但是现在我不知道如果发生任何问题如何返回值

override suspend fun getCompressedVideo(context: Context, video: Uri) {

        val outputFile = withContext(Dispatchers.IO) {

            val inputFile = video.getRealPathFromVideoUri(context)
            val loadJNI: LoadJNI = LoadJNI();
            try {

                val workFolder: String = context.filesDir.absolutePath

                val outputFile: String = getFileFullName(
                    FilesConstants.VIDEO_FOLDER,
                    String.format(FilesConstants.VIDEO_NAME_FILE_FORMAT, System.currentTimeMillis())
                );

                val complexCommand = arrayOf(
                    "ffmpeg", "-y"
                    , "-i", inputFile
                    , "-strict", "experimental"
                    , "-s", "320x240"
                    , "-r", "25"
                    , "-aspect", "4:3"
                    , "-ab", "48000"
                    , "-ac", "2"
                    , "-vcodec", "mpeg4"
                    , "-movflags", "+faststart"
                    , "-ar", "22050"
                    , "-b", "2097k"
                    , outputFile
                );

                loadJNI.run(complexCommand, workFolder, context)
            }catch (th: Throwable) {
            }
        }
    }

编辑2

您的意思是这样

override suspend fun getCompressedVideo(context: Context, video: Uri) : String {

        try {
            val retValue = withContext(Dispatchers.IO) {

                val inputFile = video.getRealPathFromVideoUri(context)
                val loadJNI: LoadJNI = LoadJNI()

                val workFolder: String = context.filesDir.absolutePath

                val outputFile: String = getFileFullName(
                    FilesConstants.VIDEO_FOLDER,
                    String.format(FilesConstants.VIDEO_NAME_FILE_FORMAT, System.currentTimeMillis())
                )

                val complexCommand = arrayOf(
                    "ffmpeg", "-y"
                    , "-i", inputFile
                    , "-strict", "experimental"
                    , "-s", "320x240"
                    , "-r", "25"
                    , "-aspect", "4:3"
                    , "-ab", "48000"
                    , "-ac", "2"
                    , "-vcodec", "mpeg4"
                    , "-movflags", "+faststart"
                    , "-ar", "22050"
                    , "-b", "2097k"
                    , outputFile
                )

                loadJNI.run(complexCommand, workFolder, context)
            }

            return retValue.toString()
        } catch (th: Throwable) {
            return ""
        }
    }

并称呼它

GlobalScope.launch {
            val retValue = ffmpegFacade.getCompressedVideo(this@TestActivity, Uri.parse(""))
        }

3 个答案:

答案 0 :(得分:3)

如果您希望使用此功能

override fun getCompressedVideo(context: Context, video: Uri)

在压缩完成后返回,这不是它的工作方式。您的代码将启动并发任务,该任务将在您的getCompressedVideo返回后的任意时间完成。

相反,我认为您应该按以下方式进行处理:

override suspend fun getCompressedVideo(
        context: Context, video: Uri
): String? = withContext(Dispatchers.IO) {
    try {
        val inputFile = video.getRealPathFromVideoUri(context)
        val loadJNI = LoadJNI()
        val workFolder: String = context.filesDir.absolutePath
        val outputFile: String = getFileFullName(
                FilesConstants.VIDEO_FOLDER,
                String.format(FilesConstants.VIDEO_NAME_FILE_FORMAT,
                        System.currentTimeMillis())
        )
        val complexCommand = arrayOf("-i", inputFile, "other-params")
        loadJNI.run(complexCommand, workFolder, context);
        outputFile
    } catch (t: Throwable) {
        null
    }
}

如您所见,这意味着将getCompressedVideo的声明更改为suspend fun。您不能直接通过Android回调调用它。因此,在呼叫现场,写

this.launch {
    val videoFile = ffmpegfacade.getCompressedVideo(context, Uri.parse("example.org/video"))
    // continue processing on the UI thread using videoFile
}

请注意,我们以launch作为接收方来呼叫thislaunch的接收者必须是CoroutineScope,并且您应该在自己的MainActivity或从中调用它的上下文中实现它。有关说明,请参见structured concurrency

答案 1 :(得分:1)

解决此问题的一种可能方法是使用GlobalScope.async构建器:

fun getCompressedVideo() = GlobalScope.async {
    val outputFile: String = "" 

    // ... compress video

    outputFile
}

// Calling getCompressedVideo() from outside
fun compressVideoAsync() {
    GlobalScope.launch(Dispatchers.Main) {
        val compression = getCompressedVideo()
        val outputFile = compression.await() // wait for result of compression operation without blocking the main thread

        // outputFile is ready to use
    }
}

答案 2 :(得分:1)

您可以像这样指定Kotlin function返回类型:

override fun getCompressedVideo(context: Context, video: Uri): String {

但是,由于它是异步的,所以您仍然不能执行此操作。

要从方法中返回,必须等到完成为止,这违背了异步执行的全部目的。

您可以改为使用high-order function指定异步任务完成后如何处理数据。

override fun getCompressedVideo(context:Context ,video: Uri, action: (String?) -> Unit) {

    GlobalScope.launch(Dispatchers.Main) {

        val inputFile = video.getRealPathFromVideoUri(context)
        val loadJNI: LoadJNI = LoadJNI();
        try {

            val workFolder: String = context.filesDir.absolutePath

            val outputFile: String = getFileFullName(
                FilesConstants.VIDEO_FOLDER,
                String.format(FilesConstants.VIDEO_NAME_FILE_FORMAT, System.currentTimeMillis())
            );

            val complexCommand = arrayOf (
                "ffmpeg", "-y"
                , "-i", inputFile
                , "-strict", "experimental"
                , "-s", "320x240"
                , "-r", "25"
                , "-aspect", "4:3"
                , "-ab", "48000"
                , "-ac", "2"
                , "-vcodec", "mpeg4"
                , "-movflags", "+faststart"
                , "-ar", "22050"
                , "-b", "2097k"
                , outputFile);

            loadJNI.run(complexCommand, workFolder, context);
            action(outputFile)

        } catch (th: Throwable) {
            action(null)
        }
    }
}