Примусово перезапустити програму при першій дії


75

З невідомої причини я не можу належним чином залишити програму, щоб після повторного натискання кнопки головного екрана та значка програми я продовжував там, де я був у програмі. Я хотів би змусити програму перезапуститись при першій діяльності.

Припускаю, це має щось спільне з onDestroy () або, можливо, onPause (), але я не знаю, що робити.

Відповіді:


156

Ось приклад перезапуску програми загальним чином за допомогою PackageManager:

Intent i = getBaseContext().getPackageManager()
             .getLaunchIntentForPackage( getBaseContext().getPackageName() );
i.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_CLEAR_TASK);
startActivity(i);

3
Мені це допомагає. Дякую. Я використовував так, "спробуйте {Intent i; i = getBaseContext (). GetPackageManager () .getLaunchIntentForPackage (getBaseContext (). GetPackageName ()); i.addFlags (Intent.FLAG_ACTIVITY_CLEAR_TOPN; startAnt (IE)) д) {e.printStackTrace ();}
tknv

Одна проблема такого підходу. викликається нова активність onCreate до того, як старий стек активності потрапитьDestroy
AAverin

1
@AAverin: як я можу зателефонувати onDestroy до onCreate?
олігофрен

7
не працює, просто відновіть запуск, клас програми не скидається

2
Використовуйте прапори як Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_CLEAR_TASK, це чудово працює і також очищає стек активності.
Lalit Fauzdar

30

Рішення, позначене як "відповідь", працює, але має один недолік, який був для мене критичним. За допомогою FLAG_ACTIVITY_CLEAR_TOP ваша цільова активність отримає виклик onCreate до того, як ваш старий стек активності отримає onDestroy. Поки я розчищав деякі необхідні речі в onDestroy, мені довелося обійти шлях.

Це рішення, яке працювало для мене:

public static void restart(Context context, int delay) {
    if (delay == 0) {
        delay = 1;
    }
    Log.e("", "restarting app");
    Intent restartIntent = context.getPackageManager()
            .getLaunchIntentForPackage(context.getPackageName() );
    PendingIntent intent = PendingIntent.getActivity(
            context, 0,
            restartIntent, Intent.FLAG_ACTIVITY_CLEAR_TOP);
    AlarmManager manager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
    manager.set(AlarmManager.RTC, System.currentTimeMillis() + delay, intent);
    System.exit(2);
}

Ідея полягає в тому, щоб запустити PendingIntent через AlarmManager, який буде викликаний трохи пізніше, даючи старому стеку активності деякий час для очищення.


1
Чому б вам просто не викликати метод Activity'' finish()замість System.exit? У документі сказано: "Зателефонуйте, коли ваша діяльність закінчиться і її слід закрити".
олігофрен

1
Я щойно зрозумів, що це пов’язано зі статичністю методу, отже, неможливістю викликати будь-які нестатичні методи, такі як finish. Я щойно зробив restartнестатичний і замінив виклик System.exit.
олігофрен

1
І після тестування я виявив, що використання finish () призводить до зависання мого додатка під час запуску, тоді як System.exit працює нормально ...
oligofren

3
погодитися з попереднім коментарем. Я використав PendingIntent.FLAG_CANCEL_CURRENT замість Intent.FLAG_ACTIVITY_CLEAR_TOP, щоб видалити попередження
Valeriy

15

якщо ви хочете завжди починати з кореня, ви хочете встановити для android: clearTaskOnLaunch значення true у вашій кореневій діяльності


1
так, я спробував це, але тоді, коли я натискаю піктограму ще раз, здається, викликаю Resume замість onCreate ... що означає, що я отримую екран, не починаючи жодного з моїх методів
Sephy 18.03.10

2
Або додайте прапор Intent.FLAG_ACTIVITY_CLEAR_TASKпрограмно до Наміру.
Давідеас,

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

Використовуйте цю властивість у файлі маніфесту у початковому класі (перша діяльність).


3

Чи робить FLAG_ACTIVITY_CLEAR_TOP те, що вам потрібно зробити?

Intent i = new Intent(getBaseContext(), YourActivity.class);
            i.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
            startActivity(i);

3

