-2

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?

Mike76
  • 899
  • 1
  • 9
  • 31
  • 1
    Use parcelables, despite your insistence on not using them, they are, by far, the fastest of the kind of object serialization between activities, much more so than serializable's. – t0mm13b Jul 31 '15 at 21:32
  • Implementing `Parcelable` is not that complicated, and the slowness of `Serializable` on Android has been greatly exaggerated. – Kevin Krumwiede Jul 31 '15 at 21:38
  • Is it possible to avoid using either Parcelable or Serializable? – Mike76 Jul 31 '15 at 21:41
  • Not unless you grab it statically somehow. Maybe inside a helper class. – Nick H Jul 31 '15 at 21:42
  • Currently I access the objects directly in the main activity. It is similar to using static objects. Maybe I should use Serializable and ignore the performance issue. – Mike76 Jul 31 '15 at 21:46
  • Welcome to Stack Overflow (SO). Pls read up on So tutorial @ http://stackoverflow.com/tour . You will get some rep points just by reading it. And it has some good guidelines on using this site. Good luck! – The Original Android Jul 31 '15 at 21:49
  • I was using EventBus for a while, later switched to have separate holder classes that has the relevant objects statically available. I like this approach because it detaches the activity fragment dependency, that is I can reuse fragments in other activities without problems. This can be combined with always creating new fragment instances by doing 'MyFragment.newInstance(objects..)' , storing the objects passed as params in the helper class within the newInstance method. This way the compiler can furthermore help you remember which objects that a fragment dependent on. – cYrixmorten Jul 31 '15 at 21:59
  • I will check this out. However, my whole application is running with one single main activity, so I do not need to call fragments from different activities. – Mike76 Jul 31 '15 at 22:02
  • This helper class might be the global application class, which extends application? – Mike76 Jul 31 '15 at 22:27
  • Could be, in my case I created singleton classes to have separate classes. – cYrixmorten Jul 31 '15 at 22:56

5 Answers5

1

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.

Gennadii Saprykin
  • 4,505
  • 8
  • 31
  • 41
  • Passing database ids is an option, since I allready use a database. My fragment is always attached to my activity, since I am only using one main activity. Nevertheless I would like to pass arguments to the fragments. – Mike76 Jul 31 '15 at 21:55
  • 1
    If you want to pass your custom objects as arguments then you have 3 choices: `Parcelable`, `Serializable`, and converting to `String`.. `Parcelable` is definitely the best from these 3 options – Gennadii Saprykin Jul 31 '15 at 21:56
  • Back in 2015, I did not actually understand what complexity means. Adding a bunch of serializing boilerplate code does not increase the complexity. However, adding runtime-dependencies from a fragment to an activity increases the complexity. – Mike76 Nov 15 '19 at 13:27
0

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.

Marcos Vasconcelos
  • 18,136
  • 30
  • 106
  • 167
  • Nearly all of my fragments are added to the backstack, so I think setRetainInstance(true) is not an option. Static does not make sense for my project, since I can access all required members in the main activity without making it static. – Mike76 Jul 31 '15 at 21:43
  • Yes, static is a bad way, but it will keep the references across config changes, you can retainInstance of a "StateFragment" and add it to the activity with a String TAG instead of the container id (it will be viewless) – Marcos Vasconcelos Aug 03 '15 at 19:00
0

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 );
The Original Android
  • 6,147
  • 3
  • 26
  • 31
  • So what happens when the fragment is recreated? For example during orientation change? I think I should call this method straight before I add the fragment to the fragment manager. Maybe I could make a static createInstance()-function in my fragments in order to wrap this function. – Mike76 Jul 31 '15 at 21:52
  • The call to the public method should come after you create an instance of that Fragment. So that is a requirement! I will add comment to that effect. I hope that's clear. – The Original Android Jul 31 '15 at 21:54
  • So I could instantiate the fragment, call the setList-method and then pass it to the fragment manager. But what if the fragment is automatically recreated, is the setList-method called in this case? – Mike76 Jul 31 '15 at 21:57
  • I decided to add more sample code to be clear and to answer your question. I did not wrap the method inside newInstance() as you suggested. – The Original Android Jul 31 '15 at 21:58
  • As you can see now in the sample code, setList() will be called when you create the Fragment. This is the reason I added "Note" in my post. Try it out... – The Original Android Jul 31 '15 at 21:59
  • Thx, can you tell me what happens, when this fragment is recreated during orientation change or other events? What happens with the set members? – Mike76 Jul 31 '15 at 22:06
  • @Mike76, you should call the setList() and newInstance() in onCreate() or on onCreateView(). Perhaps you should read up on Fragment Lifecycle. My answer did not include lifecycle issues, and your post did not mention it either. – The Original Android Jul 31 '15 at 22:16
  • In your answer, you put this code "MyFragment fragment1 = MyFragment.newInstance(); fragment1.setList( arrayList );" into the activity. So it should be called inside the onCreate() of the activity? Normally I instantiate my fragments just before passing them to the fragment manager. – Mike76 Jul 31 '15 at 22:21
  • @Mike76, Yes you're correct. It should be "before passing them to the fragment manager." My comment answers your issue on "orientation change" which is different issue. Again just try it out and you would learn from it :) – The Original Android Jul 31 '15 at 22:25
0

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.

N.T.
  • 2,601
  • 1
  • 14
  • 20
0

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.

matdev
  • 4,115
  • 6
  • 35
  • 56
  • This is answer prevents a possible garbage collection of currentObject which is not good for memory management. Definitely should use Parcelable or BroadcastReceiver – matdev Nov 12 '19 at 16:13
  • As I said the recommended way is Parcelable or Serializable, but the question ask for another approach, and since there will be only one object and will not be passed any context, it will not really make a difference for the memory. – Tomislav Emilov Nov 12 '19 at 16:23