Android: Jak automatycznie zrestartować aplikację po „wymuszonym zamknięciu”?

81

W aplikacji na Androida zwykle otrzymywaliśmy błąd „Wymuś zamknięcie”, jeśli nie obsłużyliśmy poprawnie wyjątków.

Jak mogę automatycznie ponownie uruchomić moją aplikację, jeśli zostanie wymuszona?

Czy zastosowano w tym celu jakieś specjalne pozwolenie?

Jasio
źródło
5
Spróbuj poprawnie ustawić wyjątki. Aplikacja, która automatycznie uruchamia się ponownie, może być denerwująca dla użytkowników.
Tomas Andrle
12
Chcę tylko ponownie uruchomić aplikację, jeśli uległa awarii. Myślę, że byłoby to bardziej przyjazne niż denerwujące, zwłaszcza gdy użytkownik jest w mojej aplikacji. I tak, próbuję rozwiązać każdy wyjątek. :)
Johnny
2
@Johnny: Udostępnij rozwiązanie swojego problemu.
Code_Life,
sprawdź ten artykuł, aby ponownie uruchomić aplikację w przypadku każdego wyjątku.
Chintan Rathod

Odpowiedzi:

100

Aby to osiągnąć, musisz zrobić dwie rzeczy:

  1. Unikaj „Wymuś zamknięcie” - standardowego sposobu awarii aplikacji.
  2. Skonfiguruj mechanizm ponownego uruchamiania, gdy awaria mimo wszystko nastąpi.

Zobacz poniżej, jak to zrobić:

  1. Wywołaj Thread.setDefaultUncaughtExceptionHandler(), aby złapać wszystkie nieprzechwycone wyjątki, w którym to przypadku uncaughtException()zostanie wywołana metoda. „Wymuś zamknięcie” nie pojawi się, a aplikacja nie będzie odpowiadać, co nie jest całkiem dobrą rzeczą. Aby ponownie uruchomić aplikację po awarii, wykonaj następujące czynności:

  2. W onCreatemetodzie w głównym działaniu zainicjuj PendingIntentczłonka:

    Intent intent = PendingIntent.getActivity(
        YourApplication.getInstance().getBaseContext(),
        0,
        new Intent(getIntent()),
        getIntent().getFlags());
    

Następnie umieść następujące w swojej uncaughtException()metodzie:

AlarmManager mgr = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
mgr.set(AlarmManager.RTC, System.currentTimeMillis() + 2000, intent);
System.exit(2);

Musisz też zadzwonić System.exit(), inaczej nie zadziała. W ten sposób Twoja aplikacja uruchomi się ponownie po 2 sekundach.

W końcu możesz ustawić flagę w zamiarze, że aplikacja się zawiesiła, aw Twojej onCreate()metodzie możesz wyświetlić okno dialogowe „Przepraszam, aplikacja się zawiesiła, mam nadzieję, że nigdy więcej :)”.

Gyuri Majercsik
źródło
4
Rozgryzłem to. teraz problem polega na tym, gdzie zaimplementować metodę uncaughtException? proszę o pomoc. dzięki.
Jay Mayu
2
@MayuMayooresan Możesz rozszerzyć klasę aplikacji lub Activity i wykonać następujące czynności w onCreate (): Thread.setDefaultUncaughtExceptionHandler (new UncaughtExceptionHandler () {...});
AgentKnopf
1
Jeśli rozszerzysz aktywność, warto zauważyć, że musisz zrobić to samo dla każdej czynności, która może działać jako punkt wejścia do Twojej aplikacji (w tym tych, które Android OS może zdecydować o uruchomieniu - na przykład gdy okno zamiera itp.)
Mick
1
Wygląda na to, że nie działa w ICS po wymuszeniu zatrzymania procesu za pomocą menu zarządzania aplikacjami.
sunghun
5
co oznacza YourApplication? Skorzystałem z porady @Mahesh, ale nie zadziałało. niech ktoś to wyjaśni.
Shervin Gharib
16

Sztuczka polega na tym, aby przede wszystkim nie wymusić zamknięcia.

Jeśli korzystasz z Thread.setDefaultUncaughtExceptionHandler()metody , możesz wychwycić wyjątki, które powodują wymuszenie zamknięcia aplikacji.

Spójrz na to pytanie, aby zapoznać się z przykładem użycia narzędzia UncaughtExceptionHandlerdo rejestrowania wyjątków zgłoszonych przez aplikację.

Dave Webb
źródło
1
Dzięki za wskazówkę. Kolejne pytanie brzmi: kiedy należy wywołać wyjątek UncaughtExceptionHandler.uncaughtException? Jeśli użytkownik nie kliknie przycisku „Wymuś zamknięcie”, czy wyjątek UncaughtExceptionHandler.uncaughtException będzie nadal wywoływany?
Johnny
3
@Johnny Wymuszenie zamknięcia pojawia się, gdy aplikacja zgłasza wyjątek, który nie jest obsługiwany. Jeśli używasz UncaughtExceptionHandler, Twoja aplikacja może obsłużyć wszystkie swoje wyjątki, a użytkownik nigdy nie zobaczy okna dialogowego Wymuś zamknięcie. Innymi słowy, UncaughtExceptionHandler jest wywoływana, gdy okno dialogowe Force Close zostało wyświetlone. Jednak będziesz chciał zachować ostrożność, jak radzisz sobie z nieoczekiwanymi wyjątkami, które przechwytuje aplikacja; kontynuowanie i udawanie, że nic się nie stało, jest oczywiście ryzykowne.
Dave Webb
Dziękuję za wyjaśnienie. To wyjaśnia dobrze o UncaughtExceptionHandler. Ale widziałem aplikacje, które automatycznie uruchamiają się ponownie po wymuszonym zamknięciu. Na przykład. Launcher (może nie jest to dobry przykład, ale widziałem, że aplikacje innych firm również działają w ten sposób). A jeśli chcę, aby moja aplikacja działała w ten sposób? Czy muszę używać jakichś uprawnień systemowych?
Johnny
10

