توسعه دهنده نِیتیوْ(Native) موبایل ( اندروید/آی او اس(کنارگذاشته شده)) Moeindeveloper.ir
استفاده از Dagger hilt به صورت پروژه محور (قسمت اول)

بعد از چند وقت تصمیم گرفتم که یک سری مقاله برای تکمیل کردن دوره توسعه اپلیکیشن های مدرن اندرویدی منتشر کنم. در دوره قبلی به علت کمبود وقت، Dagger 2 رو آموزش ندادم و به جای اون از KOIN استفاده کردم؛ اما چند وقت پیش با شنیدن ارائه Dagger Hilt این فکر به سرم زد که بیام و ی مقاله پروژه محور(سورس کد بعد از دوره در گیتهاب قرار خواهد گرفت) راجبش منتشر کنم. با ی سرچ ساده ی آموزش ساده از MindOrks پیدا کردم که خیلی ساده آموزشو پیش برده که برای این سری مقاله اکثر قسمتاشو مثل اون پیش میریم!
قسمت ها:
قدم اول: کار اپلیکیشن
برای اینکه اپلیکیشن تقریبا واقعی به نظر بیاد، به یک Web API نیاز داریم. با ی سرچ ساده، دو API برای یکی از سریال های محبوبم Game of thrones پیاده کردم?:
قدم دوم: ساخت پروژه
شروع به ساخت یک اپلیکیشن در اندروید استدیو کردم و اسم پروژه رو Ice and Fire گذاشتم.
ساختار پوشه بندی اصلی:

کتابخانه های اضافه شده:
1 implementation 'androidx.constraintlayout:constraintlayout:2.0.0-rc1'
برای استفاده از Motion layout از ورژن ۲ کانسترینت لایوت استفاده می کنم.
کتاب خانه های جت پک
1234567891011121314//android Arch components: implementation "androidx.concurrent:concurrent-futures-ktx:1.1.0-rc01" def lifecycle_version = "2.2.0" def arch_version = "2.1.0" // ViewModel implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:$lifecycle_version" // LiveData implementation "androidx.lifecycle:lifecycle-livedata-ktx:$lifecycle_version" // Annotation processor kapt "androidx.lifecycle:lifecycle-compiler:$lifecycle_version" def nav_version = "2.3.0" //navigation implementation "androidx.navigation:navigation-fragment-ktx:$nav_version" implementation "androidx.navigation:navigation-ui-ktx:$nav_version"
رتروفیت:
123//retrofit implementation 'com.squareup.retrofit2:retrofit:2.9.0' implementation 'com.squareup.retrofit2:converter-gson:2.9.0'
دگر هیلت و ماژول لایف سایکل ( برای ویومدل):
123456//dagger hilt implementation 'com.google.dagger:hilt-android:2.28-alpha' kapt 'com.google.dagger:hilt-android-compiler:2.28-alpha' //android lifecycle implementation 'androidx.hilt:hilt-lifecycle-viewmodel:1.0.0-alpha02' kapt 'androidx.hilt:hilt-compiler:1.0.0-alpha02'
در فایل Build.gradle ماژول پروژه و در قسمت Dependencies:
1classpath 'com.google.dagger:hilt-android-gradle-plugin:2.28-alpha'
و در قسمت repositories :
12345repositories { google() jcenter() mavenCentral() }
و در فایل Build.gradle ماژول اپ:
12apply plugin: 'kotlin-kapt' apply plugin: 'dagger.hilt.android.plugin'
پس از انجام این مراحل، گریدل خود را Sync کنید!
قدم سوم: ساخت لایه نتورک
برای شروع،دو کلاس برای برای اعلام وضعیت بین لایه نتورک و یو ای میسازیم و اسم اونو Resource و RequestStatus میذاریم:
12345enum class RequestStatus { SUCCESS, ERROR, LOADING }
1234567891011121314151617data class Resource<out T>(val status: RequestStatus, val data: T?, val Message: String?) { companion object { fun <T> success(data: T?): Resource<T> { return Resource(RequestStatus.SUCCESS,data,null) } fun <T> error(msg: String, data: T?): Resource<T> { return Resource(RequestStatus.ERROR,data,msg) } fun <T> loading(data: T?): Resource<T> { return Resource(RequestStatus.LOADING,data,null) } } }
سپس طبق مستندات API بالا، دیتاکلاس های نتورک رو میسازیم:

