Android'de küresel yakalanmamış istisna İşleyiciyi ayarlamanın ideal yolu


88

Android uygulamamdaki tüm iş parçacıkları için genel yakalanmamış bir istisna işleyici ayarlamak istiyorum. Bu yüzden, Applicationalt Thread.UncaughtExceptionHandlersınıfımda yakalanmamış istisnalar için varsayılan işleyici olarak bir uygulama ayarladım .

Thread.setDefaultUncaughtExceptionHandler(
                new DefaultExceptionHandler(this));

Uygulamamda, AlertDialoguygun bir istisna mesajını görüntülemeye çalışıyorum .

Ancak bu işe yaramıyor gibi görünüyor. Ne zaman, işlenmeyen herhangi bir iş parçacığı için bir istisna atıldığında, stok, işletim sistemi varsayılan iletişim kutusunu ("Üzgünüm! -Uygulama-durdu-beklenmedik şekilde iletişim kutusu") alıyorum.

Yakalanmayan istisnalar için varsayılan bir işleyici ayarlamanın doğru ve ideal yolu nedir?


1
Lütfen aynı kodu paylaşır
mısınız

2
İstisnalarınızı kaydetmek istiyorsanız, acra.ch'e bir göz atın . ACRA, hata raporlarını bir Google Dokümanına veya size E-Posta yoluyla göndermenize izin verir.
Alexander Pacha

1
@Alexander Veya Android için Google Analytics'i kullanabilir ve istediğiniz tüm istisnaları kaydedebilirsiniz ...
IgorGanapolsky

Yanıtlar:


24

Tek yapmanız gereken bu olmalı. (İşlemin daha sonra durmasına neden olduğunuzdan emin olun - işler belirsiz bir durumda olabilir.)

Kontrol edilmesi gereken ilk şey, Android işleyicinin hala aranıp aranmadığıdır. Sürümünüz çağrılıyor ancak ölümcül bir şekilde başarısız oluyor ve system_server işlemin çöktüğünü gördüğünde genel bir iletişim kutusu gösteriyor olabilir.

Oraya ulaşıp ulaşmadığını görmek için işleyicinizin üst kısmına bazı günlük mesajları ekleyin. GetDefaultUncaughtExceptionHandler'dan sonucu yazdırın ve ardından çökmeye neden olmak için yakalanmamış bir istisna atın. Neler olduğunu görmek için logcat çıktısına bir göz atın.


10
"Siz hatayı ele aldıktan sonra bir çökmeye neden olmak için yakalanmamış bir istisna atmak" hala önemlidir. Ben sadece deneyimledim. İstisnayı hallettikten sonra uygulamam kilitlendi ve yakalanmamış bir istisna atmadı.
OneWorld

@OneWorld Jepp burada da aynı - en azından kilitleme kısmı için - sonuçta uygulamanın çökmesini "kurtarmanın" bir yolu yok gibi görünüyor.
AgentKnopf

@Zainodis Bu soruya Eleştiriye bir bağlantı veren biraz konu dışı bir cevap gönderdim - sanırım uygulamanın çökmesini "kaydetmenize" izin veren bir özelliği var. Emin değilim - Sadece ücretsiz atm sürümünü kullanıyorum.
Richard Le Mesurier

@RichardLeMesurier İpucu için teşekkürler - kontrol edeceğim :)!
AgentKnopf

Garip!!! Etkinliğimdeki istisnayı ele alsam bile yakalanmamış istisna çağrılır. Herhangi bir fikir.
Hiren Dabhi

12

Basit çözümü gönderdimUzun zaman önce Android çökmelerinin özel olarak işlenmesi için . Biraz karmaşık ancak tüm Android sürümlerinde (Lollipop dahil) çalışıyor.

İlk önce biraz teori. Android'de yakalanmamış istisna işleyiciyi kullandığınızda ana sorunlar, ana (UI) iş parçacığında atılan istisnalarla birlikte gelir. Ve işte nedeni. Uygulama başladığında, uygulamanızın Ana döngüleyicisini hazırlayan ve başlatan ActivityThread.main yöntemini çağırır :

public static void main(String[] args) {
  …
  …
    Looper.prepareMainLooper();
  …
    Looper.loop();
    throw new RuntimeException("Main thread loop unexpectedly exited");
}

Ana döngüleyici, UI iş parçacığına gönderilen mesajların işlenmesinden sorumludur (UI oluşturma ve etkileşimle ilgili tüm mesajlar dahil). UI iş parçacığına bir istisna atılırsa, istisna işleyiciniz tarafından yakalanır, ancakloop() yöntemin için, UI mesajlarını işleyecek kimse kalmadığı için kullanıcıya herhangi bir iletişim kutusu veya etkinlik gösteremezsiniz. senin için.

