Advanced Repository and Network Layer Automation in Kotlin Using Annotation Processors, Dynamic Proxies, and Flow
This article presents a comprehensive guide on building a highly modular Android network layer by leveraging Kotlin coroutines, Flow, Retrofit, annotation processors, dynamic proxies, and dependency‑injection frameworks to automatically generate Repository classes and streamline MVVM data flow.
1. Introduction
The article introduces four different techniques for handling repository generation and network request encapsulation in an MVVM architecture, focusing on Kotlin, coroutines, Flow, Retrofit, and annotation processing.
2. Fancy Encapsulation (Part 1)
Defines the NetApi interface with various @GET and @POST methods, demonstrating how to declare request signatures, query parameters, headers, and body wrappers.
<span style="line-height: 26px">interface NetApi {</span>
<span style="line-height: 26px"> @GET("https://www.wanandroid.com/article/list/0/json")
suspend fun getHomeList(): CommonResult<WanAndroidHome></span>
<span style="line-height: 26px"> @GET("https://www.wanandroid.com/article/list/{path}/json")
suspend fun getHomeList(@Path("path") page: Int): CommonResult<WanAndroidHome></span>
<span style="line-height: 26px"> // ... other overloaded GET/POST methods ...</span>
<span style="line-height: 26px"> @FormUrlEncoded
@POST("https://www.wanandroid.com/user/register")
suspend fun register(@Field("username") username: String,
@Field("password") password: String,
@Field("repassword") repassword: String): String
}The corresponding NetRepository lazily creates a Retrofit service and wraps each API call into a flow { emit(...) } construct, providing a uniform reactive API.
<span style="line-height: 26px">class NetRepository private constructor() {</span>
<span style="line-height: 26px"> val service by lazy { RetrofitUtils.instance.create(NetApi::class.java) }</span>
<span style="line-height: 26px"> companion object { val instance by lazy { NetRepository() } }</span>
<span style="line-height: 26px"> fun getHomeList() = flow { emit(service.getHomeList()) }
<span style="line-height: 26px"> fun getHomeList(page: Int) = flow { emit(service.getHomeList(page)) }
<span style="line-height: 26px"> // ... other wrapper functions ...
}3. Fancy Encapsulation (Part 2)
Shows how an annotation processor can automatically generate an INetApiRepository interface whose methods mirror those of NetApi but return Flow<T> instead of raw Retrofit calls.
public interface INetApiRepository {
fun getHomeList(): Flow<CommonResult<WanAndroidHome>>
fun getHomeList(page: Int): Flow<CommonResult<WanAndroidHome>>
// ... all other API methods as Flow ...
}Dynamic proxy classes ( RepositoryProxy and BaseRepositoryProxy) locate the appropriate suspend method via reflection, invoke it, and emit the result as a Flow, handling exceptions and type conversion.
<span style="line-height: 26px">class RepositoryProxy private constructor() : BaseRepositoryProxy() {</span>
<span style="line-height: 26px"> val service = NetApi::class.java
<span style="line-height: 26px"> val api by lazy { RetrofitUtils.instance.create(service) }</span>
<span style="line-height: 26px"> fun <R> callApiMethod(serviceR: Class<R>, methodName: String, vararg args: Any): Flow<R> {</span>
<span style="line-height: 26px"> // reflection + flow emission logic ...
<span style="line-height: 26px"> }
}4. Fancy Play (Part 3)
Illustrates the use of a custom @AutoCreateRepositoryInterface annotation to trigger generation of the INetApiRepository interface, removing the need to write boilerplate repository code manually.
5. Fancy Play (Part 4)
Further reduces boilerplate by letting the proxy directly accept a class, method name, and arguments, returning a Flow without an intermediate generated interface.
<span style="line-height: 26px">fun <R> callApiSuspendMethod(clazzR: Class<R>, methodName: String, vararg args: Any): Flow<R> {</span>
<span style="line-height: 26px"> // find suspend method via reflection and emit result
<span style="line-height: 26px">}6. Summary
The four "fancy" approaches demonstrate how to:
Write a clean, coroutine‑based network layer using Retrofit, Flow, and a conventional Repository.
Automate the generation of Repository code with annotation processors, keeping only special‑case methods manual.
Leverage dynamic proxies and reflection to implement the API interface without a concrete implementation class.
Eliminate even the generated interface by invoking methods directly via reflection.
Throughout the article, concepts such as annotations, reflection, generics, annotation processing, and dynamic proxies are explored, providing a deep dive for Android developers seeking a highly reusable and maintainable data‑access layer.
Project source code is available on GitHub and Gitee.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Rare Earth Juejin Tech Community
Juejin, a tech community that helps developers grow.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
