Закрийте програму та запустіть головний екран на 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.