透過sunflower看看Google最近在Android上有什么花活(一)--- Hilt

sunflower

sunflower是什么?太陽花?Google沒出這個框架吧。

其實,sunflower是Google基于Google開發框架,加入大量Android JetPack組件的示例項目,涉及到kotlin,kotlin協程,新fragment,hilt,DataSource,paging3等等等等。

話不多說,先clone一下吧,地址如下:https://github.com/android/sunflower.git

開始

clone完成之后,打開項目,項目本身并不復雜,也沒有使用插件化,組件化之類的技術。

在編譯項目的時候,發生了gradle版本錯誤,因為項目默認的gradle版本是4.1.0,我的android studio還是4.0,通過升級android studio或者將gradle版本改成4.0.0解決。

常規操作,打開AndroidManifest文件,很簡單的配置文件,找到首頁 GardenActivity 。 同樣,極簡的代碼,一點點看。

image-20210311152642448.png

兩個知識點出現了,DataBinding和Hit。一個個來,先Hilt

Hilt

Hilt?這是什么,遇到不認識的單詞,我們一般做的是放到翻譯網站翻譯一下,主流翻譯的結果是劍柄,刀柄。還是不明覺厲,此時,我們注意到hilt的包的路徑,是不是很熟悉,dagger,依賴注入?dagger中文意思是匕首,而hilt是刀柄,是不是有點明確了,光有刀還不行,還需要一個可以更安全的使用刀,而且還能保護自己安全的刀把。

那么,先下個結論,hilt的職責是依賴注入,而且是更方便,更安全的依賴注入。

引入

  1. 在根目錄的build.gradle添加hilt-android-gradle-plugin插件

    buildscript {
        ...
        dependencies {
           ...
            classpath 'com.google.dagger:hilt-android-gradle-plugin:2.28-alpha'
        }
    }
    
  2. 在項目的build.gradle中添加依賴

        apply plugin: 'kotlin-kapt'
        apply plugin: 'dagger.hilt.android.plugin'
    
    dependencies {
      ....
        implementation "com.google.dagger:hilt-android:2.28-alpha"
        kapt "com.google.dagger:hilt-android-compiler:2.28-alpha"
    
    }
    
    • 如果不用Java8,引入的過程到這就結束了

使用

  1. 需要新建application,加入@HiltAndroidApp注解,隨后將其添加到配置文件中

    @HiltAndroidApp
    class BaseApplication : Application()
    
  2. 接下來就是剛剛提到的GardenActivity了,在代碼中出現了@AndroidEntryPoint注解,Hilt總共支持六種Android類,除了剛剛出現過得Application和Activity,還有Fragment,View,Service,BroadcastService。

    我們以Activity為例,簡單看一下具體的工作流程。新建一個Activity,添加@AndroidEntryPoint注解。

    @AndroidEntryPoint
    class HiltMainActivity : Activity() {
        
        override fun onCreate(savedInstanceState: Bundle?) {
            super.onCreate(savedInstanceState)
            setContentView(R.layout.activity_main)
        }
    }
    
    • 此時,是不是很納悶,然后呢,說好的依賴注入呢,注入的對象呢?
  3. 添加注入的對象,此處以運送貨物為例,創建Truck類

    class Truck {
        fun deliver() {
            Log.d(Util.TAG,"delivering")
        }
    }
    
  4. 將truck注入到Activity中

    @AndroidEntryPoint
    class MainActivity : AppCompatActivity() {
    
        @Inject lateinit var truck: Truck
    
        override fun onCreate(savedInstanceState: Bundle?) {
            super.onCreate(savedInstanceState)
            setContentView(R.layout.activity_main)
            truck.deliver()
        }
    }
    
    • 出現了另一個注解@Inject,這個注解的作用就是將truck注入到Activity中,而且MainActivity并沒有實例化Truck的代碼,但是能夠調用Truck的deliver方法,一個詞---方便。

    • 如果就這樣,嘗試運行的話,就會報錯了。還需要做一些改變,Truck類也是需要@Inject修飾的

      class Truck @Inject constructor() {
          fun deliver() {
              Log.d(Util.TAG,"delivering")
          }
      }
      
      • 在主構造函數之前加入@Inject注解,此舉是告訴Hilt,Truck實例是如何產生的,在主構造函數之前加入@Inject,是告訴Hilt,Truck的實例是通過主構造函數產生的。
      • 修改之后運行,成功運行

    帶參數注入

    在運輸過程中,肯定是需要一個司機的,那么就把司機當做參數傳入吧,稍作修改

    class Truck @Inject constructor(val driver: Driver) {
        fun deliver() {
            Log.d(Util.TAG,"delivering..., the driver is $driver")
        }
    }
    
    • 此時,hilt還不知道Driver是如何實例化的話,那么,我們就按照之前的格式在Driver類中加入@Inject

      class Driver @Inject constructor()
      

    運行代碼之后,結果如下:

image-20210312140533767.png

可見,成功打印出了driver的身份。

Hilt和Retrofit

以上是Hilt的基本用法,如果是要將第三方庫注入的話,使用@Inject注解就不能解決問題了,此時,就用到了另一個注解@Module。

下面,讓我們試一試hilt今天Retrofit是如何聯動的吧

引入Retrofit

首先,需要引入Retrofit

implementation 'com.squareup.retrofit2:retrofit:2.9.0'
implementation 'com.squareup.retrofit2:converter-gson:2.9.0'
implementation 'com.google.code.gson:gson:2.8.6'

Retrofit Module

成功引入之后,需要添加一個文件進行Retrofit的初始化工作

@Module
@InstallIn(ApplicationComponent::class)
class Network {

    @Provides
    @Singleton
    fun provideOkHttpClient(): OkHttpClient {
        return OkHttpClient.Builder()
            .build()
    }

    @Provides
    @Singleton
    fun provideRetrofit(okHttpClient: OkHttpClient): Retrofit {
        return Retrofit.Builder()
            .client(okHttpClient)
            .baseUrl("https://wanandroid.com")
            .addConverterFactory(GsonConverterFactory.create())
            .build()
    }

    @Provides
    @Singleton
    fun provideService(retrofit: Retrofit): ChapterApi {
        return retrofit.create(ChapterApi::class.java)
    }
}
  • @InstallIn注解,意思是將這個模塊安裝到Application中去,這樣,聲明周期就和Application一致了
  • @Provides 常用于被 @Module 注解標記類的內部的方法,并提供依賴項對象
  • 因為每次加入注解,都會創建一個實例,而我們的想法自然是單例,提高效率,這也很簡單,加上@Singleton就可以了。

嘗試獲取數據

既然準備工作都好了,就開始試著獲取數據吧

創建Api

第一步自然是創建Retrofit獲取數據的api,以wanAndroid的后臺api為依托。

interface ChapterApi {
    @GET("/wxarticle/chapters/json")
    suspend fun getChapter()
}

創建Bean文件

新建Bean文件,借助于android studio插件kotlin data classes from Json自定生成數據類

MainActivity

@AndroidEntryPoint
class MainActivity : AppCompatActivity() {

    @Inject lateinit var service: ChapterApi

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        initChapter()
    }

    private fun initChapter() {
        GlobalScope.launch {
            val chapterData: ChapterData = service.getChapter()
            Log.d(Util.TAG,chapterData.errorMsg + chapterData.errorCode)
        }
    }
}
  • 這是主界面實現的代碼,這里只是簡單的獲取了errorCode和errorMsg,但是能看到,代碼已經非常非常簡潔了
  • 借助于kotlin的協程,替代原本網絡請求中的回調,代碼行數減少了,效率自然就高了
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容