ソフトコミュ開発ブログ

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      
<< September 2018 >>
+ 人気の記事
1位: Proguard を使用してリリース用APKを出力しようとした際にエラーになるケースの対応策

2位: Android Studio で "SDK location not found. Define location with sdk.dir in the local.properties file or with an ANDROID_HOME environment variable" と表示される問題の原因と対応策

3位: エミュレータの Google Play Services のバージョンが古いために Google Maps などを使用したアプリが動作しない場合の対応策

4位: ズバリ、ラムダ式 (Lambda)とは何か? それを使うと何がうれしいのか?

5位: Android エミュレータが起動しない場合の復旧手順

6位: Android 7.0 から Intent の getSerializableExtra() が使えなくなってしまいました!

7位: Java で Firebase を使う方法のまとめ。

8位: Bitbucketから、指定した時点でのファイルをすべてまとめて zip でダウンロードする方法

9位: エクリプスでテキストエディタの背景色を黒っぽくしたらデバッグ中にどの行にいるのかわからなくなった場合の対応策

10位: OneDrive でオフィス文書が同期できなくなるケースの対応策

11位: Android Studio で2台のパソコンを行き来しながら開発作業をする方法

12位: マイクロソフトの API仕様変更に伴う 「OneDrive API活用術」のサンプルコードの修正のお知らせ

13位: Arduino の開発環境に ZIP形式のライブラリをインストールできない場合の対処方法

14位: Proguard を使用してリリース用APKを出力しようとした際にエラーになるケースの対応策

15位: 任意のレジストラで取得したドメインのSSL認証を AWS で無料で取得し、Elastic Beanstalk の WEBアプリを https で公開するまでの手順まとめ

16位: AWS (Amazon Web Service) で動作している WEBアプリを SSL対応(HTTPS対応)にする

17位: AWS (Amazon Web Service) の公式ドキュメントで 「HTTPS を終了する」とはどういう意味か?

+ ARCHIVES
+ CATEGORIES
+ MOBILE
qrcode

(C) 2016 SoftCommu All Rights Reserved.