2

I'm a computer hobbyist who is working on a very small trivia game for the Android platform.

In this game, I move the player between multiple activity/view pages (entry, question page, answer page, ultimate score page). I've created a question object that contains all data related to a single trivia question (question, four answers, pointer to correct answer, related comments that the computer makes when responding to the player's guess), and I've successfully populated an ArrayList of Question objects with data that I DOM parsed from an XML file.

What is an acceptable way of passing this data back and forth between activities as the game progresses? How can I keep these data objects alive as the user moves through the game?

I understand that global variables are highly discouraged. I have also learned that the Singleton design pattern poses many of the problems said to be associated with global variables. I'm stumped when it comes to finding alternatives to those approaches.

I understand the basics of the MVC approach. My activity *.java files are the controller files, and they're linked to the layouts (views) I've created with XML. I have two "model" objects that need to be maintained and modified as the game progresses: (1) the question-bank ArrayList mentioned above and (2) some sort of "PlayerProgress" object that contains all data related to the player's progress in the game.

These data objects are first instantiated at the beginning of the game, but I don't know how to keep them alive as the user moves between activities. I know that I can pass information between activities as EXTRAS, but EXTRA don't seem to be intended for this purpose. Even if EXTRAS worked for the player progress properties, I don't think I can use them to pass an ArrayList of 25-50 question objects between activities.

I have looked into serialization and parcelable, but it seems weird (and possibly inefficient) to basically decompose and then recompose my data model objects every time the user moves back and forth between different activities/views. If one of these is an acceptable/common way to accomplish this, I can happily plunge forward, but I wanted to check with others first.

I keep butting my head against this in different programming languages, and suspect that there is some bigger part of the picture that I'm failing to understand. I've read through the descriptions of objects and application life cycles in many different resources, but I still haven't managed to figure out the solution to this basic question.

I'm asking this question ("What is an acceptable way of passing data objects back and forth between activities as the game progresses") in the context of my silly trivia game, but I'm really concerned with getting a handle on the bigger picture. If folks don't have the time to spell out something so seemingly basic, perhaps you can point me to descriptions in other books that you found useful? (I've got a few slots open in my Safari bookshelf, and can track down copies of almost any technical publication.)

Thanks.

Aaron Delwiche
  • 79
  • 1
  • 10
  • " I don't think I can use them to pass an ArrayList of 25-50 question objects between activities." - you definitely can, actually – invertigo Jul 18 '13 at 19:45
  • invertigo, I was under the impression that EXTRAS are key/value pairs with values usually String or int datatypes. If a single EXTRA value can contain the entire ArrayList of 25-50 question objects, that seems ideal. I'm researching further now to make sure I haven't totally misunderstood what we can do with extras. – Aaron Delwiche Jul 19 '13 at 20:41
  • you'll have to evaluate the performance impact for your own use-case, but I use serializable extra to store a List<> of serializable objects all the time – invertigo Jul 19 '13 at 22:17
  • I will do so. I have absolutely no concrete sense of how costly it is to serialize objects. At an abstract level, it seemed potentially costly, but -- if the CPU is capable of 13,800 MIPS, I guess serializing a tiny trivia question bank would not be a big deal. – Aaron Delwiche Jul 20 '13 at 20:20

4 Answers4

2

I haven't got enough votes to answer directly in 323go's post about static variables... but that implementation is exactly Singleton. I wanted to point this out because you stated in your question that you also learned that the Singleton design pattern poses many of the problems said to be associated with global variables.

I admit extras are quite weird first time if you're used to call a function or a program with its parameters inline, but it seems it's the usual way in Android. I don't see what's the problem using extras, since it's almost transparent for you if your model objects are not really complex. I mean you just need to implement "Serializable" interface and it's done. There are some data types that are not working "by itself" with Serializable (as lists) and you'll need to implement Parcelable, but you can declare arrays insted. It seems Parcelable is "far more efficient", so if you wanna better performing you'll need to implement Parcelable anyway as someone said here: Android: Difference between Parcelable and Serializable?

