用户通过设置强制退出后是否可以知道应用程序是否正在启动?

发布于 2025-01-07 18:02:37 字数 699 浏览 3 评论 0原文

我想知道,可能在我的 Activity 的 onCreate() 中,应用程序之前是否按照正常的主页/后退按钮关闭,或者用户是否实际进入 Android 设置并选择强制关闭。

这两种情况可以区分吗?

编辑:

我想我可能没有很好地解释我的意思。我已经阅读了活动生命周期文档并且对此非常了解。

基本上,我只想知道 Activity 何时创建,用户之前是否已进入 Android 设置并点击强制停止。如果应用程序被强制停止,我想采取行动(具体来说,在启动时显示启动屏幕)。

下面的很多答案都说我可以在 onStop() 或 onDestroy() 中放置一个标志,并且如果用户强制停止,则不会调用这些方法。问题是,在到达该点之前,这些方法已经被调用了,因为这个顺序:

  1. 应用程序处于活动状态,正在使用
  2. 用户点击后退按钮(onStop(),onDestroy()调用),或主页按钮( onStop() 调用),或最近的应用程序按钮(onStop() 调用)
  3. 用户进入 android 设置,点击强制停止

在这种情况下,我会将标志放入 onStop() 上的共享首选项中,但随后用户点击强制停止和该标志在 onCreate() 中仍然处于活动状态。

我不想显示启动画面,除非用户在设置中点击了强制停止。我知道这不是应该的做法……但这个决定不是我做出的。

I want to know, probably in onCreate() of my activity, if the app was previously closed as per the normal home/back button or if the user actually went into the Android settings and selected force close.

Is it possible to distinguish these two cases?

EDIT:

I think I might not have explained what I mean well enough. I've read the activity lifecycle document and I understand that fairly well.

Basically, I just want to know when the activity is created, whether or not the user has previously gone into the Android settings and hit force stop. If the app was force stopped, I want to take an action (specifically, display the splash screen on startup).

Lots of the answers below say that I can put a flag in onStop() or onDestroy(), and that these methods won't be called if the user hits force stop. The problem is that these methods would have ALREADY been called before getting to that point, because of this sequence:

  1. app is in the active state, being used
  2. User hits back button (onStop(), onDestroy() called), or home button (onStop() called), or recent apps button (onStop() called)
  3. user goes into android settings, taps force stop

In that situation, I will have put the flag into shared preferences on onStop(), but then the user hits force stop and the flag is still active in onCreate().

I don't want to display the splash screen unless the user has hit force stop in settings. I know this is not the way it should be done... but this decision was not made by me.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(8

所谓喜欢 2025-01-14 18:02:38

我昨天遇到了同样的问题,就是这样我发现马克·墨菲说过。
但我已经成功破解了它。

实际上,每当按下“强制停止”时,系统都会清除应用程序占用的所有内存,除了两件事。

1:共享首选项2:sqlite数据库

因此,我通过在应用程序中存储一个布尔变量,操作该值,然后在每次启动应用程序时检查它来完成这个技巧。就完成了。

CONSTANTS.java

package com.mehuljoisar.forcestopdemo;

public class CONSTANTS {

//the changes made to value of below variable will be cleared on force stop,so whenever force stop occurs,the value of variable will be "isForceStopped=true" again.
    public static boolean isForceStopped = true;
}

MainActivity.java

package com.mehuljoisar.forcestopdemo;

import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.view.Menu;
import android.widget.Toast;

public class MainActivity extends Activity {

    private Context mContext;
    private Intent i;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        initialize();


        if(CONSTANTS.isForceStopped)
        {
        //this block of code will be executed in 2 scenario,
        //1: when application is started for very first time
        //2: when application is started after force stopping
            Toast.makeText(mContext, "Display Splash-screen and move to next screen", Toast.LENGTH_SHORT).show();
        //don't forget this part,it's important to make change so that next time splash screen can be avoided
             CONSTANTS.isForceStopped=false;

        //and then launch next screen
            launchSecondScreen();
        }
        else
        {
        //directly launch next screen
            launchSecondScreen();
        }
    }

    private void launchSecondScreen() {
        i.setClass(mContext, SecondActivity.class);
        startActivity(i);
        finish();
    }

    private void initialize() {
        mContext = this;
        i = new Intent();
    }


    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.activity_main, menu);
        return true;
    }

}

SecondActivity.java

package com.mehuljoisar.forcestopdemo;

import android.app.Activity;
import android.os.Bundle;

public class SecondActivity extends Activity{

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_second);
    }

}

AndroidManifest.xml

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

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

    <application
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >
        <activity
            android:name="com.mehuljoisar.forcestopdemo.MainActivity"
            android:label="@string/app_name" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        <activity
            android:name="com.mehuljoisar.forcestopdemo.SecondActivity"
            android:label="@string/app_name" >
            <intent-filter>
                <action android:name="android.intent.action.VIEW" />

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

