Android開發(fā)-Jetpack組件CameraX

CameraX 是一個(gè) Jetpack 支持庫,旨在幫助您簡化相機(jī)應(yīng)用的開發(fā)工作。它提供一致且易于使用的 API 界面,適用于大多數(shù) Android 設(shè)備麦轰,并可向后兼容至 Android 5.0(API 級別 21)。

雖然它利用的是 camera2 的功能砖织,但使用的是更為簡單且基于用例的方法款侵,該方法具有生命周期感知能力。它還解決了設(shè)備兼容性問題镶苞,因此您無需在代碼庫中包含設(shè)備專屬代碼喳坠。這些功能減少了將相機(jī)功能添加到應(yīng)用時(shí)需要編寫的代碼量。

目前處于 Alpha 版測試階段茂蚓,因?yàn)槠?API 界面尚未最終確定。我們不建議在生產(chǎn)環(huán)境中使用 Alpha 庫剃幌。CameraX 庫應(yīng)在生產(chǎn)環(huán)境中嚴(yán)格避免依賴 Alpha 庫聋涨,因?yàn)槠?API 界面可能會以與源代碼和二進(jìn)制文件不兼容的方式發(fā)生變化。

相比較于使用Camera2預(yù)覽负乡、拍照時(shí)大量的接口牍白、回調(diào),使用CameraX基本可以使用不超過100行代碼實(shí)現(xiàn)相同功能抖棘。雖然目前仍是測試版本茂腥,但個(gè)人強(qiáng)烈建議先學(xué)習(xí)下,CameraX 真的超簡單切省,超好用W罡凇!朝捆!后面正式版發(fā)布后就可以隨時(shí)使用般渡。

CameraX使用

CameraX 結(jié)構(gòu)

開發(fā)者使用 CameraX,借助名為“用例”的抽象概念與設(shè)備的相機(jī)進(jìn)行交互。目前提供的用例如下:

  • 預(yù)覽:準(zhǔn)備一個(gè)預(yù)覽 SurfaceTexture
  • 圖片拍攝:拍攝并保存照片
  • 圖片分析:提供 CPU 可訪問的緩沖區(qū)以進(jìn)行分析(例如進(jìn)行機(jī)器學(xué)習(xí))

不同用例可以相互組合使用驯用,也可以同時(shí)處于活動狀態(tài)脸秽。例如,用戶可以在應(yīng)用中使用預(yù)覽用例查看進(jìn)入相機(jī)視野的畫面蝴乔、加入圖片分析用例來確定照片里的人物是否在微笑记餐,以及包含一個(gè)圖片拍攝用例以便在人物微笑時(shí)拍攝照片。

添加依賴

    def camerax_version = "1.0.0-beta04"
     // CameraX core library using camera2 implementation
    implementation "androidx.camera:camera-camera2:$camerax_version"
     // CameraX Lifecycle Library
    implementation "androidx.camera:camera-lifecycle:$camerax_version"
     // CameraX View class
    implementation "androidx.camera:camera-view:1.0.0-alpha11"
    

布局

<androidx.camera.view.PreviewView
        android:id="@+id/viewFinder"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

使用androidx.camera.view.PreviewView類薇正。它是CameraX中顯示預(yù)覽用例的自定義視圖片酝。該類管理Surface生命周期,以及預(yù)覽縱橫比和方向铝穷。在它內(nèi)部使用TextureView或SurfaceView來顯示钠怯。

實(shí)現(xiàn)預(yù)覽

private fun startCamera() {
        val cameraProviderFuture = ProcessCameraProvider.getInstance(this)

        cameraProviderFuture.addListener(Runnable {
            // Used to bind the lifecycle of cameras to the lifecycle owner
            val cameraProvider: ProcessCameraProvider = cameraProviderFuture.get()

            // Preview
            preview = Preview.Builder()
                    .build()

            // Select back camera
            val cameraSelector = CameraSelector.Builder().requireLensFacing(CameraSelector.LENS_FACING_BACK).build()

            try {
                // Unbind use cases before rebinding
                cameraProvider.unbindAll()

                // Bind use cases to camera
                camera = cameraProvider.bindToLifecycle(
                        this, cameraSelector, preview)
                preview?.setSurfaceProvider(viewFinder.createSurfaceProvider())
            } catch (exc: Exception) {
                Log.e(TAG, "Use case binding failed", exc)
            }

        }, ContextCompat.getMainExecutor(this))
    }

就這樣就可以實(shí)現(xiàn)Camera的預(yù)覽功能,是不是很簡單曙聂,想起之前寫Camera2的痛苦晦炊,眼淚都快流下來了。

拍照

//在startCamera中增加
// ImageCapture
imageCapture = ImageCapture.Builder()
               .setCaptureMode(ImageCapture.CAPTURE_MODE_MINIMIZE_LATENCY)
               .build()

