تطوير Android / المتوسط: الحالة والبيانات والميزات الشاملة / الدرس 9
الشبكات وحدود المستودعات
حوّل الاستجابات البعيدة غير الموثوقة إلى سلوك محلي متحقق منه دون حجب الواجهة أو إخفاء الإخفاقات.
في هذه الصفحة
أهداف الدرس
- عرّف مسؤوليات النقل والتحويل والمستودع.
- اختر سياسات المهلة وإعادة المحاولة والإلغاء بحسب معنى العملية.
ابدأ بحد قابل للإخفاق
قد يفشل الطلب البعيد قبل الاتصال أو أثناء النقل أو بخطأ HTTP أو أثناء فك الترميز أو بعد استلام محتوى غير صحيح دلالياً. هذه نتائج مختلفة حتى إن عرضت الشاشة زر إعادة محاولة واحداً. عرّف عقد الخدمة منفصلاً عن المستودع الذي يتحقق من نتائجها ويخزنها. ينبغي ألا تعرف الواجهة مكتبة HTTP المنفذة. استخدم HTTPS وعميلاً مضبوطاً بمهلات صريحة؛ ولا تضعف التحقق من الشهادات لمجرد جعل خادم تطوير يبدو عاملاً.
وفّر الوصول دون حجب العرض
أعلن إذن INTERNET في جذر manifest للوصول إلى الشبكة. هو إذن عادي وليس طلب تشغيل خطيراً كالكاميرا. قد تدير مكتبة شبكة تدعم suspend الإدخال والإخراج بصورة صحيحة؛ وتغليف كل استدعاء بموزع إضافي عشوائياً لا يعوض قراءة عقدها. عند استخدام واجهات منصة حاجبة انقل الجزء الحاجب إلى موزع إدخال وإخراج محقون وأغلق الموارد دائماً. يعتمد دعم الإلغاء على تنفيذ العميل، فاختبره بدلاً من افتراض أن suspend تقاطع المقابس تلقائياً.
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<uses-permission android:name="android.permission.INTERNET" />
<application android:usesCleartextTraffic="false" />
</manifest>
احتفظ بالأنشطة والسمة وسمات application الموجودة؛ الملف المختصر توضيحي. تعزز سياسة منع النص الواضح قصد استخدام HTTPS لكنها لا تعوض مصادقة الخادم أو ضبط أمان الشبكة لكل نطاق بعناية. لا تستبدل manifest الكامل بهذا المقتطف.
تحقق من نماذج النقل قبل التخزين
قد يغيب حقل JSON أو يحتوي قيمة غير صحيحة حتى مع نجاح حالة HTTP. نمذج عدم يقين النقل منفصلاً عن المجال الموثوق. حوّل الاستجابات عبر التحقق قبل استبدال المحتوى المخبأ، وحدد هل يرفض صف غير صحيح الدفعة أم يُبلغ عنه منفرداً. احفظ المعرّفات الثابتة ومعلومات إصدار الخادم عندما تعتمد عليها المزامنة. لا تمرّر DTO خاماً عبر كل دالة تركيبية؛ فهذا ينشر افتراضات الخلفية في الواجهة ويجعل تغيير المخطط مكلفاً على نحو غير متوقع.
data class RemoteBook(val id: String?, val title: String?)
data class Book(val id: String, val title: String)
fun RemoteBook.toDomain(): Book? {
val validId = id?.takeIf { it.isNotBlank() } ?: return null
val validTitle = title?.trim()?.takeIf { it.isNotEmpty() } ?: return null
return Book(validId, validTitle)
}
interface BookService { suspend fun fetchBooks(): List<RemoteBook> }
ينفذ عميل HTTP المضبوط BookService ويمتلك فك الترميز ومعالجة الحالة. يستدعي المستودع toDomain قبل تثبيت البيانات ويبلغ عن السجلات غير الصحيحة بقصد. لا يفترض المقتطف نقطة شبكة حقيقية أو نتيجة مختلقة.
أعد المحاولة وفق المعنى
تعيد المحاولة عملية قد تكون نتيجتها السابقة مجهولة. غالباً يمكن إعادة القراءة بأمان مع تراجع محدود، لكن إنشاء سجل أو دفعاً قد يكرر الأثر ما لم يدعم الخادم مفتاح منع التكرار أو عقداً مكافئاً. ميّز فشل المصادقة عن المهلة المؤقتة؛ فتكرار بيانات اعتماد غير صحيحة يضيف حملاً فقط. احترم إرشادات إعادة المحاولة ذات الصلة من الخادم وتجنب عواصف المحاولات المتزامنة. أظهر هل المحتوى مخبأ أو يتحدث أو غير متاح، واحتفظ بالمحتوى المفيد عند خطأ تحديث قابل للتعافي بدلاً من إفراغ الشاشة.
اختبر النتائج بدلاً من خدمة حية
استخدم خدمة وهمية أو خادم اختبار محلياً مضبوطاً يعيد استجابات متأخرة وأجساماً مشوهة وأخطاء HTTP وترتيب انتهاء معكوساً. يجعل ذلك سلوك المستودع قابلاً للتكرار دون الاعتماد على اتصال عام. احجب الرموز والمحتوى الشخصي ومعاملات الاستعلام الحساسة من السجلات. توفر الاتصال إشارة فقط؛ فقد يواجه الجهاز المتصل بوابة دخول أو خلفية معطلة. عامل نتيجة الطلب الفعلية كمرجع وتجنب فحص اتصال منفصلاً يعد بالنجاح قبل بدء الطلب.
الأخطاء الشائعة وإصلاحها
تتعطل عملية التحويل رغم نجاح HTTP
- لماذا يحدث؟
- تخالف الحمولة متطلبات الحقول المفترضة.
- كيف تصلحه؟
- تحقق من DTO وأعد فشلاً صريحاً لعقد البيانات.
- كيف تتجنب تكراره؟
- اختبر حقول الاستجابة المفقودة وnull والمشوهة.
تنشئ إعادة المحاولة سجلات مكررة
- لماذا يحدث؟
- تكررت كتابة بعد مهلة ذات نتيجة مبهمة.
- كيف تصلحه؟
- استخدم مفتاح عملية ثابتاً مع منع تكرار يفرضه الخادم.
- كيف تتجنب تكراره؟
- عرّف منع تكرار الكتابة قبل تفعيل إعادة المحاولة التلقائية.
يشير كشف الاتصال إلى توفره لكن الطلبات تفشل
- لماذا يحدث؟
- اعتُبر وجود الشبكة وصولاً مؤكداً إلى الخدمة.
- كيف تصلحه؟
- عالج إخفاقات الطلب واعرض المحتوى المخبأ إن أمكن.
- كيف تتجنب تكراره؟
- اختبر البوابة المقيدة وتعطل الخادم.
اختبر فهمك
1. قد يصل طلب إنشاء انتهت مهلته إلى الخادم. لماذا لا يصلح معرّف عشوائي جديد عند الإعادة؟
اعرض الحل المشروح
يجعل المعرّف الجديد المحاولة تبدو عملية مختلفة فينشئ الخادم نسخة أخرى. احتفظ بهوية العملية الأصلية عبر المحاولات واطلب من الخلفية إعادة النتيجة المثبتة لذلك المفتاح. يجب أن يحفظ العميل الهوية أيضاً عبر إعادة إنشاء العملية إذا بقي الطلب معلقاً.
2. يفشل تحديث مع وجود قائمة مخبأة صالحة. حدد حالة الشاشة واختبار المستودع.
اعرض الحل المشروح
أبقِ القائمة مرئية واكشف فشل التحديث منفصلاً مع إعادة محاولة ومعلومات حداثة مناسبة. في الاختبار ازرع سجلات مخبأة واجعل الخدمة الوهمية ترمي خطأ إدخال وإخراج ثم حدّث وتحقق من بقاء السجلات وتغير حالة الفشل. لا يلزم اتصال حقيقي.
أهم ما تعلمته
- لا يثبت نجاح النقل صحة المجال.
- تحتاج الإعادة عقداً صريحاً للآثار الجانبية.
- تحمي المستودعات الواجهة من تفاصيل النقل وتقلبه.