如何关闭Android应用程序?


157

我想关闭我的应用程序,以使其不再在后台运行。

怎么做?这是在Android平台上的良好做法吗?

如果我依靠“后退”按钮,它将关闭应用程序,但仍处于后台。甚至有一个名为“ TaskKiller”的应用程序只是在后台杀死那些应用程序。



想知道为什么不希望他的应用程序在后台运行?
达尔潘(Darpan)

Answers:


139

Android具有根据其文档安全关闭应用程序的机制。在最后一个退出的Activity(通常是应用程序启动时首先出现的主要Activity)中,将几行放在onDestroy()方法中。对System.runFinalizersOnExit(true)的调用可确保在应用程序退出时所有对象都将被完成并进行垃圾回收。 如果愿意,您还可以通过android.os.Process.killProcess(android.os.Process.myPid())快速终止应用程序。最好的方法是在助手类中放置如下所示的方法,然后在需要终止应用程序时调用它。例如,在根活动的destroy方法中(假设应用程序永不终止该活动):

此外,Android不会将HOME键事件通知给应用程序,因此按下HOME键时无法关闭该应用程序。Android将HOME键事件保留 给自己,以便开发人员无法阻止用户离开其应用程序。但是,您可以通过以下方法确定是否按下了HOME键:在假设已按下HOME键的帮助器类中将标志设置为true ,然后在发生未显示HOME键的事件时将标志更改为false。检查是否看到活动的onStop()方法中按下的HOME键。

不要忘记处理任何菜单以及由菜单启动的活动中的HOME键。这同样适用于与搜索键。下面是一些示例类来说明:

这是一个根活动的示例,该根活动在销毁应用程序时将其杀死:

package android.example;

/**
 * @author Danny Remington - MacroSolve
 */

public class HomeKey extends CustomActivity {

    public void onDestroy() {
        super.onDestroy();

        /*
         * Kill application when the root activity is killed.
         */
        UIHelper.killApp(true);
    }

}

这是一个抽象活动,可以扩展为处理所有扩展它的活动的HOME键:

package android.example;

/**
 * @author Danny Remington - MacroSolve
 */

import android.app.Activity;
import android.view.Menu;
import android.view.MenuInflater;

/**
 * Activity that includes custom behavior shared across the application. For
 * example, bringing up a menu with the settings icon when the menu button is
 * pressed by the user and then starting the settings activity when the user
 * clicks on the settings icon.
 */
public abstract class CustomActivity extends Activity {
    public void onStart() {
        super.onStart();

        /*
         * Check if the app was just launched. If the app was just launched then
         * assume that the HOME key will be pressed next unless a navigation
         * event by the user or the app occurs. Otherwise the user or the app
         * navigated to this activity so the HOME key was not pressed.
         */

        UIHelper.checkJustLaunced();
    }

    public void finish() {
        /*
         * This can only invoked by the user or the app finishing the activity
         * by navigating from the activity so the HOME key was not pressed.
         */
        UIHelper.homeKeyPressed = false;
        super.finish();
    }

    public void onStop() {
        super.onStop();

        /*
         * Check if the HOME key was pressed. If the HOME key was pressed then
         * the app will be killed. Otherwise the user or the app is navigating
         * away from this activity so assume that the HOME key will be pressed
         * next unless a navigation event by the user or the app occurs.
         */
        UIHelper.checkHomeKeyPressed(true);
    }

    public boolean onCreateOptionsMenu(Menu menu) {
        MenuInflater inflater = getMenuInflater();
        inflater.inflate(R.menu.settings_menu, menu);

        /*
         * Assume that the HOME key will be pressed next unless a navigation
         * event by the user or the app occurs.
         */
        UIHelper.homeKeyPressed = true;

        return true;
    }

    public boolean onSearchRequested() {
        /*
         * Disable the SEARCH key.
         */
        return false;
    }
}

这是处理HOME键的菜单屏幕的示例:

/**
 * @author Danny Remington - MacroSolve
 */

package android.example;

import android.os.Bundle;
import android.preference.PreferenceActivity;

/**
 * PreferenceActivity for the settings screen.
 * 
 * @see PreferenceActivity
 * 
 */
