Android studio APK切换多个摄像头(Camera2)

news2024/11/25 6:41:43

1.先设置camera的权限

 <uses-permission android:name="android.permission.CAMERA" />

2.布局

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <TextureView
        android:id="@+id/textureView"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="1"/>

    <Button
        android:id="@+id/btnSwitchCamera"
        android:layout_width="match_parent"
        android:layout_height="100dp"
        android:textSize="50dp"
        android:text="切换相机"/>

</LinearLayout>

3.主界面代码

package com.example.multiplecameras

import android.Manifest
import android.content.pm.PackageManager
import android.graphics.SurfaceTexture
import android.hardware.camera2.*
import android.os.Build
import android.os.Bundle
import android.util.Log
import android.view.Surface
import android.view.TextureView
import android.view.TextureView.SurfaceTextureListener
import android.view.View
import androidx.annotation.NonNull
import androidx.annotation.RequiresApi
import androidx.appcompat.app.AppCompatActivity
import androidx.core.app.ActivityCompat
import com.hjq.permissions.OnPermission
import com.hjq.permissions.XXPermissions


class MainActivity : AppCompatActivity() {


    private val TAG = MainActivity::class.java.simpleName
    private var cameraManager: CameraManager? = null
    private var cameraIds: Array<String>?=null
    private var currentCameraIdIndex = 0
    private var cameraDevice: CameraDevice? = null
    private var textureView: TextureView? = null

