‫Android Kotlin Fundamentals 02.4: أساسيات ربط البيانات

هذا الدرس التطبيقي حول الترميز هو جزء من دورة "أساسيات Android Kotlin". يمكنك تحقيق أقصى استفادة من هذه الدورة التدريبية إذا اتبعت ترتيب الخطوات في دروس البرمجة. يتم إدراج جميع الدروس التطبيقية حول الترميز الخاصة بالدورة التدريبية في الصفحة المقصودة للدروس التطبيقية حول الترميز في دورة Android Kotlin Fundamentals.

مقدمة

في دروس تطبيقية سابقة ضمن هذه الدورة التدريبية، استخدمت الدالة findViewById() للحصول على مراجع إلى طرق العرض. عندما يحتوي تطبيقك على تسلسلات هرمية معقّدة للعناصر المعروضة، تكون عملية findViewById() مكلفة وتؤدي إلى تباطؤ التطبيق، لأنّ نظام التشغيل Android يتنقّل في التسلسل الهرمي للعناصر المعروضة، بدءًا من العنصر الجذر، إلى أن يعثر على العنصر المطلوب. لحسن الحظ، هناك طريقة أفضل.

لضبط البيانات في طرق العرض، استخدمت موارد السلسلة وضبطت البيانات من النشاط. سيكون الأمر أكثر فعالية إذا كان العرض على دراية بالبيانات. لحسن الحظ، يمكن إجراء ذلك أيضًا.

في هذا الدرس التطبيقي، ستتعرّف على كيفية استخدام ربط البيانات لإلغاء الحاجة إلى findViewById(). ستتعرّف أيضًا على كيفية استخدام ربط البيانات للوصول إلى البيانات مباشرةً من طريقة العرض.

ما يجب معرفته

يجب أن تكون على دراية بما يلي:

  • ما هو النشاط وكيفية إعداده باستخدام تخطيط في onCreate()
  • إنشاء عرض نصي وضبط النص الذي يعرضه العرض النصي
  • استخدام findViewById() للحصول على مرجع لعرض
  • إنشاء وتعديل تنسيق XML أساسي لعنصر عرض

أهداف الدورة التعليمية

  • كيفية استخدام مكتبة ربط البيانات لإزالة عمليات الاستدعاء غير الفعّالة إلى findViewById()
  • كيفية الوصول إلى بيانات التطبيق مباشرةً من XML

الإجراءات التي ستنفذّها

  • تعديل تطبيق لاستخدام ربط البيانات بدلاً من findViewById()، والوصول إلى البيانات مباشرةً من ملفات XML للتصميم

في هذا الدرس العملي، ستبدأ بتطبيق AboutMe وتغيّره لاستخدام ربط البيانات. سيبدو التطبيق تمامًا كما كان عند الانتهاء.

في ما يلي وظائف تطبيق AboutMe:

  • عندما يفتح المستخدم التطبيق، يعرض التطبيق اسمًا وحقلًا لإدخال اسم مستعار وزر تم وصورة نجمة ونصًا يمكن للمستخدم التنقّل فيه.
  • يمكن للمستخدم إدخال لقب والنقر على الزر تم. يتم استبدال الحقل والزر القابلَين للتعديل بعرض نص يعرض اللقب الذي تم إدخاله.


يمكنك استخدام الرمز الذي أنشأته في الدرس العملي السابق، أو يمكنك تنزيل الرمز AboutMeDataBinding-Starter من GitHub.

تستخدِم التعليمات البرمجية التي كتبتها في دروس البرمجة السابقة الدالة findViewById() للحصول على مراجع للعناصر المعروضة.

في كل مرة تستخدم فيها findViewById() للبحث عن طريقة عرض بعد إنشائها أو إعادة إنشائها، يتنقّل نظام التشغيل Android في بنية طريقة العرض الهرمية في وقت التشغيل للعثور عليها. عندما يحصل تطبيقك على عدد قليل من المشاهدات، لا يشكّل ذلك مشكلة. ومع ذلك، قد تحتوي تطبيقات الإنتاج على عشرات طرق العرض في التنسيق، وحتى مع أفضل تصميم، ستكون هناك طرق عرض متداخلة.

