Como posso programaticamente "reiniciar" uma aplicação Android?
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?
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);
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.
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.
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);
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.
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!
Intent i = getBaseContext().getPackageManager().getLaunchIntentForPackage( getBaseContext().getPackageName() );
i.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
startActivity(i);
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();
}
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);
}
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.
Tente usar FLAG_ACTIVITY_CLEAR_TASK
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);
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);
}
Inicie directamente o ecrã inicial com {[[0]} e FLAG_ACTIVITY_NEW_TASK
.
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);
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.
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!
Tenta isto:
Intent intent = getPackageManager().getLaunchIntentForPackage(getPackageName());
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
startActivity(intent);
Utilizar:
navigateUpTo(new Intent(this, MainActivity.class));
Funciona a partir do nível 16 da API (4.1), creio eu.