Can't implement Parcelable if properties of object are non-parcelable? - android

Let's say I have the following class structure
public class SipService implements Parcelable{
public SipCore sipcore;
public PhoneRinger phoneringer;
public CurrentML currentml;
public AManager amanager;
//etc...
}
All the properties of SipService are non-parcelable classes. And the properties of those properties are non-parcelable classes. And the properties of those properties of those properties are non-parcelable classes. And the properties of those properties etc.... are non-parcelable classes.
I do not have access the to the source code for any of those classes of the properties of SipService.
Does this mean that SipService can not successfully implement Parcelable?

Because you don't have access to all the member variables of the classes and can't change this, you can't make SipService parcelable.
If you would have access, you could read all the variables of the classes in your SipService and make a new instance of them. But for that you need the getters and a appropriate constructor for each class to rebuild them.
If these classes are implementing the Serializable interface, you could make it serializable. Because it's behaving pretty much the same, but the performance is better if the class implements parcelable.
OR
If you can talk to the team, suggest them to implement the parcelable/serializable interface if it's a reasonable requirement.

Related

How to pass an object to another activity? If the object already implements an interface (so it can't implement Parcelable)?

I'm trying to pass an Object from one activity to another and I know I should use Parcelable or Serializable but my Object class implements an interface already. Is there any way around this?
Objects can implement multiple interfaces:
class MyClass implements Interface1, Parcelable {
// Implement each interface
}
I think the right thing is just to use Intent.putExtras() - where you can pass primitive data types + objects of type String, Bundle, Parcelable, Serializable. You are simply using key/value pairs. And after that you can get your data by Intent.getExtras(). Everything is quite simple. Also have a look at this links, they are for bigginers, but really helpful: http://developer.android.com/guide/components/intents-filters.html and http://www.vogella.com/tutorials/AndroidIntent/article.html. If the problem is somewhere deeper - please describe it. Thanks.
Sure! A class can implement multiple interfaces. You'll just need to separate each one with a comma in your class declaration, like this...
public class YourClass implements interface1, interface2, interface3 {
//...
}
An object cannot extend more than one class but can implement many interfaces.
Parcelable and `Serializable` are the way but little complex. an easy solution is just use `Gson` or any other JSON library..
in first activity.
String objJson = new Gson().toJson(object);
intent.putExtra("key",objJson);
and in your second activity
YourClass yourClass = new Gson().fromJson(getIntent().getStringExtra("key"),YourClass.class) ;
for Gson library check this link http://www.java2s.com/Code/Jar/g/Downloadgson222jar.htm

Implementing both Serializable and Parcelable interfaces from an object in Android - conflict

I have an object that i must save to file for reuse. The class of this object already implements Parcelable for use in intents. My knowledge of saving an object to file says to implement Serializable, but when i do, i get an error in the class that contains this object at the putExtra method of an intent because both Serializable and Parcelable have this method.
Is there a way to avoid this, or just a way that i can save my object state and reload it easily?
I have looked at a few articles and i feel no more informed about how i should be saving my object.
Thanks in advance
I believe that Parcelable and Serializable both reaches the same goal in different ways and with different performances. Given that, if some class in your object hierarchy alread implements the Parcelable interface, you can override its writeToParcel method, call the super for it (so the members of the super classes will be written to the parcel if they were implement that way) and then, you should write your attributes to the parcel, always keeping in mind that the order you use to save them is the order you will use to retrieve them latter (FILO data structure)
EDIT
Just cast your object where it complains and tells about the conflict to the class you want to use as described here: https://stackoverflow.com/a/13880819/2068693
I don't know that you can implement both Serializable and Parcelable together but for convert a class from Serializable to Parcelable you can use this plugin:
Android Parcelable Code generator.
First remove implement Serializable then with ALT + Insert and click on Parcelable you can generate your class.
You have options other than Serializable, but that may meet other requirements such as avoiding library dependencies. You can write objects to file using JSON or XML, which has the advantage of being readable. You may also need to consider versioning - what happens when you have files that need to be read by a class that contains a new field. Persistence brings with it some issues you probably don't have passing Bundles/Intents back and forth.
If you choose Serializable I'd recommend structuring your objects so they can be written to and read from a Bundle. Using a static MyObject.make(Bundle) method and an instance Bundle save() method keeps all the constants and read/write in a single location.

Use Android Annotations with Parceler

I'm using Android Annotations in my Android Project. As implementing Parcelable is a lot of work I want to use Parceler and the #Parcel annotation.
The problem is that if I want to use the #FragmentArg annotation by Android Annotations it doesn't (for obvious reasons) recognize that the class will be generated with the Parcelable interface implemented.
I now have two questions:
Where does Parceler put the generated classes so that I could work with these? On parceler.org it is stated: "To use the generated code, you may reference the generated class directly, or via the Parcels utility class"
Is there another way to use Parceler or any library which generates the Parcelable boilerplate code with Android Annotations?
Until now my code for the Fragment looks like:
#EFragment(R.layout.fragment_faq)
public class FaqFragment extends ListFragment {
#FragmentArg
ArrayList<FaqItemImpl> faqItems;
// ...
}
The generated POJO class is annotated with #Parcel:
#Parcel
public class FaqItemImpl implements FaqItem {
protected String iconURL;
protected String title;
protected String question;
protected String answer;
protected ArrayList<FaqItemImpl> faqChildren;
// ...
}
In the generated FaqFragment_ the interesting part is:
// ...
public FaqFragment_.FragmentBuilder_ faqItems(ArrayList<FaqItemImpl> faqItems) {
args.putSerializable(FAQ_ITEMS_ARG, faqItems);
return this;
}
// ...
As you can see the generated class treads the POJO as Serializable...
One approach you can use is to let AA handle the hand-off of the Parcelable and let Parceler perform the serialization/deserialization. One nice feature about Parceler is it will handle collection serialization for you, so AA should just have to deal with a single Parcelable. This would effectively avoid any reference to generated code, besides AA's underscore class of course.
Here's what I mean:
#EFragment(R.layout.fragment_faq)
public class FaqFragment extends ListFragment {
#FragmentArg
Parcelable faqParcelable;
public void useFaq(){
List<FaqItemImpl> faqItems = Parcels.unwrap(faqParcelable);
// ...
}
}
Then when you're ready to build FaqFragment, you would just have to have Parceler wrap your List:
FaqFragment_.builder()
.faqParcelable(Parcels.wrap(faqItems))
.build();
Yes, this approach is not as nice as AA making the wrap/unwrap call for you, but it should work.
Edit:
Working with the Android Annotation team we've added Parceler support to #Extra, #FragmentArg and #SavedInstanceState annotated fields. This means the OP's desired functionality is in place. This should work:
#EFragment(R.layout.fragment_faq)
public class FaqFragment extends ListFragment {
#FragmentArg
ArrayList<FaqItemImpl> faqItems;
// ...
}
Unfortunetaly you cannot use #Parcelable objects with #FragmentArg (or other AA bundle injection annotations). Since you are using FaqItemImpl which itself does not implement Parcelable, AA cannot know how to deal with it. An (ugly) solution would be using the generated class:
#FragmentArg
ArrayList<FaqItemImpl.Parcelable> faqItems;
Actually there was an attempt to integrate parceler into AndroidAnnotations but was rejected due to some reasons.
There are plans to add Parcelable boilerplate generator into AA directly, unfortunetaly it needs more initial work.

Implementing Parcelable interface on polymorphic arrays

I have an array of type named ItinerarySegment, and this type has subclasses: WalkSegment, BusSegment etc.
public interface ItinerarySegment
{
}
public class WalkSegment implements ItinerarySegment
{
}
public class BusSegment implements ItinerarySegment
{
}
What sort of strategy should I follow when making the array of ItinerarySegment parcelable? The main concern here is how it will be used later when re-constructing the array via the createTypedArray method (prepared by writeTypedArray method).
In which the createTypedArray method take a Creator field parameter. The problem lies here...Where should the Creator field be defined? (in ItinerarySegment, WalkSegment, or BusSegment?).
public static final Creator<Typename> CREATOR = new Parcelable.Creator<Typename>()
{
public Typename createFromParcel(Parcel in)
{
return new Typename(in);
}
public Typename[] newArray(int size)
{
return new Typename[size];
}
};
If I make ItinerarySegment an abstract class and define the Creator field's method, then the subsequent subclasses's data will be lost since neither of their constructors are called with the Parcel parameter, instead ItinerarySegment's constructor will be called.
constructor(Parcel in);
If I make WalkSegment define Creator field, then BusSegment would have a problem.
Any clarification needed?
In order to do this using writeTypedArray() and createTypedArray() you would need to make ItinerarySegment an abstract class, not an interface. ItinerarySegment would need to implement Parcelable and it would need to have a CREATOR defined that would be called to unmarshall the Parcel and create new objects. Derived classes would also need to implement the methods writeToParcel(), describeContents() and the CREATOR.
NOTE: Because writeTypedArray() does NOT write the type of the object into the Parcel, you will need to do this yourself. Here's 2 possible ways:
The writeParcel() method of each derived class would have to write something to the Parcel at the very beginning that identifies its type (a String or int value).
The writeParcel() method of each derived class would have to call super.writeToParcel() before writing anything to the Parcel. In the ItinerarySegment.writeToParcel() method you could figure out what type of derived class it is and write something to the Parcel that identifies its type (a String or int value).
The CREATOR in ItinerarySegment would first read the identifier from the Parcel and then using that, determine which type of object to instantiate. It would then call the corresponding object's CREATOR to actually instantiate the object and return that to its caller.
This basically works like an object factory, in which the base class knows how to instantiate different types of its own derived classes.
The downside of all this is that the abstract base class would have to know about all of its derived classes. I suppose you could also do this dynamically, by have all derived classes call a static method in the base class passing its "type" and CREATOR, which the base class would then store in an array to be used as needed.
All doable, but pretty complicated.
As an alternative you can use writeParcelableArray() and readParcelableArray(), where the class name of each object is written to the Parcel so that it knows which CREATOR to call when unmarshalling.
IMHO the only time to use writeTypedArray() and createTypedArray() is when all the objects in the array are instances of the same class, and you are writing more than a handful of them into the Parcel. In that case, you save the overhead of writing the class name into the Parcel for each object, as you know they are all the same. In this case you don't need to go through all the agony I described above because you know the type of all objects beforehand (no polymorphic types).
I realize this answer is probably more than a year late, but what the heck. Maybe it will help someone else ;-)

