val contentValues = ContentValues().apply {
put(MediaStore.Images.Media.DISPLAY_NAME, "view.png")
put(MediaStore.Images.Media.MIME_TYPE, "image/png")
put(MediaStore.Images.Media.IS_PENDING, "1")
}
val contentUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI
contentResolver.run {
insert(contentUri, contentValues)?.let{ uri ->
openOutputStream(uri)?.let{ stream ->
val view = findViewById<View>(R.id.some_view)
view.drawToBitmap().compress(
Bitmap.CompressFormat.PNG,
100,
stream
)
stream.close()
contentValues.put(
MediaStore.MediaColumns.IS_PENDING, 0
)
update( uri, contentValues, null, null)
}
}
}
View のビットマップを取得するには Android KTXの View.drawToBitmap()
メソッドを使う。
API 28から getDrawingCache()
は非推奨となっている。
MediaStore
クラスで外部ストレージのURIを取得する。MediaStore
クラスを利用すると権限の認証は不要
外部ストレージURIとファイルのMimeTypeを指定しcontentResolver
でインサートする。contentResolver
オブジェクトはコンテンツプロバイダとの仲介を行ってくれる。Androidのコンテンツプロバイダ APIはファイル情報などをDBで保持している(おそらくSQLite3)
保存するファイル情報のインサートが成功すれば、保存先URIが返ってくる。
URIは content://media/external/images/media/1
のような形式。
ストレージへのファイルの書込はURIに対し openOutPutStream
オブジェクトが行う。
書込後にファイル情報DBをアップデートすることで、Photoアプリなど他のアプリで即座に画像を表示できる。
ファイル名が被ったら末尾に連番が入る。
上記の書き方だと、成功・失敗のメッセージもなくPictureフォルダにPNGファイルが保存されるのみ。
ただし、Android Q 未満は MediaStore
を使えないので、Android P以下にも対応するには参考としたStack Overflowの回答のようにバージョン毎に処理を変える必要がある。
参考サイト
【Android】Viewのスクリーンショットを撮影してギャラリーアプリで見れるようにする – Qiita
最終的にこの記事のコードとちょっと違うだけになりました。
[Android] view.getDrawingCache()がDeprecatedになったのでPixelCopyでスクリーンキャプチャを撮る | Android開発知識ゼロ人間の生活
java – How to save an image in Android Q using MediaStore? – Stack Overflow
アンドロイド – MediaStoreにメディアファイルを保存する方法
公式リファレンス
View.getDrawingCache() | Android Developers
コンテンツ プロバイダの基本 | Android Developers
別解
Canvasを利用して、Viewのビットマップを取得するコードが掲載されている。
「Android」Viewの内容をBitmapの保存方法 | | 最新IT技術情報_arkgame.com
表示範囲外は drawToBitmap()
では取得できないため、こちらの方法でCanvasに出力してから画像化する必要があると思われる。