2016-08-05 7 views
2

2つのArrayListsをIntent経由で別のアクティビティに渡そうとしています。これらの2つの配列を格納するためにこのクラスを作成しました。なぜSerializableを実装するオブジェクトのシリアル化が例外をスローしますか?

public class StorageBin implements Serializable { 
    //storage variables 
    public ArrayList<String> placesList; 
    public ArrayList<LatLng> latLngArrayList; 

    public void storeData(ArrayList<String> names, ArrayList<LatLng> locations) { 
     placesList = names; 
     latLngArrayList = locations; 
    } 
} 

私は次のように意図しています。

  StorageBin storageBin = new StorageBin(); 
      storageBin.storeData(placesList, latLngArrayList); 
      intent.putExtra("storedData", storageBin); 

最後の行は以下の例外を引き起こします。私は間違って何をしていますか?

FATAL EXCEPTION: main 
    Process: lt.wilkas.isimintinosvietoves, PID: 24702 
    java.lang.RuntimeException: Parcelable encountered IOException writing 
    serializable object (name = lt.wilkas.isimintinosvietoves.MainActivity$StorageBin) 
    at android.os.Parcel.writeSerializable(Parcel.java:1468) 
    ... 
+2

'Serializable'は、実際には直列化可能性を保証しません。 'class MyClassがSerializable {NonSerializableType field}'を実装しているクラスを簡単に書くことができ、それはうまくコンパイルされます。また、 'field'がnullの場合、*シリアル化する可​​能性があります。または、 'Serializable'を実装している' NonSerializableType'のサブクラスのインスタンスである場合。 –

+1

'MainActivity $ StorageBin'は、あなたの' StorageBin'が 'MainActivity'クラスの中でネストされているが、ネストされたクラスを' static'にしなかったので、* inner *クラスであることを意味します。 'MainActivity'クラス全体 – Andreas

+0

シリアライズ可能クラスにオブジェクトがあり、シリアライズ可能でない場合は、クラスもシリアライズできないことを正しく理解していますか? – wilkas

答えて

3

私は強くあなたのMainActivityクラスが直列化可能ではないので、それがあると思われる(どちらかそれはSerializable宣言、またはそれは非直列化可能フィールドの値を持っていないので)、およびStorageBinは内部クラスである(つまり、ネストされてではなく、静的)。

ことStorageBinが静的​​作ってみましょう:

public static class StorageBin ... 

静的であること、これは直列可能を壊していない理由はStorageBinMainActivityに隠された参照を持っているということです。これはあなたがMainActivity上のインスタンスメソッドを参照できるようにするものです(またはMainActivity.this)をStorageBinの本文に挿入します。

多くの場合、この参照は不要です。MainActivityインスタンスがガベージコレクションされないため、シリアル化が中断されるだけでなく、メモリリークも発生する可能性があります。

常にネストされたクラスstaticを実際に別のものにする必要がない限り、これらのクラスを作成します。


LatLng classのご使用も(それがSerializableを実装していないので)直列化を妨げている場合は、次の2つの選択肢があります。

  • 停止LatLngクラスを使用して、シリアル化タイプを使用します;
    • どちらかあなたの公開APIで 、
    • があなたの公開APIがLatLngを使用するように見えるようにするが、その後、シリアライズ型に変換する他の種類のリストを受け入れstoreDataように、内部
  • マークlatLngArrayListフィールドtransientを使用し、writeObjectおよびreadObjectを使用して、それぞれカスタムのシリアライズおよびデシリアライゼーションロジックを提供します。例えば

    、あなたは配列に座標をシリアル化し、あなたがデシリアライズするときLatLngインスタンスを再構築することができます

    private void writeObject(ObjectOutputStream out) throws IOException { 
        out.defaultWriteObject(); 
    
        double[] coords = new double[2 * latLngArrayList.size()]; 
        int i = 0; 
        for (LatLng latLng : latLngArrayList) { 
        coords[2*i+0] = latLng.latitude; 
        coords[2*i+1] = latLng.longitude; 
        ++i; 
        } 
        out.writeObject(coords); 
    } 
    
    private void readObject(ObjectInputStream in) 
        throws ClassNotFoundException, IOException { 
        in.defaultReadObject(); 
        double[] coords = (double[]) in.readObject(); 
        // + Check that coords.length is even. 
        latLngArrayList = new ArrayList<>(coords.size()/2); 
        for (int i = 0; i < coords.size(); i += 2) { 
        latLngArrayList.add(new LatLng(coords[i], coords[i+1])); 
        } 
    } 
    

Serializableを実装する実際直列性を保証するものではありません。あなたは簡単にクラスを書くことができます:

class MyClass implements Serializable { NonSerializableType field } 

そしてそれはうまくコンパイルされます。 fieldがnullの場合、となります。または、それがSerializableを実装するNonSerializableTypeのサブクラスのインスタンスである場合

私は、シリアライゼーションが推測ゲームであるとは言いません。正しく使用すると明らかに機能するためです。正しく使用していることを保証するのは難しいです。

+0

'MainActivity $ StorageBin'という名前はあなたの疑惑を確実にしませんか? ;-) – Andreas

+2

@Andreasは確実ではありません - あなたは 'MainActivity'が' Serializable'宣言されていないことをどのように知っていますか) –

+0

定義に 'static'を追加しようとしましたが、その後、このクラスをMainActivityクラスの外に移動しようとしましたが(「public static」も削除されますが)、例外は次のようになります。 java.lang.RuntimeException:Parcelable IOExceptionが発生して直列化可能オブジェクトが作成されました(名前= lt.wilkas.isimintinosvietoves.StorageBin ) 私はそれが私によって宣言されている "LatLng"クラスに関連していると思います。 – wilkas

関連する問題