Summary of IOC Framework Using Android Butterknife

Preface:
ButterKnife is a View injection framework focusing on Android systems. It used to write a lot of findViewById to find View objects. With ButterKnife, these steps can be easily eliminated. Jake Wharton's masterpiece is widely used. Most importantly, using ButterKnife has little loss of performance, because the annotations ButterKnife uses are not reflected at run time, but generate new class es at compile time. Project integration is also particularly convenient and easy to use.

Learn how to use ButterKnife in a project by learning this article. This paper contains the following points:

  • Preface
    • Brief introduction
    • Advantages of ButterKnife
  • Basic configuration
  • ButterKnife Registration and Binding
    • ButterKnife's Use Experience and Notices
    • Binding ButterKnife in Activity
    • Binding ButterKnife in Fragment
    • Binding ButterKnife in Adapter
  • Basic use of ButterKnife
    • Binding View
    • Binding resources
    • Event binding
    • Binding monitoring
    • Using findById
    • Setting attributes for multiple view s
    • Use precautions
    • More Binding Annotations
    • More Event Annotations
  • ButterKnife's code obfuscation
  • Butterknife plug-in: zelezny
    • Plug-in installation
    • Plug-in usage

ButterKnife project address: https://github.com/JakeWharton/butterknife

_Advantages of ButterKnife:

1. Powerful View Binding and Click Event Processing Function, Simplify Code, Improve Development Efficiency

2. Handling ViewHolder Binding in Adapter Conveniently

3. Running time will not affect the efficiency of APP, easy to use and configure.

4. Clear code and readability

Basic configuration
Configure the use of ButterKnife in the android Studio project

  • Step one: Add the following code to Project build.gradle:
buildscript {
    repositories {
        jcenter()
    }
    dependencies {
        classpath 'com.android.tools.build:gradle:2.3.3'
        classpath 'com.jakewharton:butterknife-gradle-plugin:8.8.1'  //Add this line
    }
}
  • Step two: Add the following code to App's build.gradle:
apply plugin: 'com.jakewharton.butterknife'
  • Add:
compile 'com.jakewharton:butterknife:8.8.1'
annotationProcessor 'com.jakewharton:butterknife-compiler:8.8.1'

Building the environment is particularly simple, so let's see how to use it.

ButterKnife Registration and Binding

_ButterKnife's Use Experience and Notices:

1. Binding in the Activity class: ButterKnife.bind(this); must be set ContentView (); then binding; and after the parent bind binding, the subclass does not need to bind.

2. Binding in non-Activity classes (eg: Fragment, ViewHold): ButterKnife.bind(this, view); here this cannot be replaced by getActivity ().

3. There is no need to do unbind operation in Activity. In Fragment, it must do unbind operation in onDestroyView().

4. Use ButterKnife to modify methods and controls. Do not use private or static to modify them. Otherwise, errors will be reported. Error: @BindView fields must not be private or static. (com.zyj.wifi.ButterknifeActivity.button1)

5. setContentView() cannot be implemented through annotations. (Other annotation frameworks can)

6. When using Activity to bind any object for the root view, if you use a design pattern similar to MVC, you can call ButterKnife.bind(this, activity) in Activity to bind Controller.

7. Use ButterKnife.bind(this, view) to bind the child node fields of a view. If you use inflate in the layout of a child view or in the construction method of a custom view, you can call this method immediately. Alternatively, a custom view type from XML inflate can be used in the onFinishInflate callback method.

_Binding ButterKnife in Activity:

Since onCreate binds Activity in Activity every time, I suggest writing a BaseActivity to complete the binding and inherit subclasses. Binding Activity must be after setContentView. Use ButterKnife.bind(this) for binding. The code is as follows:

public class MainActivity extends AppCompatActivity{  
    @Override  
    protected void onCreate(Bundle savedInstanceState) {  
        super.onCreate(savedInstanceState);  
        setContentView(R.layout.activity_main);  
        //Binding Initialization ButterKnife  
        ButterKnife.bind(this);  
    }  
}  

_Binding ButterKnife in Fragment:

Fragment's life cycle is different from activity. When binding a Fragment in onCreateView, set the view to null in onDestroyView. When you call bind to bind a Fragment to you, Butter Knife returns an instance of Unbinder. Call its unbind method in the appropriate life cycle (onDestroyView) callback for fragment unbinding. Use ButterKnife.bind(this, view) for binding. The code is as follows:

public class ButterknifeFragment extends Fragment{  
    private Unbinder unbinder;  
    @Override  
    public View onCreateView(LayoutInflater inflater, ViewGroup container,  
                             Bundle savedInstanceState) {  
        View view = inflater.inflate(R.layout.fragment, container, false);  
        //Return an Unbinder value (unbind), note that this cannot use getActivity()  
        unbinder = ButterKnife.bind(this, view);  
        return view;  
    }  

    /** 
     * onDestroyView Unbundling 
     */  
    @Override  
    public void onDestroyView() {  
        super.onDestroyView();  
        unbinder.unbind();  
    }  
}  

_Binding ButterKnife in Adapter:

In the ViewHolder of the Adapter, add a constructor to the ViewHolder and pass in the view when the new ViewHolder is in use. Using ButterKnife.bind(this, view) to bind, the code is as follows:

public class MyAdapter extends BaseAdapter {  

  @Override   
  public View getView(int position, View view, ViewGroup parent) {  
    ViewHolder holder;  
    if (view != null) {  
      holder = (ViewHolder) view.getTag();  
    } else {  
      view = inflater.inflate(R.layout.testlayout, parent, false);  
      holder = new ViewHolder(view);  
      view.setTag(holder);  
    }  

    holder.name.setText("Donkor");  
    holder.job.setText("Android");
    // etc...  
    return view;  
  }  

  static class ViewHolder {  
    @BindView(R.id.title) TextView name;  
    @BindView(R.id.job) TextView job;  

    public ViewHolder(View view) {  
      ButterKnife.bind(this, view);  
    }  
  }  
}  

Basic use of ButterKnife

_Binding View:

  • Control id annotation: @BindView()
@BindView( R2.id.button)  
public Button button;   
  • Multiple control id annotations in the layout: @BindViews()
public class MainActivity extends AppCompatActivity {  

    @BindViews({ R2.id.button1, R2.id.button2,  R2.id.button3})  
    public List<Button> buttonList ;  

    @Override  
    protected void onCreate(Bundle savedInstanceState) {  
        super.onCreate(savedInstanceState);  
        setContentView(R.layout.activity_main);  

        ButterKnife.bind(this);  

        buttonList.get( 0 ).setText( "hello 1 ");  
        buttonList.get( 1 ).setText( "hello 2 ");  
        buttonList.get( 2 ).setText( "hello 3 ");  
    }  
}  

_Binding resources:

  • Binding string: @BindString()
public class MainActivity extends AppCompatActivity {  

    @BindView(R2.id.button) //Binding button controls  
    public Button button ;  

    @BindString(R2.string.app_name)  //string strings in binding resource files  
    String str;  

    @Override  
    protected void onCreate(Bundle savedInstanceState) {  
        super.onCreate(savedInstanceState);  
        setContentView(R.layout.activity_main);  
        //Binding activity  
        ButterKnife.bind( this ) ;  
        button.setText( str );  
    }  
}  
  • Array array in binding string: @BindArray()
<resources>  
    <string name="app_name">City</string>  

    <string-array name="city">  
        <item>Beijing City</item>  
        <item>Tianjin City</item>  
        <item>Harbin City</item>  
        <item>Dalian</item>  
        <item>Hongkong City</item>  
    </string-array>  

</resources>  

------------------------------------------------------------------------------

public class MainActivity  extends AppCompatActivity {  

    @BindView(R2.id.button) //Binding button controls  
    public Button button ;  

    @BindString(R2.string.app_name)  //string strings in binding resource files  
    String str;  

    @BindArray(R2.array.city)  //Array array in binding string  
    String [] citys ;  

