برمجة الأندرويد

برمجة تطبيق شات الدرس الثانى

<< الدرس السابق

الدرس التالى >>

فى الدرس السابق شرحنا كيفية عمل نظام التسجيل وتسجيل الدخول من جهة ال API وكذلك من جهة الأندرويد اليوم سنتطرق الى موضوع ملازم دائما لعملية الـ Login وهو الـ Session ففى أغلب التطبيقات عندما تقوم بتسجيل الدخول فى أحد التطبيقات عندما تغلق التطبيق ثم تقوم بفتح التطبيق مرة أخرى فانك تجد انك دخلت للصفحة الرئيسية للتطبيق ولم يطلب منك تسجيل الدخول مرة اخرى هذا الامر موجود فى مواقع الويب وفى التطبيقات وكثيرا ما تجد checkbox اسمه remember me ان هذا الامر يطلق عليه الـ Session او الجلسة حيث عندما يقوم المستخدم بتسجيل الدخول نقوم بانشاء جلسة له وتظل الجلسة مفتوحة الى ان يقوم المستخدم بتسجيل الخروج بنفسه وفى بعض التطبيقات حسب طلب العميل او نظام التطبيق يتم عمل الجلسة بمدة معينة مثلا اذا مر 4 ايام دون ان يقوم المستخدم بتسجيل الدخول يتم تسجيل خروجه تلقائيا وهناك الجلسة التى تعتمد على token يتم تفحصه من جهة السيرفر وهذا ما يتم فى التطبيقات الكبيرة حيث كل مرة يتم تسجيل الدخول يتم انشاء token للجلسة وكل مرة يفتح المستخدم التطبيق يتم عمل فحص لهذا ال token لمعرفة اذا ما كان صالحا ام لا اذا لم يكن صاالحا او انتهت مدته فيتم تسجيل خروج المستخدم برمجيا فعلى سبيل المثال اذا قام المستخدم بتغيير كلمة السر فى الموقع الخاص بالتطبيق اون لاين مثلا لاحد الخدمات فانه يتم الغاء صلاحية التوكن القديم ويتم اصدار توكن جديد وفى هذه الحالة يقوم بفتح تطبيق الاندرويد او الIOS فيتم فحص التوكن وعندما لا يجده التطبيق صالحا يقوم بتسجيل الخروج وهذه عملية برمجية اى لا يوجد شىء مخصص لل Session فى الاندرويد مثل php لديها نظام مخصص بل تتم ادارة الـ Session يدويا بمعنى انه فى الدرس السابق يمكنك ببساطه تسجيل قيمة فى ال shared preference مثلا “isuserlogin” واذا نجح تسجيل الدخول تقوم بجعلها true وحفظ ال shared preference وعندما يقوم المستخدم بتسجيل الخروج تقوم بعمل “isuserlogin” بـ false وهذه ابسط طريقة لكن فى اغلب الاحيان تحتاج لتخزين بيانات اليوزر المسجل دخول حتى يمكنك الوصول اليها فى اى وقت بسهولة لهذا نقوم بإنشاء الـ SessionManager والذى غالبا يكون كلاس واحد يحتوى على مجموعة من الـ methods مثل getUser() او getUsername او getUserEmail الخ.. ويمكنك تنفيذه باستخدام shared preferences لكننا سنستخدم Realm .

 

قاعدة بيانات Realm 

تعتبر Realm بديل ممتاز لقواعد البيانات الشائعة فى الأندرويد sqlite حيث توفر Realm الكثير من الوقت والمجهود حيث يمكن بسطور قليلة ان تنفذ ما تنفذه بعشرات السطور عند استخدام sqlite وتستخدم realm على نطاق واسع يتخطى ويستخدمها اكثر من 100 الف مطور فى تطبيقاتهم وتدعم ال java و objective c و swift بالاضافة الى xamarin و react native واذا لم تستخدمها من قبل فحتما ستحبها .

تخيل ان لديك مجموعة من البيانات وليكن مثلا لديك مجموعة من المدرسين والطلاب  تريد تخزين بياناتهم فى sqlite تقوم بانشاء جدول باسم المدرسين وجدول باسم الطلاب وتقوم باضافة الطلاب والمدرسين عن طريق الاستعلامات وتجلبهم عن طريق الاستعلام ايضا وهذا بعد اعداد كلاس كبير يحتوى على الميثود الازمة واسماء الجداول واسماء الاعمدة وادخال كل قيمة فى العمود المناسب وما الى ذلك أما فى realm يكفى أن يكون لديك اوبجكت جافا وليكن Teacher يمكنك حفظه مباشرة الى Realm  كأوبجكت وكذلك لديك اوبجكت Student يمكنك حفظه مباشرة الى Realm بكل بساطة اضف ما شئت من الاوبجكتات واستدعى ما شئت بطريقة سهله وبدون انشاء كلاسات او الكثير من سطور الاستعلامات والشرح الخاص بها على الموقع الخاص بهم سهل وسلس يمكنك القاء نظرة هنا  وفهم مبدأ عملها وكيفية ادخال البيانات واسترجاعها

