I start an activity A from B with an intent with extras and based on the type of extra in onCreate I do some process and it works fine.
But when I do a orientation change the same old intent is re-delivered by the system to me and the whole process gets restarted since I go through the onCreate once again.
My code completely take care of restoring the previous state of the activity when the onCreate gets called if no old intent is delivered to it. But since the system re-delivers it make my activity think it is a new intent and restarts the whole process once again.
I tried the flag intent.getFlags() != Intent.FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY. This flag prevents re-delivery in case of long press home button and activity launched from history but no effect on orientation change.
A dirty fix was proposed in another thread Dirty Fix but I am wondering if there is a proper way to address this problem.
Thanks in advance
Use savedInstanceState to determine if the activity or fragment is restored from whatever including orientation change.
savedInstanceState will be null when activity/fragment is restored.
public void onCreate(Bundle savedInstanceState) {
...
boolean isRedeliver = savedInstanceState != null || (intent.getFlags() & Intent.FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY) != 0;
...
}
This technique is also used in official doc of fragment.
if (savedInstanceState == null) {
// During initial setup, plug in the details fragment.
DetailsFragment details = new DetailsFragment();
details.setArguments(getIntent().getExtras());
getFragmentManager().beginTransaction().add(android.R.id.content, details).commit();
}
A 'clean' solution to this problem would be to use Fragments.
Create your own Fragment subclass.
In its onCreate, be sure to call setRetainInstance(true).
In its onCreate you can start your process.
If it is just for doing some work, return null in its onCreateView.
In your Activity's onCreate:
- First try to find the current instance of your own Fragment.
- If not found, create a brand new one and commit this to your Fragment Transaction.
By calling setRetainInstance(true) and by first trying to find it before creating a new Fragment in the Activity's onCreate, you keep the same Fragment instance even after a rotation and the Fragment's onCreate won't be called again.
Related
I have a Fragment that shows different view by a AdapterViewFlipper.
The AdapterViewFlipper is being set with MyCustomAdapter that contains 'View 1', 'View 2', 'View 3', and 'View 4', and its in a layout resource file that I inflated in my own Fragment "onCreateView()".
The Problem I'm facing is whenever I rotate my device, the current view in the AdapterViewFlipper goes back to the first view that was added in MyCustomAdapter.
For Example: if the current view in the AdapterViewFlipper is showing 'View 2' and the user rotates the device, it returns back to 'View 1'.
So what I'm trying to do is to restore the current view in the AdapterViewFlipper and its state in the Fragment whenever I rotate my device.
Although I found this method that says I should declare the android:configChanges attribute at the element in the AndroidManifest and it worked like a charm but when I was reading about it Android didn't recommend it.
But this works fine in Activity.
So is there a way I can go through this myself?
So the first thing you need to do, is to make sure you are retaining the fragment itself. And not place a new instance every time your activity is re-created.
You can establish that with a simple check in your onCreate() method.
You can either check if the savedInstance Bundle parameter to onCreate() is null, in that case only you need to replace your fragment OR check if your fragment is already added to your FragmentManager.
if (savedInstanceState == null) {
// This is a brand new activity, and not a re-creation due to config change
getSupportFragmentManager().beginTransaction().replace(id, yourFragmentInstnace, stringTag);
}
OR
if (getSupportFragmentManager().findFragmentByTag(fragmentTag) == null) {
// This is a brand new activity, and not a re-creation due to config change
getSupportFragmentManager().beginTransaction().replace(id, yourFragmentInstnace, fragmentTag);
}
And you also need to call setRetainInstance(true) in your fragment's onCreate() or something.
That will retain the same instance of your fragment during a configuration change.
This should automatically allow your AdapterViewFlipper to maintain its UI state, which is the current item it's showing.
You can find a nice example here
I've been tweaking a lot with android design and capability of Android to use the maximum potential of an Android framework, I have come across transition, and my question is how to define Activity's Destroyed's animation ?. Say I am starting an activity using intent like so :
Intent intent_info = new Intent(ComponentsPage.this, SecondActivity.class);
startActivity(intent_info);
overridePendingTransition(R.anim.slide_up, R.anim.no_change);
That snippet basically opens up SecondActivity with Slide Up transition. Now i am in second activity and second activity say doesn't have any button but i want whenever Second Activity is closing (Destroyed) it close with slide down animation.
I've tried adding
overridePendingTransition(R.anim.no_change,R.anim.slide_down);
Inside onDestroy() and onStop(), but still no luck, i guess the activity is already closed when those methods are called.
When you try to finish the second activity try to override the finish method inside your SecondActivity as follows:
#Override
public void finish() {
super.finish();
overridePendingTransition(R.anim.no_change, R.anim.slide_down);
}
I have an application where there are: a splash screen, a main activity (started from the splash screen) where there's a navigationView that attach and detach some fragment.
In one fragment i need to download some information with an AsyncTask. The problem is that the AsyncTask is called in the splash screen (the splash screen survive for 3 seconds) and the download can takes more or less than 3 seconds. In the onPostExecute() in AsyncTask i want to call a function loadFeeback() (that is in the fragment class) only if the fragment is already loaded, if not i set a static variable downloaded to true.
public void onPostExecute(Feedback[] feedbacks){
Dati.feedbacks = feedbacks;
if(mainActivity != null) {
FragmentManager fragmentManager = mainActivity.getSupportFragmentManager();
FeedbackFragment feedbackFragment = ((FeedbackFragment) (fragmentManager.findFragmentById(R.id.nav_feedback)));
Dati.feedbackDownloaded = true;
if (feedbackFragment != null)
feedbackFragment.loadFeeback();
}
}
The problem is that i can't get the mainActivity reference and i can't pass the context to the AsyncTask because it is called from the splash screen.
Can anyone help me?
The Asynctask is tied to the splash activity,because it created it.
Maybe you can use a Headless Fragment( fragment without layout):
Create a fragment on precise in the onCreate function :
setRetainInstance(true)
In your splash activity create the fragment and save him with a tag :
HeadlessFragment headlessFragment = new HeadlessFragment()
getSupportFragmentMangager().beginTransaction().add(headlessFragment, "fragmenttag").commit();
Launch your asynctask in the fragment
And when your main activy is launched retrieved the fragment :
HeadlessFragment headlessFragment = getSupportFragmentMangager().findFragmentByTag("fragmenttag");
So the fragment will be attached to the main activity, and you should call whatever you need
Hope this helps.
Sorry for my poor english.
When turn the switch on it stays on.. however when i leave the activity and come back to it.. it goes back to off. I want it to stay ON OR OFF depending on whats last pressed. I have tried the code below but does not resolve my issue
SwitchButton.setChecked(true);
SwitchButton.setChecked(false);
What you need to do is override these methods in your activity:
#Override
protected void onSaveInstanceState (Bundle outState){
super.onSaveInstanceState(outState);
outState.putBoolean("CHECKED", SwitchButton.isChecked());
}
then in onCreate:
#Override
protected void onCreate (Bundle savedInstanceState){
super.onCreate(savedInstaceState);
if(savedInstanceState != null){
boolean isChecked = savedInstanceState.getBoolean("CHECKED");
SwitchButton.setChecked(isChecked);
}
}
If you are minimizing the activity and then returning back to it, and you want all controls to retain their states, then look into implementing saved instance state. This will persist the control values while you minimize / maximize the activity or rotate it. No data is permanently saved to the device. Sample code here:
http://developer.android.com/training/basics/activity-lifecycle/recreating.html#SaveState
If you are closing the app completely and want the app to remember the settings, then consider SharedPreferences, which can be used to save data locally on the device. The data persists until your app explicitly deletes it or you uninstall the app. Sample code here:
http://developer.android.com/training/basics/data-storage/shared-preferences.html
If I'm bringing Android activities from the stack to the front, how do I refresh them? So to run onCreate again etc.
My code below, in conjunction with setting activities in the Android manifest to android:launchMode="singleTask" allows me to initiate an activity if that activity is not already active within the stack, if it is active within the stack it is then brought to the front.
How do I then, if the activity is brought to the front refresh it so that onCreate is ran again etc.
Intent intent = new Intent(myActivity.this,
myActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);
startActivity(intent);
I think FLAG_ACTIVITY_CLEAR_TOP will resolved your problem:
Intent intent = new Intent(myActivity.this, myActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
startActivity(intent);
I don't think there is an explicit way to refresh onCreate, perhaps you may want to add the code you want reloaded into onResume.
This workaround may work if you want to keep your code in onCreate.
finish();
startActivity(getIntent());
If all you want to do is refresh the content, you should override the onResume method, and add in the code to perform the refresh in this method. To do this, use the following code within the activity that you want to perform the refresh, (ie, not the same activity that you are calling startActivity() from):
#Override
protected void onResume(){
super.onResume();
//add your code to refresh the content
}
Tip: If you are using Android Studio, press Alt+Insert (while you have the Java file open), then click Override Methods, find onResume, and it should provide you with a basic template for the method.
The diagram I added shows the order that the methods are run (this is known as the Activity Lifecycle). onCreate() is run whenever an Activity is first created, followed by onStart(), followed by onResume(). As you can see, when a user returns to an Activity, onCreate() is not run again. Instead, onResume() is the first method that is called. Therefore, by putting your code into the onResume() method, it will be run when the user returns to the activity. (Unlike onCreate(), which will not be run again).
Extra info: Since you will be initially setting the data in onCreate() and then refreshing it within onResume(), you might want to consider moving all of your code used to initially set the data to onResume() as well. This will prevent redundancy.
Edit: Based on your following comment, I can give the following solution:
I'm wanting to properly refresh the page, e.g. if there is a variable count initialised at 0. And though running the activity it's has became equal to 300. When the activity is called (intent) then refreshed, count will once again be equal to it's initial value. Do you know how to do this?
Without your current activity's code, there is not much to work with, but here is some pseudo-code as to how I would accomplish your problem:
public class MyActivity extends Activity {
TextView numberTextView;
int numberToDisplay;
#Override
protected void onCreate(Bundle bundle){
super.onCreate(bundle);
setContentView(myContent);
numberTextView = (TextView) findViewById(R.id.numberTextView);
numberTextView.setText(numberToDisplay+"")//converts the integer to a string
}
#Override
protected void onResume(){
super.onResume();
numberToDisplay = 0;
numberTextView.setText(numberToDisplay+"");
}
}