To pass data from an Activity to a Fragment, naturally, I think of using a Bundle. The problem in my case is that the Object I need to pass is a Google Cloud Endpoint message, which is neither Parcelable nor Serializable. So how might I pass the data?
For clarity, a Google Cloud Endpoint message is a POJO that is used to pass data to and from endpoint methods. I assume they would be Serializable, but to my surprise they aren't.
You can:
Subclass and implement Serializable or Parcelable on that class
Or use any other strategy to pass data inside of the app:
Singleton class holding any memory cache you may use
If the fragment is inside of the activity you can access the fragment from the activity and pass the variable in
In the worst of cases you can always use SharedPreferences or any kind of disk persistence
Related
Can anybody please tell why we need to serializable object for passing one activity to another activity in android? Android is following Java syntax. In java we can pass object to another class without serializable.
Thanks
In ordinary java programs passing parameters(Object type), is kind of create a new handler to the object and giving to another method (In regular words passing the reference by value).
But when it comes in android, passing object references from activity to activity, where their states have to be persisted, is a serious headache.
One way you can do is create a static object in the first activity and access from the second, though this seems to be a easiest way, there is no guarantee that the system maintains the activity in the memory. Therefore the second activity may loose the object reference.
Other way, and the mostly recommended way is serializing(Kind of flatten the object) the object and pass with the intent as extra. In android there are two ways to serialize.
Implement the java's serializable interface
Implement the android's parcelable interface
However, on the android, there is a serious performance hit that comes with using serializable, the solution is using parcelable.
You can find a pretty good tutorial and explanation on android parcelable implementation here.
We need to understand following concepts before getting to the answer:
Android uses Binder for inter-process process. It is required even for simple app because the OS and the apps run in different processes.
Marshalling:
A procedure for converting higher level application data structures into parcels for purpose of embedding into Binder transaction
Unmarshalling
A procedure for reconstructing higher-level application data-structures from parcels received though binder transactions.
You can consider Intents as higher level abstraction of Binder
Based on the documentation following is the way how intent communication occurs:
Activity A creates an Intent with an action description and passes
it to startActivity().
The Android System searches all apps for an intent filter that
matches the intent. When a match is found,
the system starts the matching activity (Activity B) by invoking
its onCreate() method and passing it the Intent.
Why Parcelable or Serializable
IPC (Inter Process Communication) requires data in Intent to be Marshalled and unMarshalled. Binder provides built-in support for marshalling many common data-types. However when we define custom object, it would impact this process and the final object received might be corrupted during the process.
When you define custom object, you need to be responsible for providing this marshalling and unmarshalling which is achieved through Parcelable and Serializable (Since comparison between these two would be another topic I won't discuss much here). Both of these provide mechanisms to perform marshalling and unmarshalling. This is the reason why you need to use Parcelable or Serializable.
Using Parcelable you write the custom code for marshalling and unmarshalling the object thereby you gain complete control over the process.
Serializable is a marker interface, which implies the user cannot marshall the data according to their requirements and its done on JVM, which doesn't give any control at your side.
Disclaimer: Description above is my understanding for the rationale behind the need for serialization based on some
documentation
There are basically two questions in your question, so let's decouple it.
Why marshall in a Parcelable instead of passing an object reference directly?
It's obvious faster and more memory efficient to reference objects rather than marshall/unmarshall them. So you shouldn't use Parcelable when you can pass the object directly.
However, there are situations where you may not have access to the object reference.
in Intent because the process that handles the Intent may not be the process that emitted the Intent (it's an inter-process communication)
in Activity lifecycle, for instance in onRestoreState(), because the whole app may have been killed by memkiller when the user wants to resume it.
everywhere else where Android frameworks requires
In IPC, why use Parcelable rather than Serializable like Java does?
That's only a performance optimization.
If We want to pass object from Activity to to Another Activity . We need to save the passing state.
//to pass :
intent.putExtra("MyClass", obj);
// to retrieve object in second Activity
getIntent().getSerializableExtra("MyClass");
What is the best solution to deal with an "AdapterA of a RecyclerViewA which is inside a FragmentA" that want to use data from another "AdapterB of a RecyclerViewB which is inside a FragmentB" ?
I am stuck,i tried to :
1- Make the data static in the adapter (no garbage collector)
2- Duplicate data that i need (waste of memory)
(it works but may be there is a better solution)
Thank you in advance. (plz ask for details if you need)
If you, in MainActivity, create a new instance of a class where you contain whatever you want both fragments to access. If you implement Serializable or Parcelable, you can also send it to each fragment using Bundle/Intent.
Then, as you have the same instance in two different fragments, if you edit data in fragment X, fragment Y will be able to access it.
See this:
|---MainActivity---|
| | |
V V V
Frag A <->Data <->Frag B
MainActivity creates a new class(data) which it sends to each of the fragments. The fragments can update the data in the class. Please note, that you have to use class if any given data type isn't supported.
If you don't feel like using Serializable or parcelable, if possible, send MainActivity as an instance to each of the fragments. From each fragment you then get the MainActivity instance and find the data you need.
If you can't pass MainActivity to either of the fragments, and cannot use Serializable/Parcelable and the data type isn't supported by bundle.putExtra or intent.putExtra, you have to use a static import.
Those are your only options.
Alternatively, you can create a class that extends "Application". Then you write:
MyApplicationClass mac = (MyApplicationClass) getApplicationContext();
Then you access the data in the application-extending class(here: the mac instance)
Final words
If you do not want to use static instance, send a parcelable/serializable class with the contents, or use a class extending Application, there is no way you can transfer the data(considering you are using a HashMap which you claim cannot be sent by Intent or Bundle). If you had a data type or class that was possible to send using Intent or Bundle, you wouldn't have to use static instance or parcelable/serializable class. But with the position you are in, I have presented all the options you have. There are basically no other ways than using a class containing the hashmap, using a static instance or utilizing the Application class.
I have a GAE backend and an Android client. I have generated the client library successfully and that works fine. Now, I'm trying to send an object via an intent from one activity to another in Android. To my horror I noticed that the generated GAE models are final classes that don't implement parcelable or serializable interfaces. Because of that I decided to try and use gson to parse them to json string and then back to the original object. That however fails on fields like DateTime for some reason. My next try was to just let the classes implement serializable (bad idea to touch generated classes!!) but the issue with that was that since these classes extend AbstractMap the serializable output is a HashMap rather than my original object! Now I'm thinking about letting it implement Parcelable but that's a lot of work and sounds like a very bad idea since these models are generated and could change (thus removing my parcelable work.)
I know that people here love code so here is my problem written in code:
Activity A (MainActivity) is trying to send a "UserScore" object (generated from GAE) to activity B.
Intent intent = new Intent(MainActivity.this, ResultsActivity.class);
intent.putExtra(ResultsActivity.BUNDLE_USERSCORE, userScore);
startActivityForResult(intent, REQUEST_COUNTDOWN);
This would've given my error since userScore isn't parcelable or serializable but in this case I made it serializable. Activity B (ResultsActivity) receives:
Object extra = getIntent().getSerializableExtra(BUNDLE_USERSCORE);
Now you would expect the extra object to be of the type UserScore but since it was sent via intent and is a subclass of AbstractMap it is in fact a HashMap.
So, my question is: has anybody encountered this issue and found a way to properly send GAE models via intents in android?
I'm creating simple application that uses JSON format and SQLite database to store parsed information into that. I'm aiming to support both normal devices and tablets, so I'm using Android Fragment API.
My problem is that I'm not sure where I should store the reference to my database, at this moment I have main activity that incorporates two fragments - list fragment and details fragment (both of them are adjusted for tablets and normal phones).
I need to fill mentioned list with information from database and in future I want to implement additional search function so reference to database must be shared by almost all fragments/activities.
In addition I have special class(Util) that stores HTTP object and JSON parser. Is it good idea to add static database reference to that class and create new instance of it in seperate thread (initialization block) ? Or I should consider create it in MainActivitity and create getter and setter ? My MainActivity implements appropriate interfaces from list fragment so I'd need to cast it.
I have a class in my Android app that I've made Parcelable so that it can be passed between Activities.
I would like to be able to save this object to the filesystem. It seems that since I've already implemented Parcelable, it would make sense to pipe the output of this to the filesystem and read it back later.
Is there a correct way to do this? Or must I implement both Parcelable and Serialiazble if I want to both pass the object between Activities and also save it to the filesystem?
From http://developer.android.com/reference/android/os/Parcel.html
Parcel is not a general-purpose serialization mechanism. This class (and the corresponding Parcelable API for placing arbitrary objects into a Parcel) is designed as a high-performance IPC transport. As such, it is not appropriate to place any Parcel data in to persistent storage: changes in the underlying implementation of any of the data in the Parcel can render older data unreadable.
For this problem, I did the following:
Implemented Serializable in my object
Added a toJSON() method to convert the object to a JSON object
Used a custom JSONSerializer to write the JSON objects to a file
Added a constructor that takes a JSON object as a parameter, used by the custom JSONSerializer
It ended up being pretty simple...I can paste some sample code if needed.