Закрийте програму та запустіть головний екран на Android


76

У мене є дві різні діяльності. Перший запускає другий. Під час другого заходу я телефоную System.exit(0), щоб змусити програму закритись, але перша дія автоматично відображається замість того, щоб програма повернулася на головний екран. Як я можу цього уникнути і повернути програму на головний екран?


Оскільки у стеку є більше одного Activity, тому System.exit (?) Перезапустить його. (Я думаю)
Yousha Aleayoub

Відповіді:


45

Справді варто подумати про те, щоб не вийти з програми. Зазвичай програми Android працюють не так.


2
Оскільки в додатку для Android немає виходу. Чи є спосіб, яким я можу пройти всі дії програми, щоб я зателефонував Finish () для кожного, тобто закінчив усі розпочаті дії?
Арута

2
Навіщо потрібно це робити? Діяльність перебуває у неналежному стані, оскільки ви вийшли з системи чи в іншому стані? Ви можете перевірити це в межах, onResumeа потім finishактивності.
Джеймс,

2
Проблема, як користувача та розробника, полягає в тому, що автоматичне очищення пам'яті в Android працює не так добре. Там так багато додатків із «поганою поведінкою», що у мого телефону починає закінчуватися пам’ять, і коли він стає низьким, інтерфейс починає заїкатися. Це на відносно високій специфікації (на цей час) HTC Desire. Думаю, саме тому я та інші інколи задаємо це питання.
Richard Le Mesurier

1
@Richard: Чи не кращим рішенням буде припинення будь-якої діяльності, коли у вашій програмі викликається onPause? Єдиний спосіб, яким додаток повинен спричинити уповільнення, - це якщо у вас все ще працюють AsyncTasks тощо, коли ви призупинені, коли вони не мають потреби. Наприклад, ігри повинні вийти з основного циклу після onPause. (І ранній вихід із циклу не враховується.)
idbrii

2
@pydave: Я з вами згоден. Але, здається, багато дискусій на цей тип теми, і я поділився деяким досвідом розробників та користувачів із "реального світу". Справа в тому, що на даний момент мій телефон помітно гальмує, оскільки доступна пам’ять зменшується. Здається, у мене є так би мовити програми "у фоновому режимі", які використовують цю пам'ять. Якщо я вб'ю ці програми, я маю досвід, що мій пристрій пришвидшується. Що змушує мене думати, що було б непогано, якби 1) розробники могли написати код, щоб повністю вбити процес і звільнити його пам’ять, або 2) андроїд GC працював трохи краще, ніж зараз. ymmv
Richard Le Mesurier

88

Коротка відповідь: зателефонуйте moveTaskToBack(true)на свійActivity замість System.exit(). Це приховає вашу програму, доки користувач не захоче її використовувати знову.

Більш довга відповідь починається з іншого питання: чому ви хочете вбити вашу програму?

ОС Android управляє управлінням пам’яттю та процесами тощо, тому моя порада - просто нехай Android турбується про це за вас. Якщо користувач хоче залишити вашу програму, він може натиснути кнопку «Додому», і ваша програма фактично зникне. Якщо пізніше телефону знадобиться більше пам'яті, тоді ОС припинить роботу вашої програми.

Поки ви належним чином реагуєте на події життєвого циклу , ні вам, ні користувачеві не потрібно дбати про те, чи працює ваша програма все ще чи ні.

Отже, якщо ви хочете приховати виклик своєї програми moveTaskToBack()та дозволити Android вирішити, коли її вбивати.


4
Для отримання додаткової інформації по аргументу Дейва, подивіться на stackoverflow.com/questions/2033914 / ...
CommonsWare

Існує правомірне використання вбивства програми - наприклад, я роблю закриту бета-версію, і мені потрібно закрити програму, якщо користувач не має відповідного пароля.
Matt Lyons

4
@Matt: Чому б вам просто не зупинити користувача на екрані пароля? Якщо вони не можуть пройти цей момент, чому тоді вам потрібно змушувати програму вимикатись?
idbrii

Особливим випадком може бути, коли користувач натискає кнопку "Назад", щоб вийти з програми. За замовчуванням обробник onKeyUp () для цього виконує обробку () у цій ситуації. Але мій досвід полягає в тому, що finish () не завжди очищає пам'ять належним чином, тоді як System.exit (0) робить це. Отже, у цій конкретній ситуації, коли користувач по суті попрощався з вашим додатком і неявно сказав, що вона не хоче зберігати жодного стану, я виявив, що виклик System.exit (0) робить набагато кращу роботу з очищення вгору.
Карл,

