Bundle の putSerializable() で List や Map や CharSequence を実装したオブジェクトを渡すのはやばい

今まで気付かなかった...orz

Bundle の putSerializable() で List や Map や CharSequence を実装したオブジェクトを渡すと、永続化するときに元がどんなクラスであろうが List を実装していれば ArrayList に、Map を実装していればは HashMap に、CharSequence を実装していれば String になってしまう...。(Parcel.java の writeValue() あたり)

public class MainActivity extends Activity {

    public static class OreMap extends HashMap<String,Object> {
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        
        if (savedInstanceState != null) {
            Object oreMap = savedInstanceState.getSerializable("oreMap"); 
            Log.v("", "oreMap: " + oreMap.getClass().getName());
        }
    }
    
    @Override
    protected void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);
        
        outState.putSerializable("oreMap", new OreMap());
    }
}

アプリ起動後にkillしてもう一度アプリ起動したときの結果。

oreMap: java.util.HashMap

OreMap が HashMap に変わってしまう。

Bundle が永続化されるまでは、Bundle は単純なマップでオブジェクトを持ってるだけだから問題は起こらないけど、killされて戻ってきたときなんかに、getSerializable() すると他のクラスに化けていて、ClassCastException など起こしたり。


ダサいけど Object [] にして回避するのが手っ取り早い...。

outState.putSerializable("oreMap", new Object [] { new OreMap() });
Object oreMap = ((Object[]) savedInstanceState.getSerializable("oreMap"))[0]; 
Log.v("", "oreMap: " + oreMap.getClass().getName());