Android CameraX打开摄像头预览教程
大家好,本篇文章主要讲的是Android CameraX打开摄像头预览教程,感兴趣的同学赶快来看一看吧,对你有帮助的话记得收藏一下
目录
前言
引入依赖
权限
界面
开启预览
运行测试
增加开关
小结
前言
目标很简单,用CameraX打开摄像头预览,实时显示在界面上。看看CameraX有没有Google说的那么好用。先按最简单的来,把预览显示出来。
引入依赖
模块gradle的一些配置,使用的Android SDK版本为31,启用了databinding
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | apply plugin: 'com.android.application' apply plugin: 'kotlin-android' apply plugin: 'kotlin-android-extensions' apply plugin: 'kotlin-kapt' android { compileSdkVersion 31 buildToolsVersion "31.0.0" defaultConfig { minSdkVersion 21 targetSdkVersion 31 } dataBinding { enabled = true } } |
引入CameraX依赖(CameraX 核心库是用camera2实现的),目前主要用1.1.0-alpha11版本
1 2 3 4 5 6 7 | dependencies { implementation "androidx.camera:camera-core:1.1.0-alpha11" implementation "androidx.camera:camera-camera2:1.1.0-alpha11" implementation "androidx.camera:camera-lifecycle:1.1.0-alpha11" implementation "androidx.camera:camera-view:1.0.0-alpha31" implementation "androidx.camera:camera-extensions:1.0.0-alpha31" } |
使用1.0.2版本的CameraX核心库会报错,找不到getOrCreateInstance
方法。
??? bug "NoSuchMethodError getOrCreateInstance"
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | ```log CrashHandler: In thread: Thread[main, 5 ,main] UncaughtException detected: java.lang.NoSuchMethodError: No static method getOrCreateInstance(Landroid/content/Context;)Lcom/google/common/util/concurrent/ListenableFuture; in class Landroidx/camera/core/CameraX; or its super classes (declaration of 'androidx.camera.core.CameraX' appears in /data/app/com.rustfisher.tutorial2020- 1 /base.apk) at androidx.camera.lifecycle.ProcessCameraProvider.getInstance(ProcessCameraProvider.java: 149 ) at com.rustfisher.tutorial2020.camera.SimplePreviewXAct.onCreate(SimplePreviewXAct.java: 36 ) at android.app.Activity.performCreate(Activity.java: 6161 ) at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java: 1112 ) at android.app.ActivityThread.performLaunchActivity(ActivityThread.java: 2507 ) at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java: 2640 ) at android.app.ActivityThread.access$ 800 (ActivityThread.java: 182 ) at android.app.ActivityThread$H.handleMessage(ActivityThread.java: 1493 ) at android.os.Handler.dispatchMessage(Handler.java: 111 ) at android.os.Looper.loop(Looper.java: 194 ) at android.app.ActivityThread.main(ActivityThread.java: 5682 ) at java.lang.reflect.Method.invoke(Native Method) at java.lang.reflect.Method.invoke(Method.java: 372 ) at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java: 963 ) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java: 758 ) ``` |
权限
需要动态申请android.permission.CAMERA
权限
1 | <uses-permission android:name= "android.permission.CAMERA" /> |
本文略过动态申请权限的地方
界面
CameraX为开发者贴心地准备了androidx.camera.view.PreviewView
把它放在一个FrameLayout里,如下的act_simple_preivew_x.layout
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | <?xml version= "1.0" encoding= "utf-8" ?> <layout> <FrameLayout xmlns:android= "http://schemas.android.com/apk/res/android" android:id= "@+id/container" android:layout_width= "match_parent" android:layout_height= "match_parent" > <androidx.camera.view.PreviewView android:id= "@+id/previewView" android:layout_width= "match_parent" android:layout_height= "match_parent" /> </FrameLayout> </layout> |
开启预览
在activity中开启相机预览
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 | // SimplePreviewXAct.java import android.os.Bundle; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.appcompat.app.AppCompatActivity; import androidx.camera.core.Camera; import androidx.camera.core.CameraSelector; import androidx.camera.core.Preview; import androidx.camera.lifecycle.ProcessCameraProvider; import androidx.core.content.ContextCompat; import androidx.databinding.DataBindingUtil; import androidx.lifecycle.LifecycleOwner; import com.google.common.util.concurrent.ListenableFuture; // import com.rustfisher.tutorial2020.R; // import com.rustfisher.tutorial2020.databinding.ActSimplePreivewXBinding; import java.util.concurrent.ExecutionException; public class SimplePreviewXAct extends AppCompatActivity { private ActSimplePreivewXBinding mBinding; private ListenableFuture<ProcessCameraProvider> cameraProviderFuture; @Override protected void onCreate( @Nullable Bundle savedInstanceState) { super .onCreate(savedInstanceState); mBinding = DataBindingUtil.setContentView( this , R.layout.act_simple_preivew_x); cameraProviderFuture = ProcessCameraProvider.getInstance( this ); cameraProviderFuture.addListener(() -> { try { ProcessCameraProvider cameraProvider = cameraProviderFuture.get(); bindPreview(cameraProvider); } catch (ExecutionException | InterruptedException e) { // 这里不用处理 } }, ContextCompat.getMainExecutor( this )); } void bindPreview( @NonNull ProcessCameraProvider cameraProvider) { Preview preview = new Preview.Builder().build(); CameraSelector cameraSelector = new CameraSelector.Builder() .requireLensFacing(CameraSelector.LENS_FACING_BACK) .build(); preview.setSurfaceProvider(mBinding.previewView.getSurfaceProvider()); Camera camera = cameraProvider.bindToLifecycle( this , cameraSelector, preview); } } |
注意我们这里使用的是androidx.appcompat.app.AppCompatActivity
为了获得ProcessCameraProvider,用ProcessCameraProvider.getInstance
方法拿到一个cameraProviderFuture
。
在cameraProviderFuture
完成后取出ProcessCameraProvider(cameraProvider
)。
要开启预览,通过Preview.Builder
构建一个Preview。用CameraSelector来选择后置摄像头。
Preview的SurfaceProvider由layout中的androidx.camera.view.PreviewView提供。
cameraProvider.bindToLifecycle
绑定上后,启动摄像头预览
运行测试
运行到手机上,打开这个Activity就可以看到摄像头预览。图像宽高比正常,没有拉伸现象。
荣耀 EMUI 3.1 Lite,Android 5.1 运行正常
Redmi 9A,MIUI 12.5.1稳定版,Android 10 运行正常
一加5,H2OS 10.0.3,Android 10 运行正常
增加开关
在layout里加2个按钮,控制相机开关
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 | <?xml version= "1.0" encoding= "utf-8" ?> <layout> <LinearLayout xmlns:android= "http://schemas.android.com/apk/res/android" android:layout_width= "match_parent" android:layout_height= "match_parent" android:orientation= "vertical" > <LinearLayout android:layout_width= "match_parent" android:layout_height= "wrap_content" android:background= "@color/colorPrimaryDark" android:gravity= "center" android:orientation= "horizontal" android:padding= "4dp" > <Button android:id= "@+id/start" style= "@style/NormalBtn" android:layout_width= "wrap_content" android:layout_height= "wrap_content" android:text= "打开" /> <Button android:id= "@+id/end" style= "@style/NormalBtn" android:layout_width= "wrap_content" android:layout_height= "wrap_content" android:layout_marginStart= "12dp" android:text= "关闭" /> </LinearLayout> <FrameLayout xmlns:android= "http://schemas.android.com/apk/res/android" android:id= "@+id/container" android:layout_width= "match_parent" android:layout_height= "match_parent" > <androidx.camera.view.PreviewView android:id= "@+id/previewView" android:layout_width= "match_parent" android:layout_height= "match_parent" /> </FrameLayout> </LinearLayout> </layout> |
根layout换成LinearLayout
修改bindPreview
方法,先检查传入的ProcessCameraProvider是否为空
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | private void bindPreview(ProcessCameraProvider cameraProvider) { if (cameraProvider == null ) { Toast.makeText(getApplicationContext(), "没获取到相机" , Toast.LENGTH_SHORT).show(); return ; } Preview preview = new Preview.Builder().build(); CameraSelector cameraSelector = new CameraSelector.Builder() .requireLensFacing(CameraSelector.LENS_FACING_BACK) .build(); preview.setSurfaceProvider(mBinding.previewView.getSurfaceProvider()); Camera camera = cameraProvider.bindToLifecycle( this , cameraSelector, preview); } |
修改后的activity部分代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 | import android.os.Bundle; import android.widget.Toast; import androidx.annotation.Nullable; import androidx.appcompat.app.AppCompatActivity; import androidx.camera.core.Camera; import androidx.camera.core.CameraSelector; import androidx.camera.core.Preview; import androidx.camera.lifecycle.ProcessCameraProvider; import androidx.core.content.ContextCompat; import androidx.databinding.DataBindingUtil; import com.google.common.util.concurrent.ListenableFuture; // import com.rustfisher.tutorial2020.R; // import com.rustfisher.tutorial2020.databinding.ActSimplePreivewXBinding; import java.util.concurrent.ExecutionException; public class SimplePreviewXAct extends AppCompatActivity { private ActSimplePreivewXBinding mBinding; private ListenableFuture<ProcessCameraProvider> mCameraProviderFuture; private ProcessCameraProvider mCameraProvider; private boolean mRunning = false ; @Override protected void onCreate( @Nullable Bundle savedInstanceState) { super .onCreate(savedInstanceState); mBinding = DataBindingUtil.setContentView( this , R.layout.act_simple_preivew_x); mCameraProviderFuture = ProcessCameraProvider.getInstance( this ); mCameraProviderFuture.addListener(() -> { try { mCameraProvider = mCameraProviderFuture.get(); } catch (ExecutionException | InterruptedException e) { // 这里不用处理 } }, ContextCompat.getMainExecutor( this )); mBinding.start.setOnClickListener(v -> { if (mCameraProvider != null && !mRunning) { bindPreview(mCameraProvider); } }); mBinding.end.setOnClickListener(v -> { mCameraProvider.unbindAll(); mRunning = false ; }); } private void bindPreview(ProcessCameraProvider cameraProvider) { if (cameraProvider == null ) { Toast.makeText(getApplicationContext(), "没获取到相机" , Toast.LENGTH_SHORT).show(); return ; } Preview preview = new Preview.Builder().build(); CameraSelector cameraSelector = new CameraSelector.Builder() .requireLensFacing(CameraSelector.LENS_FACING_BACK) .build(); preview.setSurfaceProvider(mBinding.previewView.getSurfaceProvider()); Camera camera = cameraProvider.bindToLifecycle( this , cameraSelector, preview); mRunning = true ; } } |
拿到mCameraProvider
后不要立刻绑定生命周期。
如果要开启预览,则调用bindPreview(mCameraProvider)
。记录一下现在相机已经开启预览mRunning = true
。
如果要停止预览,则解绑生命周期mCameraProvider.unbindAll()
。这个方法需要在主线程调用。
运行起来后,可以用按钮来控制相机预览的开关。相比之前,PreviewView的高度变小了一点(让了点位置给按钮)。
但视频宽高比例正常,没有被拉伸。默认的配置下,还有自动对焦的功能。
小结
从简单的打开相机预览来看,CameraX简化了开发者的工作。提供了PreviewView,开发者不需要自定义SurfaceView或者TextureView。实时预览中,相机能够自动对焦。本文用的是1.1.0-alpha11,而CameraX还在发展之中。
到此这篇关于Android CameraX打开摄像头预览教程的文章就介绍到这了
伪原创工具 SEO网站优化 https://www.237it.com/