I need to pass objects to my fragments in order to initialize them.
Currently I am doing this with ((MyActivity)getActivity()).getX(). (direct access to the activity)
However, I would like to pass the required objects as parameter.
I definitely do not want to add parcelable objects to the bundle, since they require an excessive amount of useless boilerplate code. My goal is to reduce complexity, not increasing it.
And I do not want to add serializable objects to the bundle, since they are slow and cause an unnecessary overhead.
What is the best way to pass objects to fragments?
Any ideas to solve the problem in a more convenient way?
I definitely do not want to add parcelable objects to the bundle, since they require an excessive amount of useless boilerplate code. My goal is to reduce complexity, not increasing it.
You write this code in your model classes which is separated from your activities and fragments. There is no complexity in implementing Parcelable. And it is a common way to pass objects to a Fragment.
Any other solutions? Well, you still can do this ((MyActivity)getActivity()).getX() as long as your fragment is attached to your activity. In this case it is even faster than Parcelable because there is no serialization at all.
Other ways would be to write objects to database, pass their ids to a Fragment and then use a query to retrieve objects.
You can also use SharedPreferences, but that's rarely used. For this you will need to convert your object to String.
You can do the Android way: Parcelable.
You can serialize then.
You can do the poor way : static
You can do the retained way: Create a Fragment with setRetainInstance(true) and save your objects references.
I understand you don't want to use parcelable / serializable objects to a Bundle. I also agree with you since I got lazy, and my phone app is getting complicated.
Here's what you can do, and it works reliably.
Make a public method in your Fragment class, sample below.
Have the Activity, preferably no other place, call that public method. Remember Activity is always present, Fragments and Adapters may not due to its lifecycle.
The timing of the call is crucial if you're not using Bundles. I have used it without any problems.
The advantage of this technique is that it is fast, especially compared to Bundles. Many developers do not consider this however.
Note: If you are using simple fundamental Java types, do use Bundles! As suggested by Google.
Sample code:
public class MyFragment extends Fragment {
...
public void setList(final ArrayList<String> arrayList) {
...
}
In the Activity:
MyFragment fragment1 = MyFragment.newInstance(<parameters>);
fragment1.setList( arrayList );
Do you need to change the properties once they have been set on the fragment? If not, you can use setArguments(Bundle). If it is a fairly light object you can even skip implementing Parcelable and just set each property individually. The advantage is that the arguments are preserved upon orientation change. The disadvantage is that you need to call this method before attaching your fragment, hence it is not very useful once the fragment is in use.
It's way too late for my answer, but if someone else is wondering. The recommended way is to use Parcelable or Serializable, but you can always do something like this:
public class ObjectManager {
private static final String TAG = "ObjectManager";
private static ObjectManager instance;
private Object currentObject;
public static ObjectManager getInstance() {
if (instance == null)
instance = new ObjectManager();
return instance;
}
public Object getCurrentObject() {
return currentObject;
}
public void setCurrentObject(Object object) {
this.currentObject = object;
}
}
And then use it: where you needed as long as your app is running
//Use on the object you would like to save
ObjectManager.getInstance().setCurrentObject(object);
//Get the instance from pretty much everywhere
Object = ObjectManager.getInstance().getCurrentObject();
You can use it always, but it will be most likely to be useful, if you pass objects bigger than the Bundle max size.
Related
I use a third-party API (JAudioTagger) and I would like to start an activity with an object of this API (AudioFile).
The problem is this object does not implement Parcelable or Serializable.
What is the best way to do this ?
EDIT
Google's answer : http://developer.android.com/guide/faq/framework.html
You have a few options, none of which are easy or perfect (depending on the object and use-case).
Create a custom object that extends the AudioFile object and implements either Serializable or Parcelable - which can be tedious, but not impossible. With custom objects like this, the documentation may be lacking for this option.
Someone mentioned static as an option. This can generally work well, except you are talking about Android. Android can destroy and re-create the JVM for your app at any time when it is not visible to the user. So, if this AudioFile class is playing in the background in your app, strange behavior could occur if Android decides to kill the process.
You can use an object in the Application class, but is potentially has the same issues as #2.
Use SharedPreferences and some kind of index system to retrieve the file.
You can create a class of your own, which would accept an object of type AudioFile, and populate fields with its values.
public class MyAudioFile implements Parcelable{
private File file;
//other fields...
public MyAudioFile(AudioFile audioFile){
this.file = audioFile.getFile();
//populate other fields
}
//parcelable stuff
}
I wanted to pass arraylist of objects from one fragment to another i tried the following ways, wanted to know what are the pro's and con's of the following or is their any better approach
First
public myFragment(ArrayList<E> myarray) {
super();
this.myarray=myarray;
}
In the above code i created a constructor in the fragment class and used it to modify the arraylist
but as i read from net this is not the best practice i searched for other's
Second
public static myFragment newInstance(ArrayList<E> myarray1) {
// TODO Auto-generated constructor stub
MyFragment myFragment=new MyFragment();
myarray=myarray1;
}
here i created a static method which modify's the static arraylist myarray
Third
public static myFragment newInstance(ArrayList<E> myarray1) {
// TODO Auto-generated constructor stub
MyFragment myFragment=new MyFragment();
Bundle bundle=new Bundle();
bundle.putSerializable(TAG,myarray1);
myFragment.setArguments(bundle);
return myFragment;
}
In this code i created a Serializable arraylist and passed it to bundel then
myarray=(ArrayList<E>) bundle.getSerializable(TAG);
retrived the arraylist from bundle
Fourth
the forth method which i got on net was using parcelable instead of Serializable but it was bit difficult to create a parcelable, if any one can share easy way to create a parceable as i have array list inside arraylist.
So which of them is best approach or is their any better approach to send custom object from one fragment to another and what are their pro's and con's
1) You shouldn't ever override Fragment's constructor, it will cause unexpected crashes when system tries to recreate the fragment using the reflection.
2) You shouldn't use static ArrayList to hold the data because if you run into situation where you want to instatiate two fragments of the same kind, one will override the data from the second one
3) Serializable is acceptable way, but it's rather slow compared to the Parcelable since it uses reflection to restore your data
4) Parcelable is a way to go. It's a bit of pain to make your class Parcelable but it's way faster than option 3., and safer than options 1. and 2.
another ideas:
5) If you don't need to persist the data, you can construct a singleton class which will hold the data in the ArrayList, and you can access it from anywhere in the application
6) If you need to persist the data, you should store it in the database, and when you go from one Activity to antoher, or from one Fragment to another, you just pass the ID of the object in question and pull the data from DB.
I would suggest using the newInstance() static method as this is the way that Google suggests that you create fragments (see http://developer.android.com/guide/components/fragments.html ) and make sure you have a no args constructor. (also limitations of others as Tomislav Novoselec has said)
A nice way I've found to easily convert objects to implement the Parcelable interface is this Android studio plugin > android-parcelable-intellij-plugin. There is also a website to help you do it too if you prefer > parcelable.com
(Parcelable objects are also more efficient than serializable too I've been told, so use them were you can)
I'm part of an Android project that uses a global class that contains public static variables, like the example below:
public class Globals {
public static MyObject variable = "this is a test";
}
In the middle of using the application, this global variable's value will be changed let's say:
#Override
public void onCreate(Bundle savedInstanceState) {
Globals.variable = new MyObject(somethingHere);
}
And I came across using Headless Retained Fragments from these blog posts:
http://www.androiddesignpatterns.com/2013/04/retaining-objects-across-config-changes.html
http://www.vogella.com/tutorials/AndroidFragments/article.html#headlessfragments
Problem:
I need to have a reference of an initialized object all over the application.
Question:
which is better to implement, a good practice, and practical? Or is there another way I could store a reference of an object all over the application?
The global class has been used over the project, and works fine, but are there any downsides of this implementation?
are there any downsides of this implementation?
Memory leaks, depending on what you are storing there. Leaks are why static data members are considered poor form in classic Java, even if we tend to use them more in Android app development.
Also, this data needs to be considered a cache, one that has to be able to be lazy-created on first access. Your process can be terminated at any point (wiping out the static data member) and the user can return to any activity in your app (courtesy of the recent-tasks list). If you want this data to survive process termination, the most likely solution will be to persist it in a file, database, or SharedPreferences.
All that being said, a retained fragment is a per-activity solution, not a per-application solution, and so it is not a valid alternative for your scenario AFAICT.
Let's assume I have a class MainActivity.
This contains a number of objects stored in fields, such as instances of Player, Enemy, Level, etc. Each of these objects needs to be able to refer to every other object.
What is the best way to go about this?
Make these fields static, and refer to them accordingly, i.e.
MainActivity.player.setHealth(0);
Create getter methods for each field, and simply pass each object a reference to MainActivity, so that they can call these getter methods, i.e.
mainActivity.getPlayer().setHealth(0);
Pass each object a reference to every other object, and store these references in fields within each object, so that they can be referred to directly, i.e.
player.setHealth(0);
Not a real answer but just to give you some tips.
Your Player should be like so:
public class Player
{
private static Player _player = null;
int _health;
...
public static Player getInstance()
{
if (_player == null)
_player = new Player(...);
return _player;
}
public void increaseHealth(int amount)
{
_health += amount;
}
}
Then in any part of your application when you need a Player you can do:
Player p = Player.getInstance();
and you will get the same player all the time. You can do a similar thing with your level class as only 1 level will be active at any one time.
However the Enemy class will need a different approach. I would make a List inside the Level class and get at them like so:
Level l = Level.getInstance();
List<Enemy> enemiesOnLevel = l.getEnemies();
// do something with them
Have a look in the Android docs here: http://developer.android.com/guide/faq/framework.html#3. There is also the possibility to serialize your object into primitive datatypes and pass those within your Intent to the new Activity.
A couple more options to share objects between activities are to use parcable, which I think is probably the highest performance method, and shared preferences.
In my app I used to learn (the little I know about android programming), I used gson to serialize the object to json, then stored it in shared preferences in activity A , then recreated it from shared preferences in activity B, and then stored it again.
I'm trying to persist data objects throughout my Android app. I want to be able to access an object in one activity, modify it, save it, navigate to a new activity, and access the same object with the updated value.
What I'm essentially talking about is a cache, but my data objects are complex. For example, ObjectA contains ObjectB which contains ObjectC. Does anyone know if a good method, tool, or framework for persisting complex objects in Sql?
Put a static field in a subclassed Application. Also inside your manifest, put:
android:name="MyApp" inside your application tags.
Also to access from other files, simply use:
MyApp myApp = (MyApp)getApplicationContext();
See here How to declare global variables in Android?:
class MyApp extends Application {
private String myState;
public String getState(){
return myState;
}
public void setState(String s){
myState = s;
}
}
class Blah extends Activity {
#Override
public void onCreate(Bundle b){
...
MyApp appState = ((MyApp)getApplicationContext());
String state = appState.getState();
...
}
}
You could use an ORM framework, like OrmLite for mapping objects into sql, but it may be an overkill for you situation.
You could also make these shared object Parcelable and pass them between the Activities thru the Intents.
You could also save these objects into the SharedPreferences, so each Activity can access them whenever they feel the need to it, and the objects are also persisted this way. This may mean more IO access though, so take that into consideration as well. You could use e.g. Gson to serialize the objects more painlessly for this.
These are the solutions I'd consider. But whatever you do, don't put this common object into some kind of "standard" global static variable, like using a custom Application class, static field or any implementation of the Singleton pattern, these are really fragile constructs on Android.
Why don't you use a JSON serialization mechanism ?
In association with a static access to your objects you can easily build a lite-weight database with some basic functionnalities:
loadObjectsFromCache
saveObjectsInCache
getObjects
You can also store your objects in differents files, and use a streaming json parser like this one: http://code.google.com/p/google-gson/
It's the same that this one: http://developer.android.com/reference/android/util/JsonReader.html
but can be used even if your application api level is inferior to 11.
It use less memory than the basic DOM parser:
http://developer.android.com/reference/org/json/JSONObject.html,
but with the same speed.