Overview Butterknife is an open source library developed by Jake Wharton, who works at Square. Using this library and the Android ButterKnife Zelezny plugin in AS can greatly improve development efficiency, and you can get rid of the cumbersome findViewById(int id) and do not need to manually @bind(int id). You can directly use the plugin to generate it. This blog will analyze Butterknife in depth. Project address: JakeWharton/butterknife ButterKnife has the following advantages: 1. Powerful View binding and Click event processing functions to simplify code and improve development efficiency 2. Conveniently handle the ViewHolder binding problem in Adapter 3. It will not affect the efficiency of APP during operation and is easy to use and configure 4. The code is clear and readable How to import ButterKnife Configure the following in the project's build.grade file: - buildscript {
- repositories {
- jcenter()
- mavenCentral()
- Maven {
- url "https://plugins.gradle.org/m2/"
- }
- }
- dependencies {
- classpath 'com.android.tools.build:gradle:2.2.0'
- //Configure apt here for butterknife to use
- classpath 'com.neenbedankt.gradle.plugins:android-apt:1.8'
-
- }
- }
For example: - buildscript {
- repositories {
- jcenter()
- mavenCentral()
- Maven {
- url "https://plugins.gradle.org/m2/"
- }
-
- }
-
- dependencies {
- classpath 'com.android.tools.build:gradle:2.2.2'
- classpath 'com.neenbedankt.gradle.plugins:android-apt:1.8'
- }
- }
-
- allprojects {
- repositories {
- jcenter()
- }
- }
-
- task clean(type: Delete ) {
- delete rootProject.buildDir
- }
Configure the following in the app's build.grade file: - apply plugin: 'com.android.application'
- apply plugin: 'com.neenbedankt.android-apt'
-
- android{...}
-
- dependencies {
- //View binding butterknife
- compile 'com.jakewharton:butterknife:8.4.0'
- apt 'com.jakewharton:butterknife-compiler:8.4.0'
- }
For example: - apply plugin: 'com.android.application'
- apply plugin: 'android-apt'
-
- android {
- compileSdkVersion 24
- buildToolsVersion "24.0.3"
-
- defaultConfig {
-
- minSdkVersion 14
- targetSdkVersion 24
- versionCode 1
- versionName "1.0"
- }
- buildTypes {
- release {
- minifyEnabled false
- proguardFiles getDefaultProguardFile( 'proguard-android.txt' ), 'proguard-rules.pro'
- }
- }
- }
-
- dependencies {
- compile fileTree(dir: 'libs' , include: [ '*.jar' ])
-
- compile 'com.jakewharton:butterknife:8.4.0'
- apt 'com.jakewharton:butterknife-compiler:8.4.0'
- }
How to use ButterKnife 1) Since you need to bind the Activity in onCreate every time, I suggest writing a BaseActivity to complete the binding, and then the subclass can inherit it. Note: ButterKnife.bind(this); must be done after settingContentView when binding Activity: The implementation is as follows (the same as FragmentActivity): - public abstract class BaseActivity extends Activity {
- public abstract int getContentViewId();
-
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(getContentViewId());
- ButterKnife.bind(this);
- initAllMembersView(savedInstanceState);
- }
-
- protected abstract void initAllMembersView(Bundle savedInstanceState);
-
- @Override
- protected void onDestroy() {
- super.onDestroy();
- ButterKnife.unbind(this); //Unbind, the official document only unbinds fragments
- }
- }
2) Bind fragment - public abstract class BaseFragment extends Fragment {
- public abstract int getContentViewId();
- protected Context context;
- protected View mRootView;
-
- @Nullable
- @Override
- public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
- mRootView =inflater.inflate(getContentViewId(),container, false );
- ButterKnife.bind(this,mRootView);//Bind framgent
- this.context = getActivity();
- initAllMembersView(savedInstanceState);
- return mRootView;
- }
-
- protected abstract void initAllMembersView(Bundle savedInstanceState);
-
- @Override
- public void onDestroyView() {
- super.onDestroyView();
- ButterKnife.unbind(this); //Unbind
- }
- }
3) Control id annotation: @BindView() - package com.myl.test;
-
- import android.support.v7.app.AppCompatActivity;
- import android.os.Bundle;
- import android.widget.Button;
-
- import butterknife.BindView;
- import butterknife.ButterKnife;
-
- public class ButterknifeActivity extends AppCompatActivity {
-
- @BindView( R.id.button1 )
- public Button button1;
-
- // Note: The button's modification type cannot be: private or static . Otherwise, an error will be reported: Error: @BindView fields must not be private or static static . (com.myl.test.ButterknifeActivity.button1)
-
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_butterknife);
- //Bind activity
- ButterKnife.bind( this );
-
- button1.setText( "I am a button " );
- }
- }
4) Multiple control ID annotations: @BindViews() - package com.myl.test;
-
- import android.support.v7.app.AppCompatActivity;
- import android.os.Bundle;
- import android.widget.Button;
- import java.util.List;
- import butterknife.BindViews;
- import butterknife.ButterKnife;
-
- public class Main2Activity extends AppCompatActivity {
-
- @BindViews({ R.id.button1 , R.id.button2 , R.id.button3 })
- public List<Button> buttonList;
-
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_main2);
-
- ButterKnife.bind(this);
-
- buttonList.get( 0 ).setText( "hello 1 " );
- buttonList.get( 1 ).setText( "hello 2 " );
- buttonList.get( 2 ).setText( "hello 3 " );
- }
- }
5) @BindString(): Bind string - package com.myl.test;
-
- import android.os.Bundle;
- import android.support.v7.app.AppCompatActivity;
- import android.widget.Button;
-
- import butterknife.BindString;
- import butterknife.BindView;
- import butterknife.ButterKnife;
-
- public class ButterknifeActivity extends AppCompatActivity {
-
- @BindView( R.id.button1 ) //Bind button control
- public Button button1;
-
- @BindString( R.string.app_name ) // Bind string string
- String meg;
-
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_butterknife);
-
- //Bind activity
- ButterKnife.bind( this );
-
- button1.setText(meg);
- }
- }
6) @BindArray(): Bind the array in the string - <resources>
- <string name = "app_name" >Campus Assistant</string>
-
- <string-array name = "city" >
- <item>Dongguan City</item>
- <item>Guangzhou</item>
- <item>Zhuhai City</item>
- <item>Zhaoqing City</item>
- <item>Shenzhen City</item>
- </string-array>
-
- </resources>
-
- package com.myl.test;
-
- import android.os.Bundle;
- import android.support.v7.app.AppCompatActivity;
- import android.widget.Button;
-
- import butterknife.BindArray;
- import butterknife.BindView;
- import butterknife.ButterKnife;
-
- public class ButterknifeActivity extends AppCompatActivity {
-
- @BindView( R.id.button1 ) //Bind button control
- public Button button1;
-
- @BindArray(R.array.city) //Bind the array in string
- String [] cities;
-
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_butterknife);
-
- //Bind activity
- ButterKnife.bind( this );
-
- button1.setText( cities[0] );
- }
- }
7) @BindBitmap(): Bind Bitmap resource - package com.myl.test;
-
- import android.graphics.Bitmap;
- import android.os.Bundle;
- import android.support.v7.app.AppCompatActivity;
- import android.widget.ImageView;
-
- import butterknife.BindBitmap;
- import butterknife.BindView;
- import butterknife.ButterKnife;
-
- public class ButterknifeActivity extends AppCompatActivity {
-
- @BindView( R.id.imageView ) //Bind the ImageView control
- public ImageView imageView ;
-
- @BindBitmap( R.mipmap.wifi ) //Bind Bitmap resource
- public Bitmap wifi_bitmap;
-
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_butterknife);
-
- //Bind activity
- ButterKnife.bind( this );
-
- imageView.setImageBitmap(wifi_bitmap);
- }
- }
8) @BindColor(): Bind a color value - package com.myl.test;
-
- import android.os.Bundle;
- import android.support.v7.app.AppCompatActivity;
- import android.widget.Button;
-
- import butterknife.BindColor;
- import butterknife.BindView;
- import butterknife.ButterKnife;
-
- public class ButterknifeActivity extends AppCompatActivity {
-
- @BindView( R.id.button1 ) //Bind a control
- public Button button1;
-
- @BindColor( R.color.colorAccent ) int black ; //Bind a color value
-
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_butterknife);
-
- //Bind activity
- ButterKnife.bind( this );
-
- button1.setTextColor( black );
-
- }
- }
9) Adapter ViewHolder Binding - public class TestAdapter extends BaseAdapter {
- private List<String> list;
- private Context context;
-
- public TestAdapter(Context context, List<String> list) {
- this.list = list;
- this.context = context;
- }
-
- @Override
- public int getCount() {
- return list== null ? 0 : list. size ();
- }
-
- @Override
- public Object getItem( int position) {
- return list.get(position);
- }
-
- @Override
- public long getItemId( int position) {
- return position;
- }
-
- @Override
- public View getView( int position, View convertView, ViewGroup parent) {
- ViewHolder holder;
- if (convertView == null ) {
- convertView = LayoutInflater. from (context).inflate(R.layout.layout_list_item, null );
- holder = new ViewHolder(convertView);
- convertView.setTag(holder);
- } else {
- holder = (ViewHolder) convertView.getTag();
- }
- holder.textview.setText( "item=====" + position);
- return convertView;
- }
-
- static class ViewHolder {
- @Bind(R.id.hello_world)
- TextView textview;
-
- public ViewHolder( View view ) {
- ButterKnife.bind(this, view );
- }
- }
- }
10) Click event binding: No need to declare view, no need to setOnClickLisener() to bind click event a. Bind a method directly - @OnClick(R.id.submit)
- public void submit( View view ) {
- // TODO submit data to server...
- }
b. All monitoring method parameters are optional - @OnClick(R.id.submit)
- public void submit() {
- // TODO submit data to server...
- }
c. Define a specific type, which will be automatically converted - @OnClick(R.id.submit)
- public void sayHi(Button button) {
- button.setText( "Hello!" );
- }
d. Multiple views can handle the same click event uniformly, which is very convenient and avoids the trouble of repeated method calls - @OnClick(R.id.submit)
- public void sayHi(Button button) {
- button.setText( "Hello!" );
- }
e. Custom views can bind their own listeners without specifying an id - public class FancyButton extends Button {
- @OnClick
- public void onClick() {
- // TODO do something!
- }
- }
f. Add addTextChangedListener to EditText (that is, the method of adding multiple callback methods to listen), use the specified callback to implement the method you want to callback. If you don't use any annotations, click to read the comments on the source code. - @OnTextChanged(value = R.id.mobileEditText, callback = OnTextChanged.Callback.BEFORE_TEXT_CHANGED)
- void beforeTextChanged(CharSequence s, int start, int count , int after ) {
-
- }
- @OnTextChanged(value = R.id.mobileEditText, callback = OnTextChanged.Callback.TEXT_CHANGED)
- void onTextChanged(CharSequence s, int start, int before, int count ) {
-
- }
- @OnTextChanged(value = R.id.mobileEditText, callback = OnTextChanged.Callback.AFTER_TEXT_CHANGED)
- void afterTextChanged(Editable s) {
-
- }
Code Obfuscation - -keep class butterknife.** { *; }
- -dontwarn butterknife.internal.**
- -keep class **$$ViewBinder { *; }
-
- -keepclasseswithmembernames class * {
- @butterknife.* <fields>;
- }
-
- -keepclasseswithmembernames class * {
- @butterknife.* <methods>;
- }
Use of Zelezny plugin In AndroidStudio->File->Settings->Plugins->Search Zelezny, download and add it, you can quickly generate instance objects of the corresponding components without writing them manually. When using it, right-click on the layout resource code of the Activity, Fragment or ViewHolder where you want to import annotations, ->Generate -> Generate ButterKnife Injections, and then a selection box as shown in the figure will appear. ButterKnife implementation principle For those who have some knowledge of ButterKnife, the way to inject fields is to use the annotation @BindView(R.id.tv_account_name), but first we need to inject ButterKnife.bind(Activity activity) in the Activity declaration. We know that annotations are divided into several categories, some are effective in the source code, some are effective when the class file is generated, and some are effective at runtime. They are RetentionPolicy.SOURCE, RetentionPolicy.CLASS, and RetentionPolicy.RUNTIME, among which RetentionPolicy.RUNTIME consumes the most performance. ButterKnife uses compiler-time injection. When using it, you need to configure classpath 'com.neenbedankt.gradle.plugins:android-apt:1.8'. This configuration indicates that annotation processing is performed during compilation. To process annotations, you need to inherit AbstractProcessor and in boolean process(Set ButterKnife Implementation Knowing that annotations can be processed during compilation, we can get the field attributes and the class of the annotation, and then generate an injection file, generate an inner class of the injection class, and then process the field. After compilation, it will be merged into the injection class to achieve the purpose of implanting new code segments. For example: we inject @VInjector(R.id.tv_show) TextView tvShow; we can get the value of the tvShow variable and the id R.id.tv_show, and then perform pattern processing injectObject.tvShow = injectObject.findViewById(R.id.tv_show);, and then add the code to the class where the component is located as an inner class, completing a DI (injection). a) First create a view annotation b) Create an annotation processor to get the attributes of the annotation and the class to which it belongs c) Parse annotations and separate and combine classes and attributes d) Combine Class and attributes to generate a new Java File APT generated Java File, and pattern code Use Javac to generate subclasses of the injection class at compile time Project UML diagram Brief description: Main categories: VInjectProcessor —-> Annotation processor, you need to configure the annotation processor - resources
- -META-INF
- - services
- - javax.annotation.processing.Processor
Processor content: - com.myl.viewinject.apt.VInjectProcessor #Specify the full class name of the processor
VInjectHandler —-> Annotation processing class, mainly performs injection class and annotation field parsing and encapsulation, and maps the same type of fields using map collection. exp: Map Custom ButterKnife Implementation Due to WeChat word limit, please click the original link in the lower left corner to view!~ |