وسنستخدم Realm فى موضوعنا اليوم لانشاء كلاس الـ Session Manager حيث سنحتاج الى تخزين بيانات المستخدم وجلب بيانات المستخدم من اى مكان فى التطبيق

بداية نقوم بتهيئة Realm باضافتها للمشروع فى ملف الـ gradle الخاص بالـ project نفسه

ثم فى ملف الـ gradle الخاص بالـ app

 

ثم نقوم بعمل مزامنة والان نحن مستعدون للعمل

 

تهيئة Realm 

يجب عليك تهيئة Realm للعمل او ما يعرف بشكل شائع بالـ config  لكن قبل ذلك نحتاج لعمل init او ابتداء لل Realm وهو عباره عن استخدام الميثود init واعطائها الكونتكست والطريقة الافضل لعمل ذلك هو استخدام الـ custom application class اى نقوم بعمل class يرث الـ application لنستطيع تنفيذ كود به

ويجب علينا تسجيل هذا الامر فى  المنيفست الذى يعمل كرئيس مجلس ادارة فى كل تطبيق بموضع هذا الكلاس وأن هذا الكلاس APP سيتم تنفيذه كـ Application class وذلك عن طريق الخاصية name

الان يمكننا المتابعة وفعل ما نريد بـ Realm سواء عمل config لها ام بدء استخدامها لذلك سأقوم الان بعمل كلاس الـ Session

 

الـ Session 

هو كلاس سنقوم بكتابته وسوف يكون مسؤولا عن دخول المستخدم وتسجيل دخوله وتسجيل خروجه وحفظ البيانات الازمة التى نحتاجها عند تسجيل الدخول

سوف نقوم عمل هذا الكلاس Singletone لاننا لا نحتاج لأكثر من اوبجكت من هذا الكلاس بمواصفات مختلفة وبشكل عام  عندما يكون لديك كلاس لا تحتاج لانشاء عدة نسخ منه بمواصفات مختلفة لاشياء مختلفة استخدم باترن ال Singletone كما هو موضح فى الكود التالى :

الان فى الـكونستراكتور نبدأ بعمل كونفيج للـ Realm كالتالى

قمنا بتعريف Realm بالاعلى ثم أنشأنا realmConfig وهو عباره عن new RealmConfig ثم استخدمنا deleteRealm if Migration Nedded اى اذا قمنا بتعديل الاوبجكتس مستقبلا مثلا اضفنا خاصية جديدة للمستخدم ففى هذه الحالة سيكون الـ config محتفظ بالهيكلة القديمة للأوبجكت لذلك نجعله يحذف ويبدأ من جديد ثم build  وفى السطر الذى يليه قمنا باستدعاء instance Realm وهم يستخدمون pattern الـ Singletone ايضا وفى الكونستراكتور يأخذ الـ config اعطيناه الـ config وبهذا تكون realm جاهزة للاستخدام .

أول شىء اريده هو تسجيل المستخدم لذلك سأقوم بإنشاء Method لذلك يمكنك تسميتها startSession او loginUser او الاسم الذى تحب

لاحظ السطر realm.copyToRealm هو من يقوم بتخزين وادخال الـ user الى قاعدة البيانات وستلاحظ ايضا انه تم تنفيذ الامر داخل Transaction حيث يجب أن تتم الامور فى Realm داخل Transaction سواء بالميثود executeTransaction() كما فعلنا الان او بطريقة اخرى كالتاالى :

لكن سنستمر بالطريقة الاولى

وطبعا لاحظت الخط الأحمر وهنا يخبرك انه لا يمكن نسخ أى Object مباشرة للـ Realm يجب أن يرث هذا الـ Object من RealmObject هكذا تعمل Realm لذلك سنذهب للـ Object User ونقوم بجعله يرث Realm Object كالتالى :

وبهذا يختفى الخط الاحمر الذى يشير لخطأ فى user فى كلاس Session

 

جلب البيانات من Realm 

كما رأيت ان الميثود copyToRealm فانها بمثابة INSERT تقوم بالادخال وفى المثال السابق كلما استدعى login user ستقوم بتخزين يوزر جديد وفى الحقيقة انا لا اريد هذا اريد مسح اليوزر القديم لكن قبل ذلك كيف اجلب البيانات اصلا واعرف ان كان هناك User مسجل قبل ذلك ام لا يمكن ببساطة جلب او استدعاء البيانات وهو بمثابة SELECT كالتالى :

