In my Android application i have loaded some images and data from the internet into expandable list view.And i have handled orientation changes as follows.
#Override
public Object onRetainNonConfigurationInstance() {
isOrentationChnged=true;
final Object data = arrGroupelements;
return data;
}
in my onCreate()
if(!isOrentationChnged){
new LongRunning().execute();
}else{
if((String[][])getLastNonConfigurationInstance()==null){
new LongRunning().execute();
}else{
arrGroupelements= (String[][]) getLastNonConfigurationInstance();
expList.setAdapter(new ExpAdapter(cont));
}
}
isOrentationChnged=false;
LongRunning is a AsynacTask which have used to get the data from the internet and it loads previously loaded data after orientation change (without getting new data from the internet again) but it is very slow.Is there any alternative way to do this efficiently ??
Finally i got simple way to speed up the orientation changes in an activity.
IDEA:
Each and every orientation change will recreate the activity the solution to this you can avoid the activity recreation by adding following code line to activity tag on your application's manifest file.
android:configChanges="orientation|keyboardHidden|screenSize"
above line avoid the activity recreation after orientation changes so your activity will be more responsive on orientation changes.
As per David unless isOrentationChnged is set to static it will always be false when your Activity is recreated.
You don't really need that variable anyway just do this in onCreate:
arrGroupelements = (String[][]) getLastNonConfigurationInstance();
if (null==arrGroupelements){
new LongRunning().execute();
} else {
expList.setAdapter(new ExpAdapter(cont));
}
This way if the activity is being recreated then your data will be used, otherwise the longrunning operation will run.
By the way I don't see you using arrGroupelements in your Adapter constructor.
Related
I have five EditText lines with data that is saved in a database. Thereafter, how do I clear the five EditText lines and make them null and then close my Activity without the user seeing the View updating to show the lines being cleared?
Activity code
public class AddorUpdateActivity extends AppCompatActivity {
// Save data to database
...
// Return to MainActivity
Intent returnMain = new Intent(AddorUpdateActivity.this, MainActivity.class);
startActivity(returnMain);
// Clear the EditText lines before finishing.
cEditText.setText(null); dEditText.setText(null); eEditText.setText(null);
fEditText.setText(null); gEditText.setText(null);
// Close the EditActivity.
finish();
}
cEditText.setText(null); dEditText.setText(null); eEditText.setText(null); fEditText.setText(null); gEditText.setText(null);
Remove all of the above lines from your code. You should be fine.
When activity is destroyed all of its views are also destroyed. However, when you try to create a new instance of same type of view as the one that's destroyed, there's a possibility that your views might get restored automatically (assuming you have not set setRetainInstance to false and assigned IDs to your views)
If you don't want that simply add setRetainInstance = false in your xml and remove all above code. This way your views will not be restored. However, be careful with this approach as device rotation WILL lead to data loss in your views. In such cases you should either save data in view models or implement onSavedInstanceState and onRestoreInstanceState methods in your activity.
I facing a bit of trouble when using AsyncTaskLoader and the screen orientation changes. Let me give you some context on how my app is structured: I have a very simple app which fetches results from a url and displays it. The app consists of one FragmentActivity and three Fragments. My three fragment are as follows:
First fragment is an edittext and a button to submit input.
Second fragment shows a loading spinner
Third fragment replaces the loading-fragment when the data is fetched to show the results.
The AsyncTaskLoader is used to load data from either a content provider (if it is cached) or from the network.
Everything works great until the screen oreintaion changes! I looked at the output of LoaderManager.enableDebugLogging(true) and it seems the source of the problem is that LoaderCallbacks.onLoadFinished doesn't get called in my activity.
Here is a piece of the code that launches the loader:
/* This function is defined in the "first" fragment in an interface and
* implemented in the activity */
#Override
public void onFormSubmission(String word) {
showLoadingFragment();
if ( mWord == null || mWord.equals(word) ) {
getSupportLoaderManager().initLoader(0, word, this);
} else {
getSupportLoaderManager().restartLoader(0, word, this);
}
// Store the word
mWord = word;
}
The code that displays the result:
#Override
public void onLoadFinished(Loader<Bundle> loader, Bundle data) {
// Validation and other stuff
ResultFragment fragment = new ResultFragment();
// Add the fragment to the 'result_fragment_container' FrameLayout
getSupportFragmentManager()
.beginTransaction()
.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN)
.setCustomAnimations(android.R.anim.fade_in, android.R.anim.fade_out)
// Replace loading fragment with the result
.replace(R.id.result_fragment_container, fragment)
.commitAllowingStateLoss();
}
Approaches I tried but failed:
Setting setRetaininstance(true) in fragments.
Setting android:configChanges="orientation|keyboardHidden|keyboard" in the manifest.
I'm out of ideas, so any help would be appreciated.
You should put getSupportLoaderManager().initLoader(0, null, this); in the onActivityCreated method. The initLoader will create or reconnect with a loader if it already exists
Hi I can suggest 2 possible solutions:
1) From your question I'm not entirely sure what process your performing which is never calling OnLoadFinished() in the AsyncTask. I'll assume is a Async DB call or Web server call etc?
Regardless the onLoadFinished() probably doesn't get called because your Activity is Destroyed on rotation. you need to save the state you updated before rotation and onDestroy() is called
You can try keep a class variable status flag. This is set in your "update" Async task which flags whether your Async task is still running ie "updating" or not.
So:
bUpdating = true when your update async task starts. Ie within
onPreExecute()
bUpdating = false when its finished. Ie within
onPostExecute()
Then when onDestroy() is called (always called before the screen rotate) you could check bUpdating. IF TRUE then you could save all details on screen, which would have been saved in the Async task, to SharePreferences
Within onResume() check your specific SharePreferences variables and if they exist then kickoff the Async update again.
So in short this will:
save details to SharedPreferences BEFORE screen rotation - onDestroy() - if boolean says Async task running.
onResume() AFTER screen rotation check SharedPreferences and save details via Async.
Following this you should be guaranteed that your onLoadFinished() method is called.
There is probably a more reliable way also to check for Screen Rotation, i haven't done much with it.
2) Of course another alternative is to actually block screen rotation entirely on your particular Activity (because really, do you NEED rotation on that screen?).
I have an application which records video in background and uploads 10second segments. It was causing large headaches with screen rotation and my Async tasks, so I blocked rotation entirely as it was completely unnecessary. Here is code for the AndroidManifest.xml file to lock Screen orientation as Portrait:
<activity
android:name="com.blah.YourActivity"
android:label="Register"
android:screenOrientation="portrait">
</activity>
I hope that can help you out
Edit: Also, could be better more categorical ways to know that screen is rotating:
ie this sort of code:
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
if (newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE) {
Log.e(TAG, "ORIENTATION_LANDSCAPE");
} else if (newConfig.orientation == Configuration.ORIENTATION_PORTRAIT) {
Log.e(TAG, "ORIENTATION_PORTRAIT");
}
}
Example taken from this post
you could just put your SharePreferences save in there. but onResume() will still be used to grab your details back from.
Also a link to SharePreferences incase you've not used it before
Edit2!: One other thing. I just re-read your question, and you mention "Loader" for some reason i had it in my head this was saving data, not loading. Have you tried simply re-calling AsyncTaskLoader() when onResume() is called?? If your not saving then you can ignore everything i said about retaining your data to SharePreferences because you can just kickoff the load Async task again at onResume() (which runs after Rotation)
I have seen the following links before posting this question
http://www.devx.com/wireless/Article/40792/1954
Saving Android Activity state using Save Instance State
http://www.gitshah.com/2011/03/how-to-handle-screen-orientation_28.html
How to save state during orientation change in Android if the state is made of my classes?
I am not getting how should i override the following function :
#Override
public Object onRetainNonConfigurationInstance() {
return someExpensiveObject;
}
In my application i have layout with one editext visible and other editext get visible when the data of first editext validates to true.I have set the visbility of all other editextes and textviews to false and make them visible after validating.
So in my activity if the screen orientation is changed then all the items having android:visibility="false" get invisible.
I have also came to know that when our activities screen orientation changes it calls onStop() followed by onDestroy() and then again starts a fresh activity by calling onCreate()
This is the cause .. But i am not getting how to resolve it ..
Here You can see the screenshots of my application :
in this image all fields are loaded
and in another image when the screen orientation is changed to landscape they are all gone
Any link to tutorial or piece of code will be highly appreciable.
And also my application crashes when a progress dialog is shown up and i try to change screen orientation.How to handle this ??
Thanks
Well if you have the same layout for both screens then there is no need to do so just add below line in your manifest in Activity node
android:configChanges="keyboardHidden|orientation"
for Android 3.2 (API level 13) and newer:
android:configChanges="keyboardHidden|orientation|screenSize"
because the "screen size" also changes when the device switches between portrait and landscape orientation.
From documentation here: http://developer.android.com/guide/topics/manifest/activity-element.html
There is another possibility using which you can keep the state as it is even on Orientation change using the onConfigurationChanged(Configuration newConfig).
Called by the system when the device configuration changes while your activity is running. Note that this will only be called if you have selected configurations you would like to handle with the configChanges attribute in your manifest. If any configuration change occurs that is not selected to be reported by that attribute, then instead of reporting it the system will stop and restart the activity (to have it launched with the new configuration).
At the time that this function has been called, your Resources object will have been updated to return resource values matching the new configuration.
There are 2 ways of doing this, the first one is in the AndroidManifest.xml file. You can add this to your activity's tag. This documentation will give you an in depth explanation, but put simply it uses these values and tells the activity not to restart when one of these values changes.
android:configChanges="keyboardHidden|orientation|screenSize|screenLayout"
And the second one is: overriding onSaveInstanceState and onRestoreInstanceState. This method requires some more effort, but arguably is better. onSaveInstanceState saves the values set (manually by the developer) from the activity before it's killed, and onRestoreInstanceState restores that information after onStart() Refer to the official documentation for a more in depth look. You don't have to implement onRestoreInstanceState, but that would involve sticking that code in onCreate().
In my sample code below, I am saving 2 int values, the current position of the spinner as well as a radio button.
#Override
public void onSaveInstanceState(#NonNull Bundle savedInstanceState) {
spinPosition = options.getSelectedItemPosition();
savedInstanceState.putInt(Constants.KEY, spinPosition);
savedInstanceState.putInt(Constants.KEY_RADIO, radioPosition);
super.onSaveInstanceState(savedInstanceState);
}
// And we restore those values with `getInt`, then we can pass those stored values into the spinner and radio button group, for example, to select the same values that we saved earlier.
#Override
public void onRestoreInstanceState(#NotNull Bundle savedInstanceState) {
spinPosition = savedInstanceState.getInt(Constants.KEY);
radioPosition = savedInstanceState.getInt(Constants.KEY_RADIO);
options.setSelection(spinPosition, true);
type.check(radioPosition);
super.onRestoreInstanceState(savedInstanceState);
}
How do I retain the state of an activity in android? I have two layouts for portrait and landscape in layout and layout-land. I am loading the value from service at the time I am showing progress dialog. If loaded user rotates the device to landscape at the time also loading. How do I avoid that? user typed content in webview that also refreshed. How do I avoid that, can anybody provide an example?
Thanks
When orientation changes, the Activity is reloaded by default. If you do not want this behavior then add this to the Activity definition in your manifest:
android:configChanges="orientation|keyboardHidden"
For more detail, see Handling Runtime Changes
You can use the onRetainNonConfigurationChange() callback to store arbitrary data. It is called just before your application is about to be recreated.
Then, in onCreate() just check if some data were put aside by calling getLastNonConfigurationInstance() that returns the Object you put aside or null.
See this article on android developers.
Here's a sample borrowed from the link above:
#Override
public Object onRetainNonConfigurationInstance() {
//this is called by the framework when needed
//Just return what you want to save here.
return MyBigObjectThatContainsEverythingIWantToSave;
}
Automagic restore of previously saved state:
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
final MyDataObject MyBigObjectThatContainsEverythingIWantToSave = (MyDataObject) getLastNonConfigurationInstance();
if (MyBigObjectThatContainsEverythingIWantToSave == null) {
//No saved state
MyBigObjectThatContainsEverythingIWantToSave = loadMyData();
} else {
//State was restored, no need to download again.
}
...
}
When orientation changes, the Activity is reloaded by default. If you do not want this behavior then add this to the Activity definition in your android manifest file :
android:configChanges="orientation|screenSize|keyboardHidden"
I am trying to stop my app from resetting whenever the user flips the screen. I don't really want to set it to portrait permanently.
My problem is I have settings which erase and a service which stops each time the screen flips. I would like to keep things as they are regardless of the screen orientation.
On your Activity in your AndroidManifest, set the following:
<activity android:name="YourActivity" android:configChanges="orientation|keyboardHidden"></activity>
This tells your Activity to not "re-create" itself on screen orientation changes or keyboard change state
You can save the data by using :
#Override
public Object onRetainNonConfigurationInstance() {
return super.onRetainNonConfigurationInstance();
}
return the data you want to save.
In the onCreate function you can check if there is any data saved by doing the following
final Object data = (Object) getLastNonConfigurationInstance());
if (data == null) {
//Retrieve data
}else{
//Use the saved data
settings = data;
}
You can read about this topic at the Android Dev Guide :