iT邦幫忙

2026 iThome 鐵人賽

DAY 20
0
Software Development

從 Fragment 到 Compose — 老 Android App 重寫的架構取捨系列 第 20 篇

Day 20|CameraX 在 Compose:AndroidView 逃生門原則

  • 分享至 

  • xImage
  •  

動筆前先答(兩題)

1.【決策邊界|平台能力】 舊 App 有 14 個地方要拍照,全部是開系統相機(ACTION_IMAGE_CAPTURE Intent),拍完回到 App。專案裡還留著一個自己用 CameraX 寫的相機畫面,但整份程式碼都被註解掉了,沒有人在用。

新版有三種選擇:

  • (A) 照舊開系統相機:用 ActivityResultContracts.TakePicture 把照片寫進 App 指定的位置。
  • (B) 在 App 裡用 CameraX:預覽畫面是傳統 View(PreviewView),用 AndroidView 包進 Compose。
  • (C) 在 App 裡用 CameraX:預覽改用官方的 Compose 元件(camera-compose 的 CameraXViewfinder),不經過 AndroidView。

請寫下:

  • 你預設選哪一種?在什麼條件下會改選另一種?至少想想這幾種需求:
    • 照片上要壓時間、地點、單號當作配送證明。
    • 要確保照片是當下拍的,不能從相簿挑舊照片充數。
    • 一次要連拍好幾張。
    • 配送員的手機品牌、型號很雜,系統相機的行為各家不同。
  • 「用 AndroidView 包一個傳統 View」在什麼情況下是合理的逃生門?什麼情況下應該等官方的 Compose 元件,或乾脆不在 App 裡做相機?
  • 舊 App 為什麼可能寫了 CameraX 版本又整個註解掉?列出你猜的兩個原因,以及各自要怎麼查證。

我的回答:
1.要用(B)。
因為可以從 PreviewView 押上時間、地點、單號等浮水印。
一律強制啟動相機拍照,禁止用 Photo Picker API 從相簿挑照片。
連拍的話用(A)不方便。
配送員的手機品牌、型號很雜,系統相機的互動,靠App自建相機比較能解決。

2.【預測再驗證|穩定性與記憶體】 選了 (A) 系統相機之後,有人這樣寫拍照按鈕:

@Composable
fun ProofPhotoButton(onPhoto: (Uri) -> Unit) {
    val context = LocalContext.current
    var pendingUri by remember { mutableStateOf<Uri?>(null) }
    val launcher = rememberLauncherForActivityResult(ActivityResultContracts.TakePicture()) { success ->
        if (success) pendingUri?.let(onPhoto)
    }
    Button(onClick = {
        val uri = createPhotoUri(context)   // 用 FileProvider 建一個給相機 App 寫入的位置
        pendingUri = uri
        launcher.launch(uri)
    }) {
        Text("拍照")
    }
}

先在手機的「開發人員選項」打開「不保留活動」,按拍照、拍一張、按確認回到 App。

先寫下預測,再實際操作驗證:

  1. onPhoto 會不會被呼叫?如果會,拿到的是什麼?
  2. 把 remember 改成 rememberSaveable,再做一次。結果有什麼不同?
  3. 關掉「不保留活動」,改成在相機畫面時,用 adb shell am kill <套件名稱> 把 App 的 process 殺掉,再拍照回來。結果又是如何?

最後回答:

  • pendingUri 應該放在哪裡才可靠?
  • 配送員打開相機後按返回、沒拍照,createPhotoUri 建的那個位置會留下什麼?要不要清,什麼時候清?

我的回答:(待補)


上一篇
Day 19|硬體與生命週期:掃描綁 Compose lifecycle、權限流程
下一篇
Day 21|離線佇列:Room + WorkManager
系列文
從 Fragment 到 Compose — 老 Android App 重寫的架構取捨 共 22 篇
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言