【问题标题】:Kotlin coroutines return StringKotlin 协程返回字符串
【发布时间】:2019-05-11 12:47:04
【问题描述】:

我正在尝试将方法从 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
            }
        }
    }

return outputFile这行编译出错,谁能帮忙,我是第一次使用协程

编辑

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

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(""))
        }

【问题讨论】:

    标签: android kotlin android-asynctask kotlin-coroutines coroutinescope


    【解决方案1】:

    如果你期待这个功能

    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
    }
    

    这里请注意,我们调用launchthis 作为接收者。 launch 的接收者必须是 CoroutineScope 并且你应该在你的 MainActivity 或任何你调用它的上下文中实现它。请参阅structured concurrency 了解说明。

    【讨论】:

    • 我应该在 catch 中返回什么,没有返回值,请检查我上面的编辑并告诉我这是否是您的意思
    • 在您的新代码中,无论如何您都不会从getCompressedVideo 返回任何内容。如果您这样做,我不确定您的目标是什么。我的版本显示了一个函数,该函数返回 String 并抛出块中发生的任何异常。您可以在调用站点上使用普通的try-catch 来捕获它们,或者如果您愿意,您可以在函数中捕获它们并返回您喜欢的任何内容。就像你在纯代码中一样。
    • 这个方法应该用于获取视频uri并读取它并使用ffmpeg对其进行压缩并将其保存到内存中并返回压缩视频的新uri
    • 所以你的意思是我需要改变方法并让它返回字符串值,在 try 我应该返回 outputfile 并且在 catch 我应该返回 null 例如,你的意思是?跨度>
    • 是的,null 如果这对你有用。但对于某些事情没有成功的情况,通常例外情况会更好。要点是您的选择是相同的,就好像它是一个普通的、不可暂停的功能一样。在调用端和实现端。
    【解决方案2】:

    解决它的一种可能方法是使用GlobalScope.async builder:

    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
        }
    }
    

    【讨论】:

      【解决方案3】:

      您可以像这样指定 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)
              }
          }
      }
      

      【讨论】:

        猜你喜欢
        • 2020-03-12
        • 2018-02-22
        • 2018-04-13
        • 2020-12-08
        • 2017-11-08
        • 2019-09-24
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多