public class SettingsScreen extends PreferenceActivity {
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        addPreferencesFromResource(R.layout.settings_screen);
    }

    public void onStart() {
        super.onStart();

        /*
         * This can only invoked by the user or the app starting the activity by
         * navigating to the activity so the HOME key was not pressed.
         */
        UIHelper.homeKeyPressed = false;
    }

    public void finish() {
        /*
         * This can only invoked by the user or the app finishing the activity
         * by navigating from the activity so the HOME key was not pressed.
         */
        UIHelper.homeKeyPressed = false;
        super.finish();
    }

    public void onStop() {
        super.onStop();

        /*
         * Check if the HOME key was pressed. If the HOME key was pressed then
         * the app will be killed either safely or quickly. Otherwise the user
         * or the app is navigating away from the activity so assume that the
         * HOME key will be pressed next unless a navigation event by the user
         * or the app occurs.
         */
        UIHelper.checkHomeKeyPressed(true);
    }

    public boolean onSearchRequested() {
        /*
         * Disable the SEARCH key.
         */
        return false;
    }

}

这是处理应用程序中HOME键的帮助程序类的示例:

package android.example;

/**
 * @author Danny Remington - MacroSolve
 *
 */

/**
 * Helper class to help handling of UI.
 */
public class UIHelper {
    public static boolean homeKeyPressed;
    private static boolean justLaunched = true;

    /**
     * Check if the app was just launched. If the app was just launched then
     * assume that the HOME key will be pressed next unless a navigation event
     * by the user or the app occurs. Otherwise the user or the app navigated to
     * the activity so the HOME key was not pressed.
     */
    public static void checkJustLaunced() {
        if (justLaunched) {
            homeKeyPressed = true;
            justLaunched = false;
        } else {
            homeKeyPressed = false;
        }
    }

    /**
     * Check if the HOME key was pressed. If the HOME key was pressed then the
     * app will be killed either safely or quickly. Otherwise the user or the
     * app is navigating away from the activity so assume that the HOME key will
     * be pressed next unless a navigation event by the user or the app occurs.
     * 
     * @param killSafely
     *            Primitive boolean which indicates whether the app should be
     *            killed safely or quickly when the HOME key is pressed.
     * 
     * @see {@link UIHelper.killApp}
     */
    public static void checkHomeKeyPressed(boolean killSafely) {
        if (homeKeyPressed) {
            killApp(true);
        } else {
            homeKeyPressed = true;
        }
    }

    /**
     * Kill the app either safely or quickly. The app is killed safely by
     * killing the virtual machine that the app runs in after finalizing all
     * {@link Object}s created by the app. The app is killed quickly by abruptly
     * killing the process that the virtual machine that runs the app runs in
     * without finalizing all {@link Object}s created by the app. Whether the
     * app is killed safely or quickly the app will be completely created as a
     * new app in a new virtual machine running in a new process if the user
     * starts the app again.
     * 
     * <P>
     * <B>NOTE:</B> The app will not be killed until all of its threads have
     * closed if it is killed safely.
     * </P>
     * 
     * <P>
     * <B>NOTE:</B> All threads running under the process will be abruptly
     * killed when the app is killed quickly. This can lead to various issues
     * related to threading. For example, if one of those threads was making
     * multiple related changes to the database, then it may have committed some
     * of those changes but not all of those changes when it was abruptly
     * killed.
     * </P>
     * 
     * @param killSafely
     *            Primitive boolean which indicates whether the app should be
     *            killed safely or quickly. If true then the app will be killed
     *            safely. Otherwise it will be killed quickly.
     */
    public static void killApp(boolean killSafely) {
        if (killSafely) {
            /*
             * Notify the system to finalize and collect all objects of the app
             * on exit so that the virtual machine running the app can be killed
             * by the system without causing issues. NOTE: If this is set to
             * true then the virtual machine will not be killed until all of its
             * threads have closed.
             */
            System.runFinalizersOnExit(true);

            /*
             * Force the system to close the app down completely instead of
             * retaining it in the background. The virtual machine that runs the
             * app will be killed. The app will be completely created as a new
             * app in a new virtual machine running in a new process if the user
             * starts the app again.
             */
            System.exit(0);
        } else {
            /*
             * Alternatively the process that runs the virtual machine could be
             * abruptly killed. This is the quickest way to remove the app from
             * the device but it could cause problems since resources will not
             * be finalized first. For example, all threads running under the
             * process will be abruptly killed when the process is abruptly
             * killed. If one of those threads was making multiple related
             * changes to the database, then it may have committed some of those
             * changes but not all of those changes when it was abruptly killed.
             */
            android.os.Process.killProcess(android.os.Process.myPid());
        }

    }
}

