LoginSignup
4
5

More than 5 years have passed since last update.

【Android】異なるActivityにbitmap画像を渡す方法(FAILED BINDER TRANSACTION !!! (parcel size = 00000000 )が起きたときの対処法)

Last updated at Posted at 2019-03-16

概要

Androidで異なるActivityにbitmapを渡す際、bitmapのサイズが大きすぎてタイトルのようなエラーとなってしまったので、その原因と対処法を示す。

原因

Androidで画像(bitmap)をActivity間で受け渡しする際、
以下のように行う。

SubActivity.kt

// 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に変換して利用する。

以下に実装例を示す。

SubActivity.kt
/**
 * 渡す側の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.xmlandroidx.core.content.FileProvider" を定義して、 res/xml/provider_paths.xml を作成する必要がある。※1

MainActivity.kt
/**
 * 受け取る側の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

AndroidManifest.xml
    <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>
res/xml/provider_paths.xml
<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
    <cache-path name="cache" path="." />
</paths>

これで異なるActivityに画像を渡すことができる。

4
5
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
5