Android Corner
Android Corner
خواندن ۳ دقیقه·۸ ماه پیش

Discovering Kotlin: Concepts

تو این پست کُدامون رو با اینا تمیز‌تر میکنیم:

* This keyword

* Destructuring declaration

* Function iteral

* The benefits of getter


استفاده از this برای اشاره کردن به کلاس استفاده شده

به این کد نگاه کنید:

private fun isCurrentlyConnected(connectivityManager: ConnectivityManager?): Boolean { if (connectivityManager == null) { return false } else { val network = connectivityManager.activeNetwork if (network != null) { val capabilities = connectivityManager.getNetworkCapabilities(network) return capabilities?.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) ?: false } else { return false } } }

اگه یکم دقت کنین این ساختار یه extension function تو کاتلینه چون یه کلاس رو بعنوان پارامتر دریافت کرده (اینجوری تو جاوا می‌نویسیم) تو کاتلین اینجوری میشه با extension function.

private fun ConnectivityManager?.isCurrentlyConnected(): Boolean { if (this == null) { return false } else { val network = this.activeNetwork if (network != null) { val capabilities = getNetworkCapabilities(network) return capabilities?.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) ?: false } else { return false } } }

خب یکم ساده‌تر شد. باز میتونه ساده‌تر بشه، اگه بیایم این if-else های تودرتو رو با when condition عوض کنیم (چون همه‌ی شرط ها یک کاندیشن رو درنظر دارن درنتیجه میشه از when استفاده کرد). اینجوری:

private fun ConnectivityManager?.isCurrentlyConnected(connectivityManager: ConnectivityManager?) = when (connectivityManager) { null -> false else -> connectivityManager.activeNetwork ?.let(::getNetworkCapabilities) ?.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) ?: false }

الان بهتر شد. خب باز میتونیم بهترش کنیم، چون داریم یه extension function برای کلاس ConnectivityManager می‌نویسیم پس تو این block، ما به instance کلاسی که براش extension مینویسم، دسترسی داریم و میتونیم با استاده از کیبورد "this" به این instance دسترسی داشته باشیم.

private fun ConnectivityManager?.isCurrentlyConnected() = when (this) { null -> false else -> activeNetwork ?.let(::getNetworkCapabilities) ?.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) ?: false }

دلیل‌اش هم اینه که اگه شما بیاین این کد رو دیکامپایل کنین و بایت‌کدهاش رو نگاه کنید، میبینید که extension function تو کاتلین میاد (مثلا اینجا) ConnectivityManager رو به عنوان پارامتر میگیره و برای همین بهش دسترسی داریم.

برای مثال بیشتر:

fun <T> CheckboxState.TriState<T>.asToggleableState() = when (this) { is CheckboxState.TriState.Exclude -> ToggleableState.Indeterminate is CheckboxState.TriState.Include -> ToggleableState.On is CheckboxState.TriState.None -> ToggleableState.Off }

د: destructuring declaration

فرض کنید ما این سه تا متغیر رو داریم:

val chapters = remember(state) { state.processedChapters } val listItem = remember(state) { state.chapterListItems } val isAnySelected = remember(state) { state.isAnySelected }

اینجا کدمون ساده هستش ولی چون داریم همش با یه state کار میکنیم، اگه این کار رو بکنیم بنظرم ساده‌تر بشه:

val (chapters, listItem, isAnySelected) = remember(state) { Triple( first = state.processedChapters, second = state.chapterListItems, third = state.isAnySelected, ) }

نکته: Triple یه کلاسه تو لایبرری استاندارد کاتلین که میتونه سه object رو براتون hold کنه.

چ: Function Literal

به این کد نگاه کنید:

val isAdult : Boolean = user.age> 18 val isValidUser : Boolean = isAdult && user.isActive

یک کاری رو داره با فراخوانی یک object تکراری انجام میده. که میتونید با استفاده از lambda assignment این‌کار رو ساده تر کنید. اینجوری:

val isValidUser: (User) -> Boolean = { user -> user.age > 18 && user.isActive }

با این کار، خیلی چیزا رو میتونید encapsulate هم بکنید.

استفاده از فانکشن get(همون getter)

این قسمت ربطی به تمیزکاری نداره، ولی قطعا performance رو تحت تاثیر قرار میده. چرا و کِی باید از get استفاده کنیم؟ بیاید با یه مثال اینو بگم:

// first way val trackers = trackerManager.trackers.filter { it.isLoggedIn } // the second way val trackers get() = trackerManager.trackers.filter { it.isLoggedIn }

توی روش اول ما مستقیما trackers رو Initializ کردیم، ولی تو روش دوم از مقدار رو ریختیم توی getter متغیر.

روش دوم چند مزیت داره:

ی- Lazy Initialization: شما وقتی از فانکشن get استفاده میکنید، وقتی مقداردهی میشه متغیر، که این متغیر صدا زده بشه- درنتیجه getter اش هم صدا زده میشه: پس همین اول کاری مقدار دهی نمیشه. این میتونه خیلی خوب باشه وقتی مثلا دارید یه کار نسبتا سنگینی می‌کنید.

د- Dynamic Calculation: اگه مقدارهایی دارید که هِی درحال تغییر ان، میتونید این تغییرهارو تو بدنه get اعمال کنید.

3- میتویند مقدار هارو تغییر بدید یا فیلترشون کنین(Filtering or Transformation) یا Encapsulate شون کنین و ... .

kotlin
اینجا جاییکه در مورد مسائل و اخبار اندرویدی حرف میزنیم. cornerdroid@gmail.com / کانال: https://t.me/AndroidCorner
شاید از این پست‌ها خوشتان بیاید