    private var captureRequestBuilder: CaptureRequest.Builder? = null
    private var cameraCaptureSession: CameraCaptureSession? = null
    private var surfaceTexture: SurfaceTexture? = null

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)


        XXPermissions.with(this)
            .request(object : OnPermission {
                @RequiresApi(Build.VERSION_CODES.LOLLIPOP)
                override fun hasPermission(granted: List<String>, isAll: Boolean) {
                    Log.e("TAG", "hasPermission=" + granted.size + "       " + isAll)
                    initView()
                }

                override fun noPermission(denied: List<String>, quick: Boolean) {
                    Log.e("TAG", "noPermission=" + denied.size + "       " + quick)
                }
            })

    }


    @RequiresApi(Build.VERSION_CODES.LOLLIPOP)
    fun initView(){
        cameraManager = getSystemService(CAMERA_SERVICE) as CameraManager
        textureView = findViewById(R.id.textureView)

        // 设置 TextureView 的监听器,用于在 SurfaceTexture 准备好时打开相机
        textureView!!.surfaceTextureListener = surfaceTextureListener

        // 相机切换按钮的点击事件监听器
        findViewById<View>(R.id.btnSwitchCamera).setOnClickListener {
            Log.e("TAG", "switchCamera()=========")
            switchCamera()
        }
    }

    private val surfaceTextureListener: SurfaceTextureListener = object : SurfaceTextureListener {
        override fun onSurfaceTextureAvailable(surface: SurfaceTexture, width: Int, height: Int) {
            surfaceTexture = surface
            Log.e("TAG", "onSurfaceTextureAvailable")
            openCamera()
        }

        override fun onSurfaceTextureSizeChanged(
            surface: SurfaceTexture,
            width: Int,
            height: Int
        ) {
        }

        override fun onSurfaceTextureDestroyed(surface: SurfaceTexture): Boolean {
            return false
        }

        override fun onSurfaceTextureUpdated(surface: SurfaceTexture) {}
    }

    @RequiresApi(Build.VERSION_CODES.LOLLIPOP)
    private fun openCamera() {
        Log.e("TAG", "openCamera============")
        try {
            cameraIds = cameraManager!!.cameraIdList
        } catch (e: Exception) {
            e.printStackTrace()
        }
        if (cameraIds != null && cameraIds!!.isNotEmpty()) {
            val cameraId = cameraIds!![currentCameraIdIndex]
            if (ActivityCompat.checkSelfPermission(
                    this,
                    Manifest.permission.CAMERA
                ) != PackageManager.PERMISSION_GRANTED
            ) {
                // TODO: Consider calling
                //    ActivityCompat#requestPermissions
                // here to request the missing permissions, and then overriding
                //   public void onRequestPermissionsResult(int requestCode, String[] permissions,
                //                                          int[] grantResults)
                // to handle the case where the user grants the permission. See the documentation
                // for ActivityCompat#requestPermissions for more details.
                return
            }
            Log.e("TAG", "openCamera============$cameraId")
            cameraManager!!.openCamera(cameraId, cameraCallback, null)
        }
    }

    private val cameraCallback: CameraDevice.StateCallback = @RequiresApi(Build.VERSION_CODES.LOLLIPOP)
    object : CameraDevice.StateCallback() {
        @RequiresApi(Build.VERSION_CODES.O)
        override fun onOpened(@NonNull camera: CameraDevice) {
            cameraDevice = camera
            Log.e("TAG", "onOpened============$cameraDevice")
            startPreview()
        }

        override fun onDisconnected(@NonNull camera: CameraDevice) {
            cameraDevice!!.close()
        }

        override fun onError(@NonNull camera: CameraDevice, error: Int) {
            cameraDevice!!.close()
        }
    }

    @RequiresApi(Build.VERSION_CODES.O)
    private fun startPreview() {
        if (cameraDevice == null) {
            return
        }
        Log.e("TAG", "startPreview=====1=======$cameraDevice")
        try {
            val surface = Surface(surfaceTexture)

            // 创建 CaptureRequest.Builder,并设置 Surface 作为目标
            captureRequestBuilder = cameraDevice!!.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW)
            captureRequestBuilder!!.addTarget(surface)

            Log.e("TAG", "startPreview===2=========${cameraDevice!!.id}")
            // 创建相机捕获会话
            cameraDevice!!.createCaptureSession(
                listOf(surface),
                captureSessionCallback,
                null
            )
        } catch (e: Exception) {
            Log.e("TAG", "e============${e.message}")
        }
    }

    private val captureSessionCallback: CameraCaptureSession.StateCallback =
        @RequiresApi(Build.VERSION_CODES.LOLLIPOP)
        object : CameraCaptureSession.StateCallback() {
            override fun onConfigured(@NonNull session: CameraCaptureSession) {
                cameraCaptureSession = session
                // 设置重复预览请求
                try {
                    cameraCaptureSession!!.setRepeatingRequest(
                        captureRequestBuilder!!.build(),
                        null,
                        null
                    )
                } catch (e: CameraAccessException) {
                    e.printStackTrace()
                }
            }

            override fun onConfigureFailed(@NonNull session: CameraCaptureSession) {
                Log.e(TAG, "Failed to configure camera capture session")
            }
        }

    private fun switchCamera() {
        if (cameraIds != null && cameraIds!!.size > 1) {
            cameraDevice!!.close()
            currentCameraIdIndex = (currentCameraIdIndex + 1) % cameraIds!!.size
            val cameraId = cameraIds!![currentCameraIdIndex]
            try {
                if (ActivityCompat.checkSelfPermission(
                        this,
                        Manifest.permission.CAMERA
                    ) != PackageManager.PERMISSION_GRANTED
                ) {
                    // TODO: Consider calling
                    //    ActivityCompat#requestPermissions
                    // here to request the missing permissions, and then overriding
                    //   public void onRequestPermissionsResult(int requestCode, String[] permissions,
                    //                                          int[] grantResults)
                    // to handle the case where the user grants the permission. See the documentation
                    // for ActivityCompat#requestPermissions for more details.
                    return
                }
                cameraManager!!.openCamera(cameraId, cameraCallback, null)
            } catch (e: CameraAccessException) {
                e.printStackTrace()
            }
        }
    }

    @RequiresApi(Build.VERSION_CODES.LOLLIPOP)
    override fun onPause() {
        super.onPause()
        cameraDevice?.close()
    }

    override fun onResume() {
        super.onResume()
        if (cameraDevice == null && surfaceTexture != null) {
            openCamera()
        }
    }


}

XXPermissions.with(this)
    .request(object : OnPermission {
        @RequiresApi(Build.VERSION_CODES.LOLLIPOP)
        override fun hasPermission(granted: List<String>, isAll: Boolean) {
            Log.e("TAG", "hasPermission=" + granted.size + "       " + isAll)
          
        }

        override fun noPermission(denied: List<String>, quick: Boolean) {
            Log.e("TAG", "noPermission=" + denied.size + "       " + quick)
        }
    })

