أساسيات أندرويد بجافا

التسجيل والتصحيح

18 دقيقة الدرس 7 من 12

التسجيل والتصحيح

يقضي كل مطوّر Android جزءًا كبيرًا من وقته في قراءة مخرجات السجلات والتنقّل خطوةً بخطوة عبر الكود داخل المُصحِّح. إتقان هاتين الأداتين ليس اختياريًا — فهما أدواتك الأساسية لفهم ما يفعله تطبيقك في وقت التشغيل، وتشخيص الأعطال، والتحقق من الصحة. يتناول هذا الدرس Logcat بعمق، ويستعرض سير عمل المُصحِّح داخل Android Studio.

فهم Logcat

Logcat هو سجل نظام Android. كل مكوّن من مكوّنات نظام التشغيل، وكل مكتبة، وكل تطبيق على الجهاز يكتب في هذا التدفق المشترك الواحد. تُظهر لك نافذة أدوات Logcat في Android Studio ذلك التدفق مُصفَّيًا حسب العملية والجهاز ومستوى السجل في الوقت الفعلي.

نقطة الدخول لرسائل السجل الخاصة بك هي الفئة android.util.Log. تُعرض فيها طريقة ثابتة واحدة لكل مستوى تسجيل:

import android.util.Log; public class NetworkRepository { // عرّف ثابت TAG — بالاتفاق، استخدم اسم الفئة. // أبقه أقل من 23 حرفًا (الأجهزة القديمة تقطع ما هو أطول). private static final String TAG = "NetworkRepository"; public void fetchUser(int userId) { Log.d(TAG, "fetchUser() called with userId=" + userId); try { // ... استدعاء شبكي ... Log.i(TAG, "fetchUser() succeeded for userId=" + userId); } catch (Exception e) { Log.e(TAG, "fetchUser() failed for userId=" + userId, e); } } }

مستويات السجل الخمسة

يُعرّف Android خمسة مستويات للسجل، مرتّبةً من أدنى شدّةً إلى أعلاها:

  • VERBOSE (Log.v) — المخرجات الأكثر تفصيلًا؛ تُعطَّل عادةً في إصدارات الإنتاج. استخدمها لمعلومات التتبّع التفصيلية للغاية التي تريدها مؤقتًا فحسب.
  • DEBUG (Log.d) — رسائل وقت التطوير: دخول الطرق والخروج منها، وقيم المتغيرات، ونقاط التحقق من التدفق. هي أداة العمل اليومي في التصحيح.
  • INFO (Log.i) — رسائل معلوماتية تُؤكّد المعالم المتوقعة: "سجّل المستخدم الدخول"، "اكتمل إحماء ذاكرة التخزين المؤقت"، "حُمِّل الإعداد".
  • WARN (Log.w) — وقع شيء غير متوقع لكن التطبيق قادر على الاستمرار: تُستخدم واجهة برمجية منتهية الصلاحية، أو نجحت عملية مُعادة المحاولة في المرة الثانية.
  • ERROR (Log.e) — وقع فشل كبير. مرّر دائمًا كائن Throwable الكامل كوسيطة ثالثة حتى يُحفَظ تتبع المكدس في السجل.
الوسيطة الثالثة لـ Log.e وLog.w هي الاستثناء نفسه وليس رسالته. كتابة Log.e(TAG, e.getMessage()) يُضيّع تتبع المكدس كليًا — فلن ترى إلا نص الرسالة. اكتب دائمًا Log.e(TAG, "وصف", e) للحصول على السلسلة الكاملة من الأسباب مطبوعةً تحت رسالتك.

تعريف TAG جيدة

TAG هو ما تُصفّي عليه في Logcat. توجد طريقتان شائعتان:

  • private static final String TAG = "NetworkRepository"; — نص عادي تكتبه مرة واحدة لكل فئة. بسيط ويمكن التنبؤ به.
  • private static final String TAG = NetworkRepository.class.getSimpleName(); — يتطابق تلقائيًا مع اسم الفئة؛ يبقى صحيحًا بعد إعادة التسمية باستخدام أداة إعادة الهيكلة.

كلاهما مقبول. القاعدة المهمة هي: TAG واحدة لكل فئة، مُعرَّفة كثابت، لا تُنشأ داخل الكود المتكرر. تجنّب كتابة Log.d("my-feature-debug-thing", ...) متناثرًا عبر ملفات متعددة — فلن تتمكن من التصفية باتساق.

استخدام نافذة أدوات Logcat

افتح Logcat عبر View → Tool Windows → Logcat (أو تبويب Logcat في أسفل Android Studio). أهم عناصر التحكم:

  • مُختار الجهاز / العملية — صفّي إلى المحاكي أو الجهاز المتصل، ثم إلى عملية تطبيقك (تُعرض كـ com.example.myapp).
  • قائمة مستوى السجل المنسدلة — اختيار DEBUG يُظهر DEBUG وINFO وWARN وERROR؛ اختيار ERROR يُظهر ERROR فحسب. المستويات الأدنى شاملة دائمًا للمستويات الأعلى.
  • شريط البحث / التصفية — اكتب وسمًا أو اسم حزمة أو أي نص. استخدم سهم القائمة المنسدلة للتبديل بين "إظهار التطبيق المحدد فحسب" وتعبير تصفية مخصص مثل tag:NetworkRepository level:error.
  • زر مسح Logcat — يمسح المخزن المؤقت للتمرير. مفيد قبل إعادة إنتاج خطأ محدد حتى لا تُشتّتك الأسطر القديمة غير ذات الصلة.
اضبط مُرشِّح العملية فورًا. تدفق الجهاز الخام صاخب بشكل هائل — تُصدر خدمات النظام مئات الأسطر في الثانية. تحديد العملية بمعرّف تطبيقك يجعل المخرجات ذات الصلة تبرز على الفور.

حذف سجلات Verbose وDebug من إصدارات الإنتاج

استدعاءات Log رخيصة لكنها ليست مجانية، والنصوص التي تمرّرها إليها قد تحتوي على بيانات حساسة (معرّفات المستخدمين، والرموز المميزة، والمسارات الداخلية). ثمة نهجان معياريان لإسكاتها في الإنتاج:

النهج الأول — حارس BuildConfig.DEBUG:

if (BuildConfig.DEBUG) { Log.d(TAG, "Cache miss for key: " + key); }

الثابت BuildConfig.DEBUG هو true في إصدارات التصحيح وfalse في إصدارات الإنتاج. يُزيل JIT الفرع الميت كليًا من APK الإنتاج، لذلك لا تكلفة في وقت التشغيل على الإطلاق.

النهج الثاني — قاعدة ProGuard/R8: أضف هذا إلى proguard-rules.pro لحذف جميع استدعاءات verbose وdebug في وقت البناء:

-assumenosideeffects class android.util.Log { public static int v(...); public static int d(...); }
لا تُسجّل كلمات المرور أو الرموز المميزة أو أي بيانات تعريف شخصية (PII) — حتى على مستوى DEBUG. ملفات السجل مقروءة لأي شخص لديه وصول USB إلى الجهاز (عبر adb logcat)، وبعض الأجهزة تكتبها في تخزين مقروء للجميع. تعامل مع كل سطر سجل باعتباره مرئيًا محتملًا.

التصحيح باستخدام مُصحِّح Android Studio

يُريك Logcat ما حدث. أما المُصحِّح فيتيح لك تجميد الوقت وفحص الحالة الكاملة لبرنامجك. لربط المُصحِّح، شغّل التطبيق بأيقونة الحشرة (Debug 'app') بدلًا من أيقونة التشغيل. يُصرف Android Studio APK قابل للتصحيح ويثبّته ثم يربط مُصحِّح JDWP.

إضافة نقطة إيقاف: انقر في الهامش يسار رقم السطر. تظهر دائرة حمراء. عندما تصل التنفيذ إلى ذلك السطر يتوقف التطبيق ويعرض Android Studio نافذة أدوات Debug.

أهم عناصر تحكم المُصحِّح:

  • التخطّي (F8) — ينفّذ السطر الحالي وينتقل إلى التالي في نفس الطريقة. لا يدخل الطرق المُستدعاة.
  • الدخول (F7) — يدخل الطريقة المُستدعاة في السطر الحالي. ضروري لتتبّع الكود الخاص بك.
  • الخروج (Shift+F8) — يُكمّل الطريقة الحالية ويعود إلى مُستدعيها.
  • استئناف البرنامج (F9) — يتابع التنفيذ حتى نقطة الإيقاف التالية أو انتهاء التطبيق.
  • تقييم التعبير (Alt+F8) — اكتب أي تعبير Java وقيّمه في إطار المكدس الحالي. يمكنك استدعاء طرق وقراءة حقول وحتى تغيير قيم المتغيرات.

تعرض لوحة Variables كل متغير محلي وحقل في النطاق. وسّع الكائنات لرؤية الحقول المتداخلة. تتيح لك لوحة Watches تثبيت تعبيرات محددة لتكون مرئية دائمًا عبر ضربات متعددة لنقطة الإيقاف.

نقاط الإيقاف الشرطية

إذا تكرّرت حلقة 1,000 مرة وتعطّلت فقط في التكرار 753، فنقطة الإيقاف العادية عديمة الفائدة — ستضطر إلى الضغط على F9 آلاف المرات. انقر بزر الماوس الأيمن على دائرة نقطة الإيقاف واختر Edit breakpoint. أدخل شرطًا مثل:

i == 753 && item != null

سيتوقف المُصحِّح الآن فقط عندما يُقيَّم ذلك التعبير بـ true. هذه واحدة من أقوى ميزات مُصحِّح IDE وهي ضرورية لتشخيص الأعطال المتقطعة.

ربط المُصحِّح بعملية جارية

إذا كان تطبيقك يعمل بالفعل وتريد تصحيحه دون إعادة تشغيله، استخدم Run → Attach Debugger to Android Process. اختر عمليتك من القائمة. هذا لا يُقدَّر بثمن لتصحيح أخطاء ترتيب التهيئة حيث يؤثر إعادة التشغيل على التوقيت.

سير العمل العملي

تبدو جلسة التصحيح المنتجة عادةً كالتالي:

  1. أعِد إنتاج الخطأ واقرأ مخرجات Logcat. ابحث عن أول سطر E أو أي أسطر W غير متوقعة قرب وقت الفشل.
  2. إن كان عطلًا، ابحث عن فئة الاستثناء وأول سطر من كودك في تتبع المكدس — هذه نقطة دخولك.
  3. ضع نقطة إيقاف على ذلك السطر وأعد التشغيل في وضع التصحيح.
  4. عند ضرب نقطة الإيقاف، استخدم لوحة Variables لفحص الحالة. قيّم تعبيرات لاختبار الفرضيات دون تعديل الكود.
  5. تتبّع مسار الكود المشتبه به حتى تُحدّد القيمة الخاطئة أو الفرع غير المتوقع.
  6. صحّح، أعد التشغيل، تأكد أن مخرجات Log.d تُظهر الآن التدفق المتوقع، ثم احذف أي أسطر سجل تصحيح مؤقتة قبل إيداع الكود.
أبقِ استدعاءات Log.i وLog.e ذات المعنى في كودك بشكل دائم. إنها لا تُقدَّر بثمن لتشخيص المشكلات التي يُبلّغ عنها المستخدمون أو التي تُكتشف في CI — مواقف لا يمكنك فيها ربط مُصحِّح. فكّر فيها كأدوات تشخيصية دائمة، لا كبنية تحتية مؤقتة.

الخلاصة

فئة android.util.Log هي أداتك التشخيصية خفيفة الوزن — خمسة مستويات من VERBOSE إلى ERROR، كل منها مقترن بـ TAG يجعل التصفية في Logcat فورية. احمِ رسائل مستوى DEBUG بـ BuildConfig.DEBUG للحفاظ على نظافة وأمان إصدارات الإنتاج. للفحص الأعمق، يتيح لك مُصحِّح Android Studio إيقاف التنفيذ وفحص كل متغير وتقييم تعبيرات اعتباطية وتطبيق نقاط إيقاف شرطية لعزل الأعطال المتقطعة. معًا، يُزيلان التخمين من تطوير Android.