1. 程式人生 > >Kotlin--›初識Android Proxy介面動態代理

Kotlin--›初識Android Proxy介面動態代理

介面的動態代理, 使用這個技術最多的就是Retrofit框架了.

首先要注意: 動態代理只能代理介面,也就是interface宣告的類

否則會拋異常:

Caused by: java.lang.IllegalArgumentException: com.angcyo.proxydemo.Target is not an interface
        at java.lang.reflect.Proxy$ProxyClassFactory.apply(Proxy.java:589)
        at java.lang.reflect.Proxy$ProxyClassFactory.apply
(Proxy.java:566) at java.lang.reflect.WeakCache$Factory.get(WeakCache.java:230) at java.lang.reflect.WeakCache.get(WeakCache.java:127) at java.lang.reflect.Proxy.getProxyClass0(Proxy.java:419) at java.lang.reflect.Proxy.newProxyInstance(Proxy.java:820) at com.angcyo
.proxydemo.MainActivity.onCreate(MainActivity.kt:18) at android.app.Activity.performCreate(Activity.java:6975) at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1213) at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2770) at android.app
.ActivityThread.handleLaunchActivity(ActivityThread.java:2892) at android.app.ActivityThread.-wrap11(Unknown Source:0) at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1593) at android.os.Handler.dispatchMessage(Handler.java:105) at android.os.Looper.loop(Looper.java:164) at android.app.ActivityThread.main(ActivityThread.java:6541) at java.lang.reflect.Method.invoke(Native Method) at com.android.internal.os.Zygote$MethodAndArgsCaller.run(Zygote.java:240) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:767)

1:宣告一個需要代理的介面

interface ITarget {
  fun testFun1()

  fun testFun2(arg1: String, arg2: List<String>)

  fun testFun3(arg1: String, arg2: List<String>): String

  fun testFun4(arg1: String, arg2: ArrayList<String>): String
}

2:介面的預設實現

class Target : ITarget {
   override fun testFun4(arg1: String, arg2: ArrayList<String>): String {
       Log.i("angcyo", "log fun4")
       return "fun4"
   }

   override fun testFun1() {
       Log.i("angcyo", "log fun1")
   }

   override fun testFun2(arg1: String, arg2: List<String>) {
       Log.i("angcyo", "log fun2")

   }

   override fun testFun3(arg1: String, arg2: List<String>): String {
       Log.i("angcyo", "log fun3")
       return "fun3"
   }
}

之後, 我們用動態代理技術, 可以攔截所有的方法請求.

你可以任意修改返回值, 或者執行其他操作;

3.建立動態代理

 //代理 target 物件, 攔截真實物件的操作, 做自己想做的事
  val proxy = Proxy.newProxyInstance(this.classLoader, arrayOf(ITarget::class.java)) { proxy, method, args ->
      if (method.name == "toString") {
          null
      } else {
          Log.i("angcyo", "呼叫方法:$method 返回型別:${method.returnType}")
          args?.let {
              for (any in it) {
                  Log.i("angcyo", "引數型別:" + any.javaClass.simpleName)
              }
          }

          if (method.name == "testFun4") {
              method.invoke(oldTarget, *args)
          }
      }
      null
  }

建立好了代理物件之後, 將代理物件強制賦值給原來的物件.

//通常情況下, 都是採用反射的方式, 用新的代理物件替換原來的真實物件.
val targetField = this.javaClass.getDeclaredField("target")
targetField.isAccessible = true
targetField.set(this, proxy)

之後, 呼叫物件的方法, 就會被代理物件攔截並執行.

 fun onTest(view: View) {
     //之後呼叫物件的方法, 都會被代理類執行
     target.testFun1()
     target.testFun2("fun2", listOf("1", "2"))
     val res3 = target.testFun3("fun3", listOf("a", "b", "c"))
     Log.i("angcyo", "result:" + res3)
     val res4 = target.testFun4("fun4", arrayListOf("1", "2"))
     Log.i("angcyo", "result:" + res4)
 }

也許你還想學習更多, 來我的群吧, 我寫程式碼的能力, 遠大於寫文章的能力:

聯絡作者

請使用QQ掃碼加群, 小夥伴們都在等著你哦!

關注我的公眾號, 每天都能一起玩耍哦!