This is the third day of my participation in Gwen Challenge

Before you know it, the text challenge has come to the third day. Today, write an application of reflection and annotation

For those unfamiliar with reflection, read Understanding Java Reflection and dynamic Proxies in the JDK

For those unfamiliar with annotations, read understanding Advanced Java features annotations

First of all, this article is only an application of annotations and reflection, and there will be no discussion on Butterknife. The early implementation of Butterknife was also achieved by reflection and annotations. However, as we all know that reflection is very performance costly, Butterknife has changed its scheme, and this will be covered in future articles

1, to achieve the idea of view injection

When we realize a certain function, we must comb the logic first, we can’t start to write the requirements, so the written code is not only not good performance quality, but also often out of some unexpected bugs, so we have to develop a habit of thinking before writing the code!

So the view injection function, it automatically implements findViewById for us

How do we distinguish the View we want to inject from the other properties?

So naturally, we thought about our annotations, and we put a label on our View to say that this is the View that we need to inject

How do I get the injected view information and then execute findViewById

And that’s where we’re going to use our reflection, for those of you unfamiliar with reflection, to get the portal

We can use reflection to get all of the properties of the Activity object, and then we can tell which View we need to inject based on whether or not there’s an annotation that we define on the property, or we can use the annotation to get the ID that we need to inject, and then we can use the findViewById method to get the View instance, Reflection is then used to assign the view instance

2. Specific implementation of the code

The tag we implemented (annotations)

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)// applies to properties
public @interface InjectView {

    @IdRes int value (a);
}
Copy the code

First of all, the scope of our annotation should be on the attribute, so @target (elementType.field), because we use reflection to implement this function, the annotation life cycle is RUNTIME specific injection

public class InjectUtils {
    public static void injectView(Activity activity){
        Class<? extends Activity> activityClass=activity.getClass();

        // Get all members of this class
        Field[] declaareFields=activityClass.getDeclaredFields();
        for (Field declareField : declaareFields) {
            // Determine whether the attribute is declared by the InjectView annotation
            if(declareField.isAnnotationPresent(InjectView.class)){
                InjectView injectView=declareField.getAnnotation(InjectView.class);
                // Get the id in the annotation
                int viewId=injectView.value();
                View view=activity.findViewById(viewId);
                // Reflection sets the value of the property
                declareField.setAccessible(true);// Set the access permission to public
                try {
                    declareField.set(activity,view);// Set view to property
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                }
            }
        }

    }
}
Copy the code

GetFields gets all properties whose modifier is public, including the parent class. GetDeclaredFields gets all properties of this object, but not the parent class. You can get the superClass first and then use getDeclaredFields to get the private properties of the parent class and then use the Activity

public class MainActivity extends AppCompatActivity {
    @InjectView(R.id.tv_title)
    TextView tvTitle;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        InjectUtils.injectView(this);
        tvTitle.setText("The forgotten cool Open."); }}Copy the code

Operation effect:

3, summarize

In terms of annotations alone, annotations are pretty simple, but with annotations combined with other technologies, it can be fun, fun, and complicated! Bytecode enhancement, for example, is also a combination of annotations and bytecode technology! So let’s reinforce reflection and annotation with an example of an injected View! Now that I’ve implemented a View injection with annotations and reflection, you can use the same method to inject data after an Intent is passed!