53

Найпростіший спосіб досягти цього наведено нижче (не впливаючи на управління вбудованою пам’яттю Android. Не застосовується жоден процес вбивства).

  1. Запустіть діяльність, використовуючи цей намір:

    Intent intent = new Intent(this, FinActivity.class);
    intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
    startActivity(intent);
    finish();
    
  2. У цільовій діяльності FinActivity.classвиклик finish () у onCreate.

Пояснювані кроки:

  1. Ви створюєте намір, який стирає всі інші дії (FLAG_ACTIVITY_CLEAR_TOP)та видаляє поточну активність.

  2. Діяльність знищує себе. Альтернативою є те, що ви можете зробити заставку у finActivity. Це необов’язково.


3
ти не хочеш startActivity () перед фінішем ()?
Хтось десь

FinActivityмає бути вашою RootActivity, так? Використання цього прапора перезапустить вашу програму, FinActivity.classяк зазначено у документації developer.android.com/reference/android/content/... Я навів приклад у своїй відповіді нижче, щоб подолати це.
Дарпан

Працюю як шарм :)
Radhey

Це дійсно припиняє діяльність та послуги, але налагоджувач все ще показує потоки, що працюють у фоновому режимі, і все ще відображає, як моя програма натискає кнопку багатозадачності.
Стівен М --удар -

20

Android має механізм безпечного закриття програми відповідно до її документації. В останній активності, яка вийшла (як правило, основна, яка вперше з’явилася під час запуску програми), просто розмістіть пару рядків у методі onDestroy (). Виклик System.runFinalizersOnExit (true) гарантує, що всі об'єкти будуть доопрацьовані та сміття буде зібрано під час виходу програми. Наприклад:

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

    /*
     * Notify the system to finalize and collect all objects of the
     * application on exit so that the process running the application can
     * be killed by the system without causing issues. NOTE: If this is set
     * to true then the process will not be killed until all of its threads
     * have closed.
     */
    System.runFinalizersOnExit(true);

    /*
     * Force the system to close the application down completely instead of
     * retaining it in the background. The process that runs the application
     * will be killed. The application will be completely created as a new
     * application in a new process if the user starts the application
     * again.
     */
    System.exit(0);
}

Нарешті, Android не повідомляє програму про подію клавіші HOME , тому ви не можете закрити програму, коли натискаєте клавішу HOME . Android зберігає для себе ключову подію HOME, щоб розробник не міг перешкодити користувачам залишати свою програму.


4
Дивлячись на вихідний код AOSP, цей метод тепер застарілий: @deprecated цей метод небезпечний.
Артем Руссаковський

9

Ви також можете вказати noHistory = "true" в тезі для першої активності або закінчити першу активність, як тільки ви почнете другу (як сказав Девід).

AFAIK, "примусове закриття" вбиває процес, який розміщує JVM, в якому працює ваша програма, а System.exit () припиняє JVM, що запускає екземпляр вашого додатка. Обидва вони є формою різких закінчень і не є доцільним для нормального потоку додатків.

Подібно до того, як ловити винятки для охоплення логічних потоків, які може здійснити програма, недоцільно.


Немає можливості належним чином закрити програму, і всі дії все ще відкриті?
Арута

2
Ні, в Android насправді не існує поняття "програми"; ваші програми - це колекція дій. Якщо ви не хочете повертатися до своєї першої діяльності після закінчення другої, тоді вам слід використовувати noHistoryатрибут, як згадано.
Крістофер Орр,

Докладніше про діяльність та завдання ... developer.android.com/guide/topics/fundamentals.html#acttask
Самух

9

Я використовую цей метод, щоб закрити Діяльність!

public static void closeAllBelowActivities(Activity current) {
    boolean flag = true;
    Activity below = current.getParent();
    if (below == null)
        return;
    System.out.println("Below Parent: " + below.getClass());
    while (flag) {
        Activity temp = below;
        try {
            below = temp.getParent();
            temp.finish();
        } catch (Exception e) {
            flag = false;
        }
    }
}

8

Коли ви запускаєте другу діяльність, finish()першу відразу:

startActivity(new Intent(...));
finish();

1
Я не хочу систематично закінчувати першу діяльність, лише якщо я викликаю System.exit (0). Це нормальна особливість? Як працює кнопка примусового закриття в диспетчері програм?
Арута

1
ой тоді я неправильно прочитав ваше запитання, вибачте. не так виглядає стандартний життєвий цикл програми для Android. кнопка FC використовує щось подібне, android.os.Process.killProcess(android.os.Process.myPid());що не так, як ви зазвичай хочете, щоб ваші програми виходили. але ви можете скористатися цим, або ви можете розглянути startActivityForResultта finishActivityі створити щось, де перша дія закінчується, лише якщо друга закінчується певним кодом відповіді.
Девід Хедлунд,

6

android.os.Process.killProcess(android.os.Process.myPid()); працює нормально, але рекомендується нехай платформа Android турбується про управління пам'яттю :-)


4

Ви не можете зробити System.exit (), це не безпечно.

Ви можете зробити це: Process.killProcess (Process.myPid ());


Вам потрібен правильний дозвіл - <koristi-дозвіл android: name = "android.permission.KILL_BACKGROUND_PROCESSES" />
Кевін Паркер,

Працює для мого додатка, який працює як власник пристрою. Жодних нових дозволів не було потрібно. Все ще залишає багатозадачний вигляд.
Стівен М --удар -

4

Я використовую це:

1) Батьківська активність викликає вторинну активність методом "startActivityForResult"

2) У другорядній діяльності, коли закривається:

int exitCode = 1; // Select the number you want
setResult(exitCode);
finish();

3) А в батьківській діяльності перевизначте метод "onActivityResult":

public void onActivityResult(int requestCode, int resultCode, Intent data) {
    super.onActivityResult(requestCode, resultCode, data);
    int exitCode = 1;
    if(resultCode == exitCode) {
        super.setResult(exitCode); // use this if you have more than 2 activities
        finish();
    }
}

Для мене це чудово працює.


4

Використовуйте finishметод. Це простіший і простіший метод.

this.finish();

2

Майте на увазі, що під час роботи з програмами, які використовують постійні підключення до сокета, finish()метод не розриває зв’язок. За звичайних обставин finish()це найкращий варіант, але якщо вам абсолютно потрібно вийти з програми та випустити весь ресурс, який вона використовує, тоді використовуйте killProcess. У мене не було проблем із його використанням.


2

Почніть другу діяльність за допомогою startActivityForResult, а у другій - поверніть значення, яке одного разу в методі onActivityResult першого заходу закриває основну програму. Я думаю, що це правильний спосіб, яким це робить Android.


2

Ви неправі. Існує один спосіб убити програму. У класі з супер класу Application, ми використовуємо деякий поле, наприклад, killApp. Коли ми запускаємо екран заставки (перша активність) onResume(), ми встановлюємо параметр false для поля killApp. У кожній діяльності, яку ми маємо, коли onResume()її називають в кінці, ми називаємо щось подібне:

if(AppClass.killApp())
    finish();

Кожну діяльність, яка потрапляє на екран, потрібно викликати onResume(). Коли його викликають, ми повинні перевірити, чи killAppсправжнє наше поле . Якщо це правда, потрібна поточна діяльність finish(). Щоб викликати повну дію, ми використовуємо наступну конструкцію. Наприклад, у дії для кнопки:

AppClass.setkillApplication(true);
   finish();
   return;

система android не вбиває активність у таких станах, як onStart (), onRestart () та onResume () згідно з документацією. ваша пропозиція абсолютно помилкова!
анонім

2

Спробуйте наступне. Це працює для мене.

ActivityManager am = (ActivityManager) this.getSystemService(ACTIVITY_SERVICE);
List<ActivityManager.RunningTaskInfo> taskInfo = am.getRunningTasks(1); 
ComponentName componentInfo = taskInfo.get(0).topActivity;
am.restartPackage(componentInfo.getPackageName());

2

Скажімо, у вас є стек активності, такий як A> B> C> D> E. Ви перебуваєте в діяльності D, і ви хочете закрити програму. Це те, що ти будеш робити -

В Діяльність, звідки Ви бажаєте закрити (Діяльність D) -

