15

I would like to have two main activities in my app. So in my manifest I put:

<activity
    android:name="mypackage1.MainActivity"
    android:label="@string/title_activity_main">

    <intent-filter>
        <action android:name="android.intent.action.MAIN" />

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

<activity
    android:name="mypackage2.MainActivity2"
    android:label="@string/title_activity_main2">

    <intent-filter>
        <action android:name="android.intent.action.MAIN" />

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

</activity>

Two icons are created in my apps menu. But when I click on each of them the first activity MainActivity is always launched. Is it possible to have two main activities? If so, what's wrong with what I did? Thanks

Tim Biegeleisen
  • 502,043
  • 27
  • 286
  • 360
Gyonder
  • 3,674
  • 7
  • 32
  • 49

3 Answers3

21

The LAUNCHER intent filter is what determines what shows up in the app drawer/launcher. That is why you get two icons shown up.

However, you also set the DEFAULT intent filter, which sets the default Activity for the whole package. Since you set it twice, you get the problem of precedence of the first/latest registered. When you remove the DEFAULT filter, you will be able to start whatever you click on in the launcher.

In short, remove the following line from both Activities:

<category android:name="android.intent.category.DEFAULT" /> 
Shade
  • 9,936
  • 5
  • 60
  • 85
14

Yes, just mark two or more of your <activity>s as LAUNCHER within your manifest. In addition you have to set the android:taskAffinity attribute on both of your Launcher-Activities which specify the exact package and Activity to be started.

<activity android:label="MyApp" android:name=".MyApp" android:taskAffinity="com.example.MainActivity">
        <intent-filter>
            <action android:name=".MyApp"/>
            <action android:name="android.intent.action.MAIN"/>
            <category android:name="android.intent.category.LAUNCHER"/>
        </intent-filter>
</activity>


<activity android:label="Settings" android:name=".Settings" android:taskAffinity="com.example.SettingsActivity" >
    <intent-filter>
        <action android:name=".Settings"/>
        <action android:name="android.intent.action.MAIN"/>
        <category android:name="android.intent.category.LAUNCHER"/>
    </intent-filter>
</activity>
poitroae
  • 21,129
  • 10
  • 63
  • 81
  • From the docs - "By default, all activities in an application have the same affinity.", so you don't have to set it. – Shade Mar 20 '13 at 14:53
  • 1
    I read the question, and tried it out in a test app. My answer is valid and works just fine. You don't have to set a different affinity. – Shade Mar 20 '13 at 14:56
  • 2
    Well it works as @poitroae suggested. So I'm going to accept it as correct. – Gyonder Mar 20 '13 at 14:58
  • @Gyonder, sure it does - I suggest mostly the same thing without the irrelevant task affinity setting. You're doing something that is not necessary and you don't understand. – Shade Mar 20 '13 at 14:59
  • @poitroae, the LAUNCHER filter is what determines what shows up in the app drawer/launcher. The DEFAULT was the problem in this case, since that was setting the default activity for the whole package. When you remove that, you start whatever you click on in the launcher. – Shade Mar 20 '13 at 15:02
  • Ok @Shade, I see your point. Your answer is better. I 'll go for your and put a plus to poitroae.thanks – Gyonder Mar 20 '13 at 15:04
  • Thanks. Will extend the answer with the above comment for future reference. – Shade Mar 20 '13 at 15:05
  • 16
    I'm late to the party: having the taskAffinity set on one launcher activity (A) solves an issue where clicking the the second launcher (B) in the app drawer/launcher opens the in-memory activity (A) of the application versus opening the intended activity (B). – wblaschko Aug 26 '14 at 23:32
0

Use android:documentLaunchMode="intoExisting", to launch a separate task based on the intent's Component name and data URI. Without this (by default), the activity will share all the same activities, as android:documentLaunchMode default to none.

intoExisting: The system searches for a task whose base intent's ComponentName and data URI match those of the launching intent. If the system finds such a task, the system clears the task, and restarts with the root activity receiving a call to onNewIntent(android.content.Intent). If the system does not find such a task, the system creates a new task. source

    <activity
        android:name=".CameraActivity"
        android:exported="true"
        android:documentLaunchMode="intoExisting"
        android:label="@string/app_1_label">
        <intent-filter>
            <action android:name="android.intent.action.MAIN" />
            <category android:name="android.intent.category.LAUNCHER" />
        </intent-filter>
    </activity>

    <activity
        android:name=".ProfilePoseNetActivity"
        android:exported="true"
        android:documentLaunchMode="intoExisting"
        android:label="@string/app_2_label">
        <intent-filter>
            <action android:name="android.intent.action.MAIN" />
            <category android:name="android.intent.category.LAUNCHER" />
        </intent-filter>
    </activity>

The intention of potroae using task affinities to prevent your 2 activities from sharing the same task. However, it is annoying to have to select a task name, i.e. com.example/SettingsActivity for every task you want to launch separately.

Ben Butterworth
  • 22,056
  • 10
  • 114
  • 167