1
这应该杀死所有调用System.exit(0)的应用程序,包括作为应用程序一部分运行的所有活动。所有其他应用程序将继续运行。如果只想杀死应用程序中的一个活动,而不是杀死应用程序中的所有活动,则需要调用要杀死的活动的finish()方法。
Danny Remington-OMS

2
非常感谢这个nfo。我正在使用AndEngine制作游戏,当我将其称为Finish时,即使在所有活动中,android仍然无法完全清除,并且当游戏重新启动时,它会被完全错误地发现,我的GL纹理都被毛刺了,等等。因此,在调查之后,以为是AndEngine,我才意识到它一定出了问题,因为当我想要退出时android试图保留该过程。所有评论“哦,你不应该叫出口,它破坏了用户体验”是胡说八道。天气,应用程序应保持打开状态。……

17
任何生产应用程序都不应使用此代码。任何生产应用程序都不应调用中显示的任何代码killApp(),因为Google指出这将导致不可预测的行为。
CommonsWare,

1
System.runFinalizersOnExit(true); 不建议使用方法,安全关闭应用程序(收集垃圾)的另一种方法是什么?
Ajeesh

1
最初发布时尚未弃用。由于当前的AP当时是7,而现在的API现在是19,所以现在可能还有另一种方法。
Danny Remington-OMS 2014年

68

是!您当然可以关闭您的应用程序,以便它不再在后台运行。就像其他人所评论finish()的那样,谷歌推荐的方法并不意味着您的程序已经关闭。

System.exit(0);

正确的位置将关闭您的应用程序,而不会在后台运行任何内容。但是,请明智地使用此操作,不要打开文件,打开数据库句柄等。这些内容通常可以通过finish()命令清除。

当我在应用程序中选择“退出”时,我个人讨厌它并没有真正退出。


44
绝对不建议使用System.exit()。
CommonsWare 2010年

14
我不会说这不是推荐的方法,但是您能否提供一种解决方案来保证应用程序立即退出后台?如果不是这样,那么System.exit是直到Google提供更好的方法之前的方法。
卡梅隆·麦克布赖德

74
是谁决定您不“应该”接受创建实际并未退出的方法的同一个人?如果用户不希望自己的应用程序关闭,那么第五大最受欢迎的付费应用程序将不会成为任务杀手。人们需要释放内存,而核心操作系统无法完成工作。
卡梅隆·麦克布赖德

19
同意这是不明智的建议,但由于提供了实际的答案而被投票赞成。我对听到“您真的不想这样做”感到非常厌倦,没有后续的解释。与iPhone相比,Android绝对是有关此类文档的噩梦。
DougW

11
在Android中使用任务杀手没有内存优势。如果前台应用需要更多内存,Android将销毁并清除所有不在前台的应用。在某些情况下,Android甚至会重新打开被任务杀手关闭的应用程序。Android将使用最近使用的应用程序填充所有不需要的内存,以减少应用程序切换时间。不要使用退出按钮来构建应用程序。不要在ANDROID上使用任务管理器。geekfor.me/faq/youshouldnt-using-a-task-killer-with-androidandroid-developers.blogspot.com/2010/04/…–
Janusz

23

这是我做到的方式:

我只是放

Intent intent = new Intent(Main.this, SOMECLASSNAME.class);
Main.this.startActivityForResult(intent, 0);

在打开活动的方法内部,然后在旨在关闭我放置的应用程序的SOMECLASSNAME方法内部:

setResult(0);
finish();

我将以下内容放入我的主班:

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    if(resultCode == 0) {
        finish();
    }
}

18

经过这么长时间后,现在就回答我自己的问题(因为CommonsWare在最受欢迎的答案中指出我们不应这样做):

当我想退出该应用程序时:

  1. 我用FLAG_ACTIVITY_CLEAR_TOP(将退出其后开始的所有其他活动,即所有这些活动)退出我的第一个活动(启动屏幕或当前位于活动堆栈底部的任何活动)。只需在活动堆栈中进行此活动即可(不要出于某种原因提前完成)。
  2. 我呼吁finish()这项活动

就是这样,对我来说效果很好。


3
这实际上不会杀死您的应用程序。它仍将显示在应用程序列表中。我只是杀死了你所有的活动。
Joris Weimar 2012年

1
FLAG_ACTIVITY_CLEAN_TOP不适用于Sony智能手机。在AndroidManifest.xml中clearTaskOnLaunch =“true”属性的活动:你可以变通方法,通过增加机器人
Rusfearuth