Önerilen çözüm oldukça basit. Looper.loopYöntemi kendi başımıza çalıştırıyoruz ve onu try-catch bloğu ile çevreliyoruz. Bir istisna yakalandığında, onu istediğimiz gibi işleriz (örneğin, özel rapor etkinliğimizi başlatırız) ve Looper.loopyöntemi tekrar çağırırız .

Aşağıdaki yöntem bu tekniği göstermektedir ( Application.onCreatedinleyiciden çağrılmalıdır ):

private void startCatcher() {
    UncaughtExceptionHandler systemUncaughtHandler = Thread.getDefaultUncaughtExceptionHandler();

    // the following handler is used to catch exceptions thrown in background threads
    Thread.setDefaultUncaughtExceptionHandler(new UncaughtHandler(new Handler()));

    while (true) {
        try {
            Looper.loop();
            Thread.setDefaultUncaughtExceptionHandler(systemUncaughtHandler);
            throw new RuntimeException("Main thread loop unexpectedly exited");
        } catch (Throwable e) {
            showCrashDisplayActivity(e);
        }
    }
}

Gördüğünüz gibi yakalanmamış istisna işleyicisi yalnızca arka plan iş parçacıklarında atılan istisnalar için kullanılır. Aşağıdaki işleyici, bu istisnaları yakalar ve bunları UI iş parçacığına yayar:

static class UncaughtHandler implements UncaughtExceptionHandler {

    private final Handler mHandler;

    UncaughtHandler(Handler handler) {
        mHandler = handler;
    }

    public void uncaughtException(Thread thread, final Throwable e) {
        mHandler.post(new Runnable() {
            public void run() {
                throw new BackgroundException(e);
            }
        });
    }
}

Bu tekniği kullanan örnek bir proje GitHub depomda mevcuttur: https://github.com/idolon-github/android-crash-catcher


Tahmin edilebileceği gibi, bu şekilde yalnızca özel hata iletişim kutusunu göstermek değil, aynı zamanda kullanıcının istisnayı görmezden gelmesine ve uygulamayla çalışmaya devam etmesine izin vermek de mümkündür (ve yayınlanan uygulamalar için kötü bir fikir gibi görünse de, hata ayıklama veya test oturumu sırasında oldukça kullanışlıdır).
Idolon

Merhaba, bu yakalanmamış istisnaları yakalamada işe yarasa da, bazı nedenlerden dolayı bu kod her zaman istisnalar atıyor. Başlangıçta bunun startCatcher yönteminde sahip olduğunuz RuntimeException satırından kaynaklandığını düşünmüştüm, ancak kaldırdıktan sonra hala istisna alıyorum. Bunun gerekli olup olmadığından emin değilim. Her neyse, aldığım istisna java.lang.RuntimeException: Performing pause of activity that is not resumed. Kendi döngüleyicimi başlatmaya çalıştığımda, sistemin başlamak üzere olan etkinliği duraklattığına inanıyorum. Emin değilim ama herhangi bir yardım memnuniyetle karşılanacaktır. Teşekkürler
sttaq

ayrıca startCatcher'ı kaldırırsam, yani uygulamayı kodunuz olmadan çalıştırırsam, istisnasız her şey yolunda gider.
sttaq

@sttaq Hangi Android sürümünü kullanıyorsunuz?
Idolon

Sanırım bunu 2.3.x'te deniyordum
sttaq

3

UncaughtException () yönteminizde, previousHandler tarafından ayarlandığı yerde previousHandler.uncaughtException () öğesini çağırmayın.

previousHandler = Thread.getDefaultUncaughtExceptionHandler();

2

FWIW Bunun biraz konu dışı olduğunu biliyorum, ancak Crittercism'in ücretsiz planını kullanıyoruz başarıyla kullanıyoruz. Ayrıca, uygulamanın çökmemesi için istisnayı ele almak gibi bazı premium özellikler de sunarlar.

Ücretsiz sürümde, kullanıcı hala çökmeyi görüyor, ancak en azından e-postayı ve yığın izini alıyorum.

Ayrıca iOS sürümünü de kullanıyoruz (ancak meslektaşlarımdan bunun o kadar iyi olmadığını duydum).


İşte benzer sorular:


1

Sen arayana kadar çalışmıyor

android.os.Process.killProcess(android.os.Process.myPid());

UncaughtExceptionHandler'ınızın en sonunda.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.