2

I just finished a couple of activities in my game and now I was going to start to wire them both up to use real game data, instead of the test data I was using just to make sure each piece worked. Since multiple Activities will need access to this game data, I started researching the best way to pass this data to my Activities.

I know about using putExtra with intents, but my GameData class has quite a bit of data and not just simple key value pairs. Besides quite a few basic data types, it also has large arrays. I didn't really want to try and pass all that, unless I can pass the entire object, instead of just key/data pairs.

I read the following post and thought it would be the way to go, but so far, I haven't got it to work.

How to declare global variables in Android?

I created a simple test app to try this method out, but it keeps crashing and my code seems to look the same as in the post above - except I changed the names. Here is the error I am getting. Can someone help me understand what I am doing wrong?

12-23 00:50:49.762: ERROR/AndroidRuntime(608): Caused by: java.lang.ClassCastException: android.app.Application

It crashes on the following statement:

GameData newGameData = ((GameData)getApplicationContext());  

Here is my code:

package mrk.examples.MainActivity;

import android.app.Application;

public class GameData extends Application {
    private int intTest;

    GameData () {
        intTest = 0;
    }

    public int getIntTest(){
        return intTest;
    }

    public void setIntTest(int value){
        intTest = value;
    }
}

// My main activity

package mrk.examples.MainActivity;

import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.util.Log;

public class MainActivity extends Activity {

    int intLocal;

    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        GameData newGameData = ((GameData) getApplicationContext());
        newGameData.setIntTest(0);
        intLocal = newGameData.getIntTest();
        Log.d("MainActivity", "IntLocal = " + intLocal);
        newGameData.setIntTest(1);
        Log.d("MainActivity", "IntLocal = " + intLocal
                + " newGameData IntTest: " + newGameData.getIntTest());
        Intent intentNew = new Intent(this, PassData2Activity.class);
        startActivity(intentNew);
    }
}

// My test Activity to see if it can access the data and its previous state from the last activity

package mrk.examples.MainActivity;

import android.app.Activity;
import android.os.Bundle;
import android.util.Log;

public class PassData2Activity extends Activity {

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        GameData gamedataPass = ((GameData)getApplicationContext());
        Log.d("PassData2Activity", "gamedatapass IntTest =  " +
                                         gamedataPass.getIntTest());           
    }
}

Below is the relevant portion of my manifest:

<application android:icon="@drawable/icon"
             android:label="@string/app_name">    
    <activity android:name=".MainActivity"
              android:label="@string/app_name">
        <intent-filter>
            <action android:name="android.intent.action.MAIN" />
            <category android:name="android.intent.category.LAUNCHER" />
        </intent-filter>            
    </activity>

    <activity android:name=".PassData2Activity"></activity>

</application> 

<application android:name=".GameData"
         android:icon="@drawable/icon"
         android:label="@string/app_name">        
</application>

Please help me understand why this code is crashing?

Also, if you think this is just the wrong approach to let multiple activities have access to the same data, please give your suggestion. Please keep in mind that I am talking about quite a few variables and some large arrays.

Community
  • 1
  • 1
Alex
  • 319
  • 6
  • 14

3 Answers3

7

I'm not sure, but I think you want to combine those tags in the manifest into a single tag, like this. (You may also need to fully spell out the package name of your app, instead of using the initial . as a shortcut.)

<application android:icon="@drawable/icon"
             android:name=".GameData"
             android:label="@string/app_name">    
    <activity android:name=".StaticGameData"
              android:label="@string/app_name">
        <intent-filter>
            <action android:name="android.intent.action.MAIN" />
            <category android:name="android.intent.category.LAUNCHER" />
        </intent-filter>            
    </activity>

    <activity android:name=".PassData2Activity"></activity>
</application> 

(By the way, I'd avoid using the names GameData for the application, and StaticGameData for the activity; these make me think that StaticGameData would be a subclass of GameData.)

Dan Breslau
  • 11,472
  • 2
  • 35
  • 44
  • Don't worry, I don't use those names in my real app. I just slapped some names together in this test app to try and test what I read in another post. I will edit my post to change the name StaticGameData to just Main to hopefully make it more clear. I tried making these manifest changes you suggested and it still crashes; however, I do agree your suggestion makes a cleaner manifest, so I will use it and keep looking for the source of the crash. – Alex Dec 23 '10 at 19:58
  • @Mike: Try capturing the value returned from getApplicationContext(), like so: `Context appContext = getApplicationContext(); GameData newGameData = (GameData) appContext;` Then set a breakpoint before the second of these lines. You should be able to see exactly what kind of object is being returned as the Application Context. (It's probably a plain `Application`, but it might be helpful to verify this.) – Dan Breslau Dec 23 '10 at 20:04
  • @Mike: Also, you **might** need to uninstall and re-install the app in order for manifest changes to take effect. Again, I'm not sure, but I think that's been my experience. – Dan Breslau Dec 23 '10 at 20:06
  • 1
    I found the problem. After you manifest changes, I didn't look at the error again - I just assumed it was the same error. I was just about to debug with your suggested changes to find out what type of object was being returned, when I decided to check the log again. Guess what, with your manifest changes, it now gave a different error - one that I understood. It said: "access to constructor not allowed". Now that I think about it, the original post didn't have one either, but in my version I added it in. I didn't realize I couldn't use one in this situation. I removed it and it ran fine. – Alex Dec 23 '10 at 20:44
  • Giving you the accepted answer, since your manifest changes was what gave me a more readable error that I could fix. Thanks again. – Alex Dec 23 '10 at 20:46
2

Not sure this will work, but try using getApplication() instead of getApplicationContext().

Kevin Coppock
  • 133,643
  • 45
  • 263
  • 274
  • I gave that a shot, but it didn't work. Thanks for the suggestion though. I may have found the issue. I'll test and post back in a second. – Alex Dec 23 '10 at 20:31
0

I haven't read the whole story yet, but: you can pass custom objects to an intent with putExtra if they implement parcelable, I think.

  • I will look into that and see if that would suit my needs better or if I should stay with the approach I am currently testing. Thanks for the input. – Alex Dec 23 '10 at 20:45