بكل سلاسة فقط تقوم باستخدام الميثود where ثم تعطيها الكلاس كـباراميتر وهنا اعطيناها الكلاس User ثم findFirst واذا كنت تريد جلب list كل المستخدمين المسجلين نفس الامر لكن استخدمنا الميثود findAll بهذه البساطه والسهولة هل تريد التحديد بشروط مثلا عندما الusername = اسم معين لا بأس realm تعطيك امكانية عمل هذا بسهولة عن طريق الميثود equalTo كالتالى

فى السطر الاول سيجلب اول اسم مستخدم اسمه ahmed  ون كان هناك مستخدم واحد اسمه ahmed فسيكون هو اذا لم يوجد فستكون ال u = null وكذلك الـ users الـ List سيجلب كل المستخدمين الذى الـ username الخاص بهم هو ali مسجلين مسبقا فى الـ Realm طبعا هذه الامور لن نستخدمها فى كلاس الـ Session لكن ذكرتها للتوضيح فقط  لتتعلم كيفية استرجاع البيانات   (بلاش نقول جلب البيانات لانها تذكرنى بأمر اخر   )

تعديل البيانات فى Realm

يمكنك تعديل البيانات بسهولة فى realm   كالتالى

وسيتم التعديل تخيل مجرد ان تقوم باسناد قيمة جديدة للـ object يتم التحديث مباشرة فى realm لكن طبعا بشكل عام يجب ان تتم اى عملية على realm داخل transaction لذلك الكود السابق لن يعمل يجب ان يكون اسناد قيمة جديدة للاوبجكت داخل transaction

وبهذا يتم تعديل البيانات بشكل فورى فى Realm وستجد العديد من الامثلة الاخرى والتفاصيل اكثر عند التعديل والاضافة والعمليات الاخرى والـ queries  المختلفة فى الشرح الخاص بموقع Realm 

 

حذف البيانات فى Realm

بنفس بساطة التعديل يمكنك الحذف حيث تتوفر لنا ميثود deleteFromRealm تذكر ان الكلاس User يرث RealmObject لكى لا تتعجب من توفر الميثود deleteFromRealm فى الاوبجكت u .

او حذف الكل للنتائج المتعددة عند استخدام الميثود findAll() لكن لا نستقبل البيانات فى List بل فى RealmResult حتى تتاح لنا الـ method deleteAllFromRealm

 

او يمكنك حذف المستخدمين بالكامل بحيث لا يبقى لهم اثر

طبعا فى الامثلة السابقة استخدمت الـ User لكن اثناء استخدامك يمكن تخزين أى اوبجكت تريد فقط اجعله يرث من RealmObject وبهذا نكون شرحنا العمليات الأساسية فى Realm وكما رأيت سهله جدا وعملية جدا وتغنيك عن الكثير من تعقيدات الـ sqlite العادية فى التعامل

 

نعود الان إلى الـ Session مرة أخرى لنكمل الميثود loginUser التى سنبدأ بها الـ Session

نقوم بالتأكد انه لايوجد تسجيل دخول من قبل وأنه لا يوجد ولا User حتى اذا نسيت اثناء البرمجة او حدث خطأ وقمت باستدعاء الميثود loginuser دون ان يكون قد قمت بعمل logout لا يحدث مشاكل  لذلك ساقوم بعمل تسجيل خروج ان وجد مستخدم سابق ثم اتمام تسجيل الدخول  بنفس الميثود كالتالى :

وطبعا الميثود logut باللون الأحمر لاننا لم نقم بتنفيذها بعد سأقوم بذلك الان

الان لدينا 2 Methods الاولى login تأخذ User كـ parameter وتقوم بحفظه والميثود logout تقوم بحذف المستخدم من قاعدة البيانات والان نريد عمل Method اخرى مهمة جدا فى الـ Session وهى isUserLoggedIn لتعود لنا بـ true اذا كان المستخدم سجل الدخول من قبل (موجود فى قاعدة البيانات ) او false ان لم يكن سجل الدخول ويمكننا عملها ببساطة كالتالى :

وهى عباره عن انها تفحص قيمة الـ Users ان كان هناك اى بيانات مسجلة بـ Realm تحت User فان هناك مستخدم قد سجل الدخول وستعود بـ true  اما اذا كان لا يوجد والراجع بـ null فانه لا يوجد مستخدم وستعود بـ false والسطر مختصر يمكنك كتابتها ايضا بهذه الطريقة ان اردت

