هيئة مراقبة بسيطة تكتشف أخطاء Android ANR (التطبيق لا يستجيب).
لا توجد حاليًا طريقة لتطبيق Android لاكتشاف أخطاء ANR والإبلاغ عنها.
إذا لم يكن تطبيقك موجودًا في متجر Play (إما لأنك لا تزال تعمل على تطويره أو لأنك تقوم بتوزيعه بشكل مختلف)، فإن الطريقة الوحيدة للتحقق من خطأ ANR هي سحب الملف /data/anr/traces.txt.
بالإضافة إلى ذلك، وجدنا أن استخدام متجر Play لم يكن بنفس فعالية القدرة على اختيار خدمة تتبع الأخطاء الخاصة بنا.
هناك مشكلة مُدخلة في أداة تعقب الأخطاء لنظام التشغيل Android تصف هذا النقص، فلا تتردد في تمييزها بنجمة ;)
يقوم بإعداد مؤقت "المراقبة" الذي سيكتشف متى يتوقف مؤشر ترابط واجهة المستخدم عن الاستجابة. عندما يحدث ذلك، فإنه يثير خطأ مع جميع تتبعات مكدس المواضيع (الرئيسي أولاً).
نعم! أنا سعيد لأنك سألت: هذا هو سبب تطويره في المقام الأول!
نظرًا لأن هذا يؤدي إلى حدوث خطأ، يمكن لمعالج الأعطال اعتراضه والتعامل معه بالطريقة التي يريدها.
من بين مراسلي حوادث العمل المعروفين ما يلي:
setReportMainThreadOnly()
)وليس هناك سبب يمنعه من العمل مع [أدخل نظام الإبلاغ عن الأعطال المفضل لديك هنا] .
الوكالة الدولية للطاقة عبارة عن خيط بسيط يقوم بما يلي في حلقة:
في ملف app/build.gradle
، أضف:
implementation 'com.github.anrwatchdog:anrwatchdog:1.4.0'
في فئة التطبيق الخاصة بك، في onCreate
، أضف:
new ANRWatchDog (). start ();
تحميل أحدث جرة
ضع الجرة في دليل libs/
الخاص بمشروعك
يعتبر تتبع المكدس ANRError
خاصًا بعض الشيء، فهو يحتوي على آثار المكدس لجميع سلاسل الرسائل التي تعمل في تطبيقك. لذلك، في التقرير، كل caused by
القسم ليس هو سبب الاستثناء السابق ، ولكن تتبع المكدس لخيط مختلف.
فيما يلي مثال على القفل الميت:
FATAL EXCEPTION: |ANR-WatchDog|
Process: anrwatchdog.github.com.testapp, PID: 26737
com.github.anrwatchdog.ANRError: Application Not Responding
Caused by: com.github.anrwatchdog.ANRError$_$_Thread: main (state = WAITING)
at testapp.MainActivity$1.run(MainActivity.java:46)
at android.os.Handler.handleCallback(Handler.java:739)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:135)
at android.app.ActivityThread.main(ActivityThread.java:5221)
Caused by: com.github.anrwatchdog.ANRError$_$_Thread: APP: Locker (state = TIMED_WAITING)
at java.lang.Thread.sleep(Native Method)
at java.lang.Thread.sleep(Thread.java:1031)
at java.lang.Thread.sleep(Thread.java:985)
at testapp.MainActivity.SleepAMinute(MainActivity.java:18)
at testapp.MainActivity.access$100(MainActivity.java:12)
at testapp.MainActivity$LockerThread.run(MainActivity.java:36)
من هذا التقرير، يمكننا أن نرى أن المكدس يتتبع خيطين. الأول (الخيط "الرئيسي") عالق في MainActivity.java:46
بينما الخيط الثاني (المسمى "App: Locker") مقفل في وضع السكون في MainActivity.java:18
.
ومن هنا، إذا نظرنا إلى هذين الخطين، فبالتأكيد سنفهم سبب القفل الميت!
لاحظ أن بعض مكتبات تقارير الأعطال (مثل Crashlytics) تقوم بالإبلاغ عن جميع تتبعات مكدس مؤشر الترابط في وقت حدوث استثناء لم يتم اكتشافه. في هذه الحالة، قد يكون وجود كافة سلاسل الرسائل في نفس الاستثناء أمرًا مرهقًا. في مثل هذه الحالات، ما عليك سوى استخدام setReportMainThreadOnly()
.
لتعيين مهلة مختلفة (5000 مللي هو الافتراضي):
if ( BuildConfig . DEBUG == false ) {
new ANRWatchDog ( 10000 /*timeout*/ ). start ();
}
افتراضيًا، ستتجاهل المراقبة أخطاء ANR إذا كان مصحح الأخطاء مرفقًا أو إذا كان التطبيق ينتظر إرفاق مصحح الأخطاء. وذلك لأنه يكتشف توقف التنفيذ ونقاط التوقف على أنها أخطاء ANR. لتعطيل هذا وإصدار خطأ ANRError
حتى لو كان مصحح الأخطاء متصلاً، يمكنك إضافة setIgnoreDebugger(true)
:
new ANRWatchDog (). setIgnoreDebugger ( true ). start ();
إذا كنت تفضل عدم تعطل التطبيق عند اكتشاف خطأ ANR، فيمكنك تمكين رد الاتصال بدلاً من ذلك:
new ANRWatchDog (). setANRListener ( new ANRWatchDog . ANRListener () {
@ Override
public void onAppNotResponding ( ANRError error ) {
// Handle the error. For example, log it to HockeyApp:
ExceptionHandler . saveException ( error , new CrashManager ());
}
}). start ();
يعد هذا أمرًا مهمًا جدًا عند تسليم تطبيقك في مرحلة الإنتاج. عندما تكون في يد المستخدم النهائي، ربما يكون من الأفضل عدم التعطل بعد 5 ثوانٍ، ولكن ببساطة قم بالإبلاغ عن ANR إلى أي نظام إبلاغ تستخدمه. ربما، بعد بضع ثوانٍ أخرى، سيتم "إزالة التجميد" من التطبيق.
إذا كنت ترغب في الإبلاغ عن سلاسل الرسائل الخاصة بك فقط في خطأ ANRError، وليس جميع سلاسل الرسائل (بما في ذلك سلاسل رسائل النظام مثل سلسلة رسائل FinalizerDaemon
)، فيمكنك تعيين بادئة: سيتم الإبلاغ فقط عن سلاسل الرسائل التي يبدأ اسمها بهذه البادئة .
new ANRWatchDog (). setReportThreadNamePrefix ( "APP:" ). start ();
وبعد ذلك، عندما تبدأ موضوعًا، لا تنس تعيين اسمه إلى شيء يبدأ بهذه البادئة (إذا كنت تريد الإبلاغ عنه):
public class MyAmazingThread extends Thread {
@ Override
public void run () {
setName ( "APP: Amazing!" );
/* ... do amazing things ... */
}
}
إذا كنت ترغب في الحصول على تتبع مكدس مؤشر الترابط الرئيسي فقط وليس جميع سلاسل الرسائل الأخرى، فيمكنك:
new ANRWatchDog (). setReportMainThreadOnly (). start ();
في بعض الأحيان، تريد معرفة أن التطبيق قد تم تجميده لمدة معينة، ولكن لا تقم بالإبلاغ عن خطأ ANR حتى الآن. يمكنك تحديد المعترض الذي سيتم استدعاؤه قبل الإبلاغ عن الخطأ. ويتمثل دور المعترض في تحديد ما إذا كان ينبغي، في ضوء مدة التجميد المحددة، إثارة أو تأجيل خطأ ANR أم لا.
new ANRWatchDog ( 2000 ). setANRInterceptor ( new ANRWatchDog . ANRInterceptor () {
@ Override
public long intercept ( long duration ) {
long ret = 5000 - duration ;
if ( ret > 0 ) {
Log . w ( TAG , "Intercepted ANR that is too short (" + duration + " ms), postponing for " + ret + " ms." );
}
return ret ;
}
})
في هذا المثال، يبدأ ANRWatchDog بمهلة قدرها 2000 مللي ثانية، لكن المعترض سيؤجل الخطأ حتى يتم الوصول إلى 5000 مللي ثانية على الأقل من التجميد.
ANRWatchDog عبارة عن سلسلة رسائل، لذا يمكنك مقاطعتها في أي وقت.
إذا كنت تقوم بالبرمجة باستخدام إمكانية العمليات المتعددة لنظام Android (مثل بدء نشاط في عملية جديدة)، فتذكر أنك ستحتاج إلى مؤشر ترابط ANRWatchDog لكل عملية.
ANR-Watchdog مجاني للاستخدام لأغراض تجارية وغير ربحية وسيظل كذلك دائمًا.
إذا كنت ترغب في إظهار بعض الدعم أو التقدير لعملي، فأنت حر في التبرع !
سيكون هذا موضع تقدير كبير (بالطبع) ولكنه ليس ضروريًا بأي حال من الأحوال لتلقي المساعدة أو الدعم، والذي يسعدني تقديمه مجانًا :)