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?


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 :)”.


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ę.


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);
            }
});

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();  
    }

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));
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.