‫Android KTX   جزء من Android Jetpack.

‫Android KTX هي مجموعة من إضافات Kotlin التي يتم تضمينها مع Android Jetpack ومكتبات Android الأخرى. توفّر إضافات KTX لغة Kotlin مختصرة وواضحة لاستخدامها مع Jetpack ونظام Android الأساسي وواجهات برمجة التطبيقات الأخرى. ولإجراء ذلك، تستفيد هذه الإضافات من العديد من ميزات لغة Kotlin، بما في ذلك ما يلي:

  • دوال الإضافات
  • سمات الإضافة
  • الدوالّ اللامدا
  • المَعلمات المُعنوَنة
  • القيم التلقائية للمَعلمات
  • الكوروتينات

على سبيل المثال، عند العمل مع SharedPreferences، عليك إنشاء محرِّر قبل أن تتمكّن من إجراء تعديلات على بيانات الإعدادات المفضّلة. يجب أيضًا تطبيق هذه التغييرات أو إجراؤها عند الانتهاء من التعديل، كما هو موضّح في المثال التالي:

sharedPreferences
        .edit()  // create an Editor
        .putBoolean("key", value)
        .apply() // write to disk asynchronously

إنّ الدوالّ اللامدا في Kotlin هي الخيار الأمثل لحالة الاستخدام هذه. تتيح لك هذه الأدوات اتّباع أسلوبٍ أكثر إيجازًا من خلال تمرير مجموعة من الرموز البرمجية لتنفيذها بعد إنشاء المحرِّر، والسماح بتنفيذ الرمز البرمجي، ثم السماح لواجهة SharedPreferences API بتطبيق التغييرات بشكلٍ موحّد.

في ما يلي مثال على إحدى وظائف Android KTX Core، وهي دالة SharedPreferences.edit، التي تضيف دالة تعديل إلى SharedPreferences. تستخدِم هذه الدالة علامة boolean اختيارية كوسيطة أولى تشير إلى ما إذا كان سيتم تأكيد التغييرات أو تطبيقها. ويتلقّى أيضًا إجراءً لتنفيذه على محرِّر SharedPreferences في شكل دالة lambda.

// SharedPreferences.edit extension function signature from Android KTX - Core
// inline fun SharedPreferences.edit(
//         commit: Boolean = false,
//         action: SharedPreferences.Editor.() -> Unit)

// Commit a new value asynchronously
sharedPreferences.edit { putBoolean("key", value) }

// Commit a new value synchronously
sharedPreferences.edit(commit = true) { putBoolean("key", value) }

يمكن للمتصل اختيار ما إذا كان يريد تأكيد التغييرات أو تطبيقها. دالة action lambda هي نفسها دالة إضافة مجهولة في SharedPreferences.Editor تعرض Unit، كما هو موضّح في توقيعها. لهذا السبب، يمكنك داخل كتلة تنفيذ العمل مباشرةً على SharedPreferences.Editor.

أخيرًا، يحتوي توقيع SharedPreferences.edit() على الكلمة الرئيسية inline. تُعلِم هذه الكلمة الرئيسية مُجمِّع Kotlin بضرورة نسخ الرمز الثنائي المجمَّع للدالة ولصقه (أو دمجه) في كل مرة يتم فيها استخدام الدالة. ويؤدي ذلك إلى تجنُّب تكاليف إنشاء فئة جديدة لكل action عند كل مرة يتم فيها استدعاء هذه الدالة.

إنّ نمط تمرير الرمز البرمجي باستخدام الدوالّ اللامدا وتطبيق الإعدادات التلقائية المعقولة التي يمكن تجاوزها وإضافة هذه السلوكيات إلى واجهات برمجة التطبيقات الحالية باستخدام inline وظائف الإضافات هو نموذجي للتحسينات التي تقدّمها مكتبة Android KTX.

استخدام Android KTX في مشروعك

لبدء استخدام Android KTX، أضِف التبعية التالية إلى ملف build.gradle في مشروعك:

رائع

repositories {
    google()
}

Kotlin

repositories {
    google()
}

وحدات AndroidX

يتم تنظيم Android KTX في وحدات تحتوي كلّ منها على حِزمة واحدة أو أكثر.

يجب تضمين عنصر ربط لكل عنصر في الوحدة في ملف build.gradle الخاص بالتطبيق. تذكَّر إلحاق رقم الإصدار بالعنصر. يمكنك العثور على أرقام أحدث إصدار في القسم المقابل لكل عنصر أثري في هذا الموضوع.