Jeśli korzystasz z Crittercism lub innej usługi raportowania błędów, zaakceptowana odpowiedź jest prawie poprawna.

final UncaughtExceptionHandler defaultHandler = Thread.getDefaultUncaughtExceptionHandler();
Thread.setDefaultUncaughtExceptionHandler(new UncaughtExceptionHandler() {
            public void uncaughtException(Thread thread, Throwable ex) {
              Intent launchIntent = new Intent(activity().getIntent());
              PendingIntent pending = PendingIntent.getActivity(CSApplication.getContext(), 0,
                    launchIntent, activity().getIntent().getFlags());
              getAlarmManager().set(AlarmManager.RTC, System.currentTimeMillis() + 2000, pending);
              defaultHandler.uncaughtException(thread, ex);
            }
});
Renetik
źródło
2
public class ForceCloseExceptionHandalingActivity extends Activity {
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        setContentView(MyLayout());
        Thread.setDefaultUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
            @Override
            public void uncaughtException(Thread paramThread, Throwable paramThrowable) {
                myHandaling(paramThread, paramThrowable);
            }
        });
    }

    private ViewGroup MyLayout(){
        LinearLayout mainLayout = new LinearLayout(this);
        mainLayout.setOrientation(LinearLayout.VERTICAL);  
        Button btnHello =new Button(this);
        btnHello.setText("Show all button");
        btnHello.setOnClickListener(new OnClickListener() {         
            @Override
            public void onClick(View v) {                   
                setContentView(MyLayout2());            
            }
        });             
        mainLayout.addView(btnHello);       
        return mainLayout;
    }

    private ViewGroup MyLayout2(){
        LinearLayout mainLayout = new LinearLayout(this);
        mainLayout.setOrientation(LinearLayout.VERTICAL);  
        Button btnHello =new Button(this);
        btnHello.setText("I am a EEROR uncaughtException");
        btnHello.setOnClickListener(new OnClickListener() {         
            @Override
            public void onClick(View v) {                   
                Log.e("Alert","btn  uncaughtException::");
                Toast.makeText(ForceCloseExceptionHandalingActivity.this, "Alert uncaughtException222",Toast.LENGTH_LONG).show();
                View buttone = null;
                setContentView(buttone);            
            }
        });     
        Button btnHello2 =new Button(this);
        btnHello2.setText("I am a EEROR Try n catch");
        btnHello2.setOnClickListener(new OnClickListener() {            
            @Override
            public void onClick(View v) {   

                try{
                    View buttone = null;
                    setContentView(buttone);
                }
                catch (Exception e) {
                    Log.e("Alert","Try n catch:::");
                    Toast.makeText(ForceCloseExceptionHandalingActivity.this, "Alert Try n catch",Toast.LENGTH_LONG).show();
                    setContentView(MyLayout());
                }

            }
        });     
        mainLayout.addView(btnHello);
        mainLayout.addView(btnHello2);
        return mainLayout;
    }
    public void myHandaling(Thread paramThread, Throwable paramThrowable){
        Log.e("Alert","Lets See if it Works !!!" +"paramThread:::" +paramThread +"paramThrowable:::" +paramThrowable);
        Toast.makeText(ForceCloseExceptionHandalingActivity.this, "Alert uncaughtException111",Toast.LENGTH_LONG).show();
        Intent in =new Intent(ForceCloseExceptionHandalingActivity.this,com.satya.ForceCloseExceptionHandaling.ForceCloseExceptionHandalingActivity.class);
        startActivity(in);
        finish();
        android.os.Process.killProcess(android.os.Process.myPid()); 
    }
    @Override
    protected void onDestroy() {
        Log.e("Alert","onDestroy:::");
        Toast.makeText(ForceCloseExceptionHandalingActivity.this, "Alert onDestroy",Toast.LENGTH_LONG).show();
        super.onDestroy();  
    }
Satya
źródło
ten kod pobiera „Thread.setDefaultUncaughtExceptionHandler” i wywołuje po jego zamknięciu ..
Satya
2

Po prostu dodaj tę klasę do swojego pakietu

public class MyExceptionHandler implements
    java.lang.Thread.UncaughtExceptionHandler {
private final Context myContext;
private final Class<?> myActivityClass;

public MyExceptionHandler(Context context, Class<?> c) {
    myContext = context;
    myActivityClass = c;
}

public void uncaughtException(Thread thread, Throwable exception) {
    StringWriter stackTrace = new StringWriter();
    exception.printStackTrace(new PrintWriter(stackTrace));
    System.err.println(stackTrace);// You can use LogCat too
    Intent intent = new Intent(myContext, myActivityClass);
    String s = stackTrace.toString();
    //you can use this String to know what caused the exception and in which Activity
    intent.putExtra("uncaughtException", "Exception is: " + stackTrace.toString());
    intent.putExtra("stacktrace", s);
    myContext.startActivity(intent);
    //for restarting the Activity
    Process.killProcess(Process.myPid());
    System.exit(0);
}}

W aplikacji lub w każdej klasie aktywności, wewnątrz metody onCreate (), po prostu wywołaj:

Thread.setDefaultUncaughtExceptionHandler(new MyExceptionHandler(this,
            SplashScreenActivity.class));
Suraj Vaishnav
źródło