概要
Androidで異なるActivityにbitmapを渡す際、bitmapのサイズが大きすぎてタイトルのようなエラーとなってしまったので、その原因と対処法を示す。
原因
Androidで画像(bitmap)をActivity間で受け渡しする際、
以下のように行う。
// MainActivityを起動するための、intentを初期化する
val intent: Intent = Intent(context, MainActivity::class.java)
// intentにbitmapをセットする
intent.putExtra("bitmap", bitmap)
// MainActivityを起動する
startActivity(intent)
このとき、putExtraでセットするbitmapのサイズが大きすぎる場合、以下のような例外が発生する。
E/JavaBinder: !!! FAILED BINDER TRANSACTION !!! (parcel size = 12583424)
12583424
はこのときセットしたbitmapのサイズ
対処法
bitmapは容量が大きいので、異なるActivityに画像データを渡したい場合、
bitmapを直接渡すのではなく、Uriに変換して渡し、
受け取る側のActivityでは、必要に応じてUriをbitmapに変換して利用する。
以下に実装例を示す。
/**
* 渡す側のActivity
*/
// MainActivityを起動するための、intentを初期化する
val intent: Intent = Intent(context, MainActivity::class.java)
// bitmapをuriに変換する
val uri: Uri = bitmapToUri(bitmap)
// intentにuriをセットする
intent.putExtra("uri", uri)
// MainActivityを起動する
startActivity(intent)
/**
* bitmapをuriに変換する
*
* @param bitmap ビットマップ形式のデータ
* @return bitmapから取得したcontent://スキーマ形式のuri
* /
private fun bitmapToUri(bitmap: Bitmap): Uri {
// 一時ファイル作成用のキャッシュディレクトリを定義する
val cacheDir: File = this.cacheDir
// 現在日時からファイル名を生成する
val fileName: String = System.currentTimeMillis().toString() + ".jpg"
// 空のファイルを生成する
val file = File(cacheDir, fileName)
// ファイルにバイトデータを書き込み開始する
val fileOutputStream: FileOutputStream? = FileOutputStream(file)
// ファイルにbitmapを書き込む
bitmap.compress(Bitmap.CompressFormat.JPEG, 100, fileOutputStream)
// ファイルにバイトデータを書き込み終了する
fileOutputStream?.close()
// ファイルからcontent://スキーマ形式のuriを取得する
val contentSchemaUri: Uri = FileProvider.getUriForFile(this@SubActivity, "com.hoge.fuga.fileprovider.fileprovider", file)
return contentSchemaUri
}
bitmapをuriに変換するのは、上記のように結構めんどくさい。
一度fileにしてからbitmapを流し込んでUriにする必要がある。
Uriは content://スキーマ形式のuri と file://スキーマ形式のuri がある。それぞれ精製方法とできることが異なるので注意が必要。
また、 FileProvider.getUriForFile()
は、 AndroidManifest.xml
に androidx.core.content.FileProvider"
を定義して、 res/xml/provider_paths.xml
を作成する必要がある。※1
/**
* 受け取る側のActivity
*/
// intentからuriを取得する
val uri = intent.getExtras().get("uri") as Uri?
// uriをnullチェックする
uri?.let { nonNullUri: Uri ->
// uriをbitmapに変換する
val bitmap = MediaStore.Images.Media.getBitmap(this.contentResolver, nonNullUri) as? Bitmap
}
※1
<application>
// 省略
<provider
android:name="androidx.core.content.FileProvider"
android:authorities="com.hoge.fuga.fileprovider"
android:enabled="true"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/provider_paths" />
</provider>
</application>
<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
<cache-path name="cache" path="." />
</paths>
これで異なるActivityに画像を渡すことができる。