I want to send an object between Activities. Reading up on this i have come to conclusion that using Parcelable is the best way to go as it has the least performance impacts. The reason i want to do this is because i need to download data from the network to create an Object, so i don't want to keep downloading the data.
However, in order to use a Parcel the class needs to implement Parcelable. As i am trying to send an Object defined in a Library i cannot edit the class to include this.
What would be the best way to solve my predicament?
I have tried extending the library class and implementing Parcelable but failed with a ClassCastException. I have also seen mentioned that i should make a Parcelable class that wraps around my library class and send it that way?
Thanks!
How about using the parceler library? You can tell your Application to parcel library classes:
#ParcelClass(LibraryParcel.class)
public class AndroidApplication extends Application{
//...
}
If that works, you could use the following code to wrap/unwrap:
Parcelable wrapped = Parcels.wrap(new Example("Andy", 42));
Example example = Parcels.unwrap(wrapped);
example.getName(); // Andy
example.getAge(); // 42
Did you try to use Bundle ?
For example if you have parcelable class User
Bundle bundle = new Bundle();
List<User> users = new ArrayList<User>();
String userName = user.setUserName("some name");
boolean isOnline = user.setOnline(true);
users.add(user);
bundle.putParcelableArrayList("USER", users);
And you may retrieve this as:
public ArrayList<User> getParcelableArrayList(Bundle bundle){
List<User> userList = new ArrayList<User>();
userList = bundle.getParcelableArrayList("USER");
}
Related
Hi I hope someone here can help me, I am working in an android app, I already serialize the following gson object
Screenshot:
the jsonobject has many subclasses like:
PreferencialaboraEstudio,Preferencialaboralarea, and more classes,
I transfer this gson object from an activity to a new activity, in order to deserialize this object I have implemented the following code in the new activity:
Intent intent = getIntent();
String Postulado = intent.getStringExtra("Postulado");//Postulado from extra is actually a gson object
Candidato candidato = gson.fromJson(Postulado, Candidato.class);
CandidatoPreferenciaLaboralEstado preflaboraledo = gson.fromJson(Postulado, CandidatoPreferenciaLaboralEstado.class);
I have the problem in CandidatoPreferenciaLaboralEstado, as you can see in the picture there are two items of this type class in the gson object, but my code only returns the first item and not the second one, is there a way to get all the items of this type "CandidatoPreferenciaLaboralEstado" from the gson?
Thank you very much for your time and assistance in this matter.
Not sure how your root model is, but you can have something like this:
public class Postulado {
private CandidatoPreferenciaLaboralEstado candidatoPreferenciaLaboralEstado;
private CandidatoSoftware candidatoSoftware;
public class CandidatoPreferenciaLaboralEstado {
private List<CandidatoPrefAttributes> candidatoAttributesList;
public class CandidatoPrefAttributes {
private Integer cveCandidato;
private Integer cveCandidatoPreferenciaLaboralEstado;
//More
}
}
public class CandidatoSoftware {
private List<CandidatoSoftwareAttributes> candidatoAttributesList;
public class CandidatoSoftwareAttributes {
private Integer cveCandidato;
private Integer cveCandidatoSoftware;
//More
}
}
}
With respective getters.
Also looks that the candidates (CandidatoPreferenciaLaboralEstado and CandidatoSoftware) and Candidate Preferences are very similar, maybe you can unify that models to one (Candidate and CandidatePrefferences) and use multiple serialized names like:
#SerializedName(value="candidatoPreferenciaLaboralEstado", alternate={"candidatoSoftware"})
Hope this can help you!
If i have an object form interface in my class, how i can pass it to activity?
My solution was to change it as static object, it's work fine but sometimes it create a memory leaks because of all the old references which the garbage collector cannot collect, and i cannot implement 'Serializable' on my interface.
public class MyClass {
protected OnStringSetListener onstringPicked;
public interface OnStringSetListener {
void OnStringSet(String path);
}
//......//
public void startActivity(){
Intent intent=new Intent(context,Secound.class);
// ?! intent.putExtra("TAG", inter);
context.startActivity(intent);
}
}
In my opinion, using Bundles would be a nice choice. Actually bundles internally use Parcelables. So, this approach would be a good way to go with.
Suppose you would like to pass an object of type class MyClass to another Activity, all you need is adding two methods for compressing/uncompressing to/from a bundle.
To Bundle:
public Bundle toBundle(){
Bundle bundle = new Bundle();
// Add the class properties to the bundle
return bundle;
}
From Bundle:
public static MyClass fromBundle(Bundle bundle){
MyClass obj = new MyClass();
// populate properties here
return obj;
}
Note: Then you can simply pass bundles to another activities using putExtra. Note that handling bundles is much simpler than Parcelables.
Passing in custom objects is a little more complicated. You could just mark the class as Serializable
and let Java take care of this. However, on the android, there is a serious performance hit that comes with using Serializable. The solution is to use Parcelable.
Extra info
I'm developing an android application that deals with bitmaps. Right now I'm using an LRUCache to store these bitmaps, but there are going to be multiple fragments that require access to this cache. What's the best way to handle to handle a global application cache? Should I use a singleton? Should I create a new cache for each activity/fragment that requires access to it?
To avoid Singletons in Android Development, like in your question I would suggest anybody using Fragments to store real global Objects in the MainActivity. It should look like this:
MainActivity:
public class MainActivity extends FragmentActivity{
//eg a ArrayList
private ArrayList<MyObjects> mObjectContainer = new ArrayList<MyObject>();
//Do something with the list and fill it
public ArrayList<MyObjects> getObjectContainer(){
return mObjectContainer;
]
public void addObject(MyObject object){
if(!mObjectContainer.contains(object)){
mObjectContainer.add(object);
}
}
}
Fragment:
public class MyFirstFragment extends Fragment{
onCreateView(...){
//make typical Fragment init like create View
ArrayList<MyObjects> list = ((MainActivity)getActivity()).getObjectContainer();
//add a new Object
((MainActivity)getActivity).addObject(new MyObject("any data"));
}
}
I want to test an Android activity CommentActivity that normally constructs and uses an instance of CommentsDataSource (both are classes that I wrote).
public class CommentActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
:
CommentsDataSource = new CommentsDataSource(..);
:
}
:
}
I'm willing to create MockCommentsDataSource myself and would like to avoid using a third-party mocking framework. (Why? Because I'm a teaching trying to reduce the amount of information I need to cram into the semester and the amount of software my students need to install. I've seen other posts that recommend Guice, roboguice, and Spring.)
My question is how to pass a CommentsDataSource (or MockCommentsDataSource) to the Activity. It doesn't seem practical to make them Serializable or Parcelable, which they would have to be in order to be passed in through the Intent that starts CommentActivity. While I could easily pass in a debug flag, using it would require CommentActivity to know about MockCommentsDataSource, which is really none of its business (and in a separate application):
public class CommentActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
:
debugMode = getIntent().getBooleanExtra(DEBUG_MODE, false);
// Get a connection to the database.
final CommentsDataSource cds = (debugMode ?
new MockCommentsDataSource() : // Abstraction violation
new CommentsDataSource(this));
:
}
:
}
How should I inject MockCommentsDataSource into CommentActivity? FWIW, I'm using Eclipse and am developing for recent SDK versions.
One solution that occurs to me is to use the abstract factory pattern, since it would be relatively easy to make the factories serializable. Is that the best approach, given my constraints?
Here are two ideas:
Not using factory:
This will probably work only for unit tests and not for integration tests:
Create a method that returns CommentsDataSource, e.g. getCommentsDataSource()
Create a class that inherits CommentActivity
Override the getCommentsDataSource() with a method that returns MockCommentsDataSource
Test the new class
Using factory:
As you mentioned, you can change the CommentActivity code to get the CommentsDataSource from a factory method. this way you can have the mock class returned by the factory method.
Hope this helps!
I have a simple and ugly solution to offer, using a private static field to inject the dependency:
private static Client client;
and set the field value from the test using reflection:
public static void setStaticFieldValue(final Class<?> clazz,
final String name, final Object value) throws Exception {
final Field field = clazz.getDeclaredField(name);
field.setAccessible(true);
field.set(null, value);
}
then, in i.e. onCreate(), use that "injected" test instance if the field is set and use the regular one otherwise.
Ugly, but requires only few changes relevant to testing to the class under test.
Serialisation:
Bundle activityArguments = new Bundle();
Stack<Class<? extends WizardStep>> wizardSteps = new Stack<Class<? extends WizardStep>>();
wizardSteps.push(CreateAlarmStep5View.class);
wizardSteps.push(CreateAlarmStep4View.class);
wizardSteps.push(CreateAlarmStep3View.class);
wizardSteps.push(CreateAlarmStep2View.class);
wizardSteps.push(CreateAlarmStep1View.class);
activityArguments.putSerializable("WizardSteps", wizardSteps);
Deserialisation:
Stack<Class<? extends WizardStep>> wizardSteps =
(Stack<Class<? extends WizardStep>>) getIntent().getExtras().getSerializable("WizardSteps");
Exception:
12-20 23:19:45.698: E/AndroidRuntime(12145): Caused by: java.lang.ClassCastException: java.util.ArrayList cannot be cast to java.util.Stack
Its known bug. I surprise that it still exists.
Use generic container like:
public class SerializableHolder implements Serializable {
private Serializable content;
public Serializable get() {
return content;
}
public SerializableHolder(Serializable content) {
this.content = content;
}
}
If you use GSON library, convert your Stack to String and use as single String for Bundle without Serialize. It should work.
Just cast the serializable you retrieved from the bundle to a List, create a new Stack, and then add all the List items to the stack:
Serializable serializable = savedInstanceState.getSerializable("key");
List<Something> list = (List<Something>) serializable;
Stack<Something> stack = new Stack<Something>();
stack.addAll(list);
Why cast to List and not ArrayList you ask? Because if this is fixed in some Android version, you won't have a ClassCastException again.
I hope am not talking any nonsense!
Stack does not implement Serializable but rather just extends the Serializable Vector which is equivalent to ArrayList
I am unaware of the real definition of equivalent and how loose could that be, but it is sufficient to say that the first super class of Stack that is Serializable is Vector.
Since we see this exception, then I would probably assume that casting the Serializable to ArrayList should not throw this exception. Otherwise, I am talking nonsense.