يحتوي Android KTX على وحدة أساسية واحدة توفّر امتدادات Kotlin لواجهات برمجة التطبيقات الشائعة للإطارات الأساسية والعديد من الإضافات الخاصة بالنطاق.

باستثناء الوحدة الأساسية، تستبدل جميع عناصر وحدة KTX التبعية الأساسية لـ Java في ملف build.gradle. على سبيل المثال، يمكنك استبدال تبعية androidx.fragment:fragment بأحد تبعيات androidx.fragment:fragment-ktx. تساعد هذه البنية في إدارة الإصدارات بشكل أفضل ولا تضيف متطلبات إضافية لبيان التبعية.

Core KTX

توفّر وحدة Core KTX إضافات للمكتبات الشائعة التي تشكّل جزءًا من إطار عمل Android. لا تحتوي هذه المكتبات على تبعيات مستندة إلى Java عليك إضافتها إلى build.gradle.

لتضمين هذه الوحدة، أضِف ما يلي إلى ملف build.gradle في تطبيقك:

Groovy

dependencies {
    implementation "androidx.core:core-ktx:1.13.1"
}

Kotlin

dependencies {
    implementation("androidx.core:core-ktx:1.13.1")
}

في ما يلي قائمة بالحِزم المضمّنة في وحدة KTX الأساسية:

مجموعة KTX

تحتوي إضافات "المجموعات" على وظائف مساعدة للعمل مع مكتبات المجموعات التي تُوفّر استهلاكًا منخفضًا للذاكرة في Android، بما في ذلك ArrayMap وLongSparseArray LruCache وغيرها.

لاستخدام هذه الوحدة، أضِف ما يلي إلى ملف build.gradle في تطبيقك:

رائع

dependencies {
    implementation "androidx.collection:collection-ktx:1.4.5"
}

Kotlin

dependencies {
    implementation("androidx.collection:collection-ktx:1.4.5")
}

تستفيد إضافات المجموعات من تحميل عامل التشغيل الزائد في Kotlin لمحاولة تبسيط إجراءات مثل تسلسل المجموعات، كما هو موضّح في المثال التالي:

// Combine 2 ArraySets into 1.
val combinedArraySet = arraySetOf(1, 2, 3) + arraySetOf(4, 5, 6)

// Combine with numbers to create a new sets.
val newArraySet = combinedArraySet + 7 + 8

Fragment KTX

توفّر وحدة Fragment KTX عددًا من الإضافات لتبسيط واجهة برمجة التطبيقات Fragment API.

لتضمين هذه الوحدة، أضِف ما يلي إلى ملف build.gradle في تطبيقك:

Groovy

dependencies {
    implementation "androidx.fragment:fragment-ktx:1.8.3"
}

Kotlin

dependencies {
    implementation("androidx.fragment:fragment-ktx:1.8.3")
}

باستخدام وحدة Fragment KTX، يمكنك تبسيط معاملات الأجزاء باستخدام لامدا، على سبيل المثال:

fragmentManager().commit {
   addToBackStack("...")
   setCustomAnimations(
           R.anim.enter_anim,
           R.anim.exit_anim)
   add(fragment, "...")
}

يمكنك أيضًا الربط بعنصر ViewModel في سطر واحد باستخدام عنصرَي الربط لسمة viewModels و activityViewModels:

// Get a reference to the ViewModel scoped to this Fragment
val viewModel by viewModels<MyViewModel>()

// Get a reference to the ViewModel scoped to its Activity
val viewModel by activityViewModels<MyViewModel>()

Lifecycle KTX

تحدِّد حزمة KTX لدورة الحياة LifecycleScope لكل عنصر Lifecycle. يتم إلغاء أي دالة معالجة متزامنة تم تشغيلها في هذا النطاق عند إتلاف Lifecycle. يمكنك الوصول إلى CoroutineScope من Lifecycle باستخدام السمتَين lifecycle.coroutineScope أو lifecycleOwner.lifecycleScope.

لتضمين هذه الوحدة، أضِف ما يلي إلى ملف build.gradle في تطبيقك:

رائع

dependencies {
    implementation "androidx.lifecycle:lifecycle-runtime-ktx:2.8.7"
}

Kotlin

