هذا الدرس التطبيقي حول الترميز هو جزء من دورة "أساسيات 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 لأنّها غير مفعّلة تلقائيًا. ويرجع ذلك إلى أنّ ربط البيانات يزيد من وقت التجميع وقد يؤثّر في وقت بدء تشغيل التطبيق.
- إذا لم يكن لديك تطبيق AboutMe من تجربة سابقة، احصل على الرمز AboutMeDataBinding-Starter من GitHub. افتحه في Android Studio.
- افتح ملف
build.gradle (Module: app)
. - داخل القسم
android
، قبل قوس الإغلاق، أضِف القسمdataBinding
واضبطenabled
علىtrue
.
dataBinding {
enabled = true
}
- عندما يُطلب منك ذلك، زامِن المشروع. إذا لم يُطلب منك ذلك، اختَر ملف > مزامنة المشروع مع ملفات Gradle.
- يمكنك تشغيل التطبيق، ولكن لن تظهر لك أي تغييرات.
الخطوة 2: تغيير ملف التنسيق ليكون قابلاً للاستخدام مع ربط البيانات
لاستخدام ميزة ربط البيانات، عليك تضمين تنسيق XML في العلامة <layout>
. وذلك لكي لا يكون الصف الجذر مجموعة عرض، بل تخطيطًا يحتوي على مجموعات عرض وطرق عرض. يمكن لكائن الربط بعد ذلك معرفة التنسيق وطرق العرض فيه.
- افتح ملف
activity_main.xml
. - انتقِل إلى علامة التبويب نص.
- أضِف
<layout></layout>
كعلامة خارجية حول<LinearLayout>
.
<layout>
<LinearLayout ... >
...
</LinearLayout>
</layout>
- اختَر الرمز > إعادة تنسيق الرمز لإصلاح المسافة البادئة للرمز.
يجب أن تكون بيانات مساحة الاسم للتصميم في العلامة الخارجية.
- قُصّ بيانات مساحة الاسم من العلامة
<LinearLayout>
والصِقها في العلامة<layout>
. يجب أن تبدو علامة<layout>
الافتتاحية كما هو موضّح أدناه، ويجب أن تحتوي علامة<LinearLayout>
على خصائص العرض فقط.
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
- أنشئ تطبيقك وشغِّله للتأكّد من أنّك نفّذت هذه الخطوة بشكل صحيح.
الخطوة 3: إنشاء عنصر ربط في النشاط الرئيسي
أضِف مرجعًا إلى عنصر الربط في النشاط الرئيسي، حتى تتمكّن من استخدامه للوصول إلى طرق العرض:
- افتح ملف
MainActivity.kt
. - قبل
onCreate()
، أنشئ متغيّرًا لكائن الربط على المستوى الأعلى. يُطلق على هذا المتغير عادةً اسمbinding
.
ويتم إنشاء نوعbinding
، أي الفئةActivityMainBinding
، بواسطة برنامج الترجمة البرمجية خصيصًا لهذا النشاط الرئيسي. ويتم اشتقاق الاسم من اسم ملف التصميم، أيactivity_main + Binding
.
private lateinit var binding: ActivityMainBinding
- إذا طلب منك "استوديو Android" ذلك، استورِد
ActivityMainBinding
. إذا لم يُطلب منك ذلك، انقر علىActivityMainBinding
واضغط علىAlt+Enter
(Option+Enter
على جهاز Mac) لاستيراد هذا الصف المفقود. (للاطّلاع على المزيد من اختصارات لوحة المفاتيح، يُرجى مراجعة اختصارات لوحة المفاتيح.)
يجب أن تبدو عبارةimport
مشابهة للعبارة الموضّحة أدناه.
import com.example.android.aboutme.databinding.ActivityMainBinding
بعد ذلك، استبدِل الدالة setContentView()
الحالية بتعليمات تنفّذ ما يلي:
- تنشئ هذه الدالة عنصر الربط.
- تستخدِم الدالة
setContentView()
من الفئةDataBindingUtil
لربط التنسيقactivity_main
بـMainActivity
. تتولّى هذه الدالةsetContentView()
أيضًا إعداد بعض عمليات ربط البيانات للعروض.
- في
onCreate()
، استبدِل طلبsetContentView()
بسطر الرمز التالي.
binding = DataBindingUtil.setContentView(this, R.layout.activity_main)
- استيراد
DataBindingUtil
import androidx.databinding.DataBindingUtil
الخطوة 4: استخدام عنصر الربط لاستبدال جميع طلبات findViewById()
يمكنك الآن استبدال جميع طلبات findViewById()
بمراجع للعناصر المعروضة في عنصر الربط. عند إنشاء عنصر الربط، ينشئ المترجم أسماء طرق العرض في عنصر الربط من أرقام تعريف طرق العرض في التصميم، ويحوّلها إلى تنسيق camel case. على سبيل المثال، done_button
تصبح doneButton
في عنصر الربط، وnickname_edit
تصبح nicknameEdit
، وnickname_text
تصبح nicknameText
.
- في
onCreate()
، استبدِل الرمز الذي يستخدمfindViewById()
للعثور علىdone_button
بالرمز الذي يشير إلى الزر في عنصر الربط.
استبدِل هذا الرمز:findViewById<Button>(R.id.
done_button
)
بالرمز التالي:binding.doneButton
من المفترض أن يبدو الرمز النهائي لضبط أداة معالجة النقرات فيonCreate()
على النحو التالي.
binding.doneButton.setOnClickListener {
addNickname(it)
}
- كرِّر الخطوات نفسها لجميع عمليات استدعاء
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
داخل هذه الدالة.
- يتطلّب
nicknameText
String
، وnicknameEdit.text
هوEditable
. عند استخدام ربط البيانات، من الضروري تحويلEditable
إلىString
بشكلٍ صريح.
binding.nicknameText.text = binding.nicknameEdit.text.toString()
- يمكنك حذف عمليات الاستيراد التي تظهر باللون الرمادي.
- حوِّل الدالة إلى Kotlin باستخدام
apply{}
.
binding.apply {
nicknameText.text = nicknameEdit.text.toString()
nicknameEdit.visibility = View.GONE
doneButton.visibility = View.GONE
nicknameText.visibility = View.VISIBLE
}
- أنشئ تطبيقك وشغِّله...من المفترض أن يظهر ويعمل تمامًا كما كان من قبل.
يمكنك الاستفادة من ربط البيانات لإتاحة فئة البيانات مباشرةً لعرض. يبسّط هذا الأسلوب الرمز البرمجي، وهو مفيد للغاية للتعامل مع الحالات الأكثر تعقيدًا.
في هذا المثال، بدلاً من ضبط الاسم والاسم المستعار باستخدام موارد السلسلة، يمكنك إنشاء فئة بيانات للاسم والاسم المستعار. يمكنك إتاحة فئة البيانات للعرض باستخدام ربط البيانات.
الخطوة 1: إنشاء فئة بيانات MyName
- في Android Studio، افتح الملف
MyName.kt
في الدليلjava
. إذا لم يكن لديك هذا الملف، أنشئ ملف Kotlin جديدًا وسمِّهMyName.kt
. - حدِّد فئة بيانات للاسم والاسم المستعار. استخدِم السلاسل الفارغة كقيم تلقائية.
data class MyName(var name: String = "", var nickname: String = "")
الخطوة 2: إضافة البيانات إلى التصميم
في الملف activity_main.xml
، يتم حاليًا ضبط الاسم في TextView
من مورد سلسلة. عليك استبدال الإشارة إلى الاسم بالإشارة إلى البيانات في فئة البيانات.
- افتح
activity_main.xml
في علامة التبويب نص. - في أعلى التنسيق، بين علامتَي
<layout>
و<LinearLayout>
، أدرِج علامة<data></data>
. هذا هو المكان الذي ستربط فيه طريقة العرض بالبيانات.
<data>
</data>
داخل علامات البيانات، يمكنك تعريف متغيرات مسماة تحتوي على مرجع إلى فئة.
- داخل العلامة
<data>
، أضِف العلامة<variable>
. - أضِف المَعلمة
name
لمنح المتغيّر الاسم"myName"
. أضِف المَعلمةtype
واضبط النوع على اسم مؤهَّل بالكامل لفئة البياناتMyName
(اسم الحزمة + اسم المتغيّر).
<variable
name="myName"
type="com.example.android.aboutme.MyName" />
الآن، بدلاً من استخدام مورد السلسلة للاسم، يمكنك الرجوع إلى المتغيّر myName
.
- استبدِل
android:text="@string/name"
بالرمز أدناه.
@={}
هو توجيه للحصول على البيانات المشار إليها داخل الأقواس المعقوفة.
يشير myName
إلى المتغيّر myName
الذي سبق أن حدّدته، والذي يشير إلى فئة البيانات myName
ويسترد السمة name
من الفئة.
android:text="@={myName.name}"
الخطوة 3: إنشاء البيانات
أصبح لديك الآن مرجع للبيانات في ملف التنسيق. بعد ذلك، يمكنك إنشاء البيانات الفعلية.
- افتح ملف
MainActivity.kt
. - أعلى
onCreate()
، أنشئ متغيّرًا خاصًا، يُعرف أيضًا باسمmyName
حسب الاصطلاح. عيِّن للمتغيّر مثيلاً لفئة البياناتMyName
، مع إدخال الاسم.
private val myName: MyName = MyName("Aleks Haecky")
- في
onCreate()
، اضبط قيمة المتغيّرmyName
في ملف التصميم على قيمة المتغيّرmyName
الذي أعلنت عنه للتو. لا يمكنك الوصول إلى المتغيّر في ملف XML مباشرةً. يجب الوصول إليه من خلال عنصر الربط.
binding.myName = myName
- قد يظهر هذا الإجراء خطأً، لأنّ عليك إعادة تحميل عنصر الربط بعد إجراء تغييرات. أنشئ تطبيقك، وسيتم حلّ الخطأ.
الخطوة 4: استخدام فئة البيانات للاسم المستعار في TextView
الخطوة الأخيرة هي استخدام فئة البيانات أيضًا للاسم المستعار في TextView
.
- فتح "
activity_main.xml
" - في عرض النص
nickname_text
، أضِف السمةtext
. أشِر إلىnickname
في فئة البيانات، كما هو موضّح أدناه.
android:text="@={myName.nickname}"
- في
ActivityMain
، استبدِلnicknameText.text = nicknameEdit.text.toString()
بالرمز لضبط الاسم في المتغيّرmyName
.
myName?.nickname = nicknameEdit.text.toString()
بعد ضبط الاسم المستعار، عليك أن تطلب من الرمز تحديث واجهة المستخدم بالبيانات الجديدة. لإجراء ذلك، يجب إبطال جميع تعبيرات الربط حتى تتم إعادة إنشائها باستخدام البيانات الصحيحة.
- أضِف
invalidateAll()
بعد ضبط الاسم المستعار ليتم إعادة تحميل واجهة المستخدم بالقيمة في عنصر الربط المعدَّل.
binding.apply {
myName?.nickname = nicknameEdit.text.toString()
invalidateAll()
...
}
- أنشئ تطبيقك وشغِّله، وسيعمل بالطريقة نفسها تمامًا كما كان من قبل.
مشروع "استوديو Android": AboutMeDataBinding
خطوات استخدام ربط البيانات لاستبدال طلبات findViewById()
:
- فعِّل ربط البيانات في قسم Android من ملف
build.gradle
:dataBinding { enabled = true }
- استخدِم
<layout>
كطريقة العرض الجذرية في تنسيق XML. - تحديد متغيّر ربط:
private lateinit var binding: ActivityMainBinding
- أنشئ عنصر ربط في
MainActivity
، واستبدِلsetContentView
:binding = DataBindingUtil.setContentView(this, R.layout.activity_main)
- استبدِل طلبات
findViewById()
بالإشارات إلى طريقة العرض في عنصر الربط. على سبيل المثال:findViewById<Button>(R.id.done_button) ⇒ binding.doneBu
tton
(في المثال، يتم إنشاء اسم طريقة العرض باستخدام تنسيق camel case منid
الخاص بطريقة العرض في XML).
خطوات ربط طرق العرض بالبيانات:
- أنشئ فئة بيانات لبياناتك.
- أضِف مربّع
<data>
داخل العلامة<layout>
. - حدِّد
<variable>
باسم ونوع يمثّل فئة البيانات.
<data>
<variable
name="myName"
type="com.example.android.aboutme.MyName" />
</data>
- في
MainActivity
، أنشئ متغيّرًا يتضمّن مثيلاً لفئة البيانات. على سبيل المثال:private val myName: MyName = MyName("Aleks Haecky")
- في عنصر الربط، اضبط المتغيّر على المتغيّر الذي أنشأته للتو:
binding.myName = myName
- في ملف 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}"
ابدأ الدرس التالي:
للحصول على روابط تؤدي إلى دروس تطبيقية أخرى في هذه الدورة التدريبية، اطّلِع على الصفحة المقصودة الخاصة بالدروس التطبيقية حول أساسيات Android Kotlin.