2016-10-08 34 views
3

我無法弄清楚從包裹寫入/讀取時如何使用polymorohism。 我知道我需要在基類中實現Parcelable,並且還需要在所有派生類中實現Parcelable(如果子類具有其他屬性,我希望將其寫入宗地)。 什麼我不明白,我不知道是否甚至可能是 - 如何從Parcelable中讀取子類,即如何知道我從包中讀取哪種子類。 我可以做一些破解,像寫一些指示器到包裹中,告訴我使用什麼類的裝載器,但我認爲會有一些更優雅的方式,否則沒有多少使用多態。Android - 多態和可編輯

爲了說明我的問題,讓說我有類是這樣的:

Shape.class

public class Shape implements Parcelable { 
public float area; 

public Shape() { 
} 

public Shape(Parcel in) { 
    area = in.readFloat(); 
} 

public void writeToParcel(Parcel dest, int flags) { 
    dest.writeFloat(area); 
    } 
//CREATOR etc.. 
} 

RectangleShape.class

public class RectangleShape extends Shape { 

    float a; 
    float b; 

    public RectangleShape(Parcel in) { 
     super(in); 
     a = in.readFloat(); 
     b = in.readFloat(); 
    } 

    public void writeToParcel(Parcel dest, int flags) { 
     dest.writeFloat(area); 
     dest.writeFloat(a); 
     dest.writeFloat(b); 
    } 

//CREATOR etc.. 
} 

CircleShape.class

public static class CircleShape extends Shape { 
     float r; 

    public CircleShape(Parcel in) { 
     super(in); 
     r = in.readFloat(); 
    } 

    public void writeToParcel(Parcel dest, int flags) { 
     dest.writeFloat(area); 
     dest.writeFloat(r); 
    } 
//CREATOR etc.. 
} 

現在,在一些其他類我有這樣的事情:

public class Geometry implements Parcelable { 

    Shape myShape; 

    public Geometry (boolean condition) { 

     if (condition) 
      myShape = new CircleShape(4.5); 
     else 
      myShape = new RectangleShape(3.4, 3.5); 
    } 


    @Override 
    public Geometry(Parcel in) { 
     in.readParcelable(??? - **how do I know what class loader to put here?**) 
    } 

    @Override 
    public void writeToParcel(Parcel dest, int flags) { 
     dest.writeParcelable(myShape,flags); 
    } 
//CREATOR etc.. 
} 

有什麼辦法,編寫成包裹它是什麼子類時,沒有實例類型的隱式檢查,我可以「告訴」機器人?

+0

我有類似的問題。就我而言,基類是一個界面,使事情變得更容易。我想我解決它的方法是在接口中擴展Parcelable(我們稱之爲「Foo」),然後在其子類中實現了'Foo',因此也實現了'Parcelable'。我不確定這是否有幫助... –

+1

我從來沒有實現可擴展的擴展,但我想一個好的建議是檢查谷歌自己如何做到這一點。 AbsSavedState是一個包含多個子類的Parcelable類。這裏是它的源代碼https://android.googlesource.com/platform/frameworks/base/+/refs/heads/master/core/java/android/view/AbsSavedState.java和View.BaseSavedState https: //android.googlesource.com/platform/frameworks/base/+/refs/heads/master/core/java/android/view/View.java#22556 – Budius

回答

1

我寫了這個小片段,並加載它變成一個FrameLayout的主要活動檢查 - 我得到了積極的成果(從包裹重建的目的是DerivedClass類型雖然對象的引用都ObjectClass型) 。

import android.app.Fragment; 
import android.os.Bundle; 
import android.os.Parcel; 
import android.os.Parcelable; 
import android.support.annotation.Nullable; 
import android.view.LayoutInflater; 
import android.view.View; 
import android.view.ViewGroup; 
import android.widget.TextView; 

public class Fragment2 extends Fragment { 

    public ObjectClass obj; 

    public static final String OBJECT_KEY = "Object key"; 

    public static Fragment2 newInstance(){ 
     Fragment2 fragment = new Fragment2(); 
     Bundle args = new Bundle(); 
     ObjectClass obj = new DerivedClass(); //a DerivedClass object 
           //referenced by an ObjectClass reference 
     args.putParcelable(OBJECT_KEY, obj); 
     fragment.setArguments(args); 
     return fragment; 
    } 

    @Nullable 
    @Override 
    public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { 
     View view = inflater.inflate(R.layout.fragment_main2, container, false); 
     if (savedInstanceState == null){ 
      Bundle args = getArguments(); 
      obj = args.getParcelable(OBJECT_KEY); //without supplying the ClassLoader 
      ((TextView)view.findViewById(R.id.section_label)).setText(obj.getTitle()); 
        //The text that is displayed is: "Child class"! 
     } 
     return view; 
    } 

    //The parent class 
    public static class ObjectClass implements Parcelable { 
     String title = "Parent class"; 

     public String getTitle(){ 
      return title; 
     } 

     @Override 
     public int describeContents() { 
      return 0; 
     } 

     @Override 
     public void writeToParcel(Parcel dest, int flags) { 

     } 

     public static final Creator<ObjectClass> CREATOR = new Creator<ObjectClass>() { 
      @Override 
      public ObjectClass createFromParcel(Parcel source) { 
       return new ObjectClass(); 
      } 

      @Override 
      public ObjectClass[] newArray(int size) { 
       return new ObjectClass[size]; 
      } 
     }; 
    } 

    //The child class 
    public static class DerivedClass extends ObjectClass { 
     String title2 = "Child class"; 

     public String getTitle() { 
      return title2; 
     } 

     @Override 
     public int describeContents() { 
      return 0; 
     } 

     @Override 
     public void writeToParcel(Parcel dest, int flags) { 

     } 

     public static final Parcelable.Creator<DerivedClass> CREATOR = new Parcelable.Creator<DerivedClass>() { 
      @Override 
      public DerivedClass createFromParcel(Parcel source) { 
       return new DerivedClass(); 
      } 

      @Override 
      public DerivedClass[] newArray(int size) { 
       return new DerivedClass[size]; 
      } 
     }; 
    } 
} 

而且在主要活動,在onCreate(Bundle)方法:

getFragmentManager().beginTransaction().replace(R.id.frameContainer, Fragment2.newInstance()).commit(); 

我的想法,使我這個檢查:由於Android必須弄清楚從重新創建對象時使用什麼類包裹(使用CREATOR)時,我想它必須將這些附加信息與指定信息(在writeToParcel(Parcel, int)方法中指定)一起存儲在捆綁包中。爲了確定這個類,我認爲它可以使用引用的類型或使用對象本身(例如使用getClass())。如果它使用對象類型本身,那當然意味着多態是可能的。從我上面的檢查看來,情況確實如此。

結論和你的例子的猜測: 我認爲你的例子,儘量不要顯式傳遞ClassLoader。通過null。從Parcel#readParcelable(ClassLoader)參數的文檔:

ClassLoader:從中實例化Parcelable對象的ClassLoader,或默認類加載器的null。

我沒有嘗試它與您的配置,所以我不知道它會以我的例子相同的方式工作。具體而言,我不確定Parcel#readParcelable(ClassLoader=null)實際上是否以與Bundle#getParcelable(String)相同的方式工作。但如果我的理由是正確的 - 它應該(我假設Bundle#getParcelable(String)使用默認的ClassLoader,只要Bundle#setClassLoader(ClassLoader)未被調用)。

請評論,讓我知道它是否適合你。

+0

謝謝,我已經用幾個月前的相同方式解決了這個問題,只是沒有寫出答案,現在就接受你的答案。 – daneejela