请求相机功能
如果您应用的基本功能是拍照,请将其在 Google Play 上的显示范围限制在装有相机的设备上。如需声明您的应用依赖于相机,请在清单文件中添加 <uses-feature>
代码:
<manifest ... >
<uses-feature android:name="android.hardware.camera"
android:required="true" />
...
</manifest>
如果您的应用使用相机,但不需要相机也可以正常运作,应将 android:required
设为 false
。这样,Google Play 便会允许未装有相机的设备下载您的应用。因此,您必须负责通过调用 hasSystemFeature(PackageManager.FEATURE_CAMERA_ANY)
检查相机在运行时的可用性。如果相机不可用,您应停用相机功能。
使用相机应用录制视频
推荐一个比startActivityForResult更方便获取一个Activity的返回结果的方法:
@NonNull
@Override
public final <I, O> ActivityResultLauncher<I> registerForActivityResult(
@NonNull ActivityResultContract<I, O> contract,
@NonNull ActivityResultCallback<O> callback) {
return registerForActivityResult(contract, mActivityResultRegistry, callback);
}
请求录制视频
录视频之前需要先生成视频保存位置Uri,方便后面使用
生成Uri方法如下:
/**
* 获取拍视频后的视频Uri
*/
fun getTakeVideoUri(context: Context): Uri {
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
val contentValue = contentValuesOf(
Pair(
MediaStore.MediaColumns.DISPLAY_NAME,
"VID_${TimeUtil.getCurrentTime_yyyyMMdd_HHmmss()}.mp4"
),
Pair(MediaStore.MediaColumns.RELATIVE_PATH, Environment.DIRECTORY_MOVIES)
)
context.contentResolver.insert(
MediaStore.Video.Media.EXTERNAL_CONTENT_URI, contentValue
)!!
} else {
val file = File(
Environment.getExternalStorageState(),
"/Movies/VID_${TimeUtil.getCurrentTime_yyyyMMdd_HHmmss()}.mp4"
)
context.getExternalFilesDir(Environment.DIRECTORY_MOVIES)?.let {
val f = File(it, "/VID_${TimeUtil.getCurrentTime_yyyyMMdd_HHmmss()}.mp4")
FileProvider.getUriForFile(context, authorities, f)
} ?: FileProvider.getUriForFile(context, authorities, file)
}
}
下一步则需要先注册回调,在OnCreate中写就行。
val getVideoResultBack = registerForActivityResult(ActivityResultContractsForCustom.TakeVideo()){
if (it == true) {
mVidUri?.let { uri ->
// 使用Dialog来播放拍完的视频
val dialog = VideoDialog()
dialog.setVideoPath(FileUtil.getRealFilePathByUri(this, uri))
dialog.show(supportFragmentManager, "video")
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) {
val absolutePath = FileUtil.getRealFilePathByUri(this, uri)
MediaUtil.mediaInsertVideo(this@MainActivity, absolutePath)
}
}
}
}
// 调用相机 mVidUri最好在每次拍照前都把其值重新更新,以免发生新拍的照片将旧照片覆盖的情况 下面方法在按钮点击后调用
getVideoResultBack?.launch(mVidUri)
这里并没有使用系统的ActivityResultContracts.TakeVideo(),主要考虑系统提供的返回bitmap,根据判断是否拍摄完成不太方便,所以采用自定义回调方式,自定义类需要继承:ActivityResultContract<Uri, Boolean?>,返回值类型选择Boolean。
ActivityResultContractsForCustom相关实现
object ActivityResultContractsForCustom {
class TakeVideo : ActivityResultContract<Uri, Boolean?>() {
@CallSuper
override fun createIntent(context: Context, input: Uri): Intent {
return Intent(MediaStore.ACTION_VIDEO_CAPTURE)
.putExtra(MediaStore.EXTRA_OUTPUT, input)
}
override fun getSynchronousResult(
context: Context,
input: Uri
): SynchronousResult<Boolean?>? {
return null
}
override fun parseResult(resultCode: Int, intent: Intent?): Boolean? {
// 根据返回是否成功来判断是否拍完视频后点击完成返回首页
return resultCode == Activity.RESULT_OK
}
}
}
另一种官方文档上提供的Intent方法:
下面都是官方提供的方式
Android 向其他应用委托操作的方法是调用一个 Intent
以描述您要执行的操作。此过程涉及三个部分:Intent
本身,用于启动外部 Activity
的调用,以及用于在焦点返回到 Activity 时处理视频的一些代码。
下面是一个调用 Intent 以拍摄视频的函数。
const val REQUEST_VIDEO_CAPTURE = 1
private fun dispatchTakeVideoIntent() {
Intent(MediaStore.ACTION_VIDEO_CAPTURE).also { takeVideoIntent ->
takeVideoIntent.resolveActivity(packageManager)?.also {
startActivityForResult(takeVideoIntent, REQUEST_VIDEO_CAPTURE)
}
}
}
请注意,startActivityForResult()
方法受调用 resolveActivity()
(返回可处理 Intent 的第一个 Activity 组件)的条件保护。执行此检查非常重要,因为如果您使用任何应用都无法处理的 Intent 调用 startActivityForResult()
,您的应用就会崩溃。所以只要结果不是 Null,就可以放心使用 Intent。
观看视频
Android 相机应用会返回 Intent
(作为 Uri
传递给 onActivityResult()
,指向视频在存储设备中所处的位置)中的视频。下面的代码会检索此视频并将其显示在一个 VideoView
中。
override fun onActivityResult(requestCode: Int, resultCode: Int, intent: Intent) {
if (requestCode == REQUEST_VIDEO_CAPTURE && resultCode == RESULT_OK) {
val videoUri: Uri = intent.data
videoView.setVideoURI(videoUri)
}
}
网友评论