ソフトコミュ開発ブログ

SoftCommu は Javaアプリ、Androidアプリの開発を行うディベロッパーです。人材教育もやっています。企業の新人研修の講師からスカイプでのオンライン家庭教師まで!技術書の執筆や翻訳もしています。
<< Android エミュレータが起動しない場合の復旧手順 | main | Android Studio で2台のパソコンを行き来しながら開発作業をする方法 >>
2016.11.26 Saturday
Android 7.0 から Intent の getSerializableExtra() が使えなくなってしまいました!

Android7.0から Intent にセットしたデータを getSerializableExtra()で取得しようとすると null が返ってくるようになってしまいました。

 

たとえば、下記のような単純な BroadcastReceiver の処理で問題が発生します。11行目の intent.getSerializableExtra("data") が null を返してくるのが今回取り上げている問題です。この結果、12行目で NullPointerException が発生します。

 

 

この BroadcastReceiver に引き渡すインテントを作成しているサンプルコードは下記のような感じになります。

 

 

intent.putExtra("data", data) という処理で、MyData というクラスのインスタンスをセットしています。5秒後に、このデータがアンドロイドのアラーム機能を経由して、MyBroadcastReceiver に引き渡される処理になっています。

 

上記の intent.getSerializableExtra("data") という処理で取得しようとしている MyData クラスは下記の通りです。ごく単純な String型一つを持っているだけのクラスです。Serializable も実装済み。

 

 

Android 6.0までは上記のコードで問題なく動作していました。それが 7.0以降、急に動作しなくなってしまいました。

 

これって Android7.0のバグでしょうか? それとも Google の意図的な仕様変更?

 

それにしてもアンドロイドでは、時々こうゆうことが起こりますよね。。。

 

ユーザーがOSをバージョンアップすると、急にアプリが落ちるようになるとか、そういう感じのこと。

 

これまで、getSerializableExtra() を使って、まったく平和にデータをやり取りできていたアプリは、Android 7.0 の普及に伴って怒涛のクラッシュレポートを受け取ることになるでしょう。。。困りましたね。。。

 

ちなみに、上記の MyData クラスに、serialVersionUID を定義してみたのですが、結果は同じでした。

 

で、この問題の回避策ですが、とりあえず Intent.getSerializableExtra() でクラスのインスタンスを丸ごと引き渡す方法はあきらめるしかないようです。

 

ただ、代わりにそのクラスの中身の String型などの変数をそれぞれバラバラに Intentにセットするのもちょっと大変ですよね。

 

BroadcastReceiver などのデータを受け取る側の処理では、

各変数に対して Intent.getStringExtra() などを呼んで値を取得していくことになってしまいますし。

 

上記の MyData クラスのような単純なクラスであれば、それも大した手間なしに可能ですが、保持している変数が多かったり、複雑な構成になっているクラスの受け渡しを String型や int型にばらして、ひとつひとつ Intent.putExtra() や Intent.getExtra() でやり取りするのは結構つらいですよね。

 

あるいは、MyData クラスを無理やり Pacelablel に変更するという方法もあります。それだとちゃんと動作するんです。だた、Pacelablel 対応はいろいろコーディングする必要があってちょっと面倒くさい。Pacelablel 対応を自動的に導入してくれるライブラリを使うという手もありますが。。。

 

いずれにしても、Android 7.0 からは getSerializableExtra() というAPIで Serializable のクラスを受け取ることはできません。その代わり、getPacelablelExtra() を使う必要があるんですね。。。。

 

うーん、Serializable のクラスを getSerializableExtra() で受け取ることはできない。だけど、Pacelablel のクラスであれば、getSerializableExtra() で受け取れる。なんじゃそりゃ。APIの設計ミスに思えてなりません。

 

 

解決方法

 

そこで考えたのが、Gsonライブラリの活用です。

 

Intentに載せて引き渡したいクラスのインスタンスを Gson を使って、JSON形式の文字列に変換し、文字列としてインテントにパックします!

 

そして、受け取り側の BroadcastReceiver では、再度 Gson を使って元のクラスのインスタンスに復元するというわけです。

 

具体的には、Intent に MyData のデータをセットする部分を下記のように変更します。

 

 

上記のようにセットしたインテントの受け取り側の BroadcastReceiver は下記のようになります。

 

 

このように、MyData自体は全く変更する必要がありません。

 

結局のところ、Javaのクラスの情報を Gson で JSON形式の文字列にすることは、一種の「シリアライズ」ということになりますよね。

 

Intent の getSerializableExtra() が、Javaの純正シリアライズに対応しなくなってしまった今、別形式の「シリアライズ」によって回避する必要が出てきてしまったわけです。

 

それにしても、Gson ってすごい便利ですね!

 

Gson に関しては、拙著 「OneDrive API活用術―Javaでクラウドアプリを開発する! 」 でも詳しく説明しておりますので、興味のある方はどうぞご参照ください!

 

| SoftCommu | Android | 11:00 | comments(0) | - |









      1
2345678
9101112131415
16171819202122
23242526272829
30      
<< April 2017 >>
+ 人気の記事
+ ARCHIVES
+ CATEGORIES
+ MOBILE
qrcode
(C) 2016 SoftCommu All Rights Reserved.