</manifest>

我希望它会有所帮助!

I ran into same issue yesterday and this is what I found stated by Mark Murphy.
But I have managed to crack it.

Actually,whenever "Force Stop" is pressed,the system will clear all the memory occupied by the application except 2 things.

1:the shared preference and 2:sqlite database.

So I have done the trick by storing a boolean variable in application,manipulating the value and then check it on each start up of application.and it's done.

CONSTANTS.java

package com.mehuljoisar.forcestopdemo;

public class CONSTANTS {

//the changes made to value of below variable will be cleared on force stop,so whenever force stop occurs,the value of variable will be "isForceStopped=true" again.
    public static boolean isForceStopped = true;
}

MainActivity.java

package com.mehuljoisar.forcestopdemo;

import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.view.Menu;
import android.widget.Toast;

public class MainActivity extends Activity {

    private Context mContext;
    private Intent i;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        initialize();


        if(CONSTANTS.isForceStopped)
        {
        //this block of code will be executed in 2 scenario,
        //1: when application is started for very first time
        //2: when application is started after force stopping
            Toast.makeText(mContext, "Display Splash-screen and move to next screen", Toast.LENGTH_SHORT).show();
        //don't forget this part,it's important to make change so that next time splash screen can be avoided
             CONSTANTS.isForceStopped=false;

        //and then launch next screen
            launchSecondScreen();
        }
        else
        {
        //directly launch next screen
            launchSecondScreen();
        }
    }

    private void launchSecondScreen() {
        i.setClass(mContext, SecondActivity.class);
        startActivity(i);
        finish();
    }

    private void initialize() {
        mContext = this;
        i = new Intent();
    }


    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.activity_main, menu);
        return true;
    }

}

SecondActivity.java

package com.mehuljoisar.forcestopdemo;

import android.app.Activity;
import android.os.Bundle;

public class SecondActivity extends Activity{

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_second);
    }

}

AndroidManifest.xml

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

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

    <application
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >
        <activity
            android:name="com.mehuljoisar.forcestopdemo.MainActivity"
            android:label="@string/app_name" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        <activity
            android:name="com.mehuljoisar.forcestopdemo.SecondActivity"
            android:label="@string/app_name" >
            <intent-filter>
                <action android:name="android.intent.action.VIEW" />

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

</manifest>

I hope it will be helpful !!

溺孤伤于心 2025-01-14 18:02:38

我不确定是否有更简单的方法,但您可以创建一个 SharedPreferences 对象,并使用 Activity 的 onStop 函数中的标志进行更新。并检查 onCreate 中的标志。我认为如果用户强制关闭应用程序,则不会调用 onStop 或 onDestroy 。

I'm not sure if there is an easier way but you could create a SharedPreferences object that is updated with a flag in the onStop function of the Activity. And check for the flag in the onCreate. I don't think the onStop or onDestroy is called if the user force closes the app.

半步萧音过轻尘 2025-01-14 18:02:38

如果用户使用“强制关闭”关闭您的应用程序,则“onStop”方法不会执行。您可以在该方法中放置一个标志(例如保存在文件、用户首选项、sql 等中)。下次应用程序启动时,检查该标志!

If the user closed your application with "force close" the "onStop" method doesn't execute. You may put a flag (like saving in a file, user preferences, sql etc) in that method. Next time the application starts, check that flag!

北城半夏 2025-01-14 18:02:38

覆盖 Home 活动中的 onBackButtonPressed(正常情况下,当使用后退按钮时,应用程序主活动关闭)。

在此函数中设置一个变量(例如,lastforceClose 为 false)SharedPreferences,然后调用 onbackbuttonpressed() 或 finish() 的超级方法来完成活动。

下次每当您启动活动时,您都可以检查共享首选项中的变量,以查看 lastforceClose 变量是否设置为 false (并且您自己现在将其更改为 true)...

您可能还想处理情况当用户通过 Android 设置删除数据时。(即密钥不存在于共享首选项 xml 文件等中)

Override the onBackButtonPressed in your Home activity(in normal case when with back button the application main activity is closed).

set a variable(say, lastforceClose as false) SharedPreferences in this function and then call super method of onbackbuttonpressed() or finish() to finish off activity.

Next time whenever you start the activity you can check out for the variable in the sharedpreferences to see lastforceClose variable if it is either set to false or not ( and you yourself change it to true now)...

You might also want to handle case here when user has deleted data through android settings.. (i.e. key not present in shared preferences xml file etc.)

自由如风 2025-01-14 18:02:38

我不是 100% 确定,但这应该有效。
1)在某些持久存储上的Activity的onDestroy中保存状态(正常关闭)。 (SharedPreferences 或 SQLite)
2)在onCreate中检查状态,如果是正常关闭则应用程序正常关闭,否则则强制关闭。重置状态。

