Activity created twice
Asked Answered
I

5

8

I have set locked orientation

enter image description here

and added the sample code with 2 simple classes like below:

SplashLandscapeActivity.java

public class SplashLandscapeActivity extends AppCompatActivity {
    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        Log.d("start", "xxxx start Activity SplashLandscapeActivity");
        new Handler().postDelayed(new Runnable() {
            @Override
            public void run() {
                startActivity(new Intent(SplashLandscapeActivity.this, TestActivity.class));
                finish();
            }
        }, 500);
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        Log.d("start", "xxxx onDestroy Activity SplashLandscapeActivity");
    }
}

TestActivity.java

public class TestActivity extends AppCompatActivity {

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        Log.d("start", "xxxx start Activity TestActivity "
                + getResources().getConfiguration().orientation);
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        Log.d("start", "xxxx onDestroy Activity TestActivity "
                + getResources().getConfiguration().orientation);
    }
}

AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example">

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <activity
            android:name=".SplashLandscapeActivity"
            android:theme="@style/SplashTheme"
            android:screenOrientation="landscape">
            <intent-filter>
                <action android:name="android.intent.action.MAIN"/>

                <category android:name="android.intent.category.LAUNCHER"/>
            </intent-filter>
        </activity>

        <activity
            android:name=".TestActivity"
            android:screenOrientation="portrait"/>
    </application>
</manifest>

When I use new Handler().postDelayed (SplashLandscapeActivity.java) to start TestActivity, It's started twice, the first one has Landscape orientation then switch back to portrait. The log showed it all:

xxxx start Activity SplashLandscapeActivity

xxxx start Activity TestActivity 2 // <== landscape

xxxx onDestroy Activity TestActivity 1

xxxx start Activity TestActivity 1 // <== portrait

xxxx onDestroy Activity SplashLandscapeActivity

And if I remove that Handler, TestActivity now started with portrait like normal.

xxxx start Activity SplashLandscapeActivity

xxxx start Activity TestActivity 1

xxxx onDestroy Activity SplashLandscapeActivity

So, my question is:

1- Is this system issue or its intended behavior? Why activity is restarted even the screenOrientation was set fixed in Manifest?

2- Actually, my real project do not have any Handler but has the same issue that activity started twice (after start with Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK). How can I deal with this issue?

Illtempered answered 22/5, 2017 at 3:14 Comment(9)
Have you tried modifying your Manifest orientation. Like keeping both in portrait modeCooky
What do you mean? I use them to simulate my issue. Anyway, my expected is this activity never started twice.Illtempered
If the handler was removed and you've launched the app while your device is in locked portrait , does the app rotates like momentarily before reaching TestActivity? or does it directly jump to TestActivity in portrait without rotating? My guess is this could be due to the config changes being called after the activity has onCreate and probably onResume executed, and if no config changes happened like when skipping the SplashLandscapeActivity and directly starting TestActivity it wouldn't be called hence it wouldn't restart TestActivity.Ludwigg
@Ludwigg onConfigurationChanged is never called on TestActivity, even if it was restarted by system (I guessed).Illtempered
I can give one tip, You can check onSaveInstanceState from onCreate method, second recreation of activity will have something different than null.Ambience
@deadfish, It's the basic knowledge and I hope the fix was easy like what you talked, but it wasn't . Also, can you answer me why activity is restarted even the screenOrientation was set fixed in Manifest?Illtempered
you shouldn't worry about why android creates and destroys these activities on rotation, your activity should gracefully handle recreation.Hugmetight
@Hugmetight Ofcause my activity is rotation successful, but my UI and logic code are failed because activity was initialized twice (onCreate, onResume)Illtempered
@Illtempered you'll need to fix your "UI and logic code" then.Hugmetight
R
4

In your manifest file edit the TestActivity block like this

<activity android:name=".TestActivity" android:launchMode="singleInstance" android:screenOrientation="portrait"/>

Ronaronal answered 31/5, 2017 at 12:19 Comment(0)
M
2

There are 2 comments to prevent TestActivity start twice. Hope Help you

  1. use sensorPortrait instead of portraitin the TestActivity. And the TestActivity will not start twice, but it will rotate it to match the way in which the device is held by the user.
  2. add android:configChanges="keyboardHidden|orientation|screenSize" to the TestAcitivty in your Manifest.xml.It will call public void onConfigurationChanged(Configuration newConfig) instead of restart.

I have not found this issue in Android N.

Morganite answered 27/5, 2017 at 6:56 Comment(3)
How about if UI is different between Land and Port, Is setContentView in onConfigurationChanged recommended? Also, can you answer me why activity is restarted even the screenOrientation was set fixed in Manifest?Illtempered
I have not found any official document to talk about why activity restart when the screenOrientation is not same as the starter. BUT it seem that android start activity with portrait because of starter is portrait, and ignore the current landscape state. The reason seems to be to predict the state you are using。So you have to handle this problem at runtime.linkMorganite
Not sure about starter or any relation, because without handler, activity is started exactly same manifest config. Anyway, thanks for your time, the main idea of this question is not about How to fix..., it's about why....Illtempered
B
1

