I'm a little confused about the Activity being destroyed and recreated when the user's device is rotated.
I've been reading around, and I understand the rationale for doing so (it basically 'forces' the developer to make sure they haven't 'missed' anything upon rotation/language/other changes)
I'm happy to respect best practice if it is seen as such, however it begs the question:
How do I 'remember' the state of the game/app, so that when the screen is rotated I have something from which to re-generate what the user was looking at?
From what I can see, absolutely everything is destroyed, the base class constructor runs and all variables in the Activity are 'null'.
I suspect the 'savedInstanceState' (Bundle class) is where I would collect that data, but reading around it only seems to be used for when the app is closed from lack of resources (and a few other extremely fringe cases)
Am I misinformed or misunderstanding the purpose of savedInstanceState? Is it wise to abandon best practice (letting the Activity be destroyed) if I'm mindful enough to not miss anything upon rotation? Thanks in advance for any advice.
I should note this question applies to game programming (I'm not using a layout XML)
Do you need your activity to be recreated? Is there work you want to do on rotation? savedInstanceState is where you would store data to be passed to the recreation of the Activity, but since you aren't using XML layouts you may consider just adding android:configChanges="orientation" to your activity in the manifest. This will give you manual control over what happens during rotation change.
In additional to my original comment, I would override config changes for keyboard being show as well:
android:configChanges="orientation|keyboardHidden"
If there is work you want to do on rotation change you can override onConfigChange and do anything you need there.
It's hard to say that there is a time when you should always override config changes, but I often do it when I have no dependency on resource folders that are size or orientation specific and I'm doing a lot of work that would take too much time to recreate.
There are other best practices to store data while activitiy config changes.1. Developer Doc Handling Runtime Changes2. Alex Lockwood : Handling Configuration Changes with Fragments, This will answer all your questions reagarding config change and storing data.
Impt:
Fragment file to store data. You must set setRetainInstace(true) in order to store data and retrieve while your activity config changes.
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// retain this fragment
setRetainInstance(true);
}
Related
I'm new in the development with Android. For a school project, I'm currently working on an application for children to help them learn writing.
The app will contain many levels that use the same concept, only the background changes. I have made a level that works fine and now to finish the work, I want to add levels using the code of the first one.
So what is a good/usual way to do that ?
I thought that I could create as many activities as levels. In each new activity, I could start the first one and give it the new background as parameter. But with 50+ levels, it seems a bit strange to me to have so many activities.
Thank you for your help :)
If changing to a new background is all a change of levels will trigger, I would just add a level member variable to the activity and (for instance) listen for the next level in order to change the background. If it turns out that you will have to change more than the background, #Vucko s answer seems viable.
Definitely do not repeat the same code fifty times in fifty different activities!
You can use fragments, particularly 1 type of Fragment called 'LevelFragment' which will have a few arguments that you can pass to it so that each level is different, those arguments should refer to the content of the level (background or whatever). This way you're reusing the same layout and the same logic, just changing some of it's behavior based on the arguments you have.
Now all you need to do is to swap out fragments in your container, while still staying in one Activity only. Since your question was kinda vague, I cannot offer any implementation tips at this point, but rather a basic guideline and a direction to consider.
You can use a BaseActivity that will be extended from all other activities for code centralization. Otherwise you can use always the same activity and start it with a parameter in the intent (for example, level number) and make your own logics according parameter value. Finally, you can give a look to fragments too, keeping central logic in the same activity.
Fragment is your solution, you can simply pass the background assets name (throw intent).
Recently I have found a way to survive configuration changes. What I do is I declare the objects I want to protect as static fields. Is this a good practice?
It's never been a good practice. In my own experience I made a music player app with full of static variables and it's ram usage rocketed to more than 75 mb which is far more than any other of it's kind. The reason is, it stores the value of variable while activity is destroyed. if you have static variable on bitmaps or any other heavy file, it makes memory leaks which is not pleasant to see by user as not all devices got enough resources (ram) to keep up with heavy usage app.
Also static variables often make NullPointerExceptions as these are used by many other activities too and having a variable null may result in total failure of app...
I advise you to store the data in a SharedPreferences and just make one static field like integer and always use that to retrieve values from SharedPrefrences, its very clean and reduces the NullPointers. Moreover just one static makes u have more control over your app... For me it saves time to change 100's of static field rather than changing 1 as it's a lot easy and memory efficient...
I hope, I may help u a little !
Not really. You can cause a memory leak, because one of your static fields can hold a reference to the current Context, which could be destroyed without the reference.
The best way to survive configuration changes is to use the recomended method - Bundles. If you have to store something bigger and/or more persistant - use files, SharedPreferences or a database.
Use static may lead to nullpointer exception. Because when configuration change the current context is destroyed and if you access those context then it throws nullPointer exception.
So sharedPreferences or database is the best option for store the data.
Hope this help :)
One of the approach to retain Activity State, especially during configuration change is to make use of Fragments.
Instead of reinitializing your activity, you can alleviate the burden by retaining a Fragment when your activity is restarted due to a configuration change.
The fragments of your activity that you have marked to retain are not destroyed by Android system, when it destroyed your activity during configuration change.
You can add such fragments to your activity to preserve stateful objects.
Compare to using "static", this Approach is what being advocated at below link:
http://developer.android.com/guide/topics/resources/runtime-changes.html
I assume you can't just put in the bundle in onSaveInstanceState for some (very good) reason. So I think you have to compare with retain fragment.
If you have a static field in your class, like:
static Object myStaticReference;
you will no more worry about all the lifecycle jungle mess with onDestroy, onCreate, onSaveInstanceState of the Activity or Fragment. This will reduce considerably the code rows and make everything just easier to debug and understand. In any case you shall not have any reference in your object to a View, Activity, Fragment, Context and the like.
If for example you have something like this:
public class MyObject {
ArrayList metaData;
Context cntx;
public MyObject(Context cntx) {
this.cntx=cntx;
}
}
Then you still are in the lifecycle jungle, and you will have to pass (and repass) the reference of the context (and any other View relations you have) any time your Activity gets recreated in onCreate and still manage with onSaveInstanceState if there is any need. So in this case it is just useless.
With retain Fragment (which I suppose should be the other way) things are different too. The retain Fragment will last even when the Activity gets recreated, but you have to manage this additional fragment (the good part is that you do not need an UI for this).
Currently im storing all of my users information and there friends information inside a class i have created called userInfoCore that extends Application so i can store the values in the Context. When my app crashes it gets rid of al those values and my users are forced to relogin, so i would like to store them in SharedPreferences to be grabbed again in the onCreate of my MainActivity.
I know how to store them, thats not the issue. The issue is i dont want to overcrowd my code with repetitive code and put the storing methods in all the onDestroy's of all my Activities, and i cant #Override onDestroy in my userInfoCore class because its not an Activity i imagine?
Some insite would be great. Thank!
EDIT:
Ive found out that this line in the android manifest is causing my Application Context data to be destroyed even when the user presses the home screen. android:launchMode="singleInstance"
My thoughts are YES i could store them in the onPause or do what #CommonsWare suggested. However like i said, i dont want to have to do all of that. If i can find the root of the cause of the issue... which i have. (The singleInstance in manifest) then i would be much happier.
Some insite would be great.
Update your persistent store when the data changes. A custom Application subclass, like any singleton, should only be treated as a cache or other transient spot for data. If you care about the values, persist them, at the point when the data is changed.
This is a good argument for using the Model-View-Presenter (or Model-View-Controller) pattern. By separating your Model (domain data and procedures) from your View and Presenter (Layout and Activity respectively) you only have to write the Store logic once.
Then you have two choices: either do as #CommonsWare suggests, have the model write itself whenever it changes, or add a simple call in each Application's onPause (onDestroy is too late! It may never get called.) to the model to tell it to save itself.
Note: the model can accept a context as a construction parameter for use in finding a shared preferences, or it can create it's own named preferences using the PreferenceManager
This might not make much sense in terms of Android SDK, but, in C++ I am used to keeping my main.cpp (and specifically main() function) as a place where I declare and initialize other classes/objects, and afterwards all the things that my application does take place in those classes. I never come back and check for anything in main.cpp afterwards.
But in Java, Android SDK, you have to override dozens of methods in main activity and all of that takes place in one single file. Example:
I have a MainActivity.java and SomeTest.java files in my project, where first is default MainActivity class which extends Activity, and SomeTest.java contains class that declares and runs new Thread. I initialize SomeTest class from MainActivity.java and pass a handle of the activity to it as a parameter:
SomeTest test = new SomeTest(MainActivity.this);
And having the handle to MainActivity, I proceed doing everything from this newly created thread. When I need to update the UI I use runOnUiThread() to create and show a new ListView (for example) on my main layout. I want to get the width and height of the newly created Listview, for what I have to override onWindowFocusChanged() in my MainActivity.java and notify the thread from there, as getWidth() and getHeight() will only have values when ListView is actually displayed on the screen. For me it's not a good practice to make such connections ('callbacks', if you will) from MainActivity to that thread.
Is there a way I can keep methods like onWindowFocusChanged() within the thread and don't touch the MainActivity.java at all?
As I said, might not make much sense.
Is there a way I can keep methods like onWindowFocusChanged() within the thread and don't touch the MainActivity.java at all?
onWindowFocusChanged() is a callback method. It is called on the activity. You cannot change this.
And having the handle to MainActivity, I proceed doing everything from this newly created thread.
That's generally not a good idea. Using a background thread to, say, load some data from a file or database is perfectly reasonable (though using Loader or AsyncTask may be better). However, usually, the background thread should neither know nor care about things like "the width and height of the newly created ListView".
You are certainly welcome to migrate some logic out of the activity and into other classes. You might use particular frameworks for that, such as fragments or custom views. However, the class structure should not be driven by your threading model. For example, let's go back to your opening statement:
in C++ I am used to keeping my main.cpp (and specifically main() function) as a place where I declare and initialize other classes/objects, and afterwards all the things that my application does take place in those classes
However, in C++, you would not say that you are locked into only ever having two classes, one of which is operating on some background thread. While you may have a class or classes that happen to use a background thread (or threads), the driving force behind the class structure isn't "I have a background thread" but "I want to reuse XYZ logic" or "I wish to use a class hierarchy in support of the strategy pattern" or some such.
Personally speaking Context idea taken from Android SDK seems to be messy. What you are describing comes from too much responsibility intended for Activity. That's why you need to track a LOT of things inside single file (Activity's life cycle, getting Context instance in order to show Dialog etc.). I don't think there's perfect solution but I would recommend using:
Fragment subclasses which are helping to divide your screen (and so on logic) into seperate parts
3rd party frameworks/libraries like AndroidAnnotations, RoboGuice, Otto which are perfect tools to avoid spaghetti code
if you would like to perform some UI updates from another class, consider using an AsyncTask passing it the Views you need to update. Let me know if you need an example
I read everything and understand your statements, I can see you've been doing programming for sometime but apparently is just starting with Android, I've done a lot of embed systems before so I totally get the concept of having a software that looks like:
void run(){
object.setup();
while(true){
otherObject.run();
}
}
But there's one fundamental flaw on the you logic of your question:
Android programming is a different programming paradigm from C++ and from computer programming and you should understand its specific paradigm instead of assume what is good practice from other paradigms.
Quote from you: create and show a new ListView (for example) on my main layout. I want to get the width and height of the newly created Listview, for what I have to override onWindowFocusChanged().
From that I can see that you've really trying to do Android stuff on a way that is not recommended on an Android context. A ListView you can easily implement from the XML layout setContentView(int) and use the Activity onCreate to instantiate any threading (AsyncTaskLoader) framework to load the data in background and deliver it back to the UI.
That doesn't mean that all your code will be dumped in one file making it a mess. This little example I put you can do with Activity that implements the loader callbacks, a separate class with the loader, a separate class with the data loading work, a separate class with the data adapter, the activity is just a central piece that organise and manage those classes on the correct moment of its life-cycle and at no point you need to call onWindowFocusChanged() and still have a nicely organised code.
Apart from that please refer to CommonsWare answer as it's usually cleverly written and correct.
What is the proper way of handling an orientation change in Android? When I researched this question there are two methods that came up.
1st Method
Use the methods onSaveInstanceState(Bundle savedInstanceState) and onRestoreInstanceState(Bundle savedInstanceState) to store and restore your Activity after being killed by the Android OS after the orientation change.
2nd Method
Added android:configChanges="orientation|keyboardHidden" to your AndroidManifest.xml so the Activity will not be destroyed when the orientation is changed.
I have tried both methods and they both work, however the first method takes a lot longer to implement. While I do see posts about the 2nd method, I want to know if this is an "accepted" and "proper" way of handling an orientation change. And what are the advantages and disadvantages for each method? Thanks!
The second method will not allow you to do certain orientation specific stuff such as load a different layout for when the screen is rotated or not (I'm thinking of resource suffixes here). I have not encountered any other ill effects, however the docs state that: "Using this attribute should be avoided and used only as a last-resort."
More info here: http://developer.android.com/guide/topics/resources/runtime-changes.html
See http://developer.android.com/guide/topics/resources/runtime-changes.html where they explain both methods and give the pros and cons and best solution.