4

For quite some time I've had troubles passing variables from one Activity to another, and I've usually had to resolve to some pretty ugly Static-class-hacks to make it work.

Generally something along the lines of a static method that I call with the type of the Activity, along with the variables the Activity requires. These gets stored in a static variable, and retrieved in the constructor of said activity.

Like I said, pretty ugly. And there's no such thing as "myActivity.StartActivity(new Activity);". All of the overloads for StartActivity takes either an Intent, or a typeof(MyOtherActivity).

So my question is, have I completely misunderstood the concept of Activities, or am I simply missing a completely obvious way to pass arguments to them?

@Edit: The reason I want to pass an actual reference to an object, instead of simply a copy of the object, is because I'm trying to pass a View Model from an overlying Activity, down to the new Activity. And of course any changes made to this view model, should be reflected on the parent activity, which will only be possible if the the two activy's viewmodels points to the same instance.

I'm writing the app using Xamarin.Android, but the code is nearly identical between C# and Java, so answers in either those languages is fine.

Falgantil
  • 1,290
  • 12
  • 27
  • 2
    possible duplicate of http://stackoverflow.com/questions/2091465/how-do-i-pass-data-between-activities-in-android – dsharew Oct 19 '15 at 09:54
  • Partially true. The answers on the link you provided answers how to move the basic value types such as ints and strings to a separate Activity, but not how to pass an actual reference object, such as an object of my own custom type. – Falgantil Oct 19 '15 at 09:57
  • googled it for you. http://stackoverflow.com/questions/2736389/how-to-pass-object-from-one-activity-to-another-in-android – dsharew Oct 19 '15 at 10:03
  • Right but all those results suggests making it Serializable. Which means I will loose the reference to the object. Which is exactly what I want to preserve. In other words, I want to give it not an object, but a reference to an object. – Falgantil Oct 19 '15 at 10:04
  • Why do you want so? please update your question stating your reason. – dsharew Oct 19 '15 at 10:06
  • How about using `Fragments`? – Milen Oct 20 '15 at 07:39

2 Answers2

7

The problem is that Android can kill the process hosting your app at any time (if it is in the background). When the user then returns to your app, Android will create a new process to host your app and will recreate the Activity at the top of the stack. In order to do this, Android keeps a "serialized" version of the Intent so that it can recreate the Intent to pass it to the Activity. This is why all "extras" in an Intent need to be Parcelable or Serializable.

This is also why you cannot pass a reference to an object. When Android recreates the process, none of these objects will exist anymore.

Another point to consider is that different activities may run in different processes. Even activities from the same application may be in different processes (if the manifest specifies this). Since object references don't work across process boundaries, this is another reason why you cannot pass a reference to an object in an Intent.

David Wasser
  • 93,459
  • 16
  • 209
  • 274
  • From what you're saying, it sounds like an incredibly unstable environment to make apps for, considering you never know what part of your app is running, hence making it difficult to create a navigation flow that wont break when exiting and entering the app again at a later point. Is this really true? – Falgantil Oct 19 '15 at 10:55
  • Yes, that's really true. It means you need to architect your app with this in mind. You aren't the first Android developer to stumble over this, and you won't be the last either. – David Wasser Oct 19 '15 at 14:49
  • This sound like incredibly difficult scenario to test for. Does Android provide some way to force the OS to kill the process hosting your app and then recreate the process so you can test that your mobile app behaves properly in this wildly unstable scenario? – deltamind106 Dec 27 '22 at 18:31
  • No, but you can do it yourself. You can use adb commands or Android Studio to kill your app's OS process when it is in the background, then just navigate back to it on your device. – David Wasser Dec 27 '22 at 22:43
0

You can also use The Application class to store objects globally and retrieve them:

using Android.Runtime;

namespace SomeName
{
[Application]
public class App : Application
{
public string Name { get; set;}

public App (IntPtr javaReference, JniHandleOwnership transfer) : base(javaReference, transfer)
{
}

public override void OnCreate ()
{
    base.OnCreate ();

    Name = "";
}
}
}

And you can access the data with:

App application = (App)Application.Context;
application.Name = "something";

I choose to do this on the Application calss because this class is called on the App startup so you don't have to initiate it manually.
Keep in mind that variables which are scoped to the Application have their lifetime scoped to the application by extension.
This class will be Garbage Collected if the Android feels it is necessary so you have to modify the code to include this case also.
You can use SharedPreferences or a Database to save your variables in case they get deleted and retrieve them from the App class for faster results.

Don't be overly wasteful in how you use this approach though, as attaching too much information on this class it can lead to a degradation in performance. Only add information that you know will be needed by different parts of the application, and where the cost of retrieving that information exceeds the cost of storing it as an application variable.

Investigate which information you need to hold as application wide state, and what information can simply be retrieved straight from your database. There are cost implications for both and you need to ensure you get the balance right.

And don't forget to release resources as needed on OnStop and OnDestroy
I rarely use intents, i find this way better.

CDrosos
  • 2,418
  • 4
  • 26
  • 49
  • This is what OP was referring to when he was talking about using "static variables". You don't need an `Application` class for this, you can just use static variables. OP is looking for a more "elegant" solution ;-) – David Wasser Oct 19 '15 at 14:51
  • who is OP? :) , with an Application class you can do staff and be sure that will be done on the start of the Application till the end. Why this solution isn't elegant? what kind of solution could be "elegant"? integrated support from Android for global variables? – CDrosos Oct 19 '15 at 14:54
  • On the right track bug just some background info on why this is a little volatile... Your process can be killed at any time by the OS (EG: Activity has been background for a while, high memory pressure from other apps etc), the `Application` class could be torn down and recreated without you even noticing. The `Name` property in this case would get reset; an improved solution would be to persist it to shared preferences through the getter and setter or restore "objects" through a database. – matthewrdev Oct 20 '15 at 00:37
  • 1
    @matthewrdev you were right, i haven't say anything about that possibility, i have edit the answer with more info and i believe now its a much better answer. – CDrosos Oct 21 '15 at 19:14