Como posso programaticamente "reiniciar" uma aplicação Android?

Primeiro, sei que não se deve matar / reiniciar uma aplicação no Android. No meu caso de uso, eu quero refazer a minha aplicação em um caso específico onde um servidor envia uma informação específica para o cliente.

O Utilizador só pode ser ligado no servidor com uma instância da aplicação (ou seja, não são permitidos múltiplos dispositivos). Se outra instância Obtém que "logted-in" - lock, então todas as outras instâncias desse usuário tem que apagar seus dados (reinicialização de fábrica), para manter consistência.

é possível obter à força o bloqueio, porque o utilizador pode apagar o aplicativo e reinstalá-lo, o que resultaria num ID de instância diferente e o utilizador não seria capaz de libertar o bloqueio mais. Portanto, é possível forçar a fechadura.

Por causa dessa força-possibilidade, temos sempre de verificar, num caso concreto, que tem a fechadura. Isso é feito em (quase) cada pedido para o servidor. O servidor pode enviar uma "identificação errada". Se isso for detectado, a aplicação cliente deve excluir tudo.


Esse era o caso de uso. Não para a execução-pergunta:

Eu tenho um Activity a que inicia o Login Activity L ou o principal Activity B da aplicação, dependendo de um campo sharedPrefs. Depois de iniciar L ou B ele se fecha de modo que apenas L ou B está funcionando. Então, no caso de o usuário estar logado já B está em execução agora.

B inicia C. C chama startService para o IntentService D. Isso resulta neste pilha:

A) > B > C > D

do método onHandleIntent de D, um evento é enviado para um Leitor de resultados r.

r agora lida com esse evento, fornecendo ao Utilizador uma janela onde ele pode escolher reiniciar a aplicação de fábrica (apagar a base de dados, sharedPrefs, etc.)

Depois do reinício da fábrica, quero reiniciar a aplicação (para fechar todas as actividades) e apenas iniciar uma de novo que, em seguida, lança o login Activity L e termina por si próprio:

a) > L

O método onClick da janela parece-se com o seguinte:
@Override
public void onClick(DialogInterface dialog, int which) {

    // Will call onCancelListener
    MyApplication.factoryReset(); // (Deletes the database, clears sharedPrefs, etc.)
    Intent i = new Intent(MyApp.getContext(), A.class);
    i.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
    i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
    MyApp.getContext().startActivity(i);
}
E esta é a classe MyApp:

public class MyApp extends Application {
    private static Context context;

    @Override
    public void onCreate() {
        super.onCreate();
        context = getApplicationContext();
    }

    public static Context getContext() {
        return context;
    }

    public static void factoryReset() {
        // ...
    }
}

o problema agora é que se eu usar o FLAG_ACTIVITY_NEW_TASK as actividades B E C ainda estão em execução. Se eu carregar no botão de trás no login Activity Eu vejo C, Mas eu quero voltar para o home screen.

Se Eu não definir o FLAG_ACTIVITY_NEW_TASK Eu recebo o erro:

07-07 12:27:12.272: ERROR/AndroidRuntime(9512): android.util.AndroidRuntimeException: Calling startActivity() from outside of an Activity  context requires the FLAG_ACTIVITY_NEW_TASK flag. Is this really what you want?

Eu não posso usar as actividades ' Context, Porque o ServiceIntent D também pode ser chamado a partir de uma tarefa de fundo que é a começar pelo AlarmManager.

Então como poderia resolver isto para a pilha de actividades tornar-se (a) > L?

 162
Author: Peter Mortensen, 2011-07-07

20 answers

Pode usar PendingIntent para configurar o lançamento da sua actividade inicial no futuro e, em seguida, fechar a sua aplicação

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);
 244
Author: Oleg Koshkin, 2015-05-11 16:40:05

Você pode simplesmente ligar:

public static void triggerRebirth(Context context, Intent nextIntent) {
    Intent intent = new Intent(context, YourClass.class);
    intent.addFlags(FLAG_ACTIVITY_NEW_TASK);
    intent.putExtra(KEY_RESTART_INTENT, nextIntent);
    context.startActivity(intent);
    if (context instanceof Activity) {
      ((Activity) context).finish();
    }

    Runtime.getRuntime().exit(0);
}

Que é usado na biblioteca ProcessPhoenix


Em alternativa:

Aqui está uma versão melhorada da resposta de @Oleg Koshkin.

