يصف هذا الدرس كيفية استخدام إضافات أندرويد فيKotlin لتحسين دعم تطوير أندرويد. في هذا الدرس سوف نستعرض الخطوات اللازمة لاستخدام ملحقات أندرويد الإضافية في لغة البرمجة Kotlin، لتعزيز تجربة التطوير في أندرويد.
ربط العرض View Binding
الخلفية
كل مطوري أندرويد يعرفون جيدًا الدالة ()findViewById
. والتي هي من دون أدنى شك، مصدر لكثير من المتاعب والأخطاء المحتملة والشيفرات السيئة والتي يصعب قراءتها وصيانتها. صحيح أن هناك العديد من المكتبات المتاحة لتوفير حلول لهذه المشكلة، إلّا أن هذه المكتبات تتطلب حقول تأشير annotating fields لكل عنصر معروض من نوع View.
توفر لنا ملحقات أندرويد الإضافية لـ Kotlin تجربة مماثلة لما توفره بعض تلك المكتبات، دون أن نكون في حاجة إلى كتابة شيفرات إضافية.
في الأساس، هذا يسمح لنا بكتابة الشيفرة التالية:
// Using R.layout.activity_main from the 'main' source set import kotlinx.android.synthetic.main.activity_main.* class MyActivity : Activity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) // Instead of findViewById<TextView>(R.id.textView) textView.setText("Hello, world!") } }
textView
هي خاصية إضافية لـ Activity، ولها نفس النوع المعلن في activity_main.xml
(أي TextView
).
استخدام إضافات أندرويد لـKotlin
إعداد الارتباطات Configuring the Dependency
سنستخدم في هذا الدرس Gradle، لكن يمكنك تحقيق نفس النتائج باستخدام IntelliJ IDEA project structure أو Maven.
إضافات أندرويد هي جزء من ملحقة Kotlin الخاصة بكل من IntelliJ IDEA وAndroid Studio. لذلك لا تحتاج إلى تثبيت ملحقات إضافية.
كل ما تحتاجه هو إتاحة ملحقة Gradle لأندرويد في ملف الوحدة build.gradle
:
apply plugin: 'kotlin-android-extensions'
استيراد الخصائص التركيبية synthetic properties
من الملائم استيراد جميع خصائص الودجةwidget) ) لخطاطة (layout) معينة دفعة واحدة:
import kotlinx.android.synthetic.main.<layout>.*
وهكذا إذا كان اسم ملف الخطاطة هو activity_main.xml
، فسنقوم باستيراد
kotlinx.android.synthetic.main.activity_main.*
إن كنّا نريد أن نستدعي الخصائص التركيبية على View، فيجب علينا أيضًا استيراد
kotlinx.android.synthetic.main.activity_main.view.*
وبمجرد أن نفعل ذلك، يمكننا حينها استدعاء الإضافات المقابلة والتي هي اسماء خصائص سُمّيت على إثر عناصر العرضviews الموجودة في ملف XML. فعلى سبيل المثال، بالنسبة لهذا العرض:
<TextView android:id="@+id/hello" android:layout_width="fill_parent" android:layout_height="wrap_content"/>
ستكون هناك خاصية اسمها hello
:
activity.hello.text = "Hello World!"
الوضع التجريبي Experimental Mode
تشمل الملحقات الإضافية لأندرويد العديد من الميزات التجريبية مثل دعم LayoutContainer ومولّدات تقديم الصنف Parcelable (Parcelable implementation generator). هذه الميزات لا تُعتبر جاهزة بعدُ للإنتاج، لذلك نحتاج إلى التحوّل للوضع التجريبي في build.gradle
من أجل استخدامها:
androidExtensions { experimental = true }
دعم LayoutContainer
تدعم الملحقات الإضافية لأندرويد أنواع مختلفة من الحاويات containers. وأبسط تلك الحاويات Activity، Fragment وView. ولكن يمكنك أن تحوّل (افتراضيًا) أي صنف إلى حاوية لإضافات أندرويد من خلال تطبيق الواجهةLayoutContainer ، على سبيل المثال:
import kotlinx.android.extensions.LayoutContainer class ViewHolder(override val containerView: View) : ViewHolder(containerView), LayoutContainer { fun setup(title: String) { itemTitle.text = "Hello World!" } }
لاحظ أنك تحتاج إلى التحوّل إلى الوضع التجريبي لاستخدام LayoutContainer.
دعم النكهات Flavor Support
تدعم ملحقات أندرويد الإضافية نكهات أندرويد ((Android flavors. لنفترض أن لديك نكهة اسمها free
في ملف build.gradle
خاصّتك:
android { productFlavors { free { versionName "1.0-free" } } }
يمكنك استيراد كافة الخصائص التركيبية للخطاطة free/res/layout/activity_free.xml
بإضافة هذا الاستيراد:
import kotlinx.android.synthetic.free.activity_free.*
في الوضع التجريبي، يمكنك تحديد أي اسم آخر (وليس فقط flavor)، على سبيل المثال freeDebug
أو freeRelease
يصلحان كذلك.
التخزين المؤقت لعناصرView
استدعاء ()findViewById
يمكن أن يكون بطيئًا، خصوصًا في حالة تشعبات العرض (view hierarchies) الكبيرة، لذلك تحاول إضافات أندرويد التقليل من عدد مرّات استدعاء ()findViewById
بواسطة التخزين المؤقت للعروض في الحاويات.
افتراضيًا، اضافات أندرويد تضيف دالة تخزين مؤقت مخفية وحقل تخزين إلى كل حاوية (Activity، Fragment، View أو LayoutContainer implementation) مكتوبة بـ Kotlin. التابع method)) صغير جدًا لذلك لا يزيد حجم APK كثيرًا.
في المثال التالي، يتم استدعاء ()findViewById
مرة واحدة فقط:
class MyActivity : Activity() fun MyActivity.a() { textView.text = "Hidden view" textView.visibility = View.INVISIBLE }
لكن في الحالة التالية:
fun Activity.b() { textView.text = "Hidden view" textView.visibility = View.INVISIBLE }
لا يمكننا أن نعرف ما إذا كان سيتم استدعاء هذه الدالة في أنشطة مصادرنا فقط أم أيضا في كل أنشطة جافا. لهذا السبب، لن نستخدم التخزين المؤقت هنا، حتى لو تم تمرير أحد عيّنات instance الصنف MyActivity
من المثال السابق كمستقبِل.
تغيير استراتيجية التخزين المؤقت للصنف View
يمكنك تغيير استراتيجية التخزين المؤقت بشكل شامل أو بالنسبة لكل حاوية على حدة. وهذا أيضًا يتطلب التحول إلى الوضع التجريبي.
يتم تحديد استراتيجية التخزين المؤقت الشاملة للمشروع في ملف build.gradle
:
androidExtensions { defaultCacheImplementation = "HASH_MAP" // also SPARSE_ARRAY, NONE }
افتراضيًا، الملحقات الإضافية لأندرويد تستخدم HashMap
كمرجع احتياطي للتخزين، ولكن يمكنك التبديل لتطبيق SparseArray
، أو إيقاف التخزين المؤقت وحسب. هذا الأخير مفيد بشكل خاص إن أردت الاكتفاء باستخدام الجزء المقسّم Parcelable من إضافات Android.
يمكنك أيضًا التأشير على حاوية ما بـ ContainerOptions@
لتغيير استراتيجية التخزين المؤقت:
import kotlinx.android.extensions.ContainerOptions @ContainerOptions(cache = CacheImplementation.NO_CACHE) class MyActivity : Activity() fun MyActivity.a() { // findViewById() will be called twice textView.text = "Hidden view" textView.visibility = View.INVISIBLE }
Parcelable
بدءًا من الإصدار Kotlin 1.1.4، وفّرت الملحقات الإضافية لأندرويد مولّدات تطبيق للصنف Parcelable كميزة تجريبية.
إتاحة دعم Parcelable
قم بتطبيق ملحقة Gradle المسمّاة kotlin-android-extensions
كما هو موضح [أعلاه] (#إعداد الارتباطات) وقم بتشغيل الوضع التجريبي.
كيفية الاستخدام
قم بالتأشير على الصنف بـ Parcelize@
، وسيتم إنشاء تطبيق Parcelable تلقائيًا.
import kotlinx.android.parcel.Parcelize @Parcelize class User(val firstName: String, val lastName: String, val age: Int): Parcelable
يتطلّب Parcelize@
التصريح بجميع الخصائص المتسلسلة في المنشئ constructor الأولي. ستقوم إضافات أندرويد بإطلاق تحذير على كل الخصائص ذات الحقول المصرّح بها في جسم الصّنف، كما أنّه لا يمكن تطبيق Parcelize@
إذا لم تكن كل معاملات المنشئ الأوّلية خصائصًا.
إن كان صنفك يتطلب تسلسلاً منطقيًا أكثر تقدمًا، فيمكنك كتابته داخل صنف مرافق:
@Parcelize data class Value(val firstName: String, val lastName: String, val age: Int) : Parcelable { private companion object : Parceler<User> { override fun User.write(parcel: Parcel, flags: Int) { // Custom write implementation } override fun create(parcel: Parcel): User { // Custom read implementation } } }
الأنواع المدعومة
يدعم Parcelize@
طيفًا واسعًا من الأنواع:
- الأنواع الأولية Primitive types (ونسخها المغلّفة boxed versions).
- Objects وenums .
-
String
،CharSequence
. -
Exception
. -
Size
،SizeF
،Bundle
،IBinder
،IInterface
،FileDescriptor
-
SparseArray
،SparseIntArray
،SparseLongArray
،SparseBooleanArray
. -
كل الأنواع المتسلسلة
Serializable
(حتىDate
مدعوم) وتطبيقاتParcelable
. -
تجميعات كل الأنواع المدعومة:
List
(مُحالة علىArrayList
)، وSet
(مُحالة علىLinkedHashSet
)، وMap
(مُحالة علىLinkedHashMap
). -
بالإضافة إلى عدد من التطبيقات الملموسة:
ArrayList
،LinkedList
،SortedSet
،NavigableSet
،HashSet
،LinkedHashSet
،TreeSet
،SortedMap
،NavigableMap
،HashMap
،LinkedHashMap
،TreeMap
،ConcurrentHashMap
. - الجداول التي تحتوي الأنواع المدعومة.
- النسخ الفارغة Nullable versions من كل الأنواع المدعومة.
تخصيص الـ Parcelers
حتى إن لم يكن النوع مدعوما مباشرة، يمكنك كتابة كائن Parceler
لأجل دعمه.
class ExternalClass(val value: Int) object ExternalClassParceler : Parceler<ExternalClass> { override fun create(parcel: Parcel) = ExternalClass(parcel.readInt()) override fun ExternalClass.write(parcel: Parcel, flags: Int) { parcel.writeInt(value) } }
أمّا عناصر Parcelers الخارجية يمكن تطبيقها باستخدام التأشيرات TypeParceler@
أو WriteWith@
:
// Class-local parceler @Parcelable @TypeParceler<ExternalClass, ExternalClassParceler>() class MyClass(val external: ExternalClass) // Property-local parceler @Parcelable class MyClass(@TypeParceler<ExternalClass, ExternalClassParceler>() val external: ExternalClass) // Type-local parceler @Parcelable class MyClass(val external: @WriteWith<ExternalClassParceler>() ExternalClass)
ترجمة -وبتصرّف- للمقال Kotlin Android Extensions لصاحبه Yan Zhulanow
تم التعديل في بواسطة zahershullar
أفضل التعليقات
لا توجد أية تعليقات بعد
انضم إلى النقاش
يمكنك أن تنشر الآن وتسجل لاحقًا. إذا كان لديك حساب، فسجل الدخول الآن لتنشر باسم حسابك.