dependencies {
    implementation("androidx.lifecycle:lifecycle-runtime-ktx:2.8.7")
}

يوضّح المثال التالي كيفية استخدام lifecycleOwner.lifecycleScope ل إنشاء نص محسوب مسبقًا بشكل غير متزامن:

class MyFragment: Fragment() {
    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        viewLifecycleOwner.lifecycleScope.launch {
            val params = TextViewCompat.getTextMetricsParams(textView)
            val precomputedText = withContext(Dispatchers.Default) {
                PrecomputedTextCompat.create(longTextContent, params)
            }
            TextViewCompat.setPrecomputedText(textView, precomputedText)
        }
    }
}

LiveData KTX

عند استخدام LiveData، قد تحتاج إلى احتساب القيم بشكل غير متزامن. على سبيل المثال، قد تحتاج إلى استرداد الإعدادات المفضّلة للمستخدم وعرضها في واجهة مستخدمك. في هذه الحالات، يوفّر LiveData KTX دالة liveData لإنشاء liveData تُشغِّل دالة suspend وتعرض النتيجة كعنصر LiveData.

لتضمين هذه الوحدة، أضِف ما يلي إلى ملف build.gradle في تطبيقك:

رائع

dependencies {
    implementation "androidx.lifecycle:lifecycle-livedata-ktx:2.8.7"
}

Kotlin

dependencies {
    implementation("androidx.lifecycle:lifecycle-livedata-ktx:2.8.7")
}

في المثال التالي، loadUser() هي دالة تعليق تمّ الإعلان عنها في مكان آخر. يمكنك استخدام دالة الإنشاء liveData لاستدعاء loadUser() بشكل غير متزامن، ثم استخدام emit() لعرض النتيجة:

val user: LiveData<User> = liveData {
    val data = database.loadUser() // loadUser is a suspend function.
    emit(data)
}

لمزيد من المعلومات حول استخدام الكوروتينات مع LiveData، يمكنك الاطّلاع على مقالة استخدام الكوروتينات في لغة Kotlin مع مكوّنات بنية التطبيق.

يحتوي كل مكوّن من مكوّنات مكتبة Navigation على إصدار KTX خاص به يُعدّل واجهة برمجة التطبيقات لتكون أكثر إيجازًا وأكثر توافقًا مع لغة Kotlin.

لتضمين هذه الوحدات، أضِف ما يلي إلى ملف build.gradle في تطبيقك:

رائع

dependencies {
    implementation "androidx.navigation:navigation-runtime-ktx:2.8.4"
    implementation "androidx.navigation:navigation-fragment-ktx:2.8.4"
    implementation "androidx.navigation:navigation-ui-ktx:2.8.4"
}

Kotlin

dependencies {
    implementation("androidx.navigation:navigation-runtime-ktx:2.8.4")
    implementation("androidx.navigation:navigation-fragment-ktx:2.8.4")
    implementation("androidx.navigation:navigation-ui-ktx:2.8.4")
}

استخدِم دوالّ الإضافات وتفويض الموقع للوصول إلى وسيطات الوجهة والتنقّل إلى الوجهات، كما هو موضّح في المثال التالي:

class MyDestination : Fragment() {

    // Type-safe arguments are accessed from the bundle.
    val args by navArgs<MyDestinationArgs>()

    ...
    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        view.findViewById<Button>(R.id.next)
            .setOnClickListener {
                // Fragment extension added to retrieve a NavController from
                // any destination.
                findNavController().navigate(R.id.action_to_next_destination)
            }
     }
     ...

}

Palette KTX

تقدّم وحدة Palette KTX دعمًا لأسلوب Kotlin في العمل مع لوحات الألوان.

لاستخدام هذه الوحدة، أضِف ما يلي إلى ملف build.gradle في تطبيقك:

Groovy

dependencies {
    implementation "androidx.palette:palette-ktx:1.0.0"
}

Kotlin

dependencies {
    implementation("androidx.palette:palette-ktx:1.0.0")
}

على سبيل المثال، عند العمل مع مثيل Palette، يمكنك استرداد ملف التمويه selected لقيمة target معيّنة باستخدام عامل التشغيل get ([ ]):

val palette = Palette.from(bitmap).generate()
val swatch = palette[target]

Reactive Streams KTX

تتيح لك وحدة Reactive Streams KTX إنشاء بث LiveData قابل للرصد من ناشر ReactiveStreams.