Se quiser mesmo reiniciar a sua actividade, incluindo a eliminação do processo actual, tente seguir o código. Coloque-o numa sala de HelperClass ou onde precisar.

public static void doRestart(Context c) {
        try {
            //check if the context is given
            if (c != null) {
                //fetch the packagemanager so we can get the default launch activity 
                // (you can replace this intent with any other activity if you want
                PackageManager pm = c.getPackageManager();
                //check if we got the PackageManager
                if (pm != null) {
                    //create the intent with the default start activity for your application
                    Intent mStartActivity = pm.getLaunchIntentForPackage(
                            c.getPackageName()
                    );
                    if (mStartActivity != null) {
                        mStartActivity.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
                        //create a pending intent so the application is restarted after System.exit(0) was called. 
                        // We use an AlarmManager to call this intent in 100ms
                        int mPendingIntentId = 223344;
                        PendingIntent mPendingIntent = PendingIntent
                                .getActivity(c, mPendingIntentId, mStartActivity,
                                        PendingIntent.FLAG_CANCEL_CURRENT);
                        AlarmManager mgr = (AlarmManager) c.getSystemService(Context.ALARM_SERVICE);
                        mgr.set(AlarmManager.RTC, System.currentTimeMillis() + 100, mPendingIntent);
                        //kill the application
                        System.exit(0);
                    } else {
                        Log.e(TAG, "Was not able to restart application, mStartActivity null");
                    }
                } else {
                    Log.e(TAG, "Was not able to restart application, PM null");
                }
            } else {
                Log.e(TAG, "Was not able to restart application, Context null");
            }
        } catch (Exception ex) {
            Log.e(TAG, "Was not able to restart application");
        }
    }

Isto também irá reiniciar as classes jni e todas as instâncias estáticas.

 74
Author: mikepenz, 2016-08-22 12:43:32
O Jake Wharton publicou recentemente a sua biblioteca ProcessPhoenix, O Que Faz isto de forma fiável. Basicamente só tens de ligar.
ProcessPhoenix.triggerRebirth(context);

A biblioteca irá terminar automaticamente a actividade de chamada, matar o processo de aplicação e reiniciar a actividade por omissão da aplicação depois.

 54
Author: TBieniek, 2015-09-04 12:37:05
IntentCompat.makeRestartActivityTask

A nova forma de o fazer é usando IntentCompat.makerestartactivityask

Faça uma intenção que possa ser usada para reiniciar a tarefa de uma aplicação em o seu estado base. Isto é como a makeMainActivity (ComponentName), mas também define a intenção das bandeiras.FLAG_ACTIVITY_NEW_ tarefa e FLAG_ACTIVITY_CLEAR_TASK.

PackageManager packageManager = context.getPackageManager();
Intent intent = packageManager.getLaunchIntentForPackage(context.getPackageName());
ComponentName componentName = intent.getComponent();
Intent mainIntent = IntentCompat.makeRestartActivityTask(componentName);
context.startActivity(mainIntent);
System.exit(0);
 31
Author: Ilya Gazman, 2016-03-14 15:32:44
Há um truque muito bom. O meu problema era que uma biblioteca jni c++ vazou recursos. A dada altura, deixou de funcionar. O usuário tentou sair do aplicativo e lançá-lo novamente -- sem resultado, porque terminar uma atividade não é o mesmo que terminar (ou matar) o processo. (A propósito, o usuário poderia ir para a lista das aplicações em execução e impedi-lo de lá -- isso iria funcionar, mas os usuários simplesmente não sabem como terminar as aplicações.)

Se se quiser observar o efeito desta funcionalidade, adicione uma variável static à sua actividade e aumente cada uma delas, por exemplo, carregue no botão. Se você sair da atividade da aplicação e, em seguida, invocar a aplicação novamente, esta variável estática irá manter o seu valor. (Se o aplicativo realmente saiu, a variável seria atribuída o valor inicial.)

(e eu tenho que comentar porque eu não queria corrigir o bug em vez disso. A Biblioteca foi escrita há décadas e vazou recursos desde então. A direcção acredita que sempre funcionou. O custo de fornecer uma solução em vez de uma solução... Acho que percebeste a ideia.)

Agora, como poderia repor uma biblioteca partilhada pelo jni (também conhecida por dynamic,. so) no estado inicial? Eu escolhi reiniciar a aplicação como um novo processo.

O truque é esse sistema.o exit () fecha a actividade actual e o Android recria a aplicação com uma actividade a menos.

Então o código é:

/** This activity shows nothing; instead, it restarts the android process */
public class MagicAppRestart extends Activity {
    // Do not forget to add it to AndroidManifest.xml
    // <activity android:name="your.package.name.MagicAppRestart"/>
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        System.exit(0);
    }
    public static void doRestart(Activity anyActivity) {
        anyActivity.startActivity(new Intent(anyActivity.getApplicationContext(), MagicAppRestart.class));
    }
}
A actividade de chamada apenas executa o código MagicAppRestart.doRestart(this);, a atividade de chamada onPause() é executada, e então o processo é recriado. E não se esqueça de mencionar esta atividade no AndroidManifest.xml A vantagem deste método é que não há atrasos. Funcionou no Android 2.x, mas no Android 4 algo mudou.
 26
Author: 18446744073709551615, 2014-11-13 07:54:26
Ok, eu refacturei o meu aplicativo e não vou terminar um automaticamente. Deixo isto correr sempre e acabo com o evento. Desta forma, posso usar o FLAG_ACTIVITY_CLEAR_TOP + FLAG_ACTIVITY_NEW_TASK bandeiras para obter o que eu quero:
public class A extends Activity {

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        finish();
    }

    protected void onResume() {
        super.onResume();
        // ...
        if (loggedIn) {
            startActivityForResult(new Intent(this, MainActivity.class), 0);
        } else {
            startActivityForResult(new Intent(this, LoginActivity.class), 0);
        }
    }
}

E na ResultReceiver

@Override
public void onClick(DialogInterface dialog, int which) {
    MyApp.factoryReset();
    Intent i = new Intent(MyApp.getContext(), A.class);
    i.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
    i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
    MyApp.getContext().startActivity(i);
}
Obrigado na mesma!
 14
Author: Stuck, 2011-07-07 11:40:47
Intent i = getBaseContext().getPackageManager().getLaunchIntentForPackage( getBaseContext().getPackageName() );
i.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
startActivity(i);
 13
Author: Nirav Ranpara, 2012-11-30 11:30:07

A minha solução não reiniciou o processo/aplicação. Ele só permite que o aplicativo "reiniciar" a atividade doméstica (e descartar todas as outras atividades). Parece um reinício para os usuários, mas o processo é o mesmo. Acho que, em alguns casos, as pessoas querem atingir este efeito, por isso, deixo-o aqui para que saibas.

public void restart(){
    Intent intent = new Intent(this, YourHomeActivity.class);
    this.startActivity(intent);
    this.finishAffinity();
}
 12
Author: yongsunCN, 2017-07-24 21:19:49

Modifiquei ligeiramente a resposta de Ilya_Gazman para usar novas APIs (a IntentCompat está desactualizada a partir da API 26). Execucao.getRuntime ().exit (0) parece ser melhor do que o sistema.exit (0).

 public static void triggerRebirth(Context context) {
    PackageManager packageManager = context.getPackageManager();
    Intent intent = packageManager.getLaunchIntentForPackage(context.getPackageName());
    ComponentName componentName = intent.getComponent();
    Intent mainIntent = Intent.makeRestartActivityTask(componentName);
    context.startActivity(mainIntent);
    Runtime.getRuntime().exit(0);
}
 12
Author: android_dev, 2017-10-20 11:32:58

A melhor maneira de reiniciar completamente um aplicativo é relançá-lo, não apenas para saltar para uma atividade com FLAG_ACTIVITY_CLEAR_TOP e FLAG_ACTIVITY_NEW_TASK. Então a minha solução é fazê-lo a partir do seu aplicativo ou mesmo de outro app, a única condição é saber o nome do pacote app (exemplo: 'com.exemplo.myProject')

 public static void forceRunApp(Context context, String packageApp){
    Intent launchIntent = context.getPackageManager().getLaunchIntentForPackage(packageApp);
    launchIntent.setFlags(Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS | Intent.FLAG_ACTIVITY_NEW_TASK);
    context.startActivity(launchIntent);
}

Exemplo de Utilização reiniciar ou lançar appA de appB:

forceRunApp(mContext, "com.example.myProject.appA");

Pode verificar se a aplicação está a correr:

 public static boolean isAppRunning(Context context, String packageApp){
    ActivityManager activityManager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
    List<ActivityManager.RunningAppProcessInfo> procInfos = activityManager.getRunningAppProcesses();
    for (int i = 0; i < procInfos.size(); i++) {
        if (procInfos.get(i).processName.equals(packageApp)) {
           return true;
        }
    }
    return false;
}