لنفترض أنّ لديك تخطيطًا خطيًا يحتوي على عرض قابل للتمرير يحتوي على عرض نصي. بالنسبة إلى التسلسل الهرمي الكبير أو العميق للعناصر المعروضة، قد يستغرق العثور على عنصر معروض وقتًا طويلاً بما يكفي لإبطاء التطبيق بشكل ملحوظ بالنسبة إلى المستخدم. يمكن أن يساعد تخزين طرق العرض مؤقتًا في المتغيرات، ولكن لا يزال عليك تهيئة متغير لكل طريقة عرض، في كل مساحة اسم. ومع توفّر الكثير من طرق العرض والأنشطة المتعددة، يزداد حجم البيانات أيضًا.

أحد الحلول هو إنشاء عنصر يحتوي على مرجع لكل طريقة عرض. يمكن لتطبيقك بأكمله استخدام هذا العنصر، الذي يُطلق عليه اسم عنصر Binding. وتُعرف هذه التقنية باسم ربط البيانات. بعد إنشاء عنصر ربط لتطبيقك، يمكنك الوصول إلى طرق العرض والبيانات الأخرى من خلال عنصر الربط، بدون الحاجة إلى التنقّل في بنية طرق العرض أو البحث عن البيانات.

تقدّم ميزة ربط البيانات المزايا التالية:

  • الرمز أقصر وأسهل في القراءة والصيانة من الرمز الذي يستخدم findByView().
  • يتم فصل البيانات وطرق العرض بوضوح. تزداد أهمية هذه الميزة في ربط البيانات لاحقًا في هذه الدورة التدريبية.
  • لا يتنقّل نظام التشغيل Android في بنية العرض إلا مرة واحدة للحصول على كل عرض، ويحدث ذلك أثناء بدء تشغيل التطبيق، وليس أثناء وقت التشغيل عندما يتفاعل المستخدم مع التطبيق.
  • يمكنك الحصول على أمان الأنواع للوصول إلى طرق العرض. (أمان الأنواع يعني أنّ المترجم يتحقّق من الأنواع أثناء الترجمة، ويُظهر رسالة خطأ إذا حاولت تعيين نوع غير صحيح لمتغيّر).

في هذه المهمة، عليك إعداد ربط البيانات واستخدامه لاستبدال طلبات findViewById() بطلبات إلى عنصر الربط.

الخطوة 1: تفعيل ربط البيانات

لاستخدام ربط البيانات، عليك تفعيل هذه الميزة في ملف Gradle لأنّها غير مفعّلة تلقائيًا. ويرجع ذلك إلى أنّ ربط البيانات يزيد من وقت التجميع وقد يؤثّر في وقت بدء تشغيل التطبيق.

  1. إذا لم يكن لديك تطبيق AboutMe من تجربة سابقة، احصل على الرمز AboutMeDataBinding-Starter من GitHub. افتحه في Android Studio.
  2. افتح ملف build.gradle (Module: app).
  3. داخل القسم android، قبل قوس الإغلاق، أضِف القسم dataBinding واضبط enabled على true.
dataBinding {
    enabled = true
}
  1. عندما يُطلب منك ذلك، زامِن المشروع. إذا لم يُطلب منك ذلك، اختَر ملف > مزامنة المشروع مع ملفات Gradle.
  2. يمكنك تشغيل التطبيق، ولكن لن تظهر لك أي تغييرات.

الخطوة 2: تغيير ملف التنسيق ليكون قابلاً للاستخدام مع ربط البيانات

لاستخدام ميزة ربط البيانات، عليك تضمين تنسيق XML في العلامة <layout>. وذلك لكي لا يكون الصف الجذر مجموعة عرض، بل تخطيطًا يحتوي على مجموعات عرض وطرق عرض. يمكن لكائن الربط بعد ذلك معرفة التنسيق وطرق العرض فيه.

  1. افتح ملف activity_main.xml.
  2. انتقِل إلى علامة التبويب نص.
  3. أضِف <layout></layout> كعلامة خارجية حول <LinearLayout>.
<layout>
   <LinearLayout ... >
   ...
   </LinearLayout>