لتضمين هذه الوحدة، أضِف ما يلي إلى ملف build.gradle في تطبيقك:

رائع

dependencies {
    implementation "androidx.lifecycle:lifecycle-reactivestreams-ktx:2.8.7"
}

Kotlin

dependencies {
    implementation("androidx.lifecycle:lifecycle-reactivestreams-ktx:2.8.7")
}

على سبيل المثال، نفترض أنّ قاعدة بيانات تتضمّن قائمة صغيرة من المستخدمين. في تطبيقك، يتم تحميل قاعدة البيانات في الذاكرة ثم عرض بيانات المستخدمين في واجهة المستخدم. لتحقيق هذا، يمكنك استخدام RxJava. يمكن لمكوّن Room في Jetpack استرجاع قائمة المستخدمين كFlowable. في هذا السيناريو، عليك أيضًا إدارة اشتراك الناشر في Rx طوال مدة عرض المقتطف أو النشاط.

ومع ذلك، باستخدام LiveDataReactiveStreams، يمكنك الاستفادة من RxJava و مجموعة متنوعة من عوامل التشغيل وإمكانات جدولة العمل مع الاستفادة أيضًا من بساطة LiveData، كما هو موضّح في المثال التالي:

val fun getUsersLiveData() : LiveData<List<User>> {
    val users: Flowable<List<User>> = dao.findUsers()
    return LiveDataReactiveStreams.fromPublisher(users)
}

غرفة KTX

توفّر إضافات الغرف إمكانية استخدام وحدات معالجة المهام المتزامنة لمعاملات قاعدة البيانات.

لاستخدام هذه الوحدة، أضِف ما يلي إلى ملف build.gradle في تطبيقك:

Groovy

dependencies {
    implementation "androidx.room:room-ktx:2.6.1"
}

Kotlin

dependencies {
    implementation("androidx.room:room-ktx:2.6.1")
}

في ما يلي بعض الأمثلة التي تستخدم فيها Room الآن وحدات معالجة المهام المتزامنة. يستخدم المثال الأول الدالة suspend لإرجاع قائمة بعناصر User، في حين يستخدم المثال الثاني Flow في Kotlin لإرجاع قائمة User بشكل غير متزامن. يُرجى العلم أنّه عند استخدام Flow، يتم إعلامك أيضًا بأي تغييرات في الجداول التي تُجري عليها طلبات بحث.

@Query("SELECT * FROM Users")
suspend fun getUsers(): List<User>

@Query("SELECT * FROM Users")
fun getUsers(): Flow<List<User>>

SQLite KTX

تلتفّ إضافات SQLite حول الرمز البرمجي ذي الصلة بـ SQL في المعاملات، ما يؤدي إلى إزالة الكثير من الرمز البرمجي المتكرّر.

لاستخدام هذه الوحدة، أضِف ما يلي إلى ملف build.gradle في تطبيقك:

Groovy

dependencies {
    implementation "androidx.sqlite:sqlite-ktx:2.4.0"
}

Kotlin

dependencies {
    implementation("androidx.sqlite:sqlite-ktx:2.4.0")
}

في ما يلي مثال على استخدام إضافة transaction لإجراء معاملة في قاعدة بيانات:

db.transaction {
    // insert data
}

ViewModel KTX

توفّر مكتبة ViewModel KTX دالة viewModelScope() تسهِّل بدء عمليات التشغيل المتعدّد للوظائف من ViewModel. يتم ربط CoroutineScope بـ Dispatchers.Main ويتم إلغاؤه تلقائيًا عند محو ViewModel. يمكنك استخدام viewModelScope() بدلاً من إنشاء نطاق جديد لكل ViewModel.

لتضمين هذه الوحدة، أضِف ما يلي إلى ملف build.gradle في تطبيقك:

Groovy

dependencies {
    implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:2.8.5"
}

Kotlin

dependencies {
    implementation("androidx.lifecycle:lifecycle-viewmodel-ktx:2.8.5")
}

على سبيل المثال، تبدأ الدالة viewModelScope() التالية سلسلة مهام متزامنة تُجري طلب شبكة في سلسلة مهام في الخلفية. تعالج المكتبة جميع عمليات الإعداد وعمليات إزالة النطاق المعنيّة:

class MainViewModel : ViewModel() {
    // Make a network request without blocking the UI thread
    private fun makeNetworkRequest() {
        // launch a coroutine in viewModelScope
        viewModelScope.launch  {
            remoteApi.slowFetch()
            ...
        }
    }