    @Override  
    protected void onCreate(Bundle savedInstanceState) {  
        super.onCreate(savedInstanceState);  
        setContentView(R.layout.activity_main);  
        //Binding activity  
        ButterKnife.bind( this ) ;  
        button.setText(citys[0]);  
    }  
}  
  • Binding Bitmap resources: @BindBitmap()
public class MainActivity extends AppCompatActivity {  

    @BindView( R2.id.imageView ) //Binding ImageView controls  
    public ImageView imageView ;  

    @BindBitmap( R2.mipmap.bm)//Binding Bitmap resources  
    public Bitmap bitmap ;  

    @Override  
    protected void onCreate(Bundle savedInstanceState) {  
        super.onCreate(savedInstanceState);  
        setContentView(R.layout.activity_main);  

        //Binding activity  
        ButterKnife.bind( this ) ;  

        imageView.setImageBitmap(bitmap);  
    }  

}  
  • Bind a color value: @BindColor()
public class MainActivity extends AppCompatActivity {  

    @BindView( R2.id.button)  //Binding a control  
    public Button button;  

    @BindColor( R2.color.colorAccent ) //Specific color values in color files  
    int black ;  //Binding a color value  

    @Override  
    protected void onCreate(Bundle savedInstanceState) {  
        super.onCreate(savedInstanceState);  
        setContentView(R.layout.activity_main);  

        //Binding activity  
        ButterKnife.bind( this ) ;  

        button.setTextColor(  black );  
    }  
}  

_Event binding:

  • Binding click events:

    • Binding control click event: @OnClick()

    • Binding control long press event: @OnLongClick()

public class MainActivity extends AppCompatActivity {  

    @OnClick(R2.id.button1 )   //Set a click event for button1  
    public void showToast(){  
        Toast.makeText(this, "is a click", Toast.LENGTH_SHORT).show();  
    }  

    @OnLongClick( R2.id.button1 )    //Set a long press event for button1  
    public boolean showToast2(){  
        Toast.makeText(this, "is a long click", Toast.LENGTH_SHORT).show();  
        return true ;  
    }  

    @Override  
    protected void onCreate(Bundle savedInstanceState) {  
        super.onCreate(savedInstanceState);  
        setContentView(R.layout.activity_main);  

        //Binding activity  
        ButterKnife.bind( this ) ;  
    }  
}  
  • Specify multiple id binding events:
public class MainActivity extends AppCompatActivity {  

    //Tip: When it comes to binding multiple id events, we can use Android studio's Butterknife
    //The plug-in zelezny is generated quickly and automatically, and the installation and use of the plug-in are described below.  
    @OnClick({R.id.ll_product_name, R.id.ll_product_lilv, R.id.ll_product_qixian, R.id.ll_product_repayment_methods})  
    public void onViewClicked(View view) {  
        switch (view.getId()) {  
            case R.id.ll_product_name:  
                System.out.print("I'm Clicking Event 1");  
                break;  
            case R.id.ll_product_lilv:  
                System.out.print("I'm Clicking Event 2");  
                break;  
            case R.id.ll_product_qixian:  
                System.out.print("I'm Clicking Event 3");  

                break;  
            case R.id.ll_product_repayment_methods:  
                System.out.print("I'm Clicking Event 4");  
                break;  
        }  
    }  

    @Override  
    protected void onCreate(Bundle savedInstanceState) {  
        super.onCreate(savedInstanceState);  
        setContentView(R.layout.activity_main);  

        //Binding activity  
        ButterKnife.bind( this ) ;  
    }  
}

From the example above, we can see that multiple clicks are useless for R2. If you have to use the writing of R2, you can write it one by one. The correct writing is as follows:

public class MainActivity extends AppCompatActivity {    

    @OnClick(R2.id.ll_product_name)    
    public void onViewClicked1(View view) {    
       System.out.print("I'm Clicking Event 1");               
    }    
    @OnClick(R2.id.ll_product_lilv)    
    public void onViewClicked2(View view) {    
       System.out.print("I'm Clicking Event 2");     
    }   
    @OnClick(R2.id.ll_product_qixian)    
    public void onViewClicked3(View view) {    
       System.out.print("I'm Clicking Event 3");               
    }    
    @OnClick(R2.id.ll_product_repayment_methods)    
    public void onViewClicked4(View view) {    
       System.out.print("I'm Clicking Event 4");               
    }    