</layout>
  1. اختَر الرمز > إعادة تنسيق الرمز لإصلاح المسافة البادئة للرمز.

    يجب أن تكون بيانات مساحة الاسم للتصميم في العلامة الخارجية.
  1. قُصّ بيانات مساحة الاسم من العلامة <LinearLayout> والصِقها في العلامة <layout>. يجب أن تبدو علامة <layout> الافتتاحية كما هو موضّح أدناه، ويجب أن تحتوي علامة <LinearLayout> على خصائص العرض فقط.
<layout xmlns:android="http://schemas.android.com/apk/res/android"
   xmlns:app="http://schemas.android.com/apk/res-auto">
  1. أنشئ تطبيقك وشغِّله للتأكّد من أنّك نفّذت هذه الخطوة بشكل صحيح.

الخطوة 3: إنشاء عنصر ربط في النشاط الرئيسي

أضِف مرجعًا إلى عنصر الربط في النشاط الرئيسي، حتى تتمكّن من استخدامه للوصول إلى طرق العرض:

  1. افتح ملف MainActivity.kt.
  2. قبل onCreate()، أنشئ متغيّرًا لكائن الربط على المستوى الأعلى. يُطلق على هذا المتغير عادةً اسم binding.

    ويتم إنشاء نوع binding، أي الفئة ActivityMainBinding، بواسطة برنامج الترجمة البرمجية خصيصًا لهذا النشاط الرئيسي. ويتم اشتقاق الاسم من اسم ملف التصميم، أي activity_main + Binding.
private lateinit var binding: ActivityMainBinding
  1. إذا طلب منك "استوديو Android" ذلك، استورِد ActivityMainBinding. إذا لم يُطلب منك ذلك، انقر على ActivityMainBinding واضغط على Alt+Enter (Option+Enter على جهاز Mac) لاستيراد هذا الصف المفقود. (للاطّلاع على المزيد من اختصارات لوحة المفاتيح، يُرجى مراجعة اختصارات لوحة المفاتيح.)

    يجب أن تبدو عبارة import مشابهة للعبارة الموضّحة أدناه.
import com.example.android.aboutme.databinding.ActivityMainBinding

بعد ذلك، استبدِل الدالة setContentView() الحالية بتعليمات تنفّذ ما يلي:

  • تنشئ هذه الدالة عنصر الربط.
  • تستخدِم الدالة setContentView() من الفئة DataBindingUtil لربط التنسيق activity_main بـ MainActivity. تتولّى هذه الدالة setContentView() أيضًا إعداد بعض عمليات ربط البيانات للعروض.
  1. في onCreate()، استبدِل طلب setContentView() بسطر الرمز التالي.
binding = DataBindingUtil.setContentView(this, R.layout.activity_main)
  1. استيراد DataBindingUtil
import androidx.databinding.DataBindingUtil

الخطوة 4: استخدام عنصر الربط لاستبدال جميع طلبات findViewById()

يمكنك الآن استبدال جميع طلبات findViewById() بمراجع للعناصر المعروضة في عنصر الربط. عند إنشاء عنصر الربط، ينشئ المترجم أسماء طرق العرض في عنصر الربط من أرقام تعريف طرق العرض في التصميم، ويحوّلها إلى تنسيق camel case. على سبيل المثال، done_button تصبح doneButton في عنصر الربط، وnickname_edit تصبح nicknameEdit، وnickname_text تصبح nicknameText.

  1. في onCreate()، استبدِل الرمز الذي يستخدم findViewById() للعثور على done_button بالرمز الذي يشير إلى الزر في عنصر الربط.

    استبدِل هذا الرمز: findViewById<Button>(R.id.done_button)
    بالرمز التالي: binding.doneButton

    من المفترض أن يبدو الرمز النهائي لضبط أداة معالجة النقرات في onCreate() على النحو التالي.