这部分代码是用来授权AndroidManifest.xml里面权限的第三方sdk代码

效果:

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/941497.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

vue过渡及动画

文章目录 前言类名使用自己定义动画样式多个元素过渡使用第三方库 前言 对于vue中的过渡与动画&#xff0c;官网上是这样概述的&#xff1a; Vue 在插入、更新或者移除 DOM 时&#xff0c;提供多种不同方式的应用过渡效果。包括以下工具&#xff1a; 在 CSS 过渡和动画中自动…

基于空洞卷积DCNN与长短期时间记忆模型LSTM的dcnn-lstm的回归预测模型

周末的时候有时间鼓捣的一个小实践&#xff0c;主要就是做的多因子回归预测的任务&#xff0c;关于时序数据建模和回归预测建模我的专栏和系列博文里面已经有了非常详细的介绍了&#xff0c;这里就不再多加赘述了&#xff0c;这里主要是一个模型融合的实践&#xff0c;这里的数…

避雷!教你正确区分流量卡,不看可别后悔!

分不清真假流量卡&#xff1f; 想要手机流量卡&#xff0c;不小心买到了物联卡&#xff0c;结果被商家割了韭菜&#xff1f; 对于流量卡的套路太多了&#xff1f;你是否还傻傻分不清楚&#xff0c;今天&#xff0c;这篇文章教你正确区分这两种不同类型的卡。 ​ 赶紧收藏&am…

文件重命名与隐藏编号一键搞定!让不同类型的文件整齐有序

大家好&#xff01;在整理和管理不同类型的文件时&#xff0c;我们经常遇到文件名不规范、编号杂乱的情况&#xff0c;使得文件整体显得混乱无序。为了帮助您达到整齐有序的效果&#xff0c;我们自豪地推出了一款高效的工具——文件重命名与隐藏编号软件&#xff01;让您能够轻…

Redis进阶 - JVM进程缓存

原文首更地址&#xff0c;阅读效果更佳&#xff01; Redis进阶 - JVM进程缓存 | CoderMast编程桅杆https://www.codermast.com/database/redis/redis-advance-jvm-process-cache.html 传统缓存的问题 传统的缓存策略一般是请求到达 Tomcat 后&#xff0c;先查询 Redis &…

Qt开发实例_实时监测磁盘剩余空间

一、前言 当计算机磁盘空间不足,会导致应用程序无法继续存储数据,导致错误和不稳定的情况。所以,实时检测磁盘空间剩余大小对于许多应用程序来说都非常重要。 这种需求在许多应用程序中都存在,例如文件管理器、图像编辑器、视频播放器、云存储服务等等。在这些应用程序中…

Python+Appium自动化测试-编写自动化脚本

之前已经讲述怎样手动使用appium-desktop启动测试机上的app&#xff0c;但我们实际跑自动化脚本的过程中&#xff0c;是需要用脚本调用appium启动app的&#xff0c;接下来就尝试写Python脚本启动app并登陆app。环境为Windows10 Python3.7 appium1.18.0 Android手机 今日头条…

Apex导航菜单权限动态分配的实现

改动之处 return is_have_permission_wxx(V(WXX_USER_ID), 2,V(WXX_ROLE_ID)); 改之后 return is_have_permission_wxx(V(USER_ID), 2,V(ROLE_ID)); 创建新的动态菜单“动态菜单1” 共享组件→列表→创建→动态 selectlevel,m1.NAME label,f?p&||APP_ID.:||m1.…

17-会话机制

cookie 和 session cookie存储在本地 session是在服务器端进行用户信息的保存,一个字典 Cookie: # 1. 设置 : 通过response对象设置response redirect(xxx)response render_template(xxx)response Response(xxx)response make_response(xxx)response jsonify(xxx)# 通过…

xxl-job学习(一篇文章解决)

前言&#xff1a;学习xxl-job需要有git&#xff0c;springboot的基础&#xff0c;学起来就很简单 xxl-job是一个分布式的任务调度平台&#xff0c;其核心设计目标是&#xff1a;学习简单、开发迅速、轻量级、易扩展&#xff0c;现在已经开放源代码并接入多家公司的线上产品线&a…