I am not 100% sure but this should work.
1) Save state (Normal shutdown) in onDestroy of the Activity on some persistent storage. (SharedPreferences or SQLite)
2) in onCreate check for the state, if it is normal shutdown then app was closed normally else it was force closed. reset the state.

凝望流年 2025-01-14 18:02:38

首先,听起来您可能会混淆恢复和创建。一定要仔细阅读应用程序基础知识,特别是有关活动生命周期的内容。该状态图很有帮助。

当用户“退出”应用程序时,它不一定会被销毁。事实上,除非开发人员在 onPause() 中放置一些显式销毁 Activity 的钩子,否则它可能不会被销毁。

Android 应用程序生命周期中需要理解的一个最重要的概念是:

Android 操作系统绝对不保证您的应用程序将存活多长时间,除了保证它可以随时终止(无论您愿意还是愿意)。不是。

您应该始终相应地编写您的应用程序,并且填充生命周期启动和结束挂钩的每一个都是一种很好的做法。当用户通过硬件按钮从您的应用程序中退出时,该应用程序不一定会被销毁,但是当应用程序通过强制退出关闭时,它就完全被销毁了。处理此问题的“正确”方法是让您的 onPause()onStop()和 onDestroy() 方法设置为根据活动的状态进行适当数量的清理,并且可能有某种 Preference 对象或状态变量,仅在以下情况下才会翻转onDestroy() 被调用,因为从技术上讲,即使用户没有通过任务管理器执行此操作,操作系统仍然可以为您“强制退出”应用程序。

First, it sounds like you might be confusing resuming with creating. Definitely read through the App fundamentals, specifically the stuff about Activity Lifecycle. That state diagram is helpful.

When a user "backs" out of an Application, it is not necessarily destroyed. In fact, it probably isn't destroyed unless the dev puts some hooks in the onPause() that explicitly destroys the Activity.

The single most important concept in Android App lifecycles to understand is this:

The Android OS makes absolutely no guarantee about how long your application will be alive, except for the guarantee that it can die at any time whether you want it to or not.

You should always write your app accordingly, and it is good practice to populate every single one of the lifecycle start up and wind down hooks. When a user does a hardware button back out from your app, then the app is not necessarily destroyed, but when the app is closed out via force quitting then it is absolutely destroyed. Instead of trying to finagle your way in to figuring out how the app was closed, the "proper" way to handle this is to have your onPause(), onStop(), and onDestroy() methods set up to do the appropriate amount of cleaning up based on the state of the activity, and maybe have some sort of Preference object or state variable that only gets flipped if onDestroy() is called, since technically the OS can still "force quit" the app for you even if the user doesn't do so via the task manager.

红焚 2025-01-14 18:02:38

您可以尝试保留所有应用生命周期事件的记录,然后检查各种onCreate()记录的最后一个事件是否正常。如果没有,您可以合理地推断发生了某些事情。我猜测用户调用的任何强制关闭都会导致系统向应用程序发送 kill(2) ,在这种情况下您将不会收到任何指示。 可能会有所帮助。

您还可以考虑是否可以通过不同的方式实现您所追求的目标。如果您的应用程序完全无状态,那么任何类型的关闭都不应该出现问题。如果您的应用程序有状态,那么理论上您的所有数据/应用程序事务都可以实现 ACIDity,并且这样您就可以避免由于崩溃/强制关闭而导致的不一致。

这有帮助吗?还是你在追求别的东西?

You might try persisting a record of all app lifecycle events and then checking in your various onCreate()s whether the last event recorded was normal. If not, you could reasonably infer that something happened. I'm guessing that any force close invoked by the user simply results in the system sending a kill(2) to the app, in which case you won't receive any indication. This might help.

You might also consider whether you can achieve what you're after in a different way. If your app is entirely stateless, then there shouldn't be a problem with shutdowns of any kind. If your app has state then in theory all of your data/app transactions can achieve ACIDity, and so you can avoid inconsistencies due to crashes/force closes.

Does that help or are you after something else?

梦里°也失望 2025-01-14 18:02:38

从服务而不是活动中写入状态标志怎么样?活动生命周期仍将完成,但服务生命周期不应完成。

它与您的要求并不相同,但可能足够接近。如果您显示的活动没有此要求,您需要停止该服务(并稍后重新启动)。或者只是让服务编写某种事件流并使用它来确定启动时显示的内容。

What about writing status flags from a service, not an activity? The activity lifecycle will still complete, but the service lifecycle shouldn't.

It's not identical to your requirement, but it might be close enough. You'd want to stop the service (and restart later) if you're showing an activity that doesn't have this requirement. Or just have the service write an event stream of some sort and use that to figure out what to show on startup.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文