Nota : Eu sei que esta resposta é um pouco fora de questão, mas pode ser muito útil para alguém.

 4
Author: Choletski, 2017-07-24 21:18:56

Tente usar FLAG_ACTIVITY_CLEAR_TASK

 3
Author: Pedro Loureiro, 2011-07-07 11:00:23

Aqui está um exemplo para reiniciar a sua aplicação de uma forma genérica, usando o PackageManager:

Intent i = getBaseContext().getPackageManager()
             .getLaunchIntentForPackage( getBaseContext().getPackageName() );
i.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
startActivity(i);
 3
Author: Alireza Ghanbarinia, 2016-05-11 06:34:07

O único código que não activou "a sua aplicação fechou inesperadamente" é o seguinte. Também é um código não-obsoleto que não requer uma biblioteca externa. Também não precisa de um temporizador.

public static void triggerRebirth(Context context, Class myClass) {
    Intent intent = new Intent(context, myClass);
    intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
    context.startActivity(intent);
    Runtime.getRuntime().exit(0);
}
 3
Author: Haskell McRavin, 2018-02-13 02:40:51

Inicie directamente o ecrã inicial com {[[0]} e FLAG_ACTIVITY_NEW_TASK.

 2
Author: Yijun Li, 2016-09-14 08:03:19

Tive de adicionar um manipulador para atrasar a saída:

 mgr.set(AlarmManager.RTC, System.currentTimeMillis() + 200, mPendingIntent);
        final Handler handler = new Handler();
        handler.postDelayed(new Runnable() {
            @Override
            public void run() {
                Runtime.getRuntime().exit(0);
            }
        }, 100);
 2
Author: Andy7229082, 2017-01-18 07:46:16

Pode utilizar startInstrumentation o método de Activity. Você precisa implementar vazio Instrumentation e apontado no manifesto. Depois disso você pode chamar este método para reiniciar o seu aplicativo. Assim:

try {           
    InstrumentationInfo info = getPackageManager().queryInstrumentation(getPackageName(), 0).get(0);
    ComponentName component = new ComponentName(this, Class.forName(info.name));
    startInstrumentation(component, null, null);
} catch (Throwable e) {             
    new RuntimeException("Failed restart with Instrumentation", e);
}
Tenho o nome da classe de instrumentação dinamicamente, mas podes codificá-la. Alguns como este:
try {           
    startInstrumentation(new ComponentName(this, RebootInstrumentation.class), null, null); 
} catch (Throwable e) {             
    new RuntimeException("Failed restart with Instrumentation", e);
}

Ligue startInstrumentation Faça recarregar a sua aplicação. Leia a descrição deste método. Mas não pode ser seguro se agirmos como app kill.

 1
Author: Enyby, 2016-10-05 09:41:34

A aplicação em que estou a trabalhar tem de dar ao utilizador a possibilidade de escolher quais os fragmentos a apresentar (os fragmentos são alterados dinamicamente em tempo de execução). A melhor solução para mim foi reiniciar completamente a aplicação.

Então tentei muitas soluções e nenhuma delas trabalhou para mim, mas isto:
final Intent mStartActivity = new Intent(SettingsActivity.this, Splash.class);
final int mPendingIntentId = 123456;
final PendingIntent mPendingIntent = PendingIntent.getActivity(SettingsActivity.this, mPendingIntentId, mStartActivity,
                    PendingIntent.FLAG_CANCEL_CURRENT);
final AlarmManager mgr = (AlarmManager) SettingsActivity.this.getSystemService(Context.ALARM_SERVICE);
mgr.set(AlarmManager.RTC, System.currentTimeMillis() + 100, mPendingIntent);
this.finishAffinity(); //notice here
Runtime.getRuntime().exit(0); //notice here
Espero que isso ajude outra pessoa!
 1
Author: Mitchapp, 2016-11-21 11:03:12

Tenta isto:

Intent intent = getPackageManager().getLaunchIntentForPackage(getPackageName());
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
startActivity(intent);
 1
Author: veeson, 2017-09-29 01:19:57

Utilizar:

navigateUpTo(new Intent(this, MainActivity.class));

Funciona a partir do nível 16 da API (4.1), creio eu.

 0
Author: Peter Mortensen, 2017-07-24 21:15:02

Pode reiniciar a sua actividade actual assim:

Fragmento:

activity?.recreate()

Actividade:

recreate()
 0
Author: , 2018-07-17 05:16:44