binding.doneButton.setOnClickListener {
   addNickname(it)
}
  1. كرِّر الخطوات نفسها لجميع عمليات استدعاء findViewById() في الدالة addNickname().
    استبدِل جميع مثيلات findViewById<View>(R.id.id_view) بـ binding.idView. يمكنك إجراء ذلك باتّباع الخطوات التالية:
  • احذف تعريفات المتغيّرَين editText وnicknameTextView بالإضافة إلى طلباتهما إلى findViewById(). سيؤدي ذلك إلى حدوث أخطاء.
  • أصلِح الأخطاء من خلال الحصول على طرق العرض nicknameText وnicknameEdit وdoneButton من العنصر binding بدلاً من المتغيرات (المحذوفة).
  • استبدِل view.visibility بـ binding.doneButton.visibility. يؤدي استخدام binding.doneButton بدلاً من view التي تم تمريرها إلى جعل الرمز أكثر اتساقًا.

    النتيجة هي الرمز التالي:
binding.nicknameText.text = binding.nicknameEdit.text
binding.nicknameEdit.visibility = View.GONE
binding.doneButton.visibility = View.GONE
binding.nicknameText.visibility = View.VISIBLE
  • لم يتم إجراء أي تغيير في الوظائف. يمكنك الآن إزالة المَعلمة view وتعديل جميع استخدامات view لاستخدام binding.doneButton داخل هذه الدالة.
  1. يتطلّب nicknameText String، وnicknameEdit.text هو Editable. عند استخدام ربط البيانات، من الضروري تحويل Editable إلى String بشكلٍ صريح.
binding.nicknameText.text = binding.nicknameEdit.text.toString()
  1. يمكنك حذف عمليات الاستيراد التي تظهر باللون الرمادي.
  2. حوِّل الدالة إلى Kotlin باستخدام apply{}.
binding.apply {
   nicknameText.text = nicknameEdit.text.toString()
   nicknameEdit.visibility = View.GONE
   doneButton.visibility = View.GONE
   nicknameText.visibility = View.VISIBLE
}
  1. أنشئ تطبيقك وشغِّله...من المفترض أن يظهر ويعمل تمامًا كما كان من قبل.

يمكنك الاستفادة من ربط البيانات لإتاحة فئة البيانات مباشرةً لعرض. يبسّط هذا الأسلوب الرمز البرمجي، وهو مفيد للغاية للتعامل مع الحالات الأكثر تعقيدًا.

في هذا المثال، بدلاً من ضبط الاسم والاسم المستعار باستخدام موارد السلسلة، يمكنك إنشاء فئة بيانات للاسم والاسم المستعار. يمكنك إتاحة فئة البيانات للعرض باستخدام ربط البيانات.

الخطوة 1: إنشاء فئة بيانات MyName

  1. في Android Studio، افتح الملف MyName.kt في الدليل java. إذا لم يكن لديك هذا الملف، أنشئ ملف Kotlin جديدًا وسمِّه MyName.kt.
  2. حدِّد فئة بيانات للاسم والاسم المستعار. استخدِم السلاسل الفارغة كقيم تلقائية.
data class MyName(var name: String = "", var nickname: String = "")

الخطوة 2: إضافة البيانات إلى التصميم

في الملف activity_main.xml، يتم حاليًا ضبط الاسم في TextView من مورد سلسلة. عليك استبدال الإشارة إلى الاسم بالإشارة إلى البيانات في فئة البيانات.

  1. افتح activity_main.xml في علامة التبويب نص.
  2. في أعلى التنسيق، بين علامتَي <layout> و<LinearLayout>، أدرِج علامة <data></data>. هذا هو المكان الذي ستربط فيه طريقة العرض بالبيانات.
<data>
  
</data>

داخل علامات البيانات، يمكنك تعريف متغيرات مسماة تحتوي على مرجع إلى فئة.

  1. داخل العلامة <data>، أضِف العلامة <variable>.
  2. أضِف المَعلمة name لمنح المتغيّر الاسم "myName". أضِف المَعلمة type واضبط النوع على اسم مؤهَّل بالكامل لفئة البيانات MyName (اسم الحزمة + اسم المتغيّر).
<variable
       name="myName"
       type="com.example.android.aboutme.MyName" />

الآن، بدلاً من استخدام مورد السلسلة للاسم، يمكنك الرجوع إلى المتغيّر myName.

  1. استبدِل android:text="@string/name" بالرمز أدناه.