FLAG_ACTIVITY_CLEAR_TOPне працював у мене, тому що я повинен був підтримати 2.3.3. Моє перше рішення було:

Intent intent = context.getPackageManager().getLaunchIntentForPackage(context.getPackageName());
    intent.addFlags(Build.VERSION.SDK_INT >= 11 ? Intent.FLAG_ACTIVITY_CLEAR_TASK : Intent.FLAG_ACTIVITY_CLEAR_TOP);
context.startActivity(intent);

Це майже працює, але не зовсім.

Оскільки я маю базову активність, я додав трансляцію kill, яка закриває всі мої запущені дії.

public abstract class BaseActivity extends AppCompatActivity {

    private static final String ACTION_KILL = "BaseActivity.action.kill";
    private static final IntentFilter FILTER_KILL;
    static {
        FILTER_KILL = new IntentFilter();
        FILTER_KILL.addAction(ACTION_KILL);
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        registerReceiver(killReceiver, FILTER_KILL);
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        unregisterReceiver(killReceiver);
    }

    private final BroadcastReceiver killReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            finish();
        }
    };

    public void killApp(){
        sendBroadcast(new Intent(ACTION_KILL));
    }
}

Усі мої заняття поширюються на цей клас, отже

((BaseActivity)getActivity()).killApp();
startActivity(new Intent(getActivity(), StartActivity.class));

перезапускає програму. Випробувано на genymotion v10, v16, v21 та Nexus 5 з v22.

Редагувати: це не видаляє діяльність, якщо вона була знищена під час надсилання наміру. Я все ще шукаю рішення.


3

Наступний код працює для мене, він може ідеально перезапустити повний додаток!

Intent mStartActivity = new Intent(context, StartActivity.class);
int mPendingIntentId = 123456;
PendingIntent mPendingIntent = PendingIntent.getActivity(context,mPendingIntentId,    mStartActivity, PendingIntent.FLAG_CANCEL_CURRENT);
AlarmManager mgr = (AlarmManager)context.getSystemService(Context.ALARM_SERVICE);
mgr.set(AlarmManager.RTC, System.currentTimeMillis() + 100, mPendingIntent);
System.exit(0);

Що означає значення mPendingIntentId? Виглядає як особливо магічне число - це просто довільний int?
aaaidan

Це просто довільне число, ви можете використовувати будь-яке випадкове ціле число. Це номер повідомлення в класі PendingIntent.
Беатріс Лін

2

Відповідь Марка чудово працює, за винятком мого випадку, коли моєю основною діяльністю є launchMode singleTop. Після того, як я запустив цей намір, а потім перейшов до нових дій і натиснув кнопку додому на пристрої, а потім запустив програму знову за допомогою піктограми програми, я в кінцевому підсумку створив новий екземпляр основної діяльності, з моєю попередньою активністю на задньому стеку .

Відповідно до цього питання це тому, що наміри не збігаються. Дивлячись adb dumpsys activity, я бачу, що зі моєї стандартної програми запуску Android пакет є нульовим, тоді як коли я роблю так, як пропонує Марк, пакет намірів - це назва мого пакета. Ця різниця призводить до того, що вони не збігаються і запускають новий екземпляр, коли піктограма програми натискається знову, а основна діяльність не зверху.

Тим НЕ менше, на інших пускових установках , як на Kindle, пакет буде встановлений на пусковому намірі, так що мені потрібна загальний спосіб обробки пускових установок . Я додав статичні методи на зразок таких:

static boolean mIsLaunchIntentPackageNull = true;    

public static boolean isLaunchIntent(Intent i) {
    if (Intent.ACTION_MAIN.equals(i.getAction()) && i.getCategories() != null
            && i.getCategories().contains(Intent.CATEGORY_LAUNCHER)) {
        return true;
    }

    return false;
}

public static void handleLaunchIntent(Intent i) {
    if (isLaunchIntent(i)) {
        if (i.getPackage() != null) {
            mIsLaunchIntentPackageNull = false;
        }
        else {
            mIsLaunchIntentPackageNull = true;
        }
    }
}