10

只需在您的按钮EXIT单击上编写此代码。

Intent intent = new Intent(getApplicationContext(), MainActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
intent.putExtra("LOGOUT", true);
startActivity(intent);

MainActivity.classonCreate()方法中,将以下代码作为第一行:

if (getIntent().getBooleanExtra("LOGOUT", false))
{
    finish();
}

9

使用框架API是不可能的。由操作系统(Android)决定何时删除进程或将其保留在内存中。这是出于效率方面的考虑:如果用户决定重新启动该应用程序,则该应用程序已经存在,而无需将其加载到内存中。

所以不,这不仅令人沮丧,而且不可能这样做。


4
您可以始终执行类似Integer z = null;的操作。z.intValue(); //最糟糕的答案
Joe Plante 2012年

6
诚然。您也可以将手机砸在墙上,如果施加足够的压力,它将终止所有打开的应用程序。我还是不推荐。我已经相应更新了我的帖子。
Matthias

@JoePlante也会在您打开应用程序菜单时将应用程序保留在后台。看来这是不可能的。
peresisUser 2015年

8

对于退出应用程序方式:

方式1:

调用finish();并覆盖onDestroy();。将以下代码放入onDestroy()

System.runFinalizersOnExit(true)

要么

android.os.Process.killProcess(android.os.Process.myPid());

方式二:

public void quit() {
    int pid = android.os.Process.myPid();
    android.os.Process.killProcess(pid);
    System.exit(0);
}

方式三:

Quit();

protected void Quit() {
    super.finish();
}

方式四:

Intent intent = new Intent(getApplicationContext(), LoginActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
intent.putExtra("EXIT", true);
startActivity(intent);

if (getIntent().getBooleanExtra("EXIT", false)) {
     finish();
}

方式五:

有时,调用finish()只会退出当前活动,而不会退出整个应用程序。但是,有一种解决方法。每次启动an时activity,请使用启动它startActivityForResult()。当您要关闭整个应用程序时,可以执行以下操作:

setResult(RESULT_CLOSE_ALL);
finish();

然后定义每个活动的onActivityResult(...)回调,以便当一个activity带有RESULT_CLOSE_ALL值的返回时,它也调用finish()

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    switch(resultCode){
        case RESULT_CLOSE_ALL:{
            setResult(RESULT_CLOSE_ALL);
            finish();
        }
    }
    super.onActivityResult(requestCode, resultCode, data);
}

Intent intent = new Intent(getApplicationContext(),LoginActivity.class); intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); intent.putExtra(“ EXIT”,true); startActivity(intent); 工作超好。
hitesh141

我已经开始活动A-> B-> C-> D。当按下活动DI上的后退按钮时,要转到活动A。由于A是我的起点,因此已经在堆栈上,清除了A顶部的所有活动,并且您无法从A返回到其他任何活动@Override public boolean onKeyDown(int keyCode,KeyEvent event){if(keyCode == KeyEvent.KEYCODE_BACK){Intent a = new Intent(this,A.class); a.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); startActivity(a); 返回true;} return super.onKeyDown(keyCode,event); }
hitesh141

5

这就是Windows Mobile运作的方式……好……曾经!微软在这件事上不得不说的是:

http://blogs.msdn.com/windowsmobile/archive/2006/10/05/The-Emperor-Has-No-Close.aspx(难过我记得2006年以来博客帖子的标题吗?我通过搜索“皇帝没有亲密关系”在Google上找到了这篇文章,哈哈)

简而言之:

如果在后台运行应用程序时系统需要更多内存,它将关闭该应用程序。但是,如果系统不需要更多内存,则该应用程序将保留在RAM中,并准备在下次用户需要时快速返回。

O'Reilly这个问题上的许多评论都表明,Android的行为方式几乎相同,只有当Android需要使用的内存时,它们才会关闭一段时间未使用的应用程序。

由于这是标准功能,因此将行为更改为强制关闭将改变用户体验。许多用户会习惯于轻柔地关闭其Android应用程序,因此,当他们在执行其他一些任务后又想返回一个Android应用程序而将其关闭时,他们可能会感到沮丧,因为应用程序的状态已重置,或者花费了更长的时间打开。我会坚持标准行为,因为这是预期的结果。


5

finish()Activity上调用方法会对当前的Activity产生所需的效果。