    // No need to override onCleared()
}

حزمة WorkManager KTX

يقدّم WorkManager KTX دعمًا من الدرجة الأولى لعمليات التشغيل المتعدّد.

لتضمين هذه الوحدة، أضِف ما يلي إلى ملف build.gradle في تطبيقك:

Groovy

dependencies {
    implementation "androidx.work:work-runtime-ktx:2.9.1"
}

Kotlin

dependencies {
    implementation("androidx.work:work-runtime-ktx:2.9.1")
}

بدلاً من توسيع نطاق Worker، يمكنك الآن توسيع نطاق CoroutineWorker، التي تتضمّن واجهة برمجة تطبيقات مختلفة قليلاً. على سبيل المثال، إذا أردت إنشاء CoroutineWorker بسيط لتنفيذ بعض عمليات الشبكة، يمكنك إجراء ما يلي:

class CoroutineDownloadWorker(context: Context, params: WorkerParameters)
        : CoroutineWorker(context, params) {

    override suspend fun doWork(): Result = coroutineScope {
        val jobs = (0 until 100).map {
            async {
                downloadSynchronously("https://www.google.com")
            }
        }

        // awaitAll will throw an exception if a download fails, which
        // CoroutineWorker will treat as a failure
        jobs.awaitAll()
        Result.success()
    }
}

لمزيد من المعلومات حول استخدام CoroutineWorker، اطّلِع على المعالجة المتعدّدة في CoroutineWorker.

تضيف حزمة WorkManager KTX أيضًا وظائف إضافة إلى Operations و ListenableFutures لتعليق دالة coroutine الحالية.

في ما يلي مثال على تعليق القيمة Operation التي تعرضها القيمة enqueue():

// Inside of a coroutine...

// Run async operation and suspend until completed.
WorkManager.getInstance()
        .beginWith(longWorkRequest)
        .enqueue().await()

// Resume after work completes...

وحدات KTX الأخرى

يمكنك أيضًا تضمين وحدات KTX إضافية متوفّرة خارج AndroidX.

Firebase KTX

تحتوي بعض حِزم تطوير البرامج (SDK) لمنصّة Firebase لنظام التشغيل Android على مكتبات إضافية لتنسيق Kotlin تتيح لك كتابة رمز Kotlin مألوف عند استخدام Firebase في تطبيقك. لمزيد من المعلومات، اطّلِع على المواضيع التالية:

Google Maps Platform KTX

تتوفّر إضافات KTX لحِزم تطوير البرامج (SDK) لنظام التشغيل Android من Google Maps Platform، والتي تسمح لك بالاستفادة من العديد من ميزات لغة Kotlin، مثل الدوالّ الموسّعة والمَعلمات المُسمّاة والمَعلمات التلقائية وإعلانات إزالة البنية والعمليات المتكرّرة. لمزيد من المعلومات، اطّلِع على المواضيع التالية:

حزمة KTX لـ Play Core

تضيف حزمة KTX في Play Core إمكانية استخدام وظائف Kotlin المتكررة للطلبات التي يتم تنفيذها لمرة واحدة ووظائف Flow لرصد آخر المعلومات المتعلّقة بالحالة من خلال إضافة وظائف إضافية إلى SplitInstallManager وAppUpdateManager في مكتبة Play Core.

لتضمين هذه الوحدة، أضِف ما يلي إلى ملف build.gradle في تطبيقك:

رائع

dependencies {
    implementation "com.google.android.play:core-ktx:1.8.1"
}

Kotlin

dependencies {
    implementation("com.google.android.play:core-ktx:1.8.1")
}

في ما يلي مثال على Flow لمراقبة الحالة:

// Inside of a coroutine...

// Request in-app update status updates.
manager.requestUpdateFlow().collect { updateResult ->
    when (updateResult) {
        is AppUpdateResult.Available -> TODO()
        is AppUpdateResult.InProgress -> TODO()
        is AppUpdateResult.Downloaded -> TODO()
        AppUpdateResult.NotAvailable -> TODO()
    }
}

مزيد من المعلومات

لمزيد من المعلومات حول Android KTX، يمكنك مشاهدة فيديو DevBytes.

للإبلاغ عن مشكلة أو اقتراح ميزة، استخدِم أداة تتبُّع المشاكل في Android KTX.