з механізмом повернення додому таким чином:

    Intent intentHome = appContext.getPackageManager()
            .getLaunchIntentForPackage( appContext.getPackageName());
    intentHome.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);

    // need to match launcher intent exactly to avoid duplicate activities in stack
    if (mIsLaunchIntentPackageNull) {
        intentHome.setPackage(null);
    }
    appContext.startActivity(intentHome);

тоді в основну діяльність, визначену в моєму маніфесті, я додав цей рядок:

public void onCreate(Bundle savedInstanceState) {
    [class from above].handleLaunchIntent(getIntent());

це працює для мене на Kindle та на моєму телефоні, і дозволяє мені правильно скинути програму без додавання чергового екземпляра основної діяльності.



1

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

Intent mStartActivity = new Intent(ctx.getApplicationContext(), ActivityMain.class);


    mStartActivity.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
    mStartActivity.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB)
        mStartActivity.addFlags(0x8000); // equal to Intent.FLAG_ACTIVITY_CLEAR_TASK

   int mPendingIntentId = 123456;


    PendingIntent mPendingIntent = PendingIntent.getActivity(ctx, mPendingIntentId, mStartActivity, PendingIntent.FLAG_CANCEL_CURRENT);
    AlarmManager mgr = (AlarmManager) ctx.getSystemService(Context.ALARM_SERVICE);
    mgr.set(AlarmManager.RTC, System.currentTimeMillis() + 1000, mPendingIntent);

    ActivityManager manager =  (ActivityManager) ctx.getApplicationContext().getSystemService(ctx.getApplicationContext().ACTIVITY_SERVICE);
    List<ActivityManager.RunningAppProcessInfo> activityes = ((ActivityManager)manager).getRunningAppProcesses();




    ((Activity)ctx).moveTaskToBack(true);
    manager.killBackgroundProcesses("com.yourpackagename");
    System.exit(0);

0

Вам слід оформити це питання:

Перезапустити програму Android програмно

Спосіб зробити це:

private void restartApp() 
{
   Intent intent = new Intent(getApplicationContext(), YourStarterActivity.class);
   int mPendingIntentId = MAGICAL_NUMBER;
   PendingIntent mPendingIntent = PendingIntent.getActivity(getApplicationContext(), mPendingIntentId, intent, PendingIntent.FLAG_CANCEL_CURRENT);
   AlarmManager mgr = (AlarmManager) getApplicationContext().getSystemService(Context.ALARM_SERVICE);
   mgr.set(AlarmManager.RTC, System.currentTimeMillis() + 100, mPendingIntent);
   System.exit(0);
}

-1

Після ретельного обмірковування та тестування я нарешті отримав правильний спосіб викликати свою активність для відтворення, коли в додатку залишається кнопка додому:

android:clearTaskOnLaunch

у маніфесті

@Override
public void onRestart(){
    onCreate();
}

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


2
Це звучить погано. Вам повинен знадобитися лише clearTaskOnLaunchатрибут. Як ви запускаєте свій додаток? Безпосередньо з Eclipse за допомогою інструментів ADT? Якщо так, сталася помилка, яка означала, що програми не запускались належним чином з Eclipse. З тих пір це виправлено.
Крістофер Орр,

так, безпосередньо від затемнення. але я пробував лише з clearTaskOnLaunch, і я не міг змусити це працювати ...
Сефі,

Привіт, як додати onRestart()метод. Чи можете ви дати фрагмент? Дякую

4
Люди, будь ласка, не дзвоніть onCreate()з onRestart(). Це (створення та перезапуск) - це дві різні події. Якщо ви хочете, щоб вони виконували той самий код, зробіть: void myOnCreate() { ... } void onCreate(){myOnCreate();} void onRestart() {myOnCreate();}замість цього.
18446744073709551615

1
@Fraggles, оскільки це робить ваш код неможливим . Як правило, це правильно, коли функція onRestart () викликає super.onRestart () . Але якщо ви зателефонуєте onCreate () з onRestart () , це цілком розумне припущення стане неправильним для вашого проекту. Наприклад, це також правильно, коли ви усвідомлюєте, що вам потрібні певні функціональні можливості у всіх видах діяльності, визначати свій клас ActivityWithSomething, а зміна розширює Activity до розширення ActivityWithSomething для всіх дій у проекті.
18446744073709551615
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.