1

I know how to pass object using Parcelable or Serializable but I found other approach on the internet to do it - using Application class like this:

class ComplexObject {
    // contain String, int, List<String>, other objects ...
}

class App extends Application {

    Map<String, Object> map = new HashMap<>();

    public void put(String key, Object value) {
        map.put(key, value);
    }

    public <T> T get(String key, Class<T> cls) {
        return cls.cast(map.get(key));
    }

    public void remove(String key) {
        map.remove(key);
    }

}

class ActivityA extends AppCompatActivity {

    void start(ComplexObject obj) {
        Intent intent = new Intent(this, ActivityB.class);
        ((App) getApplicationContext()).put("obj", obj);
        startActivity(intent);
    }

}


class ActivityB extends AppCompatActivity {

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        App app = ((App) getApplicationContext());
        ComplexObject obj = app.get("obj", ComplexObject.class);
        app.remove("obj");
    }
}

Is this impact performance of app?

maphongba008
  • 2,114
  • 4
  • 20
  • 33
  • 1
    why don't you use a bundle attached to intent instead? – Mehran Zamani Aug 09 '17 at 04:38
  • I think this is not right way to pass data between Activity or Fragment you have pass data using Intent Bundle as @MehranZamani suggested. – Haresh Chhelana Aug 09 '17 at 04:43
  • I use it to save data that used in many places, and so far no notable impact on performance. Also mentioned here https://stackoverflow.com/questions/4208886/using-the-android-application-class-to-persist-data. However, it's not based on a specific data. – Kharda Aug 09 '17 at 04:44
  • 1
    Strongly discouraged. If any activity will keep a reference to such an object, and the Application will also keep it in the map, then that activity will not be garbage collected when destroyed, creating a memory leak. In Android there's no such reason for extending Application, almost ever (it's also written in the docs btw!). Think about the data you're passing, and why; usually they should be so simple, that Bundle will do for you. – Alessio Aug 09 '17 at 04:48
  • @Alessio but after get the object, I remove it from the Application class, only keep in Activity – maphongba008 Aug 09 '17 at 04:49
  • @HareshChhelana because Serialize create a new object (different hashCode), if I change the property of object in activityB, the object in activityA won't change – maphongba008 Aug 09 '17 at 04:50
  • *It's your choice!* Referencing an object is way faster than sending a Bundle since you do not need to deal with serialization and deserialization and no new object is created however this approach is prone to memory leak specially when you have less knowledge to this domain. The upside of using Bundle so far is that it will guarantee safety from leaks. Another downside of sending Bundle is the Load limit. – Enzokie Aug 09 '17 at 04:51
  • And Parcelable is hard to implement, and there's a problem with circular relationship like Parent contain list of Children, Child contain a Parent ... – maphongba008 Aug 09 '17 at 04:52
  • @maphongba008 yes you do, today. But tomorrow or next month, the new programmer next to you, who's not aware of that part, will not, therefore I don't see any reason why you want to enforce what I personally think is a bad design and bad choice, and risks a memory leak. Use the system with its design, don't fight against it :) – Alessio Aug 09 '17 at 04:52
  • @maphongba008 in that case ( if I change the property of object in activityB, the object in activityA won't change) you need start activityA with result and return updated object into result to activityA from activityB. – Haresh Chhelana Aug 09 '17 at 04:56
  • 1
    @Alessio You wrote _If any activity will keep a reference to such an object, and the Application will also keep it in the map, then that activity will not be garbage collected when destroyed, creating a memory leak._ This is not correct! The garbage collector has no problems reclaiming an `Activity` with references to other live objects! This is **not a memory leak**. A memory leak would occur if there was a reference to the `Activity` in the `Application` instance, which is not the case. – David Wasser Aug 09 '17 at 13:27
  • @DavidWasser you're very correct, as I wrote it down, it can be misleading. The memory leak I had in mind, it depends on the object. If the passed object works as a callback to the activity, there's the memory leak I had in mind (this is more correct). I found [an example](https://android-developers.googleblog.com/2009/01/avoiding-memory-leaks.html) of this by Romain Guy. Also, generally speaking, I don't see any reason why to pass objects like that in Android, it's memory leak prone. – Alessio Aug 10 '17 at 04:42

2 Answers2

2

You can also do this using static members in any class (you don't need to extend Application in order to do this.

You can also store data in some persistent storage (File, SharedPreferences, SQLite database, etc.) to do this.

There are pros and cons. Here's my take on this:

From a "performance" perspective, passing a reference to an existing object by using your Application code or by using a static member variable is significantly faster than serializing an object into a Bundle and deserializing it again (using either Serializable or Parcelable). However, unless you have a huge amount of data you are doing this with, you won't be able to notice any performance loss (or gain).

From a "complexity" perspective, passing a reference to an existing object is significantly easier to understand than the serialization and deserialization process. It is also less likely to be buggy.

From a "robustness" perspective, you need to understand that Android can kill the OS process hosting your app at any time. This means that if you are passing data between one Activity and another by passing (or storing) a reference to an existing object, there are cases where the underlying object will be gone by the time the receiving Activity needs it. This can cause your app to crash, or behave unexpectedly, if you don't write code to handle this situation and act accordingly.

From a "correctness" perspective, you should pass any required data between activities as "extras" in the Intent. Android ensures that the "extras" in the Intent are stored persistently so that, in the case where Android kills the OS process hosting your app, when the user returns to the app, Android can recreate everything as it was. That said, you should not pass large amounts of data between activities this way. If you have large amounts of data to pass between activities, the "correct" way to do this is to store the data in a persistent storage (Shared Preferences, SQLite database, File, etc.) and pass enough information (an index or a key) in an Intent "extra" so that the receiving Activity can read the data from the persistent storage.

I tend to take a pragmatic approach and use the method that is most appropriate for the task at hand. There is no one method that is "best" or "correct". To use the classic consultant's answer: "It all depends..."

David Wasser
  • 93,459
  • 16
  • 209
  • 274
0

No it's not OK at all.

Except for cases when the instantiated object is very very big (say 20MB or more), where you want to find alternative solutions, for 'normal' objects you should use Parcelables and Bundles to pass them between activities. That's the system design.

You seem to ignore a very important comment on Application:

Note: There is normally no need to subclass Application. In most situations, static singletons can provide the same functionality in a more modular way. If your singleton needs a global context (for example to register broadcast receivers), include Context.getApplicationContext() as a Context argument when invoking your singleton's getInstance() method.

As I see it, you're fighting against the system, and you should really have a good reason for that. Passing objects like you're suggesting can also expose you to memory leaks, depending on the object, so be very careful.

Last but not least, and without knowing the details, you should consider why an activity is creating such an object, but another one is using it.

Alessio
  • 3,063
  • 1
  • 15
  • 17