123456789101112131415161718192021222324data class Book( @SerializedName("authors") val authors: List<String>, @SerializedName("characters") val characters: List<String>, @SerializedName("country") val country: String, @SerializedName("isbn") val isbn: String, @SerializedName("mediaType") val mediaType: String, @SerializedName("name") val name: String, @SerializedName("numberOfPages") val numberOfPages: Int, @SerializedName("povCharacters") val povCharacters: List<String>, @SerializedName("publisher") val publisher: String, @SerializedName("released") val released: String, @SerializedName("url") val url: String )
1234567891011121314151617181920212223242526272829303132data class Character( @SerializedName("aliases") val aliases: List<String>, @SerializedName("allegiances") val allegiances: List<Any>, @SerializedName("books") val books: List<String>, @SerializedName("born") val born: String, @SerializedName("culture") val culture: String, @SerializedName("died") val died: String, @SerializedName("father") val father: String, @SerializedName("mother") val mother: String, @SerializedName("name") val name: String, @SerializedName("playedBy") val playedBy: List<String>, @SerializedName("povBooks") val povBooks: List<String>, @SerializedName("spouse") val spouse: String, @SerializedName("titles") val titles: List<String>, @SerializedName("tvSeries") val tvSeries: List<String>, @SerializedName("url") val url: String )
12345678910111213141516171819202122232425262728293031323334data class House( @SerializedName("ancestralWeapons") val ancestralWeapons: List<String>, @SerializedName("cadetBranches") val cadetBranches: List<String>, @SerializedName("coatOfArms") val coatOfArms: String, @SerializedName("currentLord") val currentLord: String, @SerializedName("diedOut") val diedOut: String, @SerializedName("founded") val founded: String, @SerializedName("founder") val founder: String, @SerializedName("heir") val heir: String, @SerializedName("name") val name: String, @SerializedName("overlord") val overlord: String, @SerializedName("region") val region: String, @SerializedName("seats") val seats: List<String>, @SerializedName("swornMembers") val swornMembers: List<String>, @SerializedName("titles") val titles: List<String>, @SerializedName("url") val url: String, @SerializedName("words") val words: String )
123456data class Quote( @SerializedName("character") val character: String, @SerializedName("quote") val quote: String )
حالا نوبت میرسه به ساخت interface ها:

123456789101112131415161718192021222324252627interface IceAndFireApiHelper { suspend fun getBooks(): Response<List<Book>> suspend fun getBook( bookID: Int ): Response<Book> suspend fun getCharacters(): Response<List<Character>> suspend fun filterCharacters( name: String?, gender: String?, culture: String?, isAlive: Boolean? ): Response<List<Character>> suspend fun getCharacter(characterID: Int): Response<Character> suspend fun getHouses(): Response<List<House>> suspend fun getHouse(houseID: Int): Response<House> }
12345678910111213141516171819202122 class IceAndFireApiImpl(private val service: IceAndFireApiService) : IceAndFireApiHelper { override suspend fun getBooks(): Response<List<Book>> = service.getBooks() override suspend fun getBook(bookID: Int): Response<Book> = service.getBook(bookID) override suspend fun getCharacters(): Response<List<Character>> = service.getCharacters() override suspend fun filterCharacters( name: String?, gender: String?, culture: String?, isAlive: Boolean? ): Response<List<Character>> = service.filterCharacters(name,gender,culture,isAlive) override suspend fun getCharacter(characterID: Int): Response<Character> = service.getCharacter(characterID) override suspend fun getHouses(): Response<List<House>> = service.getHouses() override suspend fun getHouse(houseID: Int): Response<House> = service.getHouse(houseID) }
12345678910111213141516171819202122232425262728293031323334interface IceAndFireApiService { @GET("api/books") suspend fun getBooks(): Response<List<Book>> @GET("api/books/{id}") suspend fun getBook( @Path("id") bookID: Int ): Response<Book> @GET("api/characters") suspend fun getCharacters(): Response<List<Character>> @GET("api/characters") suspend fun filterCharacters( @Query("name") name: String?, @Query("gender") gender: String?, @Query("culture") culture: String?, @Query("isAlive") isAlive: Boolean? ): Response<List<Character>> @GET("api/characters/{id}") suspend fun getCharacter(@Path("id") characterID: Int): Response<Character> @GET("api/houses") suspend fun getHouses(): Response<List<House>> @GET("api/houses/{id}") suspend fun getHouse(@Path("id") houseID: Int): Response<House> }
12345678 interface QuotesApiHelper { suspend fun getQuotes(): Response<Quote> suspend fun filterQuotes( character: String ): Response<Quote> }
1234567class QuotesApiImpl(private val service: QuotesApiService): QuotesApiHelper { override suspend fun getQuotes(): Response<Quote> = service.getQuotes() override suspend fun filterQuotes(character: String): Response<Quote> = service.filterQuotes(character) }
12345678910interface QuotesApiService { @GET("quotes") suspend fun getQuotes(): Response<Quote> @GET("quotes") suspend fun filterQuotes( @Query("char") character: String ): Response<Quote> }
برای استفاده از coroutines از suspend fun استفاده میکنیم، و حتما در نظر داشته باشید که از ورژن 2.6+ رتروفیت استفاده کنید که کروتینز رو پشتیبانی کنه!
خب برای این قسمت فک کنم تا اینجا کافی باشه! در قسمت بعدی مفاهیم دگر رو به صورت کلی بررسی خواهیم کرد و پروژه رو با دگر کانفیگ میکنیم!
مطلبی دیگر از این انتشارات
اولین تجربه برنامه نویسی با کاتلین
مطلبی دیگر از این انتشارات
آموزش ویدئویی پیاده سازی تم تاریک Dark در اپلیکیشن های اندروید
مطلبی دیگر از این انتشارات
توسعه اپلیکیشن های مدرن اندرویدی قسمت سوم