private fun takePhoto() {
    // Get a stable reference of the modifiable image capture use case
    val imageCapture = imageCapture ?: return

    // Create timestamped output file to hold the image
    val photoFile = File(
            outputDirectory,
            SimpleDateFormat(FILENAME_FORMAT, Locale.CHINA
            ).format(System.currentTimeMillis()) + ".jpg")

    // Create output options object which contains file + metadata
    val outputOptions = ImageCapture.OutputFileOptions.Builder(photoFile).build()

    // Setup image capture listener which is triggered after photo has
    // been taken
    imageCapture.takePicture(
            outputOptions, ContextCompat.getMainExecutor(this), object : ImageCapture.OnImageSavedCallback {
        override fun onError(exc: ImageCaptureException) {
            Log.e(TAG, "Photo capture failed: ${exc.message}", exc)
        }

        override fun onImageSaved(output: ImageCapture.OutputFileResults) {
            val savedUri = Uri.fromFile(photoFile)
            val msg = "Photo capture succeeded: $savedUri"
            Toast.makeText(baseContext, msg, Toast.LENGTH_SHORT).show()
            Log.d(TAG, msg)
        }
    })
}
//最后綁定到Camera上
// Bind use cases to camera
camera = cameraProvider.bindToLifecycle(
          this, cameraSelector, preview,imageCapture)

完成了宁脊,這代碼簡潔程度簡直愛了断国!

圖片分析

寫一個(gè)內(nèi)部類,繼承ImageAnalysis.Analyzer

private class LuminosityAnalyzer(private val listener: LumaListener) : ImageAnalysis.Analyzer {

    private fun ByteBuffer.toByteArray(): ByteArray {
        rewind()    // Rewind the buffer to zero
        val data = ByteArray(remaining())
        get(data)   // Copy the buffer into a byte array
        return data // Return the byte array
    }

    override fun analyze(image: ImageProxy) {
        //處理圖片數(shù)據(jù)
        val buffer = image.planes[0].buffer
        val data = buffer.toByteArray()
        val pixels = data.map { it.toInt() and 0xFF }
        val luma = pixels.average()
        listener(luma)
        image.close()
    }
}
imageAnalyzer = ImageAnalysis.Builder()
        .build()
        .also {
            it.setAnalyzer(cameraExecutor, LuminosityAnalyzer { luma ->
                Log.d(TAG, "Average luminosity: $luma")
            })
        }

綁定設(shè)備

// Bind use cases to camera
camera = cameraProvider.bindToLifecycle(
        this, cameraSelector, preview, imageCapture, imageAnalyzer)

仍然是這么簡單榆苞!等CameraX正式版本發(fā)布稳衬,Camera2就扔到垃圾桶去吧。

記得申請權(quán)限白薄疚!Manifest.permission.CAMERA

可以翻墻的請看原文:Getting Started with CameraX

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市赊琳,隨后出現(xiàn)的幾起案子街夭,更是在濱河造成了極大的恐慌,老刑警劉巖躏筏,帶你破解...
    沈念sama閱讀 206,839評論 6 482
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件板丽,死亡現(xiàn)場離奇詭異,居然都是意外死亡趁尼,警方通過查閱死者的電腦和手機(jī)埃碱,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,543評論 2 382
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來酥泞,“玉大人砚殿,你說我怎么就攤上這事∩舨” “怎么了瓮具?”我有些...
    開封第一講書人閱讀 153,116評論 0 344
  • 文/不壞的土叔 我叫張陵荧飞,是天一觀的道長。 經(jīng)常有香客問我名党,道長叹阔,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,371評論 1 279
  • 正文 為了忘掉前任传睹,我火速辦了婚禮耳幢,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘欧啤。我一直安慰自己睛藻,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,384評論 5 374
  • 文/花漫 我一把揭開白布邢隧。 她就那樣靜靜地躺著店印,像睡著了一般。 火紅的嫁衣襯著肌膚如雪倒慧。 梳的紋絲不亂的頭發(fā)上按摘,一...
    開封第一講書人閱讀 49,111評論 1 285
  • 那天,我揣著相機(jī)與錄音纫谅,去河邊找鬼炫贤。 笑死,一個(gè)胖子當(dāng)著我的面吹牛付秕,可吹牛的內(nèi)容都是我干的兰珍。 我是一名探鬼主播,決...
    沈念sama閱讀 38,416評論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼询吴,長吁一口氣:“原來是場噩夢啊……” “哼掠河!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起猛计,我...
    開封第一講書人閱讀 37,053評論 0 259
  • 序言:老撾萬榮一對情侶失蹤口柳,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后有滑,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,558評論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡嵌削,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,007評論 2 325
  • 正文 我和宋清朗相戀三年毛好,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片苛秕。...
    茶點(diǎn)故事閱讀 38,117評論 1 334
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡肌访,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出艇劫,到底是詐尸還是另有隱情吼驶,我是刑警寧澤,帶...
    沈念sama閱讀 33,756評論 4 324
  • 正文 年R本政府宣布,位于F島的核電站蟹演,受9級特大地震影響风钻,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜酒请,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,324評論 3 307
  • 文/蒙蒙 一骡技、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧羞反,春花似錦布朦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,315評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至澄惊,卻和暖如春唆途,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背缤削。 一陣腳步聲響...
    開封第一講書人閱讀 31,539評論 1 262
  • 我被黑心中介騙來泰國打工窘哈, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人亭敢。 一個(gè)月前我還...
    沈念sama閱讀 45,578評論 2 355
  • 正文 我出身青樓滚婉,卻偏偏與公主長得像,于是被迫代替她去往敵國和親帅刀。 傳聞我的和親對象是個(gè)殘疾皇子让腹,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,877評論 2 345