我正在尝试将方法从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(""))
}
答案 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
作为接收方来呼叫this
。 launch
的接收者必须是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)
}
}
}