How to define parcelable of interface type in .aidl file?

I have an .aidl file that defines a single parcelable of an interface type, let's say
parcelable MyInterface;
Whereby MyInterface is a java interface declared in MyInterface.java that extends the Parcelable interface. The android parcelable mechanism requires me to define a static CREATOR in the parcelable class. But how can I do this for an interface since the interface class does not know the concrete implementation and therefor cannot implement the createFromParcel() method?
How will the android runtime decide which CREATOR (from which subclass) to call? Is it even impossible to use an interface type in an .aidl file?
about use interface in AIDL file:
I don't think there is anything there stopping you to do so. Because "parcelable MyInterface;" does not actually generate anything in gen folder, it is just needed for function signature of any AIDL interface using this MyInterface type.
CREATOR
You have to add creator definition for all your classes implements android.os.Parcelable.
I ran into similar scenario, and wanted to share what I did. I had following aidl main interface which contains another interface inside it.
//ICounterAidlInterface.aidl
import path.to.aidldirectory.CounterListener
interface ICounterAidlInterface {
int getCounter();
void setCounterListener(CounterListener listener);
}
Don't forget the import.
The question is how to represent this new type: CounterListener. Since CounterListener itself is an interface, you don't need to mark it parcelable.
You need to create another aidl file for the CounterListener too. So, I created another aidl file:
//CounterListener.aidl
interface CounterListener{
void newData(int data);
}
Hope this helps :)

Categories

Resources