在上一篇文章 Jetpack 新成员 Hilt 实践(一)起程过坑记 别离介绍了 Hilt 的常用注解、以及在实践过程中遇到的一些坑,Hilt 怎么 Android 结构类进行绑定,以及他们的生命周期z m 1 + &,这篇文章持续解说 Hilt 的用法,代码现已全部上传到 GitHub:G 8 o f !HiltWi4 S : a J I ^ O lthAppStartupSimple 假如对你有E b : E _ / Q I协助,请在库房右上角帮我点个赞。
Hilt 涉及的知识点有点多而且比较难了解,在看本篇文章之前必定要先看一下之前的文章 Jetpack 新成员 Hilt 实践(一),为了节省篇幅,这篇文章将会疏忽 Hilt 环境装备的过程等等之前文章现已介绍过的内容。
别的假如想了i k p y E解 Google 新推出的别的两个 Jetpack 新成员 App Startup
和 Paging3
的实践与原理,能够点击下方链接前去检查。
- Jetpack 最新成员 AndroidX App Startup 实践以及原理剖析
- Jetpack 新成员 PY D h ] E 4 Q #aging3 数据库实践以及源码剖析(一)
- Jetpack 新成员 Paging3 网络实践及原理剖析(二)
- 代码地址:https://github.com/hi-dhl/AndroidX-Jetpack-Practice
经过这篇文章你将学习到以下内容:
-
什么是注解?
-
@assist
注解和SavedStateHans : j ] s f Zdle
怎么运用? -
怎么运用
@Binds
注解完成接口注入? -
@Binds
和@Provides
的差异? -
限制符
@Qj E y } v y n { iualifierO F 4 ?
的运用?- 自界说限q g c { f制符
@qualifers
- 预界说的限制符
@qualiferZ k ` P p Y }s
- 自界说限q g c { f制符
-
组件效果T e 6 F Z y (域
@scopes
怎么运用? -
怎么在
Hilt
不支撑的类中履行依靠注入?-
Hilt
怎么和ContentProvider
一同运用? -
H@ M 4ilt
怎么和App Sta# g n 3rtup! d S V $
一同运用?
-
Hilt 是根据 Dagger 基础上进行开发的,假如了m & b + ! A解 DagG U ) J 7ger 朋友们,应该会感觉它们很像,可是与 Dagger 不同的是, Hilt 集成了 Jetpack 库和 Android 结构类,并删除p b B X [了大部分模板代码,让开发者只需求重视怎么进行绑定,而不需求管理一切 Dagger 装备的问题。
在上篇文章现已介绍过, Hilt 怎么 Android 结构类进行绑定,以及他们的生命周期,这篇文: ) 3 v } ? : c i章将介绍 Hilt 怎么和 Jetpack 组件(ViewModel、App Startup)一同绑定,在开始介_ ; 3 y z w P绍之前{ W u W ] W N咱们先来了解一下什么是注解。S R z l }
什么是注解
之前有小伙伴在 WX 上问过我,对注解不太了解,所以想在这儿想简略w h ,的提一下。
注解是放在 Java 源码的类、办法、字段、参数前的一种特别“注释”,注解则能够被编译器打包进入 class 文件,能够在编译,类加载,运转时被读取。
常见的三个注解 @Override
、@Deprecated
、@SuppressWarnings
-
@Override
: 确保子类重写了父类的办法,编译器会检查该办法是否正确地完成。 -
@Deprecated
:表明某个类j A 2 6 / l T *、办法现已过期,编o % l a 0 q + M译器会检C n d查,假如运用了过期的办法,会给出提示。 -
@SuppressWarnings
:编译器会疏忽产生的警告。
Hilt 怎么和 ViewModel 一同运用?
在上一篇文章仅仅简略的介绍了 Hilt 怎么和 ViewModel 一同运用,咱们持续介绍 ViewModel 的别的一个重要的参数 SavedStateHandle
,首先需求增加依靠。
在 App 模块中的 builS $ 1 . +d.gradle
文件中增加以c 5 4 : ~ b下代码。
implementation 'androi$ s A y H Xdx.hilt:hilt-lifecycle-viewmodel:1.0.0-alpha01'
kapt 'androidx.hilt:hilt-compiler:1.0.0-alpha01'
koltin 运用 kapt, Java 运用v G . B X annotationProcessor。
留意: 这个是在 Goog1 B z `le 文档上没有说到的,假如运用的是 kotlin 的话需求额外在 ApU _ a :p 模块中的 build.gradle 文件中增加以下代码,否则调用 by viewModels()
会编译不过。
// For Kotlin projects
kotlinOptions {
jvmTarge* N K ? O T Y St = "1.8"
}
在 ViewModel 的结构函数中运用 @ViewMode7 E - & ` WlInject
注解供给一个 ViewModel,假如需求用到 SavedStateHandle
,需求运用 @assist
注解增加 SavedStateHandle
依靠T E F项,代码如下所示。
class HiltViewModel @ViewModelInject constructor(
private val tasksRepository: Repository,@ g U L # B
//Saveb rdStateHandle 用于进程被停止时,保存和康复数据
@Assisted private vaP D + & G 3 o l :l savedStateHandle: SavedStat~ y :eHandle
) : ViewModel() {
// getLiveData 办法会取得一个与 key 相关联的 MutableLiveData
// 当与 key 相对应的 value 改动时 MutableLiveData 也会更新。
private val _userId: MutableLiveDatao r c -<String> = savedStateHandle.gc v o N % / p 2 uetLiveData(U7 f ? ! e u J i ?SER_KEY)
// 对外露出不行变- 8 T a ] 0 /的 LiveData
val userId: LiveData<String> = _userId
companion o) 9 jbject {
private val USER_KEY = "userId"
}
}
将用户的 u~ * v W X tserId
存储在 SavedStateHandle
中,当进程被停止时保存和康复对应的数据。
SavedStateS S 9 yHandle 是什么?SavedStateHandle 为了处理什么问题?
Activity
和 Fragmeg | A G Anj h H A d & . ; .t
一般会在下面三种状况下被毁掉(以下内容来自 Google):
-
从当前界面永久离开: 用户导航至其他界面或直接封闭 Activity (经过点击回来按钮或履行的操作调6 – ? :用了
finish()
办法)。对应 Activity 实例被永久封闭。 - Activity 装备 (configuratiox f c Q En) 被改动: 例如旋转屏幕等操作,会使 Activity 需求立即重建。
- 应用在后台时,其进程被体系杀死: 这种状况发生在设备剩下运转内存不足,体系又需求开释一些内存的时分,当进程在后台被杀身后,用户又回来该应用时 Activity 需求被重建。
ViewModel 会帮您处理第二种状况,由于在这种状况下 ViewModel 没有被毁掉,而在第三种状况下,ViewModel 被毁掉了, 当m O x N V Q }进程在后台被杀身后,则需求运用 onSaveInstanceState()
作为备用保E ^ A 6 ? ( T存数据的办法。
SavedStateHandle
的呈现便是为了处理f ) Q l F p L w { App 进程停止保存和康复数据问题,ViewModel 不需求向 A; : k F K * 8 Kctivity 发送和接纳状态。相反的,现在能够在 ViewModel 中处理保存和康复数据。
SavedStateHandle
类似于一个 Bundle,它是数据的键-值映射,这个 SavedStateHandle
包含在 ViewModel 中,它在后台进程停止时依然存在,曾经保存在 onSaveIns9 V N P { VtanceState()
中的任何数据现在都能够保存在 SavedStaU r : ~ s $ y s RteHan# d J 6 Vdle
中。
运用 @BinM & ,ds 注解完成接口注入?
注入R * 2 / + 5 Q 8接口实例有两种办法别离运用注解 @Binds
和 @ProvideG ` d r ! 3 Gs
,@Provides
的办法在上一篇文章 Jetpack 新成员 Hilt 实践(一)起程过坑H N I o )记 Hilt 怎么和 RoB v 6 R V * W nom 一同运用 和 Hilt 怎么和第三q q H g j P j I方组件一同运用 都有介绍,这儿咱们来介绍怎么运用注解 @Binds
。
interface WorkService {
fuO { - = 8 l &n init()
}
/**
* 注入结构函数,由于 Hilt 需求~ b ~ ) 9知道怎么供给] 2 g c c G T ; WorkServiceImpl 的实例
*/
class WorkServiceImpl @Inject constructor() :
Wo: + V 8 B - ;rkService {
override fun init() {
Log.e(TAG, " I am an WorkServi] r & d . ` 6 N NceImpl")
}
}
@C % bModule
@InstallIn(Apj B % ~ , 1 z vplicationComz R vponent::class)
// 这儿运用了 ActivityComponent,因p y B 4 7 p q @ F而 WorkServiceModule 绑定到 Act7 Z + / 7ivityComponent 的生命周期。
abx # p 7 ( 1 c @stract class WorkSC J ! f 3 w j eervB iceModule {
/**
* @Binds 注解告知 Ha 9 ! N U gilt 需K n m T求供给接口实例时运用哪个完成
*
* bindAnalyticsServz c # Z cice 函数需求为 Hilt 供给了以下信息
* 1. 函数, r Y回来类型告知 Hilt 供给了哪个接口的实例
* 2. 函数参数告知 Hilt 供给哪个完成
*/
@BS g + U x j , Einds
abstract fun bindAnalyticsService(
workServiceIm? T w ppl: WorkServiceImpl
): WorkService
}
运用注解 @Binds
时,需求供. 4 F T C % J给以下两个信息:
- 函数参数告知 Hilt 接口的完成类,例如参数 WorkServiceImpl 是接口 WorkService 的完成类。
- 函数回来类型告知 Hilt 供给了哪个接口的实例。
注解 @Binds 和 注解 @Provides 的差异?
-
@Binds
:需求在办法参数里边清晰指明接口的完成类。 -
@Prot / H 2 0vides
:不需求在办法参数里边清晰指明接口的完成类,由第三方结构完成,一般用于和第三方结构进行绑定(Retrofit
、Room
等等)
// 有自己的接口完成
@Binds
abstract fun bindAnalyticsService(
workServiceImpl: WorkServiceImpl
): WorkServi` . h 1ce
// 没有自己的接口完成
@Provides
fun providePersonDao(application: Application): PersonDao {
return Room
.databaseBuilder(application, AppDataBase::class.java, "dhl.db")
.fallbackToDestructiv1 ] o a +eMigration()
.allowk m T N P 4 $MainThreadQueries()
.build().personDao()
}
@Provides
fun provideGitHubService(): GitHubService {
return Retrofit.Builder()
.baseUrl("https://api.githuby L : K 4.com/"w M $ a R `)
.addConverterFactQ 5 l Y ! jory(GsonConverterFaa c Hctory.create())
.build().create(GitHubServb x 7 L D Lice::class.j8 ( v .ava)
}
限制符 @Qualifie! Q t s Rr 注解的运用
来自 Google:@Qualifier
是一种注解,当类型界说了多个绑定时,运用它来标识该类型的特定绑定。
换句话说 @Qualifier
声明同一个类型,能够在多处进行绑定,我将限制符分为两种。
- 自界说限g 9 G ? w a 4制符
- 预界说限制符
自界说限制符的运用
咱们先用注解 @Qualifier
声明两个不同的完成。
// 为每个声明的限制符,供给对应的类型实例+ N l b @ N K L,和 @Binds 或许 @Provides 一同运用
@Qualifier
// @Retention 界说了注解的生命周期,对应三个值(SOURCE、BINARY、RUNTIME)
@Retention(AnnotationRetention.BINARY)
annotation class RemoteTasksDataSource // 注解的姓名,后边直接运用它
@Qualifier
@Retention(AnnotationRetention.RUN| h W ! J m ^TIMEd a N & } ? C F)
annotation class LocalTasksDataSource
-
@Qualifier
:为每个声明的限制符,供给对应的类型实例,和@Binds
或许@Provides
一同运k S . ? T q用 -
@Retention
:界说了注解的生命周期,对应三个值(SOURCE、BINARY、RUNTIME)-
Anno# * 6tationRetention.SOURM Z k v 7 0CE
:仅编译期,不存储在二进制输出中。 -
AnnotationRetention.BINARY
:存储在二进制输出中,但对反射不行见。 -
AK o E )nnotd y # q 6 - b pationRetention.RUNTIME
:存储在二进制输出中,对反射可见。
-
一般y ] f Y _ H 5咱们自界说的注解都是 RUNTIME,所以务必要加上@Retention(RetentionPolicy.RUNTIME)
这个注解
来看一下 @Qualifier
和 @u ` a p ] ; c 9 %Provides
一同运用的比如,界说了两个办法,具有相同的回来类型,可{ x ) : ; ^ 4 d是完成不同,限制符将它们~ 6 j . j % l | J标记为两个不同的绑定。
@Singleton
@RemoteTasksDataSource
@Provides
fun provideTasksRemoteDataSource(): DataSource { // 回来值相同
rI u l E ` _ W @eturI ] R @nB ( M } % 8 S ? RemoteDataSource() // 不同的完成
}
@Singleton
@LocalTasksDataSource
@Providej C u / 3 5 us
ft W l f { 2 [ Pun provideTaskLocalDataSource(appDatabase: AppDataBase): DataSource { // 回来值相同
return LocalDataSoK 2 7 P 6 xurce(appDatabase.personDao()) // 不同的完成
}
当咱们声明完 @Qualifier
注解之后,就能够运用声明的两个 @Qualifier
,来看个比如,界说一个 Repository 结构办法里边传入用 @Q& R G 1 3 1 jualifs r @ B Rier
注解声明的两个不同完成。
@Singleton
@Provides
fun provideTasksRepository(
@LocalTasksDataSource localDataSource: DatQ y P ~ N . u G EaSource,
@RemoteTasksDataSource remoteDataSourceq K e 4 v j 7 T: DataSource
): Repository {
return TasksRepository(
localDataSource,
remote! T 1DataSource
)
}
provideTasksRepository 办法内,传入的参数F K r都是 DataSource,可是前面用 @Qualifier
注解声明晰它们不同的完成。
预界说限制符
Hilt 供给 L y / D 0 Q } B了一些预界说限制符,例如你或许在不同的状况下需求不同的 Context
(Appliction
、Activity
)Hilt 供给了 @ApplicationContext
和 @ActivityContext
两种限制符。
class HiltViewModel @ViewModelInject constructor(
@ApplicationContext appContext, , 0 S O ( %: Context,
@9 V ] _ ] % YActivityContel v s ~ o 2 Fxt actContext: Context,
private val tasksRepository: Repository,
@Assisted private val savedStateHandle: SavedStateHandle
)
组件效o A x W 果域 @scopes 的运用
默许状况下,Hilt 中的一切绑定都是无效果域的,这意味着每次应用程序恳求绑定时,Hilt 都会创立一个所需类型的新实例。
@scopes
的效果在指定效果域规模内(Application
、` { / 3 / K K aActivX K ! # 7ity
等等) 供给相同的实例。
Hilt 还允许将绑定的效果域限制到特定组件,Hilt 只为绑定效果域U P / ~ ; v到的组件的每个实n C [ /例创立一次规模绑定,一切绑定恳求共享同一个实例,咱k a E 5们来看一比w # L如。
@SY a b a ? @ Ringleton
class HiltSimple @Inject constructor() {
}
HiltSimple
用 @Singleton
声明晰其效果域,那么在 Application 规模内供给相同的实例,代码如下所示,咱们能够运转 Demo 看一下输出G h . v { A e #结果。
MainActivity: com.hi.dhl.hilt.appstartup.di.HiltK w =Simple@8f75417
HitAppCompatActivity: com.hi.dhl.hilt.appJ @ * - q V 5 n ~startup.di.Hil& c P 2 r WtSimple@8f75417
留意:绑定组件规模或许十分的昂贵,由于O L y Q K { D供给的对象会保留在内存中,直到该组件被毁掉,应该尽量减少在应用程序中运用B 2 r j {绑定` z T Q 2 7组件规模,关于要求在必定规模内运用同一实例的绑定,或许关于创立本钱昂扬的绑定,运用组件规模的绑定是适宜的。
下表列出了每个生成组件的 scope 注解对应的规模。
Android class | Generated component | Scope |
---|---|---|
Application | ApplicationComponent | @SingletoA 0 D n a Z y An |
View Modw F Y S g Q ~ rel L d 8 | ActivityRetainedComponent | @ActivityRetainedScope |
Activity | ActivityCompon1 5 ? _ | K R Cent | @ActivityScoped |
Fragment | FragmentComponent | @FragmentScoped |
View | ViewComponent | @ViewScoped |
View annotated with @WithFragX o a i L R X YmentBindings | ViewWithFragmentComponent | @ViewScoped |
Service | ServiY N H 8 K ^ 8 %ceComponent | @ServiceScoped |
在 Hilt 不支撑的类中履行依靠注入
Hilt 支撑最常见的 Android 类 Applica5 s ] 6 . 8 jtion
、Activity
、Fragment
、View
、Service
、BroadcastReceiver
等等,可是您或许需求在 Hilt 不支撑的类中履行依靠注入,在这种状况下能够运用 @EntryPoint
注解进行创立,Hilt 会供给相应的依靠。
@EntryPoint
:能够运用 @EntryPointR z v 4 b v
注解创立入口点,@EntryPoint
允许 Hilt 运用 Hilk h I S % 6 &t 无法在依靠中供给依靠的对象。
例如 Hilt 不支撑 ContentProvider
,假如你在想在 ContentProvider
中获取 Hilt 供给的依靠,你能够界– Z j说一个接口,j # T & _ ! 3 :并增加k & / h k N I ] @Eu X G y k )ntryPoint
注h O 7 x W F I解,然后增加 @InstallIn
注解指定 module 的规模,代码如下所示。
@EntryPoint
@InstallIn(ApplicationComponent::class)
inc E = g }terface InitializerEntryPoint {
fun injectWorkSw z 0 Y X k $ D Mervice(): WorkService
companion object {
fun resolve(context: Context): InitializerEntryPo6 Y e 7 jint {
val appContext = context.applicationContext ?6 w D R $ t w u : throw IllegalStateExcep_ N 5 w {tion()
return EntryPointAccessors.fromApplication(
appContext,
InitializerEntryPp z K roint::class.java
)
}
}
}
运用 EntryPointAccesso* D O M 1 f $ j ;rs
供给四个静态办法进行拜访,别离是 fromActivity
、fromApplication
、fromFragmentL T ] W ,
、fromView
等等
EntryPointAccessors 供给四个静态办法,第一个参数是 @EntryPoint
接口上 @InstallIn
注解指定 module 的规模,咱B t 2 D们在接口 InitializerEnG n e @ k 5 * t HtryPoint
用 @InstallIn
注解指定u 0 Y o modull Z 7 o f ; F ]e 的规模是 ApplicationComponent
,所以咱们应该运用 EntryPointAcC t | 6 u Jcessors
供给的静态办法 fromApplication
。
class WorkContentProvider : ContentProvider() {
overH - u = [ | T T Aride fun onCreate(): Boolean {
context?.run {
val service = InitializerEntryPoint.resolve(this).injectWorkService()
Log.e(TAG, "WorkContentProvider ${service.init()}")
}
re N P D ~ jturn true
}M D | } g
......
}
在 ContentPro8 q } K i ovider
中调X { A ! _用 EntryPointAccessors
类中的 fromAL B U & z wpplication
办法就能够获取到 Hit 供给的依靠。
Hilt 怎么和 App Startup 一同运用
App Startup 会默许供给一个 InitializationProv* F H u } b uider
,InitializationProvider. I y
承继 ContentProvider
,那么 Hilt 在 App Startup 中运用的办法和 ContentProvider
相同。
cG ; V 1 | ! flass AppInity | m f H #ializer : Initializer~ K 9 | {<Unit> {
override fun create(context: Context): Unit {
val service = InitializerEntryPoint.re? z ) % 4 R fsolve(context).injectWorkService()
Log.e(TAG, "AppInitializer ${service.init()}")
return Unit
}
override fun dependencies(): MutableList<C0 i [ E l k : { ~lass<out Initializer<*&gF : 4 @ t Ct;>> =
mutableListOf()
}
经过调用 EntryPoinE 7 S UtAccessors 的静态办法,获取到 Hit 供给的依靠,关于 App Startup 怎么运用能够& U ] W检查这篇文章 Jet^ o c k r 6 E ] `pack 最新成员 AndroidX App Startup 实5 – G践以及原理剖析
总结
到这儿关于 Hilt 的注解运用都介绍完了,代码现] i 6 ~已全部上传到了 GitHub:HiltWithAppStaR [ x ~ u A qrtupSimple。
HiltWithAppStartupSimple
包含了本篇文章` & B ) 4和 Jetpack 新成员 Hilt 实践(一)起程过坑记 文章中运用的事w ; ! 0 J G J例,假如之前[ & # Z ~ t H = ;没有看过能够先去了解一下,之后看代码会更加的清楚。
Hilt 是根据 Dagger; | D 基础上进行开发的,入门要比 Dagger 简略许多,不需求去管理一切的 Dagger 的装备问题,可是e O Q e B B S其入门的门槛仍是很高的,尤其是 Hilt 的注解,需求了解其每个注解的含义才能正确的运用,避免资源的浪费B } g . O。
这篇文章和之前4 H S h Jetpack 新成员 Hilt 实践(一)起程过坑记 的文章其中许多事例都重新去设计了,由于 Google 的供给的事例,的确很难让人了解,期望这两篇文章能够协助小伙伴们快速入门 Hilt~ ( ; , D,后边还会有更多实战事例。
计划建立一个最全、最新的 AndroidX Jetpack 相关组件的实战项目 以及 相关组件原理剖析3 = @ ? N u文章,正在逐步增加 Jetpack 新成员! i l N @ P R k,库房持续更新,能够前去检查:AndroE * y z NidX-Jetpack-Practice, 假y e H 7 2如这个库房对你有协助,请在库房右上角帮我点个赞,后边我会连续完成更多 Jetpack 新成员的项目实践。
结语
致力于分享一系列 Android 体系源码、逆向剖析、算法、Q 4 X l | 9 a B 3翻译、Jetpack 源码相关的文章,V T . ] ` M ! ^ )正在尽力写出更好的文章,假如这篇文章对你有协助给个 star,一同来学习,等待与你一同生长。
算法
由于 LeetCode 的题库庞大,每个分类都能筛选; $ w & l出数百道题,由于每个人的精力有限,不行能刷完一切标题,因而我按照经典类型标题去分类、和标题的难易程度去排序。
- 数据结构: 数组、栈、行列、字符串、链表、树……
- 算法: 查找算法、搜索算法、2 v y } O T e /位运算、排序、数学、……
每道标题都会用 Java 和 kotliw 2 z /n 去完成,而且每道标题都有解题思路、时刻复杂度和空间复杂度,假如2 [ ! t ] u S你同我相同喜欢算法、LeP H k etCode,能够重视我 GitHub 上的 LeetCode 题解:Leetcode-SolutiK s ) p P P k * [ons-with-Java-And-Kotlin,一同来学习,等待与你一同生长。
Android 10 源码系列
正在写一系列的 Android 10 源码剖析的文章,了解体系源码,不仅有助于剖析问题,在面试过程中,对咱们也是十分有协助的,假如你同我相同喜欢研究 Android 源码,能够重视我 GitH; Y nub 上e i 5的 Android10-Source-Analysis,文章都会同步到这个库房。
- 0xA01 Android 10 源码剖析:APK 是怎么生成的
- 0xA02 Android 10 源码剖析:APK 的装置流程
- 0xA03 And. O [ B Troid 10 源码剖析:APK 加载流程之资源加载
- 0xA04 Android 10 源码剖析:APK 加载流程之资源加载(二)
- 0xA05 Android 10 源码剖析r G C i ; + c:Dialog 加载绘制流程以及在 Kotlin、DataBinding 中的运用
- 0xA06 Android 10 源码剖析:WindowX w rManager 视+ _ R p A _ 1 V P图绑定以及体系结构: % . o F s
- 0xA07 Android 10 源码剖析:Window 的类型 以及 三维视图层级剖析
- 更多……
Android 应用系列
- 怎么在项目中封装 Kotlin + Android Databinding
- 再会吧 buildSrc, 拥抱 Composing builds 提高 Android 编译速度
- 为数不多的人知道+ n & L = i ] 3 f的 Kotlin 技巧以及 原了解析
- Jetpack 最新成员 AndroidX App Startup 实践以及原理剖析
- Jetpack 成员 Paging3 实践以及源码剖析(一)
- Jetpack 新成员 Paging3 网络A T ~ n L U 7 j P实践及原s 0 ! T l = ; ^ t理剖析(二)
- Jetpack 新成员 Hilt 实践(一)起程过坑记
精选译文
现在N 7 M 3 R B U正在整理和翻译一系列精选国外的技术文章,不仅仅是翻译,许多优秀的英文技术文章供给了很好思路和办法,每篇文章都会有译者考虑部分,对原文的更加深化的O h P n M ? ` t E解读,能够重视我 Gt d G t F w e xitHub 上的 Technical% W 3 L-Article-Translation,文章都会同步到这个库房。
- [译][Google工程师] 刚刚发布了 FrL v n ! ( X b Wagment 的新特性 “F( = X 7 Eragment 间传递数据的新办法” 以及源码剖s y ] j M m % u &析
- [译][Google工程师] 详解 FragmentFactory 怎么高雅运用 Koin 以及部分源码剖析
- [译][2.4K Start] 放弃 Dagger 拥抱 Koin
- [译][5k+] Kotlin 的性能( k 0 ( l X ? E p优化那些事
- [译] 解密 RxJava 的反常处理机_ w :制
- [译][1.4K+ Star] Kotlin 新秀 Coil VS Glide and Picasso
- 更多……2 c g ~ ;
东西系8 y E k # I j列
- 为数不多的} H o V # U o !人知道m E W ! ~ y I K (的 AndroidStudio 快捷键(一)
- 为数不多的人知道的 AndroidStudio 快捷键(二)i = . F , 1 j
- 关于 adb 指令你所需求知道的
- 10分钟入门 Shell 脚本编程
- 根据 Smali 文件 Android Studio 动态调试 APP
- 处理在 Android Studl q R kio 3.2 找不到 Android Device Monitor 东西