Android依赖注入

一、源代码

1.1 MainActivity

package com.piaopiao.singleinstancekotlin

import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import android.view.View
import android.widget.Button
import android.widget.Toast

@ContentView(R.layout.activity_main)
class MainActivity : AppCompatActivity() {

    @InjectView(R.id.btn1)
    private var btn1: Button? = null

    @InjectView(R.id.btn2)
    private var btn2: Button? = null

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        InjectUtils.inject(this)
        btn1?.text = "哈哈哈1"
        btn2?.text = "哈哈哈2"

    }

    @OnClick(R.id.btn1, R.id.btn2)
    fun onClick(view: View) {
        when (view.id) {
            R.id.btn1 -> Toast.makeText(this, "哈哈哈1", Toast.LENGTH_SHORT).show()
            R.id.btn2 -> Toast.makeText(this, "哈哈哈2", Toast.LENGTH_SHORT).show()
        }
    }

    @OnLongClick(R.id.btn1, R.id.btn2)
    fun onLongClick(view: View): Boolean {
        when (view.id) {
            R.id.btn1 -> Toast.makeText(this, "onLongClick===哈哈哈1", Toast.LENGTH_SHORT).show()
            R.id.btn2 -> Toast.makeText(this, "onLongClick===哈哈哈2", Toast.LENGTH_SHORT).show()
        }
        //返回true,事件不再向下传递
        return true
    }

}

1.2 InjectUtils

import android.content.Context
import java.lang.reflect.Proxy

object InjectUtils {

    fun inject(context: Context) {
        injectContentView(context)
        injectView(context)
        injectViewEvent(context)
    }

    /**
     * ioc编译文件
     *
     * @param context
     */
    fun injectContentView(context: Context) {
        val clazz = context.javaClass
        //获取当前Activity的字节码文件
        val contentView = clazz.getAnnotation(ContentView::class.java)
        //说明上面存在注解ContentView
        contentView?.apply {
            val setContentViewMethod = clazz.getMethod("setContentView", Int::class.java)
            //执行当前Activity的setContentView方法
            setContentViewMethod.invoke(context, value)
        }

    }

    /**
     * 注册View组件
     *
     * @param context
     */
    private fun injectView(context: Context) {
        val clazz = context.javaClass
        //获取当前Activity的所有字段,用getDeclaredFields不管什么修饰符都可以拿到
        clazz.declaredFields.takeIf {
            it.isNotEmpty()
        }?.forEach {
            //设置访问权限
            it.isAccessible = true
            it.getAnnotation(InjectView::class.java)?.takeIf { it ->
                it.value > -1
            }?.apply {
                val findViewByIdMethod = clazz.getMethod("findViewById", Int::class.java)
                //执行findViewById方法获取到View
                val view = findViewByIdMethod.invoke(context, value)
                //把找到的View交给当前字段field
                it.set(context, view)
            }
        }
    }

    /**
     * 处理点击事件
     *
     *
     * btn1.setOnLongClickListener(new View.OnLongClickListener() {
     *
     * @param context
     * @Override public boolean onLongClick(View v) {
     * return false;
     * }
     * });
     *
     *
     * btn1.setOnClickListener(new View.OnClickListener() {
     * @Override public void onClick(View v) {
     *
     *
     * }
     * });
     */
    private fun injectViewEvent(context: Context) {
        val clazz = context.javaClass
        //获取当前Activity字节码的所有方法
        clazz.declaredMethods.takeIf {
            it.isNotEmpty()
        }?.forEach { currentMethod ->
            currentMethod.isAccessible = true
            //获取该方法上面的所有注解
            currentMethod.declaredAnnotations.takeIf {
                it.isNotEmpty()
            }?.forEach {
                //获取该注解的类型
                val annotationClass = it.annotationClass.java
                annotationClass.getAnnotation(BaseEvent::class.java)?.apply {
                    val declaredMethod = annotationClass.getDeclaredMethod("value")
                    declaredMethod.isAccessible = true
                    //拿到ViewId
                    (declaredMethod.invoke(it) as IntArray).takeIf {
                        it.isNotEmpty()
                    }?.forEach {
                        val findViewByIdMethod = clazz.getMethod("findViewById", Int::class.java)
                        //找到id对应控件
                        findViewByIdMethod.invoke(context, it)?.apply {
                            //获取控件想要设置的办法
                            val viewEventMethod =
                                this::class.java.getMethod(setEventName, setEventType.java)
                            //获取代理对象
                            val proxyClickListener = Proxy.newProxyInstance(
                                setEventType.java.classLoader,
                                arrayOf(setEventType.java)
                            ) { proxy, method, args ->
                                //在数组对象前加*号可以将数组展开方便传值
                                currentMethod.invoke(context, *args)
                            }
                            //将代理对象作为参数传递给view的相应事件
                            viewEventMethod.invoke(this, proxyClickListener)
                        }
                    }
                }
            }
        }
    }
}

源代码

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值