详解过滤器Filter和拦截器Interceptor的区别和联系

目录 前言 区别 联系 前言 过滤器(Filter)和拦截器(Interceptor)都是用于在Web应用程序中处理请求和响应的组件&#xff0c;但它们在实现方式和功能上有一些区别。 区别 1. 实现方式&#xff1a; - 过滤器是基于Servlet规范的组件&#xff0c;通过实现javax.servlet.Filt…

热烈祝贺重庆融能成功入选航天系统采购供应商库

经过航天系统采购平台的严审&#xff0c;重庆融能机电设备股份有限公司成功入选中国航天系统采购供应商库。航天系统采购平台是航天系统内企业采购专用平台&#xff0c;服务航天全球范围千亿采购需求&#xff0c;目前&#xff0c;已有华为、三一重工、格力电器、科大讯飞等企业…

酒店资产如何管理提升资产利用效率

酒店资产管理系统是一种专门为酒店行业设计的管理软件&#xff0c;可以帮助酒店实现资产的全生命周期管理。一个好的酒店资产管理系统应该具备以下功能&#xff1a;  资产登记&#xff1a;可以对酒店的各种资产进行登记&#xff0c;包括房间、家具、设备等&#xff0c;记录资…

结合近日核污水排放问题浅析数字孪生技术革命对城市环境保护的作用

近期&#xff0c;日本核电站排放核污水引发全球关注&#xff0c;环境保护再次成为重要议题。随着数字孪生技术的进步&#xff0c;数字孪生技术正展现出其强大潜力&#xff0c;为环境保护提供前所未有的洞察和解决方案。本文将深入探讨数字孪生技术如何在环境保护领域发挥作用&a…

Mybatis-plus的saveBatch()造成雪花ID重复问题解析

前言 本文主要是针对Mybatis-plus框架&#xff0c;在调用 saveBatch() 方法时&#xff0c;出现的 id 重复导致的异常报错进行分析&#xff0c;提供后续场景出现相同场景时应该如何定位问题&#xff0c;如何进行调整方案。 问题分析及解决方案 一、场景分析 1、Yaml配置文件…

平衡二叉树及其应用详解

平衡二叉树 定义与性质 平衡二叉树&#xff08;Balanced Binary Tree&#xff09;是计算机科学中的一种数据结构&#xff0c;它是二叉排序树的一种特殊情况。 平衡二叉树满足以下性质&#xff1a; 左子树和右子树的高度差不超过 1。也就是说&#xff0c;对于任意节点&#…

TopicExchange主题交换机

目录 一、简介 二、代码展示 父pom文件 pom文件 配置文件 config 生产者 消费者 测试 结果 一、简介 主题交换机&#xff0c;这个交换机其实跟直连交换机流程差不多&#xff0c;但是它的特点就是在它的路由键和绑定键之间是有规则的。 简单地介绍下规则&#xff1…

ABeam×Startup | 德硕管理咨询(深圳)创新研究团队拜访微漾创客空间

近日&#xff0c;德硕管理咨询&#xff08;深圳&#xff09;&#xff08;以下简称&#xff1a;“ABeam-SZ”&#xff09;创新研究团队前往微漾创客空间&#xff08;以下简称&#xff1a;微漾&#xff09;拜访参观&#xff0c;并展开合作交流。会议上&#xff0c;双方相互介绍了…

python爬虫12:实战4

python爬虫12&#xff1a;实战4 前言 ​ python实现网络爬虫非常简单&#xff0c;只需要掌握一定的基础知识和一定的库使用技巧即可。本系列目标旨在梳理相关知识点&#xff0c;方便以后复习。 申明 ​ 本系列所涉及的代码仅用于个人研究与讨论&#xff0c;并不会对网站产生不好…

高精度的石英可编程压控温补振荡器

高精度的石英可编程压控温补振荡器&#xff1a;YSV531PT系列&#xff0c;七大产品特点&#xff0c;让我们一起来了解下~ 1、Q-MEMS VC-TCXO介绍 什么是石英可编程压控温补振荡器&#xff08;Q-MEMS VC-TCXO&#xff09;&#xff1f; “可编程”顾名思义就是其参数可根据用户…