وبما أنه  فى اى مكان فى التطبيق قد نحتاج لبيانات المستخدم مثل الـ id او الـ token او اى بيانات اخرى كايميل المستخدم او اسمه لذلك يجب أن نقوم بعمل ميثود تعود بالمستخدم وستكون كالتالى :

وبالتأكيد إن لم يكن المستخدم مسجل دخول فإن getUser ستعود بـ null لذلك يجب أن تأخذ هذا بعين الاعتبار حتى لا تواجه الـ NPE Exception اللطيف الذى يكدر حياتنا كمطورين

بالاضافة لهذه الـ Methods الرئيسية يمكنك اضافة أى Method تحتاجها بعد ان فهمت الفكرة مثل تحديث بيانات اليوزر أو تعديلها فى حالات معينة افعل ما يحلو لك وانشىء كلاس Session يناسب احتياجاتك

والان حان وقت الاختبار لذلك سأذهب فى صفحة الـ Splash وسأستخدم الكلاس لفحص ان كان المستخدم قد سجل الدخول أم لا  كالتالى :

 

ثم سأذهب الى صفحة الـLogin لتسجيل الدخول لبدء الـ Session كالتاالى :

 

يمكنك فعل ذلك ايضا فى صفحة تسجيل العضوية حيث بعض التطبيق بمجرد تسجيل العضوية يتم انشاء Session وتسجيل دخول العضو تلقائيا وفى بعض التطبيقات الاخرى يتم تحويل العضو لصفحة تسجيل الدخول بعد التسجيل افعل ما تحب لكن الان سنذهب لصفحة الـ Main Activity لنرحب بالمستخدم فعلا

ولاحظ اننى عرضت ايميل المستخدم لانه عندما يقوم بتسجيل الدخول يكتب ايميله وبالتالى يكون ال username فارغ يمكننا تعديل ملف الـ php ليعود الينا بالـ username ونعدل ملف الـ response كذلك لكن لا نريد ان نعطى موضوع تسجيل الدخول والتسجيل أكثر من حقه ونتابع الى الشات .

الان سنقوم بتجربة التطبيق وسنجد انه يحولنا الى صفحة تسجيل الدخول وبعد تسجيل الدخول يحولنا الى هذه الصفحة

 

وعند اغلاق التطبيق تماما  وفتحه مرة أخرى ستجد أنه يحولنا الى هذه الصفحة ايضا الـ MainActivity لان المستخدم مسجل الدخول الان بالفعل ويتم تفحص ذلك فى الـ Splash Screen لذلك يجب أن نقوم بعمل زر لتسجيل الدخول والا سيظل المستخدم مسجل الدخول دائما

 

والميثود التى قمنا بعملها سابقا تقوم بتسجيل الخروج فقط دون نقل المستخدم من الصفحة الى صفحة تسجيل الدخول ويجب ان يغلق المستخدم التطبيق ثم يفتحه مرة اخرى ليكتشف أنه تم تسجيل الخروج فعلا وسيشك بأننا تابعين لشركة TE Data لذلك سنذهب لكلاس الــ Session مرة اخرى ونقوم بااضافة ميثود تقوم بتسجيل الخروج والذهاب لصفحة الللوجين بمجرد استدعائها كالتالى :

ويمكنك استدعائها واعطائها الاكتيتفى الحالى الذى تقف فيه وهو الـ MainActivity وسترى انها ستعود للوجين مرة اخرى وبهذا تكون أنشأت الـ Session باستخدام Realm  .

 

 

 

 

<< الدرس السابق

الدرس التالى >>

السابق
برمجة تطبيق شات الدرس الأول
التالي
برمجة تطبيق شات الدرس الثالث

4 تعليقات

أضف تعليقا

  1. ابو ساجد قال:

    السلام عليكم ورحمة الله وبركاتة
    يظهر هذا الخطأ
    Error:Execution failed for task ‘:app:compileDebugJavaWithJavac’.
    > Compilation failed; see the compiler error output for details.
    فما الحل

  2. mido قال:

    User is not part of the schema for this Realm

  3. khaled shaban قال:

    اولاً السلام عليكم . وبارك الله فيكم . شرحكم ممتاز . بس أنا عاوز أسأل ع حاجه . لما انا بعمل ال Realm كده البيانات بتستخدم فى ال Realm بس مع انى ببقى عامل الداتا بيس ع ال phpMySql . ازاى ممكن أعمل ال Real وأرطها مع ال MySql

  4. Muhammed Amer قال:

    فنان وربنا

اترك تعليقاً

This site uses Akismet to reduce spam. Learn how your comment data is processed.