I don't think Shared Preferences are intended to be used as a "passing arguments tool" since it wouldn't be so efficient as it has to write and read to physical memory, what use to be "hard job" in any computer system; while exras would be sent through the memory stack (Disclaimer: I didn't tested, but it's what logic tells me). I use dannyroa's way (storing json objects) for time-persisting issues as user preferences, internet-retrieved hardly-updated-data, scorings, savegames....

And, finally... maybe you can restructure your code. Are you opening a new activity for each question? Maybe you can use just one Activity and use fragments. Then, you can have your global variable in the activity and any fragment inside can access there with getActivity().

((MyActivity)getActivity()).myGlobalVariable();
Community
  • 1
  • 1
rolgalan
  • 1,631
  • 17
  • 34
  • Thanks, Ender. I figured out that the global static object is exactly Singleton.I'm only using PREFERENCES to store one or two bits of truly persistent information about user's overall standing. I'm digging back into parcelable, serializable via your links. I obviously need to get a better handle on EXTRAS. // I now have just one question Activity and am using a view flipper to hop back and forth between question and result. This solved much of the problem that prompted original post. The fragments suggestion seems like a similar solution. Thanks! – Aaron Delwiche Jul 19 '13 at 20:45
  • Hi Ender, Just wanted to follow up and confirm the wisdom of your recommendation that I should use fragments. I am recoding a second version of the game with fragments, and it completely solves my problem for exactly the reasons that you mentioned. – Aaron Delwiche Jul 23 '13 at 20:40
1

You can put an array of parcelable objects in Intent Extras, so it's possible to send an array of parcelable question objects between activities.

Personally I'd use a sqlite database for storing the questions and pull them from the DB through a content provider.

May be overkill for your currently app but if you ever expand the question set you could alter the SQL to pull out the relevant subset of questions for each activity.

0

What I have tried is saving them in SharedPreferences.

To save objects, I use Gson library to convert it to a JSON string & convert the JSON string back into the object.

However, this means it would only work for Serializable objects & there's an overhead with the reading and writing from SharedPreferences.

Ideal solution is a combination of global static & SharedPreferences. In the event that the static variable is null, get it from SharedPreferences. Make sure to clear the static variable when the value in SharedPreferences is updated.

static String userInfo = null;
public static String getUserInfo() {
    if (userInfo != null) {
        return userInfo;
    }
    return _getStringFromPref("userInfo");
}

public static String setUserInfo(String val) {
    _putStringToPref("userInfo", val);
    userInfo = val; //or you can just set userInfo to null;
}

You can also use a local database (sqlite) instead of SharedPreferences.

dannyroa
  • 5,501
  • 6
  • 41
  • 59
  • Thanks, Dannyroa. I'm going to give the "static global" approach a try. Will circle back with an update in the comments section. – Aaron Delwiche Jul 15 '13 at 18:35
  • Aaron: I have tried static global but the problem is that when your app moves into the background, you cannot guarantee that the value will be there. If Android needs to free up memory, they clean up memory allocated to apps in the background. – dannyroa Jul 15 '13 at 18:36
  • Hmm. I understand what you're saying, dannyroa. What if I were to combine the two solutions? I wonder if I could override the method associated with the app moving to the background. At those moments, I would use the GSON library to convert it to a JSON string. Otherwise, when just moving back and forth between activities, I would use the static global. // But this would only work if I could be certain that I would always capture the event in time. – Aaron Delwiche Jul 15 '13 at 19:50
  • I personally use a combination of global static & SharedPreferences. See my updated answer. – dannyroa Jul 15 '13 at 20:14
0

In my original post, I promised to circle back after investigating all options.

Just wanted to report that the easiest solution, as Ender suggests, is the use of multiple fragments and a single activity page. This makes it possible to completely avoid global static objects since all fragments can access the MainActivity class.

Aaron Delwiche
  • 79
  • 1
  • 10