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.
interface NetApi {
@GET("https://www.wanandroid.com/article/list/0/json")
suspend fun getHomeList(): CommonResult<WanAndroidHome>
@GET("https://www.wanandroid.com/article/list/{path}/json")
suspend fun getHomeList(@Path("path") page: Int): CommonResult<WanAndroidHome>
// ... other overloaded GET/POST methods ...
@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.
class NetRepository private constructor() {
val service by lazy { RetrofitUtils.instance.create(NetApi::class.java) }
companion object { val instance by lazy { NetRepository() } }
fun getHomeList() = flow { emit(service.getHomeList()) }
fun getHomeList(page: Int) = flow { emit(service.getHomeList(page)) }
// ... 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
>
fun getHomeList(page: Int): Flow
>
// ... 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.
class RepositoryProxy private constructor() : BaseRepositoryProxy() {
val service = NetApi::class.java
val api by lazy { RetrofitUtils.instance.create(service) }
fun
callApiMethod(serviceR: Class
, methodName: String, vararg args: Any): Flow
{
// reflection + flow emission logic ...
}
}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.
fun
callApiSuspendMethod(clazzR: Class
, methodName: String, vararg args: Any): Flow
{
// find suspend method via reflection and emit result
}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.
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.