3

So, I'm trying to make something like an rpg for the android to practice programming. I have a hero object which I'm trying to pass using parcelable as recommended by others, but I'm not sure how to pass it back.

In one activity, I'll have

myIntent.putExtra("heroData", hero);

And then, in myIntent, the activity started in the original activity, I'll have

hero = (Protag) getIntent().getParcelableExtra("heroData");

note: Protag is the class of the hero object

So, the first activity does successfully pass the object to the second activity, but such that the second activity doesn't affect the object in the first activity. Like, if something happens to the object in the first activity, it'll preserve to the second activity, but if something happens to the object in the second activity, the object in the first activity is still the same.

How would I make an object that can be changed by any activity such that the changes are preserved through other activities?

aattss
  • 49
  • 4
  • 1
    You may see this [Question](http://stackoverflow.com/questions/4878159/whats-the-best-way-to-share-data-between-activities) for more details... – Akram Qalalwa Dec 30 '15 at 17:03
  • try this link - http://stackoverflow.com/questions/34316838/how-to-put-and-get-intent-of-parcelable-array-list/34373195#34373195 – Swaminathan V Dec 30 '15 at 17:05
  • 1
    It depends on what it is you are doing with your `Activity` classes, but you may look into using `Fragments` instead. You can then access/modify your `Protag` from the `Activity` both fragments are attached to. – PPartisan Dec 30 '15 at 17:16

4 Answers4

2

you are now dealing with concurrency. Since you have 2 'activities' possibly acting upon a single 'data'. However, Parcelable is a serialization technique, which means that you will lose reference once you pass a parcelable object(via parcelable). which means that you can't use a parcelable object as a central point of synchronization (both updating it with data).

If you will ONLY EVER plan on having a single object of your class, then you can make the object have static values. Otherwise this is the wrong mechanism to do this.


An AIDL one-way ascync service that notifies each thread of changes to a 'registered' object's values, is viable. (AIDL one-way is actually not hard to write, just takes some practice) Here is a project I wrote that makes use of it, to show both sync and async service usage. (My PhD Adviser's REPO for the MOOC he teaches)


Update to explain why I say this is 'concurrency'.

First of all I take a 'wide breadth' approach to what is 'concurrent' vs what you might be thinking. Your working definition of 'concurrent' is a valid one. However, it is somewhat limited in scope compared to what I'm thinking about. (usually doesn't matter, but the nuance of Android's lifecycle actually makes it important)

Android Activities have 6 life-cycle states they could possibly be in.

  • Created
  • Started (Visible)
  • Resumed (Visible)
  • Paused (partially visible)
  • Stopped (hidden)
  • Destroyed

Now here is where the issue of concurrency comes up.... When you have 2 or more Activities that are not in the 'Destroyed' state.

Plus there are a lot of things that add unpredictability to your logic that you have to think out very carefully...

Android's non-deterministic behavior.. User could press power/home/back or some other button, a phone call comes in/AMBER Alert takes priority over the phone, and/or the Garbage Collector "magic divine/unholy ritualistically" decides who lives or dies (exaggerating, but you get the point).

But lets assume that A doesn't get killed (which is actually the 'problem' scenario here).

So A makes an X object (hero or whatever) and passes by value (parcelable+intent) to B the value of X. At this time, the value(and reference) of X is in A. but the value of X is in B. Therefore, we are already in concurrency. Because the life-cycles of A and B overlap. Not just the "visible" portions of the life-cycles. So this means... where do you put the logic on "when to pass back the value of X"? Do you pass it back on onPause()? (but how? an intent wouldn't work if the User presses the back button)

Short answer: There isn't a 'great' way to do this. (at least with only Activities and Intents/Parcelables.)

You need some concurrency mechanism in place that allows the changes to X in A to propagate to change the values of X in B. (And this needs to be done reliably, correctly, and efficiently.)

The base goals of concurrent programming include correctness, performance and robustness. (from WIKI:Concurrency(CS) )

Ideally you wouldn't pass the data by value, but instead by reference, and when one class updated X (be it A or B) there only ever existed one value of X. That way when A or B was re-started it would have a 'valid' value of X. But you can't do this 'nicely' through parcelable data.

Therefore I would use a service to be the authoritative keeper of the 'value of X', any time A or B wants to update X, then they have to go through synchronized methods to get/set X. (I've never really ran into this scenario where two activities want to have the same 'live data' like this, so perhaps there is a better solution, possibly making use of handlers(but I can't think of it offhand)) With a service you will have slight time delays from when A is telling Service that X is updated to when B can get that info. but its the best I can think of off the top of my head right now.

Also the SQLite DB is designed to promote data storage like this, and has built in support for monitors to block access to the DB when another thread is accessing it. (there is nuance here I won't get into, such as 'setLockingEnabled(boolean)')

mawalker
  • 2,072
  • 2
  • 22
  • 34
  • Hi @mawalker - can you just elaborate on the 'concurrency' aspect, I'm interested to know as I thought all activities etc, unless specified otherwise run in the Main UI thread. So this wouldn't be an issue unless multiple threads were trying to access/reference/change the same object reference, then concurrency would be necessary. Incidenitly I'm currently doing the MOOC you referenced by Mr D Schmidt. – Mark Dec 30 '15 at 18:52
  • 1
    I added some (rambling) ...answer... Hope that helps – mawalker Dec 30 '15 at 19:44
  • Thank you for the in depth answer, really appreciated and now understand the limitations of parcelable interface, and the 'Concurrency' implications. I've had limited usage of this interface so far, and now understand that it doesn't pass any references, simply values. Whenever I've wanted to store/update persistent data I've always used either Shared Prefs (small amount of primitives and strings), or used a SQL database, as like you stated has inbuilt concurrency/thread safety mechanisms. – Mark Dec 30 '15 at 22:06
0

Make it static on the top class

All the activity can call it. Like

MyObject hero = topActivity.Hero

but but but

I'm not sure at all it is the correct way or the best way to do it. So maybe wait for other response

Sincerely

kevingiroux
  • 155
  • 1
  • 14
  • Depending on static objects across activities is considered bad practice, there are several other persistent data models that should be explored first. – em_ Dec 30 '15 at 17:11
  • I already try reading and writing in a file / preferences. In my case, my object cann't be store in a database (too complexe). And this solution was the only one i found for not having a freezing app. If you have another one , i will take it ^^ – kevingiroux Dec 31 '15 at 15:49
0

A possibility is:

From Activity1 launch the Activity2 using the method startActivityForResult(). In the Activity2 you will do all the modification needed to the object "hero" and then you can put it in an intent and send it back using setResult (int resultCode, Intent data). This way, when Activity1 is resumed, using onActivityResult(int requestCode, int resultCode, Intent data), you will be able to catch the object "hero" modified.

Here you can find more information on this mechanism. http://developer.android.com/training/basics/intents/result.html

0

You could write object data in shared prefs. That way there is no need for a service. You need to save the progress of the game anyway. I think changes like that should be saved in memory once the app closes the progress is back to where it was.

Edit:

Or you could save in Internal Storage. Save the Protag object as a file. It all depends how often the object changes.

Tip: You should not be writing every time you make a change to the object. Save the data in some data structure and then when everything is finalized such as the level ends or something then you write in storage or shared prefs. That way you keep it efficient otherwise all that writing in storage will slow the app down.

Arnold Balliu
  • 1,099
  • 10
  • 21