    @Override    
    protected void onCreate(Bundle savedInstanceState) {    
        super.onCreate(savedInstanceState);    
        setContentView(R.layout.activity_main);    

        //Binding activity    
        ButterKnife.bind( this ) ;    
    }    
}    

  • Custom View Using Binding Events

Without specifying id, comment OnClick directly. Looking at the code feels like a way to implement click events. In fact, the OnClickListener interface is not implemented. The code is as follows:

public class MyButton extends Button {  
  @OnClick  
  public void onClick() {}  
}  

_Binding Monitoring:

  • Listeners can be automatically configured into methods
@OnClick(R.id.submit)  
public void submit(View view) {  
  // TODO submit data to server...  
}  
  • All parameters of the listener method are optional
@OnClick(R.id.submit)  
public void submit() {  
  // TODO submit data to server...  
}  
  • Customize a specific type, which will be automatically converted
@OnClick(R.id.submit)  
    public void sayHi(Button button) {//See the change of parameters in parentheses.  
      button.setText("Hello!");  
    }  
  • Specify multiple IDS in a single binding for common event handling. Here is an example of click events. Other event monitoring is also possible.
@OnClick(R.id.submitCode,R.id.submitFile,R.id.submitTest)  
    public void sayHi(Button button) {//Multiple controls correspond to public events
      button.setText("Success!");  
    }  
  • Custom views can be bound to their own listeners by not specifying an ID.
public class FancyButton extends Button {  
  @OnClick  
  public void onClick() {  
    // TODO do something!  
  }  
}
  • Multi-method Annotation in Listener

Method annotations, whose corresponding listeners have multiple callbacks, can be used to bind to any of them. Each comment has a default callback that it binds to. Use the callback parameter to specify a replacement. Take Spinner for example.
Original code:

Spinner s=new Spinner(this);  
       //The original method: Spinner entry chooses the normal way to write listening events  
       s.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener(){  
           @Override  
           public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {  
           }  
           @Override  
           public void onNothingSelected(AdapterView<?> parent) {  
           }  
       }); 

Through Butter Knife annotations

public class MainActivity extends AppCompatActivity {  
    /*Selective listening event handling for Spinner item using annotations*/  
    @OnItemSelected(R.id.my_spiner)//The default callback is ITEM_SELECTED  
    void onItemSelected(int position) {  
        Toast.makeText(this, "position: " + position, Toast.LENGTH_SHORT).show();  
    }  
    /* 
    * Annotation onNothing Selected requires adding a callback to the annotation parameter. 
    * Note that whenever there is data in Spinner, the default is to select the 0th data, so if you want to enter the onNothingSelected() method, you need to empty the data in the Adapter. 
    */  
    @OnItemSelected(value = R.id.my_spiner, callback = OnItemSelected.Callback.NOTHING_SELECTED)  
    void onNothingSelected() {  
        Toast.makeText(this, "Nothing", Toast.LENGTH_SHORT).show();  
    }  

    @Override  
    protected void onCreate(Bundle savedInstanceState) {  
        super.onCreate(savedInstanceState);  
        setContentView(R.layout.activity_main);  

        //Binding activity  
        ButterKnife.bind( this ) ;  
        Spinner s=new Spinner(this);  
    }  
}  
  • @ Use of OnCheckedChanged Monitoring

The original method should be setOnCheckedChangeListener(). Use chestnuts

