Let's assume I have a class MainActivity.
This contains a number of objects stored in fields, such as instances of Player, Enemy, Level, etc. Each of these objects needs to be able to refer to every other object.
What is the best way to go about this?
Make these fields static, and refer to them accordingly, i.e.
MainActivity.player.setHealth(0);
Create getter methods for each field, and simply pass each object a reference to MainActivity, so that they can call these getter methods, i.e.
mainActivity.getPlayer().setHealth(0);
Pass each object a reference to every other object, and store these references in fields within each object, so that they can be referred to directly, i.e.
player.setHealth(0);
Not a real answer but just to give you some tips.
Your Player should be like so:
public class Player
{
private static Player _player = null;
int _health;
...
public static Player getInstance()
{
if (_player == null)
_player = new Player(...);
return _player;
}
public void increaseHealth(int amount)
{
_health += amount;
}
}
Then in any part of your application when you need a Player you can do:
Player p = Player.getInstance();
and you will get the same player all the time. You can do a similar thing with your level class as only 1 level will be active at any one time.
However the Enemy class will need a different approach. I would make a List inside the Level class and get at them like so:
Level l = Level.getInstance();
List<Enemy> enemiesOnLevel = l.getEnemies();
// do something with them
Have a look in the Android docs here: http://developer.android.com/guide/faq/framework.html#3. There is also the possibility to serialize your object into primitive datatypes and pass those within your Intent to the new Activity.
A couple more options to share objects between activities are to use parcable, which I think is probably the highest performance method, and shared preferences.
In my app I used to learn (the little I know about android programming), I used gson to serialize the object to json, then stored it in shared preferences in activity A , then recreated it from shared preferences in activity B, and then stored it again.
Related
I need to pass objects to my fragments in order to initialize them.
Currently I am doing this with ((MyActivity)getActivity()).getX(). (direct access to the activity)
However, I would like to pass the required objects as parameter.
I definitely do not want to add parcelable objects to the bundle, since they require an excessive amount of useless boilerplate code. My goal is to reduce complexity, not increasing it.
And I do not want to add serializable objects to the bundle, since they are slow and cause an unnecessary overhead.
What is the best way to pass objects to fragments?
Any ideas to solve the problem in a more convenient way?
I definitely do not want to add parcelable objects to the bundle, since they require an excessive amount of useless boilerplate code. My goal is to reduce complexity, not increasing it.
You write this code in your model classes which is separated from your activities and fragments. There is no complexity in implementing Parcelable. And it is a common way to pass objects to a Fragment.
Any other solutions? Well, you still can do this ((MyActivity)getActivity()).getX() as long as your fragment is attached to your activity. In this case it is even faster than Parcelable because there is no serialization at all.
Other ways would be to write objects to database, pass their ids to a Fragment and then use a query to retrieve objects.
You can also use SharedPreferences, but that's rarely used. For this you will need to convert your object to String.
You can do the Android way: Parcelable.
You can serialize then.
You can do the poor way : static
You can do the retained way: Create a Fragment with setRetainInstance(true) and save your objects references.
I understand you don't want to use parcelable / serializable objects to a Bundle. I also agree with you since I got lazy, and my phone app is getting complicated.
Here's what you can do, and it works reliably.
Make a public method in your Fragment class, sample below.
Have the Activity, preferably no other place, call that public method. Remember Activity is always present, Fragments and Adapters may not due to its lifecycle.
The timing of the call is crucial if you're not using Bundles. I have used it without any problems.
The advantage of this technique is that it is fast, especially compared to Bundles. Many developers do not consider this however.
Note: If you are using simple fundamental Java types, do use Bundles! As suggested by Google.
Sample code:
public class MyFragment extends Fragment {
...
public void setList(final ArrayList<String> arrayList) {
...
}
In the Activity:
MyFragment fragment1 = MyFragment.newInstance(<parameters>);
fragment1.setList( arrayList );
Do you need to change the properties once they have been set on the fragment? If not, you can use setArguments(Bundle). If it is a fairly light object you can even skip implementing Parcelable and just set each property individually. The advantage is that the arguments are preserved upon orientation change. The disadvantage is that you need to call this method before attaching your fragment, hence it is not very useful once the fragment is in use.
It's way too late for my answer, but if someone else is wondering. The recommended way is to use Parcelable or Serializable, but you can always do something like this:
public class ObjectManager {
private static final String TAG = "ObjectManager";
private static ObjectManager instance;
private Object currentObject;
public static ObjectManager getInstance() {
if (instance == null)
instance = new ObjectManager();
return instance;
}
public Object getCurrentObject() {
return currentObject;
}
public void setCurrentObject(Object object) {
this.currentObject = object;
}
}
And then use it: where you needed as long as your app is running
//Use on the object you would like to save
ObjectManager.getInstance().setCurrentObject(object);
//Get the instance from pretty much everywhere
Object = ObjectManager.getInstance().getCurrentObject();
You can use it always, but it will be most likely to be useful, if you pass objects bigger than the Bundle max size.
Actually,my application flow is like this Home->A->B->Info(form data)->D->Final page.From final page if I press on one button it again navigates back to A page and start the flow from onwards.If I comes to info page I should display the earliear data.Right now my approach is passing parcelable object within all acitivities from A->B->Info->D->Final.If suppose want to use Preferences, doesn't supports the parcelable object and don't want to put each string of object individually within preferences becaus I had more than 10 items within object.Is there any better approach without passing bundle between actvities.
BR,
Developer.
you can create Global class and declare Static variables and use them in anyware in the application.
Example:
public class global_variable {
public static String sample ;
}
where you want to use ;
global_variable.sample = "your value";
You could use any number of technologies to parse your data object into a string and reassemble again. Then you could store the string in preferences.
Take a look at gson to convert objects to json http://code.google.com/p/google-gson/
Or you could google xstream to convert to xml
If you create a class representing your 'object' with appropriate setters/getters and let that class implement Parceable and then pass that class between Activites as a Parceable in a Bundle, would that be bad?
If that would be bad (e.g. if the amount of object data is very big or they are somehow not Parceable in principle) and you only have one meaningful instance of a class at a time you can make that class a singleton or keep it within your Application object.
I'm trying to persist data objects throughout my Android app. I want to be able to access an object in one activity, modify it, save it, navigate to a new activity, and access the same object with the updated value.
What I'm essentially talking about is a cache, but my data objects are complex. For example, ObjectA contains ObjectB which contains ObjectC. Does anyone know if a good method, tool, or framework for persisting complex objects in Sql?
Put a static field in a subclassed Application. Also inside your manifest, put:
android:name="MyApp" inside your application tags.
Also to access from other files, simply use:
MyApp myApp = (MyApp)getApplicationContext();
See here How to declare global variables in Android?:
class MyApp extends Application {
private String myState;
public String getState(){
return myState;
}
public void setState(String s){
myState = s;
}
}
class Blah extends Activity {
#Override
public void onCreate(Bundle b){
...
MyApp appState = ((MyApp)getApplicationContext());
String state = appState.getState();
...
}
}
You could use an ORM framework, like OrmLite for mapping objects into sql, but it may be an overkill for you situation.
You could also make these shared object Parcelable and pass them between the Activities thru the Intents.
You could also save these objects into the SharedPreferences, so each Activity can access them whenever they feel the need to it, and the objects are also persisted this way. This may mean more IO access though, so take that into consideration as well. You could use e.g. Gson to serialize the objects more painlessly for this.
These are the solutions I'd consider. But whatever you do, don't put this common object into some kind of "standard" global static variable, like using a custom Application class, static field or any implementation of the Singleton pattern, these are really fragile constructs on Android.
Why don't you use a JSON serialization mechanism ?
In association with a static access to your objects you can easily build a lite-weight database with some basic functionnalities:
loadObjectsFromCache
saveObjectsInCache
getObjects
You can also store your objects in differents files, and use a streaming json parser like this one: http://code.google.com/p/google-gson/
It's the same that this one: http://developer.android.com/reference/android/util/JsonReader.html
but can be used even if your application api level is inferior to 11.
It use less memory than the basic DOM parser:
http://developer.android.com/reference/org/json/JSONObject.html,
but with the same speed.
i have a class that inherits from BroadcastReceiver and is bound to listen for PHONE_STATE events. inside of the onReceive method, i need an object instance that has to be always the exact same (at least between the state ringing and the next occurrence of ide / offhook). that means i need to store the object somewhere. it can not be serialized nor anyhow be stored in a database or in the SharedPreferences.
i thought about 2 different approaches:
using a static variable. downside: no one knows at which point android is going to delete it.
using a service. downside: the service needs to be started at the first call and then bound. this is an async call and i might have to wait for an uncertain time. also it seems kinda wrong to use a service just to store one single object.
any other, better ideas?
Don't know if it will work in your situation, but I'm usually storing an object's string representation in SharedPreferences. You can override the toString() method, which will create the string representation, and implement a parse() method that will parse the saved string and initialize an object based on its saved state. Hope this helps.
third 3) Use a singleton instance of a custom class, then you may get variable from call to call , but not persistant (if application stop).. But useful from a time to another time in the runtime application life. To avoid as much as possible to have wiped data by android framework you may tie your singleton to a service that is "foreground" see http://developer.android.com/reference/android/app/Service.html#startForeground(int,%20android.app.Notification) by this way you get a higher memory detruction protection .. That is the way I currently use singleton in service.. made long time execution (~2 weeks with normal and heavy load activity) without any trouble ...
here an singleton example
class MyData {
private static MyData mMydata= null; // unique reference ( singleton objet container)
private MyObject myobject = null; // inside the unique object container we have the unique working object to be use by the application
// can't make instance from outside... we want to have single instance
// we want that outside use method "getInstance" to be able to use the object
private MyData() {
}
// retrieve and/or create new unique instance
public static MyData getInstance() {
if (mMydata == null) mMyData = new MyData();
return mMyData;
}
// Works with your memory stored object
// get...
public myObject getMyObject() {
return myobject;
}
// set ...
public void setMyObject(MyObject obj) {
myobject = obj;
}
}
in your application to handle your "working" object your may access it like
// get object
MyObject obj = MyData.getInstance().getMyObject();
// or set a object
MyData.getInstance().setMyObject(obj);
When I'm writing a method or using a member variable, I often find I need to share them across an app. But where should they go?
I can subclass Activity, but that falls over as soon as I use a MapView and am forced to use MapActivity, so not all my activities inherit from my subclass. Is there I way around this?
Where inheritance isn't applicable, I am tending to put generic methods and member variables into a subclass of the Application object, but I'm finding it's creating a mess of code as every class needs to either grab access to the application object through via context, or I have to pass it down.
I suspect I would be better off creating MyApplication.getInstance() and keeping everything in a singleton, instead of passing the application object down through the app classes. but before I wanted to see what you guys had to say.
If you want to access the "Global Singleton" outside of an activity and you don't want to pass the Context through all the involved objects to obtain the singleton, you can just define, as you described, a static attribute in your application class, which holds the reference to itself. Just initialize the attribute in the onCreate() method.
For example:
public class ApplicationController extends Application {
private static ApplicationController _appCtrl;
public static ApplicationController getAppCtrl()
{
return _appCtrl;
}
}
One example with resources: Because subclasses of Application also can obtain the Resources, you could access them simply when you define a static method, which returns them, like:
public static Resources getAppResources()
{
return _appCtrl.getResources();
}
For global methods, use a static Util class with static methods. If you can't use static methods, then the methods shouldn't be global in the first place, and put them in the class that makes sense.
First read this:
How to declare global variables in Android?
Now why you shouldn't use a static singleton. Using a singleton is a the same thing as a global variable. Global variables reduce your maintainability because everywhere you use the global variable you break modularity or introduce global details and assumptions about your overall design. Your program can't have two of these variables because it only looks in one place for it. This means your program can't adapt easily when you have two instances instead of one.
For example, say I have a method called playTurn() and I implement it like so:
public void playTurn() {
globalPlayer.incrementClock();
globalPlayer.doSomething();
globalPlayer.doSomethingElse();
}
Now let's say I want to add a second player to the mix. Uh oh my playTurn() method assumes one player only when it used globalPlayer. If I want to add a second player to the program I have to change that method. Do this a lot and your program is very rigid and inflexible to change. Instead what if I did this:
public void playTurn(Player player) {
player.incrementClock();
player.doSomething();
player.doSomethingElse();
}
Now can do this:
playTurn( player1 );
playTurn( player2 );
I can reuse playTurn() for both player1 and player2 and I didn't have to change it. I just had to change the client of that method.
Most of the time you're being lazy and you want to get a reference to some object, and global variables are fast ways to get references to well known objects. Instead it's better to have one class that resolves the dependencies across your application at start up or the time when it makes sense. Then only that one place understands how your code is put together. For example,
public class Game {
Player player1;
Player player2;
Board board;
public void startGame() {
BlueTooth blueTooth = BlueTooth.getChannel();
player1 = new LocalPlayer();
player2 = new NetworkedPlayer( blueTooth );
board = new Board();
player1.setOpponent( player2 );
player1.setBoard( board );
player2.setOpponent( player1 );
player2.setBoard( board );
}
}
Now everyone has their dependencies, and they don't need to use static variables to find references to things. Also player1 doesn't have to know about details like that player2 is over the network, or that it's apart of a Game. What's important to note is that these objects we're connecting have a long life, possibly the entire program, but if they need to create other things at runtime that's ok for them to do.
Say for example, we need to create multiple players at runtime based on who joins the game. Well we might create a PlayerManager that we can instantiate at startup then create Player objects on the fly. PlayerManager is just a plain old object that we create in Game when we start a new game.
I hope you can start seeing this is a much better way to develop software. You might not understand it right off, but if you think about it will make more sense. It's very subtle change, but very powerful.