@={} هو توجيه للحصول على البيانات المشار إليها داخل الأقواس المعقوفة.

يشير myName إلى المتغيّر myName الذي سبق أن حدّدته، والذي يشير إلى فئة البيانات myName ويسترد السمة name من الفئة.

android:text="@={myName.name}"

الخطوة 3: إنشاء البيانات

أصبح لديك الآن مرجع للبيانات في ملف التنسيق. بعد ذلك، يمكنك إنشاء البيانات الفعلية.

  1. افتح ملف MainActivity.kt.
  2. أعلى onCreate()، أنشئ متغيّرًا خاصًا، يُعرف أيضًا باسم myName حسب الاصطلاح. عيِّن للمتغيّر مثيلاً لفئة البيانات MyName، مع إدخال الاسم.
private val myName: MyName = MyName("Aleks Haecky")
  1. في onCreate()، اضبط قيمة المتغيّر myName في ملف التصميم على قيمة المتغيّر myName الذي أعلنت عنه للتو. لا يمكنك الوصول إلى المتغيّر في ملف XML مباشرةً. يجب الوصول إليه من خلال عنصر الربط.
binding.myName = myName
  1. قد يظهر هذا الإجراء خطأً، لأنّ عليك إعادة تحميل عنصر الربط بعد إجراء تغييرات. أنشئ تطبيقك، وسيتم حلّ الخطأ.

الخطوة 4: استخدام فئة البيانات للاسم المستعار في TextView

الخطوة الأخيرة هي استخدام فئة البيانات أيضًا للاسم المستعار في TextView.

  1. فتح "activity_main.xml"
  2. في عرض النص nickname_text، أضِف السمة text. أشِر إلى nickname في فئة البيانات، كما هو موضّح أدناه.
android:text="@={myName.nickname}"
  1. في ActivityMain، استبدِل
    nicknameText.text = nicknameEdit.text.toString()
    بالرمز لضبط الاسم في المتغيّر myName.
myName?.nickname = nicknameEdit.text.toString()

بعد ضبط الاسم المستعار، عليك أن تطلب من الرمز تحديث واجهة المستخدم بالبيانات الجديدة. لإجراء ذلك، يجب إبطال جميع تعبيرات الربط حتى تتم إعادة إنشائها باستخدام البيانات الصحيحة.

  1. أضِف invalidateAll() بعد ضبط الاسم المستعار ليتم إعادة تحميل واجهة المستخدم بالقيمة في عنصر الربط المعدَّل.
binding.apply {
   myName?.nickname = nicknameEdit.text.toString()
   invalidateAll()
   ...
}
  1. أنشئ تطبيقك وشغِّله، وسيعمل بالطريقة نفسها تمامًا كما كان من قبل.

مشروع "استوديو Android": AboutMeDataBinding

خطوات استخدام ربط البيانات لاستبدال طلبات findViewById():

  1. فعِّل ربط البيانات في قسم Android من ملف build.gradle:
    dataBinding { enabled = true }
  2. استخدِم <layout> كطريقة العرض الجذرية في تنسيق XML.
  3. تحديد متغيّر ربط:
    private lateinit var binding: ActivityMainBinding
  4. أنشئ عنصر ربط في MainActivity، واستبدِل setContentView:
    binding = DataBindingUtil.setContentView(this, R.layout.activity_main)
  5. استبدِل طلبات findViewById() بالإشارات إلى طريقة العرض في عنصر الربط. على سبيل المثال:
    findViewById<Button>(R.id.done_button) ⇒ binding.doneButton
    (في المثال، يتم إنشاء اسم طريقة العرض باستخدام تنسيق camel case من id الخاص بطريقة العرض في XML).

خطوات ربط طرق العرض بالبيانات:

  1. أنشئ فئة بيانات لبياناتك.
  2. أضِف مربّع <data> داخل العلامة <layout>.
  3. حدِّد <variable> باسم ونوع يمثّل فئة البيانات.
<data>
   <variable
       name="myName"
       type="com.example.android.aboutme.MyName" />