<?xml version="1.0" encoding="utf-8"?>  
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"  
    android:layout_width="match_parent"  
    android:layout_height="match_parent"  
    android:orientation="vertical">  

    <RadioGroup  
        android:id="@+id/rg_main"  
        android:layout_width="fill_parent"  
        android:layout_height="48dp"  
        android:layout_alignParentBottom="true"  
        android:background="@color/white"  
        android:orientation="horizontal">  

        <RadioButton  
            android:id="@+id/rg_home"  
            android:layout_width="match_parent"  
            android:layout_height="match_parent"  
            android:focusable="false"  
            android:text="@string/nav_one" />  

        <RadioButton  
            android:id="@+id/rg_wealth"  
            android:layout_width="match_parent"  
            android:layout_height="match_parent"  
            android:focusable="false"  
            android:text="@string/nav_two" />  

        <RadioButton  
            android:id="@+id/rg_account"  
            android:layout_width="match_parent"  
            android:layout_height="match_parent"  
            android:focusable="false"  
            android:text="@string/nav_four" />  
    </RadioGroup>  

</LinearLayout>  

-------------------------------------------------------------------------

@OnCheckedChanged({R.id.rg_home,R.id.rg_wealth,R.id.rg_account})  
    public void OnCheckedChangeListener(CompoundButton view, boolean ischanged ){  
        switch (view.getId()) {  
            case R.id.rg_home:  
                if (ischanged){//Note: This judgment must be made here. Only when the button corresponding to the id is clicked and the ischanged state changes, will the following be executed  
                    //Write the UI of your button's changing state and related logic here.  
                }  
                break;  
            case R.id.rg_wealth:  
                if (ischanged) {  
                    //Write the UI of your button's changing state and related logic here.  
                }  
                break;  
            case R.id.rg_account:  
                if (ischanged) {  
                    //Write the UI of your button's changing state and related logic here.  
                }  
                break;  
            default:  
                break;  
        }  
    }  

_Use findById:

Butter Knife still contains the findById() method for initializing views from a view, Activity, or Dialog, and it can automatically convert types.

View view = LayoutInflater.from(context).inflate(R.layout.thing, null);  
TextView firstName = ButterKnife.findById(view, R.id.first_name);  
TextView lastName = ButterKnife.findById(view, R.id.last_name);  
ImageView iv = ButterKnife.findById(view, R.id.iv);  

_Setting attributes of multiple view s:

  • apply()

Function: Allows you to immediately manipulate all views in the list.

  • Action and Setter interfaces

Role: The Action and Setter interfaces allow you to specify simple behavior.

public class MainActivity extends AppCompatActivity {  

    @BindViews({R2.id.first_name, R2.id.middle_name, R2.id.last_name})  
    List<EditText> nameViews;  

    @Override  
    protected void onCreate(Bundle savedInstanceState) {  
        super.onCreate(savedInstanceState);  
        setContentView(R.layout.activity_main);  

        //Binding activity  
        ButterKnife.bind(this);  

        //Setting attributes for multiple view s  
        //Mode 1: Transfer values  
        ButterKnife.apply(nameViews, DISABLE);  
        //Mode 2: Specified values  
        ButterKnife.apply(nameViews, ENABLED, false);  
        //// Mode 3 Sets View's Property  
        ButterKnife.apply(nameViews, View.ALPHA, 0.0f);//An Android attribute can also be used for application methods.  
    }  

    /* 
    * Action Interface Settings Properties 
    */  
    static final ButterKnife.Action<View> DISABLE = new ButterKnife.Action<View>() {  
        @Override  
        public void apply(View view, int index) {  
            view.setEnabled(false);//The goal is to make multiple view s have this attribute  
        }  
    };  
    /* 
    * Setter Interface Settings Properties 
    */  
    static final ButterKnife.Setter<View, Boolean> ENABLED = new ButterKnife.Setter<View, Boolean>() {  
        @Override  
        public void set(View view, Boolean value, int index) {  
            view.setEnabled(value);//The goal is to make multiple view s have this property, and variable boolean values are transferable  
        }  
    };  
}  

_Cautions for Use:

  • ButterKinfe's annotation tags vary depending on the version.
    Bind tags before 8.0.0 became BindView after 8.0.0, and after 8.7.0, when Binding view, R2.id.XXX is used instead of R.id.XXX.