Intent intent = new Intent(D.this,A.class);
intent.putExtra("exit", "exit");
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP| Intent.FLAG_ACTIVITY_SINGLE_TOP);
startActivity(intent);

У вашій RootActivity (тобто вашій базовій діяльності, тут Діяльність A) -

@Override
    protected void onNewIntent(Intent intent) {
        super.onNewIntent(intent);
        if (intent.hasExtra("exit")) {
            setIntent(intent);
        }
    }

    @Override
    protected void onResume() {
        super.onResume();
        if (getIntent() != null) {
            if (("exit").equalsIgnoreCase(getIntent().getStringExtra(("exit")))) {
                onBackPressed();
            }
        }
    }

використовується onNewIntent, оскільки якщо активність активна, вона отримає перший намір, який її розпочав. Не новий. Детальніше - Документація


1

Це насправді тихо легко.

Я роблю це, зберігаючи прапор у статичній змінній, доступній для всіх. Потім, коли я виходжу, я встановлюю цей прапор і всі мої дії перевіряють цей прапор onResume. Якщо прапорець встановлений, я видаю інформацію System.exitпро цю діяльність.

Таким чином усі дії перевірятимуть прапор і витончено закриватимуться, якщо встановлений прапор.


1

Це те, що я зробив, щоб закрити програму: У моїй програмі я маю базовий клас активності, я додав статичний прапор під назвою "applicationShutDown". Коли мені потрібно закрити програму, я встановлюю для неї значення true.

У базовій діяльності onCreate і onResume після виклику супервикликів я перевіряю цей прапор. Якщо "applicationShutDown" відповідає дійсності, я називаю закінчення поточної активності.

Це спрацювало для мене:

protected void onResume() {
    super.onResume();
    if(BaseActivity.shutDownApp)
    {
        finish();
        return;

    }}

0

Виконайте другу діяльність, використовуючи стартову активність для результату:

Intent intent = new Intent(FirstActivity.this, SecondActivity.class);

//This line is important
intent.addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);

startActivityForResult(intent, REQUEST_CODE);

Додайте цю функцію до першої діяльності:

@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
    super.onActivityResult(requestCode, resultCode, data);
    if(rquestCode == REQUEST_CODE)
        if(resultCode == RESULT_CANCELED)
            finish();
}

І додайте це до другої діяльності:

@Override
public boolean onKeyDown(int keyCode, KeyEvent event)  {
    if (keyCode == KeyEvent.KEYCODE_BACK && event.getRepeatCount() == 0) {

        Log.i(TAG, "Back key pressed");
        setResult(RESULT_CANCELED);
        finish();
        return true;
    }
    return super.onKeyDown(keyCode, event);
}

0

Це не рекомендується, але ви все одно можете використовувати це. Краще скористайтеся цим рішенням, якщо вам потрібно закрити програму.

На мою думку, найкращим рішенням буде закінчити кожну діяльність у своєму додатку, як показано нижче.

Крок 1. Підтримуйте статичну змінну у головній активності. Казати,

public static boolean isQuit = false;

Крок 2. Після події натискання кнопки встановіть для цієї змінної значення true.

mainactivity.isQuit = true;
finish();

Крок 3. І для кожної діяльності у вашій заявці використовуйте onrestartметод, наведений нижче.

@Override
protected void onRestart() {
    // TODO Auto-generated method stub
    super.onRestart();
    if(mainactivity.isQuit)
        finish();
}

0

Я вирішив подібну проблему: MainActivity запускає BrowserActivity, і мені потрібно закрити програму, коли користувач натискає Назад у BrowserActivity - щоб не повертатися в MainActivity. Отже, в MainActivity:

public class MainActivity extends AppCompatActivity {
    private static final String TAG = "sm500_Rmt.MainActivity";
    private boolean m_IsBrowserStarted = false;

а потім у OnResume:

    @Override
protected void onResume() {
    super.onResume();
    if(m_IsBrowserStarted) {
        Log.w(TAG, "onResume, but it's return from browser, just exit!");
        finish();
        return;
    }
    Log.w(TAG, "onResume");

... далі продовжуйте OnResume. І при запуску BrowserActivity:

    Intent intent = new Intent(this, BrowserActivity.class);
    intent.putExtra(getString(R.string.IPAddr), ip);
    startActivity(intent);
    m_IsBrowserStarted = true;

І схоже це добре працює! :-)

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.