</data>
  1. في MainActivity، أنشئ متغيّرًا يتضمّن مثيلاً لفئة البيانات. على سبيل المثال:
    private val myName: MyName = MyName("Aleks Haecky")
  1. في عنصر الربط، اضبط المتغيّر على المتغيّر الذي أنشأته للتو:
    binding.myName = myName
  1. في ملف XML، اضبط محتوى العرض على المتغيّر الذي حدّدته في كتلة <data>. استخدِم صيغة النقطة للوصول إلى البيانات داخل فئة البيانات.
    android:text="@={myName.name}"

دورة Udacity التدريبية:

مستندات مطوّري تطبيقات Android:

يسرد هذا القسم مهامًا منزلية محتملة للطلاب الذين يعملون على هذا الدرس التطبيقي العملي كجزء من دورة تدريبية يقودها مدرّب. على المعلّم تنفيذ ما يلي:

  • حدِّد واجبًا منزليًا إذا لزم الأمر.
  • توضيح كيفية إرسال الواجبات المنزلية للطلاب
  • وضع درجات للواجبات المنزلية

يمكن للمدرّبين استخدام هذه الاقتراحات بالقدر الذي يريدونه، ويجب ألا يترددوا في تكليف الطلاب بأي واجبات منزلية أخرى يرونها مناسبة.

إذا كنت تعمل على هذا الدرس العملي بنفسك، يمكنك استخدام مهام الواجب المنزلي هذه لاختبار معلوماتك.

الإجابة عن هذه الأسئلة

السؤال 1

لماذا يجب تقليل عدد طلبات البيانات الصريحة والضمنية إلى findViewById()؟

  • في كل مرة يتم فيها استدعاء findViewById()، يتم الانتقال عبر بنية العرض الهرمية.
  • يتم تشغيل findViewById() في سلسلة التعليمات الرئيسية أو سلسلة تعليمات واجهة المستخدم.
  • ويمكن أن تؤدي هذه المكالمات إلى إبطاء واجهة المستخدم.
  • تقل احتمالية تعطل تطبيقك.

السؤال 2

كيف يمكنك وصف ربط البيانات؟

على سبيل المثال، إليك بعض العبارات التي يمكنك قولها عن ربط البيانات:

  • الفكرة الأساسية بشأن ربط البيانات هي إنشاء عنصر يربط/يخطّط/يربط بين جزأين من المعلومات البعيدة معًا في وقت الترجمة البرمجية، حتى لا تضطر إلى البحث عن البيانات في وقت التشغيل.
  • يُطلق على العنصر الذي يعرض عمليات الربط هذه اسم عنصر الربط.
  • يتم إنشاء كائن الربط بواسطة المترجم.

السؤال 3

أي مما يلي ليس من مزايا ربط البيانات؟

  • يكون الرمز أقصر وأسهل قراءةً وأسهل صيانةً.
  • يتم فصل البيانات وطرق العرض بوضوح.
  • لا يتنقّل نظام Android في بنية العرض الهرمية إلا مرة واحدة للحصول على كل عرض.
  • يؤدي استدعاء findViewById() إلى حدوث خطأ في المترجم.
  • أمان الأنواع للوصول إلى طرق العرض

السؤال 4

ما هي وظيفة العلامة <layout>؟

  • يمكنك تضمينها في العرض الجذر في التصميم.
  • يتم إنشاء عمليات الربط لجميع طرق العرض في التصميم.
  • تحدّد هذه السمة العرض الأعلى مستوى في تنسيق XML يستخدِم ربط البيانات.
  • يمكنك استخدام العلامة <data> داخل <layout> لربط متغيّر بفئة بيانات.

السؤال 5

ما هي الطريقة الصحيحة للإشارة إلى البيانات المرتبطة في تنسيق XML؟

  • android:text="@={myDataClass.property}"
  • android:text="@={myDataClass}"
  • android:text="@={myDataClass.property.toString()}"
  • android:text="@={myDataClass.bound_data.property}"

ابدأ الدرس التالي: 3.1: إنشاء جزء

للحصول على روابط تؤدي إلى دروس تطبيقية أخرى في هذه الدورة التدريبية، اطّلِع على الصفحة المقصودة الخاصة بالدروس التطبيقية حول أساسيات Android Kotlin.