Specific changes and view submission logs on gitHub:
https://github.com/JakeWharton/butterknife/blob/master/CHANGELOG.md#version-800-2016-04-25

  • By default, @bind and listener bindings are required. If the target view cannot be found, an exception is thrown.
    To suppress this behavior and create optional bindings, you can add @Nullable annotations to fields or @Optional annotations to methods.

Any annotation named @Nullable can be used for member variables. It is recommended to use the @Nullable annotation in android's "support-annotations" library.

@Nullable  
@BindView(R.id.might_not_be_there)   
TextView mightNotBeThere;  

@Optional  
@OnClick(R.id.maybe_missing)   
public void onMaybeMissingClicked() {  
    // TODO ...  
}  

_More binding annotations:

@ BindView - - > Binds a view; id is a view variable

@ BindViews - > binds multiple views; id is a list variable for a view

@ Bind Array - > Bind Array array in string; @Bind Array (R. array. city) String [] citys;

@ Bind Bitmap - > Bind image resource is Bitmap; @Bind Bitmap (R.mipmap.wifi) Bitmap bitmap;

@ BindBool - - > Bind boolean value

@ BindColor - > Bind color; @BindColor (R. color. color Accent) int black;

@ BindDimen - > Bind Dimen; @BindDimen(R.dimen.borth_width) int mBorderWidth;

@ Bind Drawable - > Bind Drawable; @Bind Drawable (R. drawable. test_pic) Drawable mTestPic;

@ Bind float - > Bind float

@ BindInt - > Bind int

@ BindString - > binds a String id as a String variable; @BindString (R. string. app_name) String meg;

_More Event Annotations:

@ OnClick - - > Click Events

@ On Checked Changed - - > Check, uncheck

@ On Editor Action - > Function Key of Soft Keyboard

@ OnFocusChange - > Focus Change

@ OnItemClick item - > is clicked. (Note that there are pits here. If there are Button and other slightly clicked control events in item, you need to set the control property focusable to false.)

@ OnItemLongClick item - > long press (return can really intercept onItemClick)

@ OnItemSelected - > item selected event

@ OnLong Click - > Long Press Event

@ OnPageChange - > Page Change Events

@ OnTextChanged - - > EditText Text text change events

@ OnTouch - > Touch Events

@ Optional - > Selective injection, if the current object does not exist, will throw an exception, in order to suppress this exception, you can add a comment on the variable or method, so that injection becomes selective, if the target View exists, then injection does not exist, then nothing is done.

//Test @Optional
@Optional  
@OnCheckedChanged(R.id.cb_test)  
public void onCheckedChanged(CompoundButton buttonView,boolean isChecked){  
    if(isChecked){  
        tvTest.setText("checked...");  
    }else{  
        tvTest.setText("Cancelled...");  
    }  
}  

ButterKnife's code obfuscation

In the obfuscation file, add the following code:

-keep class butterknife.** { *; }  
-dontwarn butterknife.internal.**  
-keep class **$$ViewBinder { *; }  

-keepclasseswithmembernames class * {  
    @butterknife.* <fields>;  
}  

-keepclasseswithmembernames class * {  
    @butterknife.* <methods>;  
}  

Butterknife plug-in: zelezny

  • Plug-in Installation:

Toolbar File finds Settings... Or use the shortcut Ctrl+Alt+s to turn it on. Search zelezny to download the plug-in and install it, restart Android Studio

 
image
  • Plug-in uses:

After installing the plug-in, the AS will be prompted to restart. After restarting, you can write a layout and create a new code class test. During testing, it is important to move the cursor to setContentView(R.layout.acty_login), to R.layout.acty_login, and then right-click Generate. Here, a gif rendering is cited to show the advantages of plug-ins more intuitively. For multiple IDs that need to be bound, it saves time to tap the code manually.

 


Author: lisx_
Link: https://www.jianshu.com/p/3678aafdabc7
Source: Brief Book
The copyright of the brief book belongs to the author. For any form of reprinting, please contact the author for authorization and indicate the source.

Keywords: PHP ButterKnife Android Fragment Gradle

Added by ThunderVike on Wed, 29 May 2019 20:53:08 +0300