I would like to know when my app is back from background. onResume() is not a good solution, because i have another activities beside the Main Activity, so it can back from background to each of them. The purpose is to use Google analytics and to know when a user is launching the app and also bring it back from the background.
Thank you all and much appreciation.
Create a common base class which extends Activity. Implement onResume() with the functionality you need. Then extend all of your other activities from this base class.
The onResume() in the base class should call super.onResume() and this should also be the first line in each of the individual activity onResume methods.
Base class
public class BaseActivity extends Activity
#Override
public void onResume(){
super.onResume();
// code to do your analytics stuff
}
Derived Activities
public class MainActivity extends BaseActivity
#Override
public void onResume(){
super.onResume();
// code for the individual activity
}
You can detect background application with ActivityManager.getRunningAppProcesses() which returns a list of RunningAppProcessInfo records. If your application is in the background check RunningAppProcessInfo.importance field equals to RunningAppProcessInfo.IMPORTANCE_BACKGROUND while RunningAppProcessInfo.processName is equals to your application package name.
More info:
http://developer.android.com/intl/es/reference/android/app/ActivityManager.RunningAppProcessInfo.html
The android.arch.lifecycle package provides an interface that let you know when the app is back from background.
Your application should implement the LifecycleObserver interface:
public class MyApplication extends Application implements LifecycleObserver {
#Override
public void onCreate() {
super.onCreate();
ProcessLifecycleOwner.get().getLifecycle().addObserver(this);
}
#OnLifecycleEvent(Lifecycle.Event.ON_STOP)
private void onAppBackgrounded() {
Log.d("MyApp", "App in background");
}
#OnLifecycleEvent(Lifecycle.Event.ON_START)
private void onAppForegrounded() {
Log.d("MyApp", "App in foreground");
}
}
To do that, you need to add this dependency to your build.gradle file:
dependencies {
implementation "android.arch.lifecycle:extensions:1.1.1"
}
As recommended by Google, you should minimize the code executed in the lifecycle methods of activities:
A common pattern is to implement the actions of the dependent
components in the lifecycle methods of activities and fragments.
However, this pattern leads to a poor organization of the code and to
the proliferation of errors. By using lifecycle-aware components, you
can move the code of dependent components out of the lifecycle methods
and into the components themselves.
You can read more here:
https://developer.android.com/topic/libraries/architecture/lifecycle
I have tried almost all the solutions from SO but no success :(.
I have a simple myJavaClass.java with a couple of functions.
One of the functions in myJavaClass : startActivity() starts MyCustomActivity
public startActivity(Context context)
{
Intent intent = new Intent(context, MyCustomActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK |Intent.FLAG_ACTIVITY_SINGLE_TOP);
context.startActivity(intent);
}
This launches MyCustomActivity() as expected.
Now I have another function in myJavaClass.java to close/finish MyCustomActivity but it is not able to do so!
I have tried
Making MyCustomActivity SingleTop in manifest and creating the activity via an intent as above
Passing an activity instance to "this" in onCreate() of MyCustomActivity and calling MyCustomActivity.activity.finish() from myJava.class but that doesnt work as well
Please help me. I have been stuck here for hours now. I know the solution is very simple and conceptual but I am a newbie. Just building Java/Android concepts!
EDIT
MyCustomActivity
public Activity activity;
OnCreate()
{
...
this = activity;
}
MyJavaClass
public closeActivity(Context context)
{
Activity customActivity = MyCustomActivity.activity;
customActivity.finish();
}
I think that what you are trying to do is fundamentally bad. For a start, outside of the Activity code, there are no guarantees that the activity still exists - the memory manager may have cleaned it up, the user may have pressed Back etc. Think of Activities as independent entities - you can start them, and you can optionally get a result back when they finish what they're doing, but that's it.
Think about whether you really have to programmatically close the activity from outside it - I'd say this is an unusual design, but there are circumstances where it may be appropriate.
If so, what I think you want is a publish/subscribe system whereby MyCustomActivity can register a listener with MyJavaClass, and then receive a callback whereupon it can 'finish' itself.
public Activity activity implements FinishListener
{
public void onCreate(...)
{
//where does MyJavaClass come from? see in a minute
MyJavaClass myjava = getMyJavaclass();
myJava.addFinishListener( this );
}
public void onFinishCallback()
{
this.finish();
}
}
and
public class MyJavaClass
{
private List<FinishListener> finishListeners = ...;
public void addFinishListener( FinishListener fl )
{
this.finishListeners.add(fl);
}
public closeActivity(Context context)
{
for ( FinishListener fl : finishListeners )
{
fl.onFinishCallback();
}
}
}
and
public interface FinishListener
{
void onFinishCallback();
}
Now the only remaining issue is how to get MyJavaClass from the Activity. That's up to you - you may already know how, you may be able to put it in your Application implementation, it could be a singleton (bad), the listeners could be static (bad) or various other options.
Oh, and don't forget to remove the listener again in the Activity's onDestroy() method!
Just try this....
public closeActivity(Activity _activity)
{
_activity.finish();
}
you can't finish activity from other class until you have the reference of instance of Activity in that class, give the reference in that class and call finish() method to stop the activity.
activity.finish();
How do I set it so the application is running in portrait mode only? I want the landscape mode to be disabled while the application is running. How do I do it programmatically?
For any Android version
From XML
You can specify android:screenOrientation="portrait" for each activity in your manifest.xml file. You cannot specify this option on the application tag.
From Java
Other option is to do it programmatically, for example in an Activity base class:
#Override
public void onCreate(Bundle savedInstanceState) {
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
}
For Android 4+ (API 14+)
Last option is to do it with activity lifecycle listeners which is only available since Android 4.0 (API 14+). Everything happens in a custom Application class:
#Override
public void onCreate() {
super.onCreate();
registerActivityLifecycleCallbacks(new ActivityLifecycleAdapter() {
#Override
public void onActivityCreated(Activity a, Bundle savedInstanceState) {
a.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
}
});
}
ActivityLifecycleAdapter is just a helper class you'll need to create which will be an empty implementation of ActivityLifecycleCallbacks (so you don't have to override each and every methods of that interface when you simply need one of them).
Yes you can do this both programmatically and for all your activities making an AbstractActivity that all your activities extends.
public abstract class AbstractActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setRequestedOrientation (ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
}
}
This abstract activity can also be used for a global menu.
You can do this for your entire application without having to make all your activities extend a common base class.
The trick is first to make sure you include an Application subclass in your project. In its onCreate(), called when your app first starts up, you register an ActivityLifecycleCallbacks object (API level 14+) to receive notifications of activity lifecycle events.
This gives you the opportunity to execute your own code whenever any activity in your app is started (or stopped, or resumed, or whatever). At this point you can call setRequestedOrientation() on the newly created activity.
class MyApp extends Application {
#Override
public void onCreate() {
super.onCreate();
// register to be informed of activities starting up
registerActivityLifecycleCallbacks(new ActivityLifecycleCallbacks() {
#Override
public void onActivityCreated(Activity activity,
Bundle savedInstanceState) {
// new activity created; force its orientation to portrait
activity.setRequestedOrientation(
ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
}
....
});
}
}
You can set this in your manifest file..
android:name=".your launching activity name"
android:screenOrientation="portrait"
and you can also achive the same by writing the code in your class file like:
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
Add android:screenOrientation="portrait" to the activity in the AndroidManifest.xml. For example:
<activity android:name=".SomeActivity"
android:label="#string/app_name"
android:screenOrientation="portrait">
Use:
android:screenOrientation="portrait"
Just write this line in your application's manifest file in each activity which you want to show in portrait mode only.
Write this to your manifest file, for every activity:
android:screenOrientation="portrait"
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//setting screen orientation locked so it will be acting as potrait
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LOCKED);
}
As from Android developer guide :
"orientation" The screen orientation has changed — the user has
rotated the device. Note: If your application targets API level 13 or
higher (as declared by the minSdkVersion and targetSdkVersion
attributes), then you should also declare the "screenSize"
configuration, because it also changes when a device switches between
portrait and landscape orientations.
"screenSize" The current available screen size has changed. This
represents a change in the currently available size, relative to the
current aspect ratio, so will change when the user switches between
landscape and portrait. However, if your application targets API level
12 or lower, then your activity always handles this configuration
change itself (this configuration change does not restart your
activity, even when running on an Android 3.2 or higher device). Added
in API level 13.
So, in the AndroidManifest.xml file, we can put:
<activity
android:name=".activities.role_activity.GeneralViewPagerActivity"
android:label="#string/title_activity_general_view_pager"
android:screenOrientation="portrait"
android:configChanges="orientation|keyboardHidden|screenSize"
>
</activity>
Adding <preference name="orientation" value="portrait" /> under <widget> in my config.xml worked for me.
(The other solutions either didn't work on my device, were overwritten during building or gave deprecation errors during the build process.)
in Manifest file which activity you want to use in "portrait" you must write these code in Activity tag
android:screenOrientation="portrait"
like this
android:icon="#drawable/icon"
android:name="com.zemkoapps.hd.wallpaper.AndroidGridLayoutActivity"
android:screenOrientation="portrait" >
but if u want screen in landscape use this code like this
android:screenOrientation="landscape"
If anyone was wondering , how you could do this for your entire application without having to make all your activities extend a common base class in Kotlin ,
see the example below :
class InteractiveStoryApplication: Application() {
override fun onCreate() {
super.onCreate()
registerActivityLifecycleCallbacks(object: ActivityLifecycleCallbacks {
override fun onActivityCreated(activity: Activity?, savedInstanceState: Bundle?) {
activity?.requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_PORTRAIT
}
override fun onActivityPaused(activity: Activity?) {
}
override fun onActivityResumed(activity: Activity?) {
}
override fun onActivityDestroyed(activity: Activity?) {
}
override fun onActivitySaveInstanceState(activity: Activity?, outState: Bundle?) {
}
override fun onActivityStarted(activity: Activity?) {
}
override fun onActivityStopped(activity: Activity?) {
}
})
}
}
and then you have to add your common base class in AndroidManifest like so:
<application android:allowBackup="true"
android:name=".InteractiveStoryApplication"
You can do it in two ways .
Add android:screenOrientation="portrait" on your manifest file to
the corresponding activity
Add
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
to your activity in `onCreate() method
Similar to Graham Borland answer...but it seems you dont have to create Application class if you dont want...just create a Base Activity in your project
public class BaseActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_base);
setRequestedOrientation (ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
}
And extend this class instead of AppCompatActivity where you want to use Potrait Mode
public class your_activity extends BaseActivity {}
For Xamarin Users:
If you extends all your activities to a BaseActivity Just add:
this.RequestedOrientation = ScreenOrientation.Portrait;
This will resolve the problem. If you want any particular activity to be in landscape override this in OnActivityCreated. As:
this.Activity.RequestedOrientation = ScreenOrientation.Landscape;
Well,
I tried every answer but it didn't work in older versions of android.
So, the final solution is to add this code to every activity just above setContentView:
setRequestedOrientation (ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
In kotlin -->
Use this in your Extends Application class fun onCreate()...
registerActivityLifecycleCallbacks(object : ActivityLifecycleCallbacks {
override fun onActivityCreated(p0: Activity, p1: Bundle?) {
p0.requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE;
}
override fun onActivityStarted(p0: Activity) {
}
override fun onActivityResumed(p0: Activity) {
}
override fun onActivityPaused(p0: Activity) {
}
override fun onActivityStopped(p0: Activity) {
}
override fun onActivitySaveInstanceState(p0: Activity, p1: Bundle) {
}
override fun onActivityDestroyed(p0: Activity) {
}
}
)}
In your Manifest type this:
<activity
android:screenOrientation="portrait"
<!--- Rest of your application information ---!>
</activity>
I want to have an activity that can only be launched from certain other activites in my app, and not from others
At the moment, this works:
public abstract class Launcher extends Activity {
protected static boolean flag = true;
protected abstract void Launch();
public static class myPrivateActivity extends Activity {
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if(flag)
finish();
setContentView(R.layout.main);
}
}
}
public class SpecialActivity extends Launcher {
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.newlayout);
}
#Override
protected void Launch {
flag = false;
Intent i = new Intent(Intent.ACTION_VIEW);
String name = myPrivateActivity.class.getName();
i.setClassName(this, name );
startActivity(i);
//finish();
}
}
and in android manifest
<activity android:name=".Launcher$myPrivateActivity"
android:label="Private?">
However, I'd like to know if there is a better solution than just using a flag?
That's a creative approach. I don't think I've ever seen something like that before.
However, I don't think it accomplishes what you're trying to accomplish. If an approach like this were taken, it would probably make sense to "harden" it further by making the abstract base class and its inner static class package private, and any concrete public subclasses final. With these changes, then I don't think the flag would any longer provide any sort of protection.
However (again), do be aware that Android's permissions model provides for custom permissions, and may be used to achieve what I think you want to do. In fact, the document at http://developer.android.com/guide/topics/security/security.html describes how to "enforce your own permissions" to configure "an application that wants to control who can start one of its activities" in the "Declaring and Enforcing Permissions" section.
Does that get you closer to your goal?
I think you can use this:
android:permission
The name of a permission that clients must have to launch the activity or otherwise get it to respond to an intent. If a caller of startActivity() or startActivityForResult() has not been granted the specified permission, its intent will not be delivered to the activity.
If this attribute is not set, the permission set by the element's permission attribute applies to the activity. If neither attribute is set, the activity is not protected by a permission.
http://developer.android.com/guide/topics/manifest/activity-element.html#prmsn
In my Android application, when I rotate the device (slide out the keyboard) then my Activity is restarted (onCreate is called). Now, this is probably how it's supposed to be, but I do a lot of initial setting up in the onCreate method, so I need either:
Put all the initial setting up in another function so it's not all lost on device rotation or
Make it so onCreate is not called again and the layout just adjusts or
Limit the app to just portrait so that onCreate is not called.
Using the Application Class
Depending on what you're doing in your initialization you could consider creating a new class that extends Application and moving your initialization code into an overridden onCreate method within that class.
public class MyApplicationClass extends Application {
#Override
public void onCreate() {
super.onCreate();
// TODO Put your application initialization code here.
}
}
The onCreate in the application class is only called when the entire application is created, so the Activity restarts on orientation or keyboard visibility changes won't trigger it.
It's good practice to expose the instance of this class as a singleton and exposing the application variables you're initializing using getters and setters.
NOTE: You'll need to specify the name of your new Application class in the manifest for it to be registered and used:
<application
android:name="com.you.yourapp.MyApplicationClass"
Reacting to Configuration Changes [UPDATE: this is deprecated since API 13; see the recommended alternative]
As a further alternative, you can have your application listen for events that would cause a restart – like orientation and keyboard visibility changes – and handle them within your Activity.
Start by adding the android:configChanges node to your Activity's manifest node
<activity android:name=".MyActivity"
android:configChanges="orientation|keyboardHidden"
android:label="#string/app_name">
or for Android 3.2 (API level 13) and newer:
<activity android:name=".MyActivity"
android:configChanges="keyboardHidden|orientation|screenSize"
android:label="#string/app_name">
Then within the Activity override the onConfigurationChanged method and call setContentView to force the GUI layout to be re-done in the new orientation.
#Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
setContentView(R.layout.myLayout);
}
Update for Android 3.2 and higher:
Caution: Beginning with Android 3.2 (API level 13), the "screen size" also changes when the device switches between portrait and landscape orientation. Thus, if you want to prevent runtime restarts due to orientation change when developing for API level 13 or higher (as declared by the minSdkVersion and targetSdkVersion attributes), you must include the "screenSize" value in addition to the "orientation" value. That is, you must declare android:configChanges="orientation|screenSize". However, if your application targets API level 12 or lower, then your activity always handles this configuration change itself (this configuration change does not restart your activity, even when running on an Android 3.2 or higher device).
From http://web.archive.org/web/20120805085007/http://developer.android.com/guide/topics/resources/runtime-changes.html
Instead of trying to stop the onCreate() from being fired altogether, maybe try checking the Bundle savedInstanceState being passed into the event to see if it is null or not.
For instance, if I have some logic that should be run when the Activity is truly created, not on every orientation change, I only run that logic in the onCreate() only if the savedInstanceState is null.
Otherwise, I still want the layout to redraw properly for the orientation.
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_game_list);
if(savedInstanceState == null){
setupCloudMessaging();
}
}
not sure if this is the ultimate answer, but it works for me.
what I did...
in the manifest, to the activity section, added:
android:configChanges="keyboardHidden|orientation"
in the code for the activity, implemented:
//used in onCreate() and onConfigurationChanged() to set up the UI elements
public void InitializeUI()
{
//get views from ID's
this.textViewHeaderMainMessage = (TextView) this.findViewById(R.id.TextViewHeaderMainMessage);
//etc... hook up click listeners, whatever you need from the Views
}
//Called when the activity is first created.
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
InitializeUI();
}
//this is called when the screen rotates.
// (onCreate is no longer called when screen rotates due to manifest, see: android:configChanges)
#Override
public void onConfigurationChanged(Configuration newConfig)
{
super.onConfigurationChanged(newConfig);
setContentView(R.layout.main);
InitializeUI();
}
What you describe is the default behavior. You have to detect and handle these events yourself by adding:
android:configChanges
to your manifest and then the changes that you want to handle. So for orientation, you would use:
android:configChanges="orientation"
and for the keyboard being opened or closed you would use:
android:configChanges="keyboardHidden"
If you want to handle both you can just separate them with the pipe command like:
android:configChanges="keyboardHidden|orientation"
This will trigger the onConfigurationChanged method in whatever Activity you call. If you override the method you can pass in the new values.
Hope this helps.
I just discovered this lore:
For keeping the Activity alive through an orientation change, and handling it through onConfigurationChanged, the documentation and the code sample above suggest this in the Manifest file:
<activity android:name=".MyActivity"
android:configChanges="orientation|keyboardHidden"
android:label="#string/app_name">
which has the extra benefit that it always works.
The bonus lore is that omitting the keyboardHidden may seem logical, but it causes failures in the emulator (for Android 2.1 at least): specifying only orientation will make the emulator call both OnCreate and onConfigurationChanged sometimes, and only OnCreate other times.
I haven't seen the failure on a device, but I have heard about the emulator failing for others. So it's worth documenting.
You might also consider using the Android platform's way of persisting data across orientation changes: onRetainNonConfigurationInstance() and getLastNonConfigurationInstance().
This allows you to persist data across configuration changes, such as information you may have gotten from a server fetch or something else that's been computed in onCreate or since, while also allowing Android to re-layout your Activity using the xml file for the orientation now in use.
See here or here.
It should be noted that these methods are now deprecated (although still more flexible than handling orientation change yourself as most of the above solutions suggest) with the recommendation that everyone switch to Fragments and instead use setRetainInstance(true) on each Fragment you want to retain.
The approach is useful but is incomplete when using Fragments.
Fragments usually get recreated on configuration change. If you don't wish this to happen, use
setRetainInstance(true); in the Fragment's constructor(s)
This will cause fragments to be retained during configuration change.
http://developer.android.com/reference/android/app/Fragment.html#setRetainInstance(boolean)
I just simply added:
android:configChanges="keyboard|keyboardHidden|orientation"
in the AndroidManifest.xml file and did not add any onConfigurationChanged method in my activity.
So every time the keyboard slides out or in nothing happens! Also checkout this article about this problem.
The onCreate method is still called even when you change the orientation of android. So moving all the heavy functionality to this method is not going to help you
Put the code below inside your <activity> tag in Manifest.xml:
android:configChanges="screenLayout|screenSize|orientation"
It is very simple just do the following steps:
<activity
android:name=".Test"
android:configChanges="orientation|screenSize"
android:screenOrientation="landscape" >
</activity>
This works for me :
Note: orientation depends on your requitement
onConfigurationChanged is called when the screen rotates.
(onCreate is no longer called when the screen rotates due to manifest, see:
android:configChanges)
What part of the manifest tells it "don't call onCreate()"?
Also,
Google's docs say to avoid using android:configChanges (except as a last resort). But then the alternative methods they suggest all DO use android:configChanges.
It has been my experience that the emulator ALWAYS calls onCreate() upon rotation.
But the 1-2 devices that I run the same code on... do not.
(Not sure why there would be any difference.)
Changes to be made in the Android manifest are:
android:configChanges="keyboardHidden|orientation"
Additions to be made inside activity are:
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
// Checks the orientation of the screen
if (newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE) {
Toast.makeText(this, "landscape", Toast.LENGTH_SHORT).show();
} else if (newConfig.orientation == Configuration.ORIENTATION_PORTRAIT) {
Toast.makeText(this, "portrait", Toast.LENGTH_SHORT).show();
}
}
Add this line to your manifest :-
android:configChanges="orientation|keyboard|keyboardHidden|screenSize|screenLayout|uiMode"
and this snippet to the activity :-
#Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
WindowManager.LayoutParams.FLAG_FULLSCREEN);
}
There are several ways to do this:
Save Activity State
You can save the activity state in onSaveInstanceState.
#Override
public void onSaveInstanceState(Bundle outState) {
/*Save your data to be restored here
Example: outState.putLong("time_state", time); , time is a long variable*/
super.onSaveInstanceState(outState);
}
and then use the bundle to restore the state.
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if(savedInstanceState!= null){
/*When rotation occurs
Example : time = savedInstanceState.getLong("time_state", 0); */
} else {
//When onCreate is called for the first time
}
}
Handle orientation changes by yourself
Another alternative is to handle the orientation changes by yourself. But this is not considered a good practice.
Add this to your manifest file.
android:configChanges="keyboardHidden|orientation"
for Android 3.2 and later:
android:configChanges="keyboardHidden|orientation|screenSize"
#Override
public void onConfigurationChanged(Configuration config) {
super.onConfigurationChanged(config);
if (newConfig.orientation == Configuration.ORIENTATION_PORTRAIT) {
//Handle rotation from landscape to portrait mode here
} else if (newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE){
//Handle rotation from portrait to landscape mode here
}
}
Restrict rotation
You can also confine your activity to portrait or landscape mode to avoid rotation.
Add this to the activity tag in your manifest file:
android:screenOrientation="portrait"
Or implement this programmatically in your activity:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
}
The way I have found to do this is use the onRestoreInstanceState and the onSaveInstanceState events to save something in the Bundle (even if you dont need any variables saved, just put something in there so the Bundle isn't empty). Then, on the onCreate method, check to see if the Bundle is empty, and if it is, then do the initialization, if not, then do it.
Even though it is not "the Android way" I have gotten very good results by handling orientation changes myself and simply repositioning the widgets within a view to take the altered orientation into account. This is faster than any other approach, because your views do not have to be saved and restored. It also provides a more seamless experience to the user, because the respositioned widgets are exactly the same widgets, just moved and/or resized. Not only model state, but also view state, can be preserved in this manner.
RelativeLayout can sometimes be a good choice for a view that has to reorient itself from time to time. You just provide a set of portrait layout params and a set of landscaped layout params, with different relative positioning rules on each, for each child widget. Then, in your onConfigurationChanged() method, you pass the appropriate one to a setLayoutParams() call on each child. If any child control itself needs to be internally reoriented, you just call a method on that child to perform the reorientation. That child similarly calls methods on any of its child controls that need internal reorientation, and so on.
Every time when the screen is rotated, opened activity is finished and onCreate() is called again.
1 . You can do one thing save the state of activity when the screen is rotated so that, You can recover all old stuff when the activity's onCreate() is called again.
Refer this link
2 . If you want to prevent restarting of the activity just place the following lines in your manifest.xml file.
<activity android:name=".Youractivity"
android:configChanges="orientation|screenSize"/>
you need to use the onSavedInstanceState method to store all the values to its parameter is has which is a bundle
#Override
public void onSaveInstanceState(Bundle outState, PersistableBundle outPersistentState) {
super.onSaveInstanceState(outState, outPersistentState);
outPersistentState.putBoolean("key",value);
}
and use
#Override
protected void onRestoreInstanceState(Bundle savedInstanceState) {
super.onRestoreInstanceState(savedInstanceState);
savedInstanceState.getBoolean("key");
}
to retrieve and set the value to view objects
it will handle the screen rotations
Note: I post this answer if someone in the future face the same problem as me. For me the following line wasn't enough:
android:configChanges="orientation"
When I rotated the screen, the method `onConfigurationChanged(Configuration new config) didn't get called.
Solution: I also had to add "screenSize" even if the problem had to do with the orientation. So in the AndroidManifest.xml - file, add this:
android:configChanges="keyboardHidden|orientation|screenSize"
Then implement the method onConfigurationChanged(Configuration newConfig)
In the activity section of the manifest, add:
android:configChanges="keyboardHidden|orientation"
Add this line in manifest : android:configChanges="orientation|screenSize"
People are saying that you should use
android:configChanges="keyboardHidden|orientation"
But the best and most professional way to handle rotation in Android is to use the Loader class. It's not a famous class(I don't know why), but it is way better than the AsyncTask. For more information, you can read the Android tutorials found in Udacity's Android courses.
Of course, as another way, you could store the values or the views with onSaveInstanceState and read them with onRestoreInstanceState. It's up to you really.
One of the best components of android architecture introduced by google will fulfill all the requirements that are ViewModel.
That is designed to store and manage UI-related data in a lifecycle way plus that will allow data to survive as the screen rotates
class MyViewModel : ViewModel() {
Please refer to this: https://developer.android.com/topic/libraries/architecture/viewmodel
After a while of trial and error, I found a solution which fits my needs in the most situations. Here is the Code:
Manifest configuration:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.pepperonas.myapplication">
<application
android:name=".App"
android:allowBackup="true"
android:icon="#mipmap/ic_launcher"
android:label="#string/app_name"
android:supportsRtl="true"
android:theme="#style/AppTheme">
<activity
android:name=".MainActivity"
android:configChanges="orientation|keyboardHidden|screenSize">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
</application>
</manifest>
MainActivity:
import android.content.res.Configuration;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentTransaction;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.View;
import android.widget.Button;
public class MainActivity extends AppCompatActivity implements View.OnClickListener {
private static final String TAG = "MainActivity";
private Fragment mFragment;
private int mSelected = -1;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Log.d(TAG, "onCreate " + "");
// null check not realy needed - but just in case...
if (savedInstanceState == null) {
initUi();
// get an instance of FragmentTransaction from your Activity
FragmentManager fragmentManager = getSupportFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
/*IMPORTANT: Do the INITIAL(!) transaction only once!
* If we call this everytime the layout changes orientation,
* we will end with a messy, half-working UI.
* */
mFragment = FragmentOne.newInstance(mSelected = 0);
fragmentTransaction.add(R.id.frame, mFragment);
fragmentTransaction.commit();
}
}
#Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
Log.d(TAG, "onConfigurationChanged " +
(newConfig.orientation
== Configuration.ORIENTATION_LANDSCAPE
? "landscape" : "portrait"));
initUi();
Log.i(TAG, "onConfigurationChanged - last selected: " + mSelected);
makeFragmentTransaction(mSelected);
}
/**
* Called from {#link #onCreate} and {#link #onConfigurationChanged}
*/
private void initUi() {
setContentView(R.layout.activity_main);
Log.d(TAG, "onCreate instanceState == null / reinitializing..." + "");
Button btnFragmentOne = (Button) findViewById(R.id.btn_fragment_one);
Button btnFragmentTwo = (Button) findViewById(R.id.btn_fragment_two);
btnFragmentOne.setOnClickListener(this);
btnFragmentTwo.setOnClickListener(this);
}
/**
* Not invoked (just for testing)...
*/
#Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
Log.d(TAG, "onSaveInstanceState " + "YOU WON'T SEE ME!!!");
}
/**
* Not invoked (just for testing)...
*/
#Override
protected void onRestoreInstanceState(Bundle savedInstanceState) {
super.onRestoreInstanceState(savedInstanceState);
Log.d(TAG, "onSaveInstanceState " + "YOU WON'T SEE ME, AS WELL!!!");
}
#Override
protected void onResume() {
super.onResume();
Log.d(TAG, "onResume " + "");
}
#Override
protected void onPause() {
super.onPause();
Log.d(TAG, "onPause " + "");
}
#Override
protected void onDestroy() {
super.onDestroy();
Log.d(TAG, "onDestroy " + "");
}
#Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.btn_fragment_one:
Log.d(TAG, "onClick btn_fragment_one " + "");
makeFragmentTransaction(0);
break;
case R.id.btn_fragment_two:
Log.d(TAG, "onClick btn_fragment_two " + "");
makeFragmentTransaction(1);
break;
default:
Log.d(TAG, "onClick null - wtf?!" + "");
}
}
/**
* We replace the current Fragment with the selected one.
* Note: It's called from {#link #onConfigurationChanged} as well.
*/
private void makeFragmentTransaction(int selection) {
switch (selection) {
case 0:
mFragment = FragmentOne.newInstance(mSelected = 0);
break;
case 1:
mFragment = FragmentTwo.newInstance(mSelected = 1);
break;
}
// Create new transaction
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
// Replace whatever is in the fragment_container view with this fragment,
// and add the transaction to the back stack
transaction.replace(R.id.frame, mFragment);
/*This would add the Fragment to the backstack...
* But right now we comment it out.*/
// transaction.addToBackStack(null);
// Commit the transaction
transaction.commit();
}
}
And sample Fragment:
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
/**
* #author Martin Pfeffer (pepperonas)
*/
public class FragmentOne extends Fragment {
private static final String TAG = "FragmentOne";
public static Fragment newInstance(int i) {
Fragment fragment = new FragmentOne();
Bundle args = new Bundle();
args.putInt("the_id", i);
fragment.setArguments(args);
return fragment;
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
Log.d(TAG, "onCreateView " + "");
return inflater.inflate(R.layout.fragment_one, container, false);
}
}
Can be found on github.
Use orientation listener to perform different tasks on different orientation.
#Override
public void onConfigurationChanged(Configuration myConfig)
{
super.onConfigurationChanged(myConfig);
int orient = getResources().getConfiguration().orientation;
switch(orient)
{
case Configuration.ORIENTATION_LANDSCAPE:
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
break;
case Configuration.ORIENTATION_PORTRAIT:
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
break;
default:
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED);
}
}
Put this below code in your Activity in Android Manifest.
android:configChanges="orientation"
This will not restart your activity when you would change orientation.
Fix the screen orientation (landscape or portrait) in AndroidManifest.xml
android:screenOrientation="portrait" or android:screenOrientation="landscape"
for this your onResume() method is not called.
You may use the ViewModel object in your activity.
ViewModel objects are automatically retained during configuration changes so that the data they hold is immediately available to the next activity or fragment instance.
Read more:
https://developer.android.com/topic/libraries/architecture/viewmodel