As you probably know, ButterKnife is an annotation processor that takes your code at compile time, evaluates the annotations (eg. @BindView
) and generates code to replace them with.
Now in the case of @BindView
what the annotation processor actually does is:
- find the desired view by its ID
and
- cast it to the expected type.
So a functional equivalent of your example would be something like this:
public class FriendsHolder extends RecyclerView.ViewHolder {
private TextView textName;
private CircleImageView imageView;
private TextView textTitle;
private TextView textCompany;
FriendsHolder(View itemView) {
super(itemView);
bindViews(itemView);
}
private void bindViews(View root) {
textName = (TextView) root.findViewById(R.id.name);
imageView = (CircleImageView) root.findViewById(R.id.image);
textTitle = (TextView) root.findViewById(R.id.title);
textCompany = (TextView) root.findViewById(R.id.company);
}
}
You can read more about the underlying processes in this blog post or have a look at some of the ButterKnife source code.
Where you can see that essentially what they do is look for the ID on the source view and try to cast it to the expected type that was read from the annotated field.
Excerpt from butterknife.internal.Utils
:
public static <T> T findRequiredViewAsType(View source, @IdRes int id, String who, Class<T> cls) {
View view = findRequiredView(source, id, who);
return castView(view, id, who, cls);
}
public static View findRequiredView(View source, @IdRes int id, String who) {
View view = source.findViewById(id);
if (view != null) {
return view;
}
// If view is null throw IllegalStateException
}
public static <T> T castView(View view, @IdRes int id, String who, Class<T> cls) {
try {
return cls.cast(view); // <-- casting
} catch (ClassCastException e) {
throw new IllegalStateException
// Exception handling...
}