I think you need to add the flag

android:configChanges="orientation|screenSize"

to your TestActivity in manifest file to look like this:

<activity
android:name=".TestActivity"
android:screenOrientation="portrait"
android:configChanges="orientation|screenSize"
/>

This should solve your problem.

Reason, why config changes is required is: Now regarding why configChanges is required is, from android docs:

If your application doesn't need to update resources during a specific configuration change and you have a performance limitation that requires you to avoid the activity restart, then you can declare that your activity handles the configuration change itself, which prevents the system from restarting your activity.

Visit android doc

Bite answered 31/5, 2017 at 9:34 Comment(6)
Your answered does not resolve my question. See my comment hereIlltempered
Have you tried. I got the following logs with the changes I suggested: D/start: xxxx start Activity TestActivity 1 D/start: xxxx onDestroy Activity SplashLandscapeActivityBite
Like my other comments, your answer is not focused on my question. Why do I need to set configChanges option while I already set fixed screenOrientation?Illtempered
But does it solves the issue? That's first concern. See my updated answer.Bite
No, it's not easy to fix my real project with your simple code, it causes many side effects. I want to ask my question here to find out the root cause of my issue that Why do I need to set configChanges option while I already set fixed screenOrientation?.Illtempered
As per your sample code, there are two activities, one in landscape and other in portrait. Android will honor the orientations as per the manifest declaration. Switching from one orientation to another will recreate your activities, unless you want to handle the configuration change by yourself. For more info on this, visit the android doc link specified in my updated answer. Hope that helps! And what side effects are you talking about? May be you need to re visit the way you have written you project?Bite
S
1

Update your manifest.xml

 <?xml version="1.0" encoding="utf-8"?>
    <manifest xmlns:android="http://schemas.android.com/apk/res/android"
        package="com.example">

        <application
            android:allowBackup="true"
            android:icon="@mipmap/ic_launcher"
            android:label="@string/app_name"
            android:supportsRtl="true"
            android:theme="@style/AppTheme">
            <activity
                android:name=".SplashLandscapeActivity"
                android:theme="@style/SplashTheme"
                android:screenOrientation="landscape"
            android:configChanges="keyboardHidden|orientation|screenSize">
                <intent-filter>
                    <action android:name="android.intent.action.MAIN"/>

                    <category android:name="android.intent.category.LAUNCHER"/>
                </intent-filter>
            </activity>

            <activity
                android:name=".TestActivity"
                android:screenOrientation="portrait"
android:configChanges="keyboardHidden|orientation|screenSize"/>
        </application>
    </manifest>
Skidmore answered 31/5, 2017 at 16:39 Comment(2)
I don't like the configChanges options, also your answer is not focused on my question.Illtempered
if you don't want configChanges then you should use this <activity android:name=".TestActivity" android:launchMode="singleInstance" android:taskAffinity=""> for more details : inthecheesefactory.com/blog/…Skidmore
O
0

Can change MainActicity to

public class SplashLandscapeActivity extends AppCompatActivity {
    static boolean isRunStop = false;
    static int counter = 0;
    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
            counter++;
            Log.d("start", "xxxx run handler SplashLandscapeActivity. Time : "+counter);
            Toast.makeText(SplashLandscapeActivity.this, ""+counter, Toast.LENGTH_SHORT).show();
            new Handler().postDelayed(new Runnable() {
            @Override
            public void run() {
                Log.d("start", "xxxx run handler SplashLandscapeActivity");
                if(!isRunStop )
                {
                      startActivity(new Intent(SplashLandscapeActivity.this, TestActivity.class));
                      isRunStop =true;
                      finish();
                }

            }
        }, 500);
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        Log.d("start", "xxxx onDestroy Activity SplashLandscapeActivity");
    }
}

Handler is called in another thread that does not go away when you change your screen orientation previous handler gone and runs. You can have more time to test handler several times to change the screen orientation.

Overwork answered 31/5, 2017 at 18:23 Comment(5)
Your answer is not focused on my question. Also, as I said the startActivity called only 1 time, but the TestActivity started twice.Illtempered
Log Log.d("start", "xxxx run handler SplashLandscapeActivity"); this code run twice.Overwork
Which your emulator version? On all my emulators, Handler just runs only 1 time.Illtempered
My emulator version is 23. For test, change increase time from 500 to 5000 and change quickly screen orientation .Overwork
Thanks for your time, but I don't want you try to make new cases.Illtempered

© 2022 - 2024 — McMap. All rights reserved.