分析方法,从入口Debug单步调试
入口,从Activity的OnCreate中的 ButterKnife.bind(this) 入手
@NonNull @UiThread
public static Unbinder
bind(
@NonNull Activity target) {
View sourceView = target.getWindow().getDecorView()
;
return
createBinding(target
, sourceView)
;
拿到DecorView,即根View,传入createBinding方法
private static
Unbinder
createBinding
(
@NonNull
Object target
,
@NonNull
View source) {
Class<?> targetClass = target.getClass()
;
if
(
debug
) Log.
d
(
TAG
,
"Looking up binding for "
+ targetClass.getName())
;
Constructor<?
extends
Unbinder> constructor =
findBindingConstructorForClass
(targetClass)
;
if
(constructor ==
null
) {
return
Unbinder.
EMPTY
;
}
//noinspection TryWithIdenticalCatches Resolves to API 19+ only type.
try
{
return
constructor.newInstance(target
,
source)
;
}
catch
(IllegalAccessException e) {
throw new
RuntimeException(
"Unable to invoke "
+ constructor
,
e)
;
}
catch
(InstantiationException e) {
throw new
RuntimeException(
"Unable to invoke "
+ constructor
,
e)
;
}
catch
(InvocationTargetException e) {
Throwable cause = e.getCause()
;
if
(cause
instanceof
RuntimeException) {
throw
(RuntimeException) cause
;
}
if
(cause
instanceof
Error) {
throw
(Error) cause
;
}
throw new
RuntimeException(
"Unable to create binding instance."
,
cause)
;
}
}
通过反射拿到 target的Class对象,这里的target是要绑定的Activity
然后调用
findBindingConstructorForClass
(targetClass)
;
@Nullable @CheckResult @UiThread
private static
Constructor<?
extends
Unbinder>
findBindingConstructorForClass
(Class<?> cls) {
Constructor<?
extends
Unbinder> bindingCtor =
BINDINGS
.get(cls)
;
if
(bindingCtor !=
null
) {
if
(
debug
) Log.
d
(
TAG
,
"HIT: Cached in binding map."
)
;
return
bindingCtor
;
}
String clsName = cls.getName()
;
if
(clsName.startsWith(
"android."
) || clsName.startsWith(
"java."
)) {
if
(
debug
) Log.
d
(
TAG
,
"MISS: Reached framework class. Abandoning search."
)
;
return null;
}
try
{
Class<?> bindingClass = cls.getClassLoader().loadClass(clsName +
"_ViewBinding"
)
;
//noinspection unchecked
bindingCtor = (Constructor<?
extends
Unbinder>) bindingClass.getConstructor(cls
,
View.
class
)
;
if
(
debug
) Log.
d
(
TAG
,
"HIT: Loaded binding class and constructor."
)
;
}
catch
(ClassNotFoundException e) {
if
(
debug
) Log.
d
(
TAG
,
"Not found. Trying superclass "
+ cls.getSuperclass().getName())
;
bindingCtor =
findBindingConstructorForClass
(cls.getSuperclass())
;
}
catch
(NoSuchMethodException e) {
throw new
RuntimeException(
"Unable to find binding constructor for "
+ clsName
,
e)
;
}
BINDINGS
.put(cls
,
bindingCtor)
;
return
bindingCtor
;
}
此方法是找出Acitvity_ViewBinding.class的Constructor对象
Activity_ViewBing是ButterKnife编译生成的class
在此class中,将注入的View和Activity关联起来
BINDINGS 是XXXActivity_ViewBinding的缓存,就是LinkedHashMap
在createBindging方法中调用
constructor.newInstance(target
,
source)
;
即调用XXXActivity_ViewBindng的构造方法
public class
AppSettingsActivity_ViewBinding
implements
Unbinder {
private
AppSettingsActivity
target
;
private
View
view2131296303
;
private
View
view2131296299
;
private
View
view2131296479
;
@UiThread
public
AppSettingsActivity_ViewBinding
(AppSettingsActivity target) {
this
(target
,
target.getWindow().getDecorView())
;
}
@UiThread
public
AppSettingsActivity_ViewBinding
(
final
AppSettingsActivity target
,
View source) {
this
.
target
= target
;
View view
;
target.
mAppName
= Utils.
findRequiredViewAsType
(source
,
R.id.
app_name
,
"field 'mAppName'"
,
TextView.
class
)
;
view = Utils.
findRequiredView
(source
,
R.id.
app_upgrade
,
"field 'mAppUpdate' and method 'updateApp'"
)
;
target.
mAppUpdate
= Utils.
castView
(view
,
R.id.
app_upgrade
,
"field 'mAppUpdate'"
,
TextView.
class
)
;
view2131296303
= view
;
view.setOnClickListener(
new
DebouncingOnClickListener() {
@Override
public void
doClick
(View p0) {
target
.updateApp()
;
}
})
;
target.
mCacheSize
= Utils.
findRequiredViewAsType
(source
,
R.id.
cache_size
,
"field 'mCacheSize'"
,
TextView.
class
)
;
target.
mToolbar
= Utils.
findRequiredViewAsType
(source
,
R.id.
toolbar
,
"field 'mToolbar'"
,
Toolbar.
class
)
;
view = Utils.
findRequiredView
(source
,
R.id.
app_clean
,
"method 'cleanCache'"
)
;
view2131296299
= view
;
view.setOnClickListener(
new
DebouncingOnClickListener() {
@Override
public void
doClick
(View p0) {
target
.cleanCache()
;
}
})
;
view = Utils.
findRequiredView
(source
,
R.id.
ic_launcher
,
"method 'setDevelopMode'"
)
;
view2131296479
= view
;
view.setOnClickListener(
new
DebouncingOnClickListener() {
@Override
public void
doClick
(View p0) {
target
.setDevelopMode()
;
}
})
;
}
@Override
@CallSuper
public void
unbind
() {
AppSettingsActivity target =
this
.
target
;
if
(target ==
null
)
throw new
IllegalStateException(
"Bindings already cleared."
)
;
this
.
target
=
null;
target.
mAppName
=
null;
target.
mAppUpdate
=
null;
target.
mCacheSize
=
null;
target.
mToolbar
=
null;
view2131296303
.setOnClickListener(
null
)
;
view2131296303
=
null;
view2131296299
.setOnClickListener(
null
)
;
view2131296299
=
null;
view2131296479
.setOnClickListener(
null
)
;
view2131296479
=
null;
}
}
在Utils.findRequiredView中使用了findViewById方法,说明实际还是通过findViewById拿到View对象的
可借鉴学习的地方:(1)使用LinkedHashmap做缓存