首页 > 解决方案 > registerForActivityResult(ActivityResultContracts.TakeVideo()) 始终为空

问题描述

我使用以下代码来捕获视频。一切正常,但在捕获视频后, registerForActivityResult(ActivityResultContracts.TakeVideo())始终为空。捕获的视频存在于给定路径中。我可以通过什么方式解决这个问题?

 private fun openCameraForMovie() {
        val packageManager = requireContext().packageManager
        Intent(MediaStore.ACTION_VIDEO_CAPTURE).also { takeVideoIntent ->
            takeVideoIntent.resolveActivity(packageManager)?.also {
                startRecording()
            }
        }
    }




 private fun startRecording() {
        try {
            val root = File(
                requireContext().getExternalFilesDir(Environment.DIRECTORY_PICTURES)
                    .toString() + "/media/"
            )

            if (!root.exists()) {
                root.mkdir()
            }

            val videoName = "vid_" + System.currentTimeMillis() + ".mp4"
            val sdImageMainDirectory = File(root, videoName)

            var fileUri: Uri? = FileProvider.getUriForFile(
                requireContext(),
                context?.applicationContext?.packageName + ".provider",
                sdImageMainDirectory
            ) ?: return

        
            mViewModel.videoUri.postValue(fileUri)

        } catch (ex: Exception) {
            Timber.d("startRecording ${ex.localizedMessage}")
        }
    }

此代码始终为空:

  private val recordVideoResult =
        registerForActivityResult(ActivityResultContracts.TakeVideo()) { it ->
            try {
                if (it != null) {
                    Timber.d(">>>> Video Bitmap: $it") 
                }
            } catch (ex: Exception) {
                Timber.d(">>>> Video Bitmap: ${ex.localizedMessage}")
            }
        }

标签: androidkotlinonactivityresult

解决方案


发生了什么?

ActivityResultContract视频保存到提供的内容Uri中 - 。

返回缩略图。

来源TakeVideo 文档,强调我的。

您不想要缩略图(无论如何这是可选的),您想要Uri指向实际视频的缩略图。但是您已经知道Uri, 因为您提供了它作为输入。

怎么办?

完成这项工作需要几个步骤:

  1. 将输入存储Uri在变量中并正确处理保存的状态,这样当您从相机应用程序返回时,您的应用程序就知道您一直在录制视频。

  2. 编写自定义TakeVideo合同,如果视频捕获成功则返回。Bitmap不能使用检查非空预览,因为预览是可选的。

它可能看起来像这样:

private AtomicReference<Uri> recordingUri = new AtomicReference<>();

private ActivityResultLauncher<Uri> recordVideoResult =
        registerForActivityResult(new TakeVideo2(), success -> {
            final Uri uri = recordingUri.getAndSet(null);
            if (success) {
                // Do something with the video.
            }
        });

@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
    // ...
    if (savedInstanceState != null) {
        recordingUri.set(savedInstanceState.getParcelable("recordingUri"));
    }
}

@Override
public void onSaveInstanceState(@NonNull Bundle outState) {
    // ...
    outState.putParcelable("recordingUri", recordingUri.get());
}

private void startRecording() {
    final Uri uri = // ...;
    recordingUri.set(uri);
    recordVideoResult.launch(uri);
}

public static class TakeVideo2 extends ActivityResultContract<Uri, Boolean> {

    @CallSuper
    @NonNull
    @Override
    public Intent createIntent(@NonNull Context context, @NonNull Uri input) {
        return new Intent(MediaStore.ACTION_VIDEO_CAPTURE)
                .putExtra(MediaStore.EXTRA_OUTPUT, input);
    }

    @Nullable
    @Override
    public final SynchronousResult<Boolean> getSynchronousResult(@NonNull Context context,
            @NonNull Uri input) {
        return null;
    }

    @Override
    public final Boolean parseResult(int resultCode, @Nullable Intent intent) {
        return resultCode == Activity.RESULT_OK;
    }
}

推荐阅读