重新启动主页按钮上的活动,但...只有第一次

53
我正在开发的应用程序在第一次安装时会有奇怪的行为。如果用户第一次正常退出应用程序,则它将永远按照应该的方式工作。如果用户在安装应用程序后第一次使用主屏幕按钮,则它会将应用程序视为应该重新启动主屏幕并在旧版本的活动前启动新版本。

因此,实际上存在两个问题。我似乎无法解决它们两个。
  1. 当用户点击主屏幕按钮以退出首次安装的应用程序时,使应用程序保持不关闭。
  2. 在这样做时,防止多个应用程序版本启动(launchMode 在这里有所帮助,但第一个组件仍然会触发)。
我的清单文件中没有定义 launchMode 属性为任何值。因此,不应出现任何奇怪的行为。我已经尝试使用应用程序的 launchmode 属性进行了实验,以查看是否可以使其按预期方式工作,但这里似乎还有更多要考虑的。在我看来,当按下主屏幕按钮时,应用程序没有理由自己关闭第一次。
我也没有在应用程序内使用 onUserLeaveHint。我必须再次通过对项目进行搜索来确保。因此,似乎根本没有尝试覆盖主屏幕按钮。
即使重新启动手机,主屏幕按钮也会再次正常工作。不确定导致初始安装将主屏幕按钮视为启动应用程序的标志的原因是什么。
一旦用户第一次退出应用程序,问题就永远得到解决。您认为我应该在哪里查找?

最近进行了应用程序内搜索,以查看是否由于 SQLite 数据库方法的 onUpgrade() 组件而触发了一些奇怪的行为。
@Override
public void onUpgrade (SQLiteDatabase db, int oldVersion, int newVersion) {
                if (newVersion > oldVersion) {

           }
       }

或者在另一个位置,如果我传递给已经安装了低于当前版本的设备一个更新版本的APK,则可能会通过清单文件触发。但是,代码的这一部分并没有让我相信它应该影响与启动顺序相关的任何内容。

下面提供了当前应用程序中使用的清单文件(名称已更改)。

<uses-sdk android:minSdkVersion="10" android:targetSdkVersion="10"/>

<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"></uses-permission>
<uses-permission android:name="android.permission.INTERNET"></uses-permission>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"></uses-permission>
<uses-permission android:name="com.android.vending.CHECK_LICENSE"></uses-permission>
<uses-permission android:name="android.permission.BLUETOOTH"/>
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/>

<uses-permission android:name="android.permission.VIBRATE" android:required="false"/>
<uses-permission android:name="android.permission.CAMERA" android:required="false"/>
<uses-feature android:name="android.hardware.camera" android:required="false"/>
<uses-feature android:name="android.hardware.camera.autofocus" android:required="false"/>

<application android:icon="@drawable/icon"
             android:label="@string/app_name"
             android:allowBackup="false"
             android:theme="@android:style/Theme.Black.NoTitleBar.Fullscreen"
             >
    <activity android:name=".MyMain"
              android:label="@string/app_name_with_version"
              android:screenOrientation="portrait"
              android:windowSoftInputMode="adjustPan"   />
    <activity android:name=".StartupActivity"
              android:label="@string/app_name"
              android:screenOrientation="portrait"
              >
        <intent-filter>
            <action android:name="android.intent.action.MAIN" />
            <category android:name="android.intent.category.LAUNCHER" />
        </intent-filter>
    </activity>
    <activity   android:name=".SelectActivity"  
                android:label="@string/app_name_with_version"
                android:screenOrientation="portrait"/>
    <activity   android:name=".ImageSelectionActivity"
                android:theme="@android:style/Theme.Dialog"
                android:label="@string/app_name_with_version"
                android:screenOrientation="portrait"
                android:configChanges="orientation|keyboardHidden"/>            
    <activity   android:name=".DetailsActivity"
                android:label="@string/app_name_with_version"
                android:screenOrientation="portrait"/>
    <activity   android:name=".EMailActivity"   
                android:label="@string/app_name_with_version"       
                android:screenOrientation="portrait"/>
    <activity   android:name=".SendTo" 
                android:label="@string/share_label" 
                android:theme="@android:style/Theme.Dialog" >
        <INTENT-FILTER>  
            <ACTION android:name="android.intent.action.MAIN">  
            <CATEGORY android:name="android.intent.category.LAUNCHER"/>  
            <INTENT-FILTER>  
                <ACTION android:name="android.intent.action.VIEW">  
                <CATEGORY android:name="android.intent.category.DEFAULT">  
                    <CATEGORY android:name="android.intent.category.BROWSABLE">  
                    <DATA android:scheme="callback" android:host="twitter"/>  
                    </CATEGORY>  
                </CATEGORY>
                </ACTION>
            </INTENT-FILTER>
            </ACTION>
        </INTENT-FILTER>
    </activity>
    <activity   android:name=".CreateMyActivity"
                android:label="@string/create_account_label"
                android:screenOrientation="portrait"
                android:theme="@android:style/Theme.Dialog"/>
    <activity   android:name=".ViewInLayoutActivity"
                android:label="@string/app_name_with_version"   
                android:screenOrientation="portrait"/>
    <activity   android:name=".Preferences"
                android:label="@string/set_preferences" 
                android:screenOrientation="portrait"
                android:theme="@android:style/Theme.Dialog"/>
    <activity   android:name=".AboutActivity"   
                android:label="@string/app_name_with_version"       
                android:screenOrientation="portrait"/>
    <activity   android:name=".InteractiveActivity" 
                android:label="@string/app_name_with_version"
                android:screenOrientation="portrait"
                android:theme="@android:style/Theme.Dialog"/>   
    <activity   android:name=".AlertFailedCommunications"
                android:screenOrientation="portrait"
                android:label="@string/alert_account_label"
                android:theme="@android:style/Theme.Dialog"/>
</application>    


实际上,这种情况只会在首次使用APK分发时发生。如果从IDE(Eclipse)卸载并重新启动,则不会在首次启动时发生这种情况。因此,这必须与远程安装有关,并且与直接安装不同。 - Jay Snayder
此外,这仅会在从安装窗口立即启动时发生。如果安装后关闭,然后从主屏幕或应用程序窗口启动它,则第一次启动永远不会进入此状态。必须有某些关于第一个窗口的生命周期导致了这种情况。 - Jay Snayder
有很多警告关于使用单个实例,你可能只是其中一个。据我所读,单个实例会使活动成为后堆栈中唯一的任务,而我认为你不希望这样做。你没有发布你的代码,所以我无法给出其他答案。请发布你的清单文件和你所提到的主要活动,我将能够给出更好的答案。 - Lettings Mall
@JaySnayder 我也遇到了同样的问题。我在一个活动中重写了onUserLeaveHint方法,一旦我使用主屏幕将应用程序置于后台并使用启动器或快捷图标再次启动它,应用程序就会重新启动。是重写onUserLeaveHint导致这种情况吗?这只会在第一次从PlayStore安装时发生。 - Aditya Kamath
4个回答

91
欢迎加入那些曾经被这个问题困扰的Android用户之列。
这是一个众所周知且长期存在的Android bug。它与应用程序首次从安装程序、Web浏览器和通过IDE(IntelliJ,Eclipse等)启动方式有关。请参阅与该问题相关的早期已提交的问题:

http://code.google.com/p/android/issues/detail?id=2373

http://code.google.com/p/android/issues/detail?id=26658

这仍然存在问题,你无法阻止其发生。你唯一能做的就是检测Android是否已经将你的根Activity启动到了现有任务中的第二个实例。你可以在根Activity的onCreate()方法中加入以下代码来实现:
if (!isTaskRoot()) {
    // Android launched another instance of the root activity into an existing task
    //  so just quietly finish and go away, dropping the user back into the activity
    //  at the top of the stack (ie: the last state of this task)
    finish();
    return;
}

1
请参见https://dev59.com/aW855IYBdhLWcg3wcz1h。 - Neil Townsend
1
我一直担心会是这样的情况。至少QA允许我们在程序中继续处理这个问题。在未来的版本中,我会使用你向我展示的解决方法,但需要先进行一些测试。非常感谢。 - Jay Snayder
3
很高兴为您翻译。如果您能前往Google Code上引用的问题并点赞/评论,我会非常感激。我们越是大力宣传此事,就越有可能在以后的版本中得到解决。作为临时解决办法,您可以告诉用户不要在安装应用程序后点击"打开"按钮。还要注意,这在通过安装程序升级应用程序后也会发生。 - David Wasser
1
同样也加星标了这些问题。你说得对,我们在这些问题上制造的噪音越多越好。这是一个奇怪的问题,很多人可能甚至不知道它的存在或者直到被人提出来并演示之前都不知道它正在发生。 - Jay Snayder
1
@UrielFrankel 请开新问题并展示问题。我们不能在另一个问题的评论线程中解决此问题。 - David Wasser
显示剩余23条评论

6

我不知道为什么会出现这种行为。但我知道自定义的Launcher有特定的launchModes设置。

例如ADW.Launcher:

android:clearTaskOnLaunch="true"
android:launchMode="singleTask" 

Android SDK示例中的主页应用程序:android-sdk\samples\android-16\Home\AndroidManifest.xml

android:launchMode="singleInstance"

引用了CommonsWare的话:如何防止自定义主页启动器应用程序重新启动活动?

我正在使用SDK中的Home示例应用程序,它使用singleInstance。有趣的是,AOSP启动器使用singleTask。


感谢您的反馈。我之前尝试过使用不同的launchModes来运行主类,这在一定程度上解决了问题,但仍会导致应用程序在按下Home键时关闭。虽然这可以防止Activity创建多个副本。 - Jay Snayder
此外,我发现当我按照指示实现lanchMode时,每次按下主页按钮应用程序都会关闭,而不仅仅是第一次。这是一个很大的缺点。 - Jay Snayder

2

以上的答案对我在使用Nativescript时没有用 - 通过在activity标签中添加这两个属性解决了问题:

android:alwaysRetainTaskState="true"
android:launchMode="singleTask"

这个链接提供了解决方案:https://github.com/NativeScript/NativeScript/issues/3415

2

看起来问题是由于应用程序的不同实例引起的。可能第一个实例是在安装程序的任务下启动的,而第二个实例是在用户单击应用程序图标时在其自己的任务下启动的。对于用户来说,他/她似乎恢复了应用程序,但实际上在这一刻他再次启动了它。

如果您希望使应用程序仅在自己的任务中运行,则可能的方法是添加

android:allowTaskReparenting="true"

将以下代码添加到您的AndroidManifest文件中,即可将应用程序移动到应用程序级别。一旦安装后首次点击应用程序图标,您的应用程序将被移动到单独的任务中。


完美而优雅地运作。 - hyb1996

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接