一、源代码
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()
}
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)
}
fun injectContentView(context: Context) {
val clazz = context.javaClass
val contentView = clazz.getAnnotation(ContentView::class.java)
contentView?.apply {
val setContentViewMethod = clazz.getMethod("setContentView", Int::class.java)
setContentViewMethod.invoke(context, value)
}
}
private fun injectView(context: Context) {
val clazz = context.javaClass
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)
val view = findViewByIdMethod.invoke(context, value)
it.set(context, view)
}
}
}
private fun injectViewEvent(context: Context) {
val clazz = context.javaClass
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
(declaredMethod.invoke(it) as IntArray).takeIf {
it.isNotEmpty()
}?.forEach {
val findViewByIdMethod = clazz.getMethod("findViewById", Int::class.java)
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)
}
viewEventMethod.invoke(this, proxyClickListener)
}
}
}
}
}
}
}