پیاده سازی Hilt در یک پروژه اندرویدی

Hilt
Hilt


هیلت چی هست؟

هیلت به کتابخونه تزریق وابستگیه که گوگل جدیدا اراِئه کرده اول اینکه یه روشه استاندارد و آسون برای تامین وابستگی ها و تزریق اونها توی پروژه اندروید هست دوم اینکه برای هر کامپوننت اندرویدی یه کانتینر در نظر میگیره و چرخه عمر اون رو خودش خودکار مدیریت میکنه.

چه مزایایی داره؟

طبق گفته ی خود سایت dagger.dev با استفاده از هیلت boilertplate کاهش پیدا میکنه منظورش اینه که بدون اینکه نگرانی در مورد راه اندازی دگر رو داشته باشید به جاش راحتتر روی تعاریف و کاربردها متمرکز بشید، قابلیت استفاده مجدد از کد ، استفاده و پیاده سازی آسون ، از بین بردن پیچیدگی های تست با دگر ، با استانداردهای تعریف شده دیگه درگیر پیچیدگی های تعریف و ایجاد و استفاده از کامپوننت و ماژول مخصوصا توی کلاسهای پیچیده نمیشید .

وابستگی های پروژه :

برای شروع دیپندنسی های زیر رو به build.gradle سطح پروژه به پروژه اضافه میکنیم:

dependencies {
def lifecycle_version = "2.3.0-alpha05"
def material_version = "1.1.0"
def room_version = "2.2.5"
def hilt_jetpack = "1.0.0-alpha01"

// Room
implementation "androidx.room:room-runtime:$room_version"
kapt "androidx.room:room-compiler:$room_version"
// Activity Ktx for by viewModels()
implementation "androidx.activity:activity-ktx:1.1.0"
//Dagger - Hilt
implementation "com.google.dagger:hilt-android:$hilt_version"
kapt "com.google.dagger:hilt-android-compiler:$hilt_version"
implementation "androidx.hilt:hilt-lifecycle-viewmodel:$hilt_jetpack"
kapt "androidx.hilt:hilt-compiler:$hilt_jetpack"
// coroutines
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.6"
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.6"
// ViewModel
implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.3.0-alpha05'
// LiveData
implementation "androidx.lifecycle:lifecycle-livedata-ktx:$lifecycle_version"
}

خب این دو تا پلاگین رو هم توی گریدل سطح app اضافه کنیم:

apply plugin: 'kotlin-kapt'
apply plugin: 'dagger.hilt.android.plugin'

و این دیپندنسی هم به گریدل سطح ماژول باید اضافه کنیم و بعد گریدل رو سینک کنیم:

classpath &quotcom.google.dagger:hilt-android-gradle-plugin:$hilt_version&quot

میخوایم تو این پروژه فرضی با استفاده از room یه سری دیتا ذخیره کنیم و لیست کنیم که وظیفه ی تامین و تزریق وابستگی ها با hilt باشه.

قدم اول:

یک کلاس انتیتی بسازیم که اسمش user باشه و id , name , familiy داخلش داشته باشه:

User
User

قدم دوم:

اینترفیس DAO مربوط به کلاس بالا رو میسازیم که شامل دو تا متد insert و getAllUsers هست:

UserDao
UserDao

قدم سوم:

کلاس ابسترکتی بسازیم که از RoomDatabase ارث بری میکنه و یه متد بدون بدنه داره که خروجیش از نوع UserDao هست :

AppDb
AppDb

تا الان بخشهای مربوط به room رو انجام دادیم حالا بریم سر پیاده سازی Hilt :

قدم چهارم:

ما نیاز داریم یه کلاسی داشته باشیم که از Application ارث بری میکنه و انوتیشن HiltAndroidApp بالای سرش هست :

HiltApplication
HiltApplication

قدم پنجم:

این کلاس Application رو توی مانیفست هم معرفی میکنیم

android:name=".HiltApplication"

قدم ششم:

ما باید یه آبجکت به نام DbModule بسازیم برای Hilt بسیازیم تا به hilt بگیم که چطور یه اینستنس از کلاس AppDb بسازه تا مجبور نشیم وقتی از AppDb میخوایم استفاده کنیم اون رو new کنیم و وابستگی هاشو تامین کنیم خود Hilt برای ما زحمتشو بکشه برای اینکار باید این کلاس رو با انوتیت Module تزیین کنیم یعنی به Hilt بفهمونیم این کلاس یه ماژول هست دومین کاری که باید بکنیم اینه که انوتیشن installIn رو بالاسر این کلاس قراار بدیم تا به هیلت بفهمونیم که این ماژول رو روی کدوم کامپوننت سوار کنه ورودی هم بهش ApplicationContext رو میدیم حالا توی این کلاس قراره چخبر باشه؟ قراره یه متد ابسترکت بسازیم که خروجیش AppDb هست و داخل این متد با استفاده از بیلدر Room کلاس AppDb رو تولید کنیم و برگردونیم این متد هم قراره بالاسرش انوتیشن provides داشته باشه که به هیلت بفهمونه هرجا نیاز به کلاس AppDb داشتی چطور باید تولیدش کنی نهایتا این کلاسه هم این شکلی میشه:

DbModule
DbModule


قدم هفتم:

حالا باید یه کلاس ریپازیتوری بسازیم که توش یه متد SaveUser داشته باشه که پارامتر ورودی اون از نوع User باشه و داخل ان متد با استفاده از کلاس UserDao متد insert اون کلاس رو صدا بزنیم و اطلاعات user رو که پاس دادیم ذخیره کنیم ،برای اینکه به userDao دسترسی داشته باشیم توی متد سازنده همین کلاس appDb رو میگیریم تا با استفاده از متد userDao بهش دسترسی پیدا کنیم. قبل از کانستراکتور کلاس ریپازیتوریمون یه انوتیشن inject قرار میدیم تا به هیلت بفهمونیم ما باید از اینستنس این کلاس استفاده کنیم.

UserRepository
UserRepository

قدم هشتم:

یه کلاس ویومدل بسازیم و کلاس UserRepository که بالا ساختیم رو اینجکت کنیم داخلش این کلاس باید قبل از متدسازنده ش یه انوتیشن ViewModelInject بذاریم و ورودی کانستراکتورش باید UserRepository باشه این انوتیشن به هیلت میفهمون که UserRepository رو اینجکت کن داخل این ویومدل داخل ویدومدل هم یه متد save میذاریم که با استفاده از coroutines و MutableLiveData یک user رو به متد save ریپازیتوریمون ارسال میکنیم و استتوس true برمیگردونیم به اکتیویتی ای که قراره متصل بشه به این ویومدل ما.

UserViewModel
UserViewModel

قدم نهم:

یه اکتیویتی میسازیم که بالاسرش انوتیشن AndroidEntryPoint رو قرار دادیم این انوتیشن وظیفه ش اینه که به هیلت بفهمونه که وابستگی های مربوط به این کامپوننتی که بالاسرش از این انوتیشن استفاده شده رو فراهم کن .این اکتیویتی متصل شده به ویومدلی که بالا ساختیم و اطلاعات ورودی user رو با استفاده از دیتابایندینگ از xml دریافت میکنه و وقتی دکمه save زده شده به متد save ویومدل ما ارسال میشه.

UserActivity
UserActivity

کارمون تموم شد :)

سورس کد هم اینجا گذاشتم:

https://github.com/ftml71/SampleHilt