Em primeiro lugar, eu sei que não se deve realmente matar / reiniciar um aplicativo no Android. No meu caso de uso, desejo redefinir o aplicativo de fábrica em um caso específico em que um servidor envia uma informação específica ao cliente.
O usuário pode fazer login apenas no servidor com UMA instância do aplicativo (ou seja, vários dispositivos não são permitidos). Se outra instância obtiver o bloqueio "logado", todas as outras instâncias desse usuário terão que excluir seus dados (redefinição de fábrica), para manter a consistência.
É possível obter o bloqueio à força, porque o usuário pode excluir o aplicativo e reinstalá-lo, o que resultaria em um ID de instância diferente e o usuário não conseguiria mais liberar o bloqueio. Portanto, é possível obter o bloqueio à força.
Por causa dessa possibilidade de força, precisamos sempre verificar, em um caso concreto, se ela possui a trava. Isso é feito em (quase) cada solicitação ao servidor. O servidor pode enviar um "ID de bloqueio errado". Se isso for detectado, o aplicativo cliente deve excluir tudo.
Esse foi o caso de uso.
Eu tenho um Activity
A que inicia o Login Activity
L ou o Activity
B principal do aplicativo, dependendo de um valor sharedPrefs. Depois de iniciar L ou B, ele se fecha para que apenas L ou B esteja em execução. Portanto, no caso em que o usuário está logado, B já está sendo executado agora.
B inicia C. C chama startService
o IntentService
D. Isso resulta nessa pilha:
(A)> B> C> D
No método onHandleIntent de D, um evento é enviado para um ResultReceiver R.
R agora lida com esse evento, fornecendo ao usuário uma caixa de diálogo onde ele pode optar por redefinir o aplicativo de fábrica (excluir o banco de dados, sharedPrefs etc.)
Após a redefinição de fábrica, desejo reiniciar o aplicativo (para fechar todas as atividades) e iniciar somente A novamente, que inicia o logon Activity
L e termina:
(A)> L
O método onClick do Dialog se parece 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 essa é a MyApp
classe:
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 é que se eu usar FLAG_ACTIVITY_NEW_TASK
as atividades B e C ainda estiverem em execução. Se eu apertar o botão voltar no login Activity
, vejo C, mas quero voltar à tela inicial.
Se eu não definir FLAG_ACTIVITY_NEW_TASK
, 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?
Não posso usar as atividades ' Context
, porque o ServiceIntent
D também pode ser chamado a partir de uma tarefa em segundo plano iniciada pelo AlarmManager
.
Então, como eu poderia resolver isso para a pilha de atividades se tornar (A)> L?