14
不,不是。它完成当前的活动,而不是应用程序。如果您完成()任务堆栈中最底部的活动,则您的应用程序似乎将退出,但Android可能会决定在其认为合适的范围内实际保留它。
Matthias 2010年

确实,但是,如果您需要完全退出应用程序,则需要为每个活动调用finish方法,并考虑可能已经启动的任何服务。我还编辑了初始答案-抱歉,遗漏了。
r1k0 2010年

3

以上所有答案均无法在我的应用程序上正常运行

这是我的工作代码

在退出按钮上:

Intent intent = new Intent(getApplicationContext(), MainActivity.class);
ComponentName cn = intent.getComponent();
Intent mainIntent = IntentCompat.makeRestartActivityTask(cn);
mainIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_NEW_TASK);
mainIntent.addFlags(Intent.FLAG_ACTIVITY_NO_HISTORY);
mainIntent.putExtra("close", true);
startActivity(mainIntent);
finish();

该代码将关闭任何其他活动,并将MainActivity置于您的MainActivity之上:

if( getIntent().getBooleanExtra("close", false)){
    finish();
}

2

把一个finish();声明如下:

myIntent.putExtra("key1", editText2.getText().toString());

finish();

LoginActivity.this.startActivity(myIntent);

在每项活动中。



2

复制以下代码,然后将AndroidManifest.xml文件粘贴到First Activity Tag下。

<activity                        
            android:name="com.SplashActivity"
            android:clearTaskOnLaunch="true" 
            android:launchMode="singleTask"
            android:excludeFromRecents="true">              
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER"
                />
            </intent-filter>
        </activity>     

还要将此代码添加到AndroidManifest.xml文件中“活动标签”下的所有代码中

 android:finishOnTaskLaunch="true"

1

2.3无法实现。我搜索了很多,并尝试了许多应用程序。最好的解决方案是同时安装(go taskmanager)和(快速重启)。一起使用它们将起作用,并释放内存。另一个选择是升级到Android冰淇淋三明治4.0.4,从而可以控制(关闭)应用程序。



1

finishAffinity()如果您要关闭应用程序的所有活动,使用可能是一个不错的选择。根据Android文档-

Finish this activity as well as all activities immediately below it in the current task that have the same affinity.

1
public class CloseAppActivity extends AppCompatActivity
{
    public static final void closeApp(Activity activity)
    {
        Intent intent = new Intent(activity, CloseAppActivity.class);
        intent.addCategory(Intent.CATEGORY_HOME);
        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK |
                IntentCompat.FLAG_ACTIVITY_CLEAR_TASK);
        activity.startActivity(intent);
    }

    @Override
    protected void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        finish();
    }
}

并在清单中:

<activity
     android:name=".presenter.activity.CloseAppActivity"
     android:noHistory="true"
     android:clearTaskOnLaunch="true"/>

然后您可以拨打电话CloseAppActivity.closeApp(fromActivity),申请将被关闭。


1

只需在onBackPressed中编写以下代码:

@Override
public void onBackPressed() {
    // super.onBackPressed();

    //Creating an alert dialog to logout
    AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(this);
    alertDialogBuilder.setMessage("Do you want to Exit?");
    alertDialogBuilder.setPositiveButton("Yes",
            new DialogInterface.OnClickListener() {
                @Override
                public void onClick(DialogInterface arg0, int arg1) {
                    Intent intent = new Intent(Intent.ACTION_MAIN);
                    intent.addCategory(Intent.CATEGORY_HOME);
                    startActivity(intent);
                }
            });

    alertDialogBuilder.setNegativeButton("No",
            new DialogInterface.OnClickListener() {
                @Override
                public void onClick(DialogInterface arg0, int arg1) {

                }
            });

    //Showing the alert dialog
    AlertDialog alertDialog = alertDialogBuilder.create();
    alertDialog.show();
}

0

通过调用finish(); 在OnClick按钮或菜单上

案例R.id.menu_settings:

      finish();
     return true;

如其他答案的评论所述,finish()不会杀死该应用程序。它可以返回到先前的Intent或后台应用程序。
猛禽2014年

0

我认为它将关闭您的活动以及与之相关的所有子活动。

public boolean onOptionsItemSelected(MenuItem item) {

        int id = item.getItemId();]
        if (id == R.id.Exit) {
            this.finishAffinity();
            return true;
        }

        return super.onOptionsItemSelected(item);
    }


By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.