51

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

所以手头确实有两个问题。我似乎无法解决这两个问题。

  1. 在用户点击主页按钮后首次安装应用程序时,请防止应用程序关闭。
  2. 执行此操作时阻止启动应用程序的多个版本(launchMode 在这里有点帮助,但第一个组件仍会触发)。

我没有launchMode将清单文件中的属性定义为任何内容。所以不应该有任何奇怪的行为作为结果。我现在已经launchmode对应用程序的属性进行了试验,看看我是否可以让它按照预期的方式运行,但这里似乎不仅仅是正确启动活动。据我所知,当按下主页按钮时,应用程序没有理由第一次自行关闭。

我也不onUserLeaveHint 在应用程序中使用。我必须通过对该项目进行搜索再次确定。因此,似乎根本没有尝试覆盖主页按钮。

即使在重新启动手机后,主页按钮也会再次正常运行。不确定是什么导致初始安装将主页按钮视为从头开始启动应用程序的标志。

一旦用户第一次退出应用程序,问题就会永久解决。关于我应该在哪里看的任何想法?

onUpgrade()最近在应用程序中进行了一次搜索,看看它是否可能因为SQLite 数据库方法的一个组件导致一些奇怪的行为才触发。

@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>    

4

4 回答 4

83

欢迎来到不断增长的被这个用户所困扰的用户列表。

这是一个众所周知且长期存在的 Android 错误。应用程序首次从安装程序、网络浏览器和 IDE(IntelliJ、Eclipse 等)启动的方式。请参阅很久以前提交的与该问题相关的这些问题:

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

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

它仍然损坏,您无法阻止这种情况发生。您唯一能做的就是检测 Android 何时将您的根活动的第二个实例启动到现有任务中。您可以通过将此代码放入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;
}
于 2013-05-08T18:17:10.557 回答
6

为什么会这样,不知道。但我知道自定义Launcher有特定的launchModes设置。

例如 ADW.Launcher:

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

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

android:launchMode="singleInstance"

引用 CommonsWare:如何防止自定义家庭启动器应用重启活动?

我将使用 SDK 中的 Home 示例应用程序,它使用 singleInstance。奇怪的是,AOSP 启动器使用 singleTask

于 2013-05-02T12:38:26.197 回答
2

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

如果您想让您的应用程序仅在自己的任务中运行,一种可能的方法是添加

android:allowTaskReparenting="true"

到您的 AndroidManifest 的应用程序级别。安装后第一次单击应用程序图标后,您的应用程序将被移动到单独的任务中。

于 2017-05-29T18:18:26.760 回答
1

上面的答案对我使用 Nativescript 不起作用 - 这通过在活动标签中添加这两个属性解决了这个问题:

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

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

于 2021-07-03T20:58:07.667 回答