What's the best way to share data between activities?
Asked Answered
S

14

263

I have one activity which is the main activity used throughout the app and it has a number of variables. I have two other activities which I would like to be able to use the data from the first activity. Now I know I can do something like this:

GlobalState gs = (GlobalState) getApplication();
String s = gs.getTestMe();

However I want to share a lot of variables and some might be rather large so I don't want to be creating copies of them like above.

Is there a way to directly get and change the variables without using get and set methods? I remember reading an article on the Google dev site saying this is not recommended for performance on Android.

Schoolbag answered 2/2, 2011 at 18:11 Comment(6)
As of Android 2.3 (Gingerbread), optimization of get/set is performed automatically by Dalvik; this is only relevant if you are targeting older versions of Android.Millenarianism
Note that the example does not copy the string data. Rather it creates a reference to the same string object.Thoer
It's hard to believe, why is there no possibility to start an activity from another activity and pass any complex object from the first to the second? Without serialization, saving the object and all that effort. Is this a security hole or what other reason is against simply passing the object reference if both activities are in the same app? (I understand it's different if they are in different apps)Braasch
Please see this #56522469Drag
LiveData is the best, most recent solution. Check my answer below.Cardwell
Dependency injectionUriisa
G
512

Here a compilation of most common ways to achieve this:

  • Send data inside intent
  • Static fields
  • HashMap of WeakReferences
  • Persist objects (sqlite, share preferences, file, etc.)

TL;DR: there are two ways of sharing data: passing data in the intent's extras or saving it somewhere else. If data is primitives, Strings or user-defined objects: send it as part of the intent extras (user-defined objects must implement Parcelable). If passing complex objects save an instance in a singleton somewhere else and access them from the launched activity.

Some examples of how and why to implement each approach:

Send data inside intents

Intent intent = new Intent(FirstActivity.this, SecondActivity.class);
intent.putExtra("some_key", value);
intent.putExtra("some_other_key", "a value");
startActivity(intent);

On the second activity:

Bundle bundle = getIntent().getExtras();
int value = bundle.getInt("some_key");
String value2 = bundle.getString("some_other_key");

Use this method if you are passing primitive data or Strings. You can also pass objects that implements Serializable.

Although tempting, you should think twice before using Serializable: it's error prone and horribly slow. So in general: stay away from Serializable if possible. If you want to pass complex user-defined objects, take a look at the Parcelable interface. It's harder to implement, but it has considerable speed gains compared to Serializable.

Share data without persisting to disk

It is possible to share data between activities by saving it in memory given that, in most cases, both activities run in the same process.

Note: sometimes, when the user leaves your activity (without quitting it), Android may decide to kill your application. In such scenario, I have experienced cases in which android attempts to launch the last activity using the intent provided before the app was killed. In this cases, data stored in a singleton (either yours or Application) will be gone and bad things could happen. To avoid such cases, you either persist objects to disk or check data before using it to make sure its valid.

Use a singleton class

Have a class to hold the data:

public class DataHolder {
  private String data;
  public String getData() {return data;}
  public void setData(String data) {this.data = data;}

  private static final DataHolder holder = new DataHolder();
  public static DataHolder getInstance() {return holder;}
}

From the launched activity:

String data = DataHolder.getInstance().getData();

Use application singleton

The application singleton is an instance of android.app.Application which is created when the app is launched. You can provide a custom one by extending Application:

import android.app.Application;
public class MyApplication extends Application {
  private String data;
  public String getData() {return data;}
  public void setData(String data) {this.data = data;}
}

Before launching the activity:

MyApplication app = (MyApplication) getApplicationContext();
app.setData(someData);

Then, from the launched activity:

MyApplication app = (MyApplication) getApplicationContext();
String data = app.getData();

Static fields

The idea is basically the same as the singleton, but in this case you provide static access to the data:

public class DataHolder {
  private static String data;
  public static String getData() {return data;}
  public static void setData(String data) {DataHolder.data = data;}
}

From the launched activity:

String data = DataHolder.getData();

HashMap of WeakReferences

Same idea, but allowing the garbage collector to removed unreferenced objects (e.g. when the user quits the activity):

public class DataHolder {
  Map<String, WeakReference<Object>> data = new HashMap<String, WeakReference<Object>>();

  void save(String id, Object object) {
    data.put(id, new WeakReference<Object>(object));
  }

  Object retrieve(String id) {
    WeakReference<Object> objectWeakReference = data.get(id);
    return objectWeakReference.get();
  }
}

Before launching the activity:

DataHolder.getInstance().save(someId, someObject);

From the launched activity:

DataHolder.getInstance().retrieve(someId);

You may or may not have to pass the object id using the intent’s extras. It all depends on your specific problem.

Persist objects to disk

The idea is to save the data in disk before launching the other activity.

Advantages: you can launch the activity from other places and, if the data is already persisted, it should work just fine.

Disadvantages: it’s cumbersome and takes more time to implement. Requires more code and thus more chance of introducing bugs. It will also be much slower.

Some of the ways to persist objects include:

Gettogether answered 2/2, 2011 at 18:21 Comment(14)
I would argue that that is not the "normal" way for larger/more complex data. It's far easier to use a static singleton or the Application object, and it works great. Now that said the OP did use a String in the example, for that, Intent is perfect and preferred.Yester
Serializable has found to have serious performance issues on the Android process model. Thats why they introduced Parcelable. Read Parcelable instead of Serializable in the above answer.Platinize
This is passing data from the main activity to a secondary activity, what about vice versa?Alessi
That's done via the setResult method. Also, in that case, the secondary activity must be invoked using startActivityForResult method.Gettogether
Great summary! Regarding the problem of singletons being destroyed, there is a simple solution for apps with lots of activities and objects: Use a subclass of Activity throughout, and in its onCreate() check any static field of the singleton that you fill when starting the app. If that field is empty, go back to the start activity using FLAG_ACTIVITY_CLEAR_TASK or a BroadcastReceiver to kill other activities.Thorite
@Gettogether I have a similar problem https://mcmap.net/q/111021/-what-is-the-correct-way-to-share-data-between-different-activities-or-fragments/892055, which of the above solutions would you suggest?Musick
^1 for WeakReferencesNomination
service and activity run as different processes and they do not share memory spaces, so most of the above suggestions won't work.Nonaligned
I wouldn't recommend saving data in application class. Read more here: developerphil.com/dont-store-data-in-the-application-objectPasley
@Gettogether with your note you perfectly explained why whole answer is wrong and therefore useless ;)Earthenware
Yes sir, indeedGettogether
Thanks for your answer. It solved my huge problem. I was searching for this since a week. Thanks a lot. But small mistake in static method. Its set data method has no return statement. Please correct that.Levana
WeakReference is not ideal as now it got clean almost instantly after it loose reference. Also in you example there's no way to clear the keys.Rico
For those who wonder, as I did, what magic allows the Application singleton to be created with type a subclass of Application, here's what the manifest should contain: <application android:name=".MyApplication"Chemulpo
A
24

What you can use:

  1. passing data between activities (like Cristian said)
  2. using a class with a lot of static variables (so you can call them without an instance of the class and without using getter/setter)
  3. Using a database
  4. Shared Preferences

What you choose depends on your needs. Probably you will use more than one way when you have "a lot of"

Aufmann answered 2/2, 2011 at 18:26 Comment(3)
Please note that statics are cleared on process deathDiversification
@Diversification of course and also when the device was turned off.Aufmann
But if the device is turned off, the app restarts from the MAIN action. After process death, you restart on whatever activity was open last, which could be a detail page somewhere deep in the app.Diversification
M
16

Do what google commands you to do! here: http://developer.android.com/resources/faq/framework.html#3

  • Primitive Data Types
  • Non-Persistent Objects
  • Singleton class - my favorite :D
  • A public static field/method
  • A HashMap of WeakReferences to Objects
  • Persistent Objects (Application Preferences, Files, contentProviders, SQLite DB)
Meghannmegiddo answered 30/10, 2011 at 15:48 Comment(3)
Google Link for Persistent Objects : developer.android.com/guide/topics/data/data-storage.htmlInsulin
Only antipatterns, Singleton class is the first design pattern, a class with static field/method behaves a lots like singletons and making database for persisting busniss objects sometimes isn't a good thing, of course isn't your fault and you are listing possible ways to acheive it, but i wonder why Google has complicated such a very stupid thing, performance problems or what??!!!! or am i not understanding the Android way??!!!!Apterous
link is broken :(Pasley
Y
14

"However I want to share alot of variables and some might be rather large so I don't want to be creating copies of them like above."

That doesn't make a copy (especially with String, but even objects are pass by value of the reference, not the object itself, and getter's like that are fine to use -- arguably better to use than other means because they are common and well understood). The older "performance myths," such as not using getters and setters, still have some value, but have also been updated in the docs.

But if you don't want to do that, you could also just make the variables public or protected in GlobalState and access them directly. And, you can make a static singleton as the Application object JavaDoc indicates:

There is normally no need to subclass Application. In most situation, 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), the function to retrieve it can be given a Context which internally uses Context.getApplicationContext() when first constructing the singleton.

Using Intent data, as other answers here note is another way to pass data, but it's usually used for smaller data and simple types. You can pass larger/more complex data, but it's more involved than just using a static singleon. The Application object is still my personal favorite for sharing larger/more complex non persistent data between Android application components though (because it has a well defined lifecycle in an Android app).

Also, as others have noted, if the data gets very complex and needs to be persistent then you can use SQLite or the filesystem too.

Yester answered 2/2, 2011 at 18:26 Comment(4)
Actually, I just stumbled on this in the docs recently: developer.android.com/guide/appendix/faq/framework.html#3. For "non-persistent complex objects" it recommends using the Application class to create and tear down a static singleton! That way you get the well-defined lifecycle Application provides, and the ease of use of a static singleton.Yester
that section of the faq seems to be removed now (I only see "non-persistent objects" and no mention of Application class). Anyway you can elaborate?Cabbage
It's currently at developer.android.com/guide/faq/framework.html#3 "How do I pass data between Activities/Services within a single application?", and no mention of the Application class.Chaetopod
I to like using an Application object, following the precedent you set in "Android in Action". But a lot of prospective employers don't like it when they see this in code challenges. They could be wrong, but they throw around their weight. BTW: that 'framework.html#3 link no longer works.Serous
C
9

There is a new and better way to share data between activities, and it is LiveData. Notice in particular this quote from the Android developer's page:

The fact that LiveData objects are lifecycle-aware means that you can share them between multiple activities, fragments, and services. To keep the example simple, you can implement the LiveData class as a singleton

The implication of this is huge - any model data can be shared in a common singleton class inside a LiveData wrapper. It can be injected from the activities into their respective ViewModel for the sake of testability. And you no longer need to worry about weak references to prevent memory leaks.

Cardwell answered 4/11, 2018 at 10:26 Comment(5)
This answer should be higher up. This is a much more maintainable and sensible way of sharing data, and conforms well with other state-keeping solutions in both front-end and back-end frameworks. The observer pattern forces consistency in data access both in terms of the data itself and how to interact with it.Axillary
Using LiveData alone does not solve the problem of sharing LiveData objects across acivities. For that, Android's developer page suggests using a singleton pattern for the sake of simplicity.Pendulum
@Pendulum yes, this is what I wrote. I didn't understand what's your commenting about.Cardwell
@AmirUval, you wrote "There is a new and better way to share data between activities, and it is LiveData". My point is, that LiveData does not address the OPs question concerning how to share data across activities. One can use the singleton pattern with any data type and there is per se no benefit in using LiveData over any other data type. If you want to share a String type, use a String type singleton. You would not want to make a LiveData<String> out of the String just for the sake of sharing the String across activitiesPendulum
@Pendulum I expect the smart reader of my answer to adapt it to the need. I wrote wrap a singleton model class with LiveData, and 2.5 years after I wrote the answer - I still recommend this approach to share data across activities, because it solves the fundamental problem which is memory leaks. I wouldn't recommend using it for a single String because a simple static variable would be enough.Cardwell
S
7

You could extend the Application class and tag on any objects you want there, they are then available anywhere in your application

Sternpost answered 3/2, 2011 at 20:1 Comment(1)
I wouldn't recommend saving data in application class. Read more here: developerphil.com/dont-store-data-in-the-application-objectPasley
S
3

There are various way to share data between activities

1: Passing data between activities using Intent

Intent intent=new Intent(this, desirableActivity.class);
intent.putExtra("KEY", "Value");
startActivity(intent)

2: Using static keyword , define variable as public static and use any where in project

      public static int sInitialValue=0;

use anywhere in project using classname.variableName;

3: Using Database

but its bit lengthy process, you have to use query for inserting data and iterate data using cursor when need. But there are no chance of losing data without cleaning cache.

4: Using shared Preferences

much easier than database. but there is some limitation you can not save ArrayList ,List and custome objects.

5: Create getter setter in Aplication class and access any where in project.

      private String data;
      public String getData() {
          return data;
      }

      public void setData(String data) {
          this.data = data;
      }

here set and get from activities

         ((YourApplicationClass)getApplicationContext()).setData("abc"); 

         String data=((YourApplicationClass)getApplicationContext()).getData();  
Swett answered 18/7, 2017 at 4:59 Comment(0)
O
2

Using the hashmap of weak reference approach, described above, and in http://developer.android.com/guide/faq/framework.html seems problematic to me. How are entire entries reclaimed, not just the map value? What scope do you allocate it in? As the framework is in control of the Activity lifecycle, having one of the participating Activities own it risks runtime errors when the owner is destroyed in advance of its clients. If the Application owns it, some Activity must explicitly remove the entry to avoid the hashmap from holding on to entries with a valid key and a potentially garbaged collected weak reference. Furthermore, what should a client do when the value returned for a key is null?

It seems to me that a WeakHashMap owned by the Application or within a singleton is a better choice. An value in the map is accessed via a key object, and when no strong references to the key exist (i.e. all Activities are done with the key and what it maps to), GC can reclaim the map entry.

Oversold answered 28/4, 2014 at 20:39 Comment(0)
T
1

Well I have a few ideas, but I don't know if they are what your looking for.

You could use a service that holds all of the data and then just bind your activities to the service for data retrival.

Or package your data into a serializable or parcelable and attach them to a bundle and pass the bundle between activities.

This one may not be at all what your looking for, but you could also try using a SharedPreferences or a preference in general.

Either way let me know what you decide.

Traynor answered 2/2, 2011 at 18:21 Comment(0)
B
1

Assuming you are calling activity two from activity one using an Intent.
You can pass the data with the intent.putExtra(),

Take this for your reference. Sending arrays with Intent.putExtra

Hope that's what you want.

Belew answered 2/2, 2011 at 18:22 Comment(0)
B
1

If your intention is to call other Activities from the current Activity, you should use Intents. Your focus could be less on persisting data than on sharing it on an as-needed basis.

However, if you really need to persist these values then you could persist them in some kind of structured text file or database on local storage. A properties file, XML file, or JSON file could store your data and be easily parsed during activity creation. Don't forget also that you have SQLite on all Android devices, so you could store them in a database table. You could also use a Map to store key-value pairs and serialize the map to local storage, but this might be too cumbersome to be useful for simple data structures.

Beast answered 2/2, 2011 at 18:23 Comment(0)
P
1

All of the aforementioned answers are great... I'm just adding one no one had mentioned yet about persisting data through activities and that is to use the built in android SQLite database to persist relevant data... In fact you can place your databaseHelper in the application state and call it as needed throughout the activates.. Or just make a helper class and make the DB calls when needed... Just adding another layer for you to consider... But all of the other answers would suffice as well.. Really just preference

Pervasive answered 1/8, 2013 at 1:13 Comment(0)
V
1

Sharing data between activites example passing an email after login

"email" is the name that can be used to reference the value on the activity that's being requested

1 Code on the login page

Intent openLoginActivity = new Intent(getBaseContext(), Home.class);
    openLoginActivity.putExtra("email", getEmail);

2 code on the home page

Bundle extras = getIntent().getExtras();
    accountEmail = extras.getString("email");
Viglione answered 28/9, 2014 at 12:54 Comment(0)
P
1

And if you wanna work with data object, this two implements very important:

Serializable vs Parcelable

  • Serializable is a marker interface, which implies the user cannot marshal the data according to their requirements. So when object implements Serializable Java will automatically serialize it.
  • Parcelable is android own serialization protocol. In Parcelable, developers write custom code for marshaling and unmarshaling. So it creates less garbage objects in comparison to Serialization
  • The performance of Parcelable is very high when comparing to Serializable because of its custom implementation It is highly recommended to use Parcelable implantation when serializing objects in android.

public class User implements Parcelable

check more in here

Procure answered 18/7, 2017 at 4:29 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.