Hot questions for Using Butter Knife in view

Question:

Android Studio by default format Butterknife code in this way:

@BindView(R.id.text_view) 
TextView mTextView

Is there a way to tell Android Studio to format code in one line, like this:

@BindView(R.id.text_view) TextView mTextView

If this is possible I would like this rule to apply only to @BindView annotation.


Answer:

in Android Studio 2.3.3 File -> Settings -> Editor ->Code Style -> Java -> Wrapping and Braces -> Field annotations -> set to "Do not Wrap"

but this will prevent AS to put the new line on all field annotations.

i don't know if it is possible to have this option only for @BindView, however, if you set the option like this, AS will not put all annotations inline. for instance if you have

@Nullable
String foo;

@BindView View bar;

and format the code, AS will leave both annotations as they are.

Question:

in my project I have this case:

@BindView(R.id.viewpager)
ViewPager viewPager;
TabLayout tabLayout;
AddParkingFragmentListener listener;



public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {

    View inflatedView = inflater.inflate(R.layout.fragment_add_parking, container, false);

    ButterKnife.bind(this, inflatedView);

    tabLayout = (TabLayout) getActivity().findViewById(R.id.tabs);
    tabLayout.setVisibility(View.VISIBLE);

    return inflatedView;
}

where I need to bind a view that is in the activity_main.xml layout. I've thought that I could use an interface to disable the visibility directly in the MainActivity, but I would also know if there is the possibility to bind this view using Butterknife, because in the MainActivity I have also this problem:

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

    View view = navigationView.getHeaderView(0);
    profile = (ImageView) view.findViewById(R.id.imgPro); 

    //this views are in the navigation view, how to bind using butterknife?
    logo = (ImageView) view.findViewById(R.id.logo);

    email = (TextView) findViewById(R.id.email_profile);

    ButterKnife.bind(this);

}

is there a way to do this or I need to use findViewById() method?

Thanks


Answer:

According the oficial documentation from Butter Knife Library

They have included findById methods which simplify code that still has to find views on a View, Activity, or Dialog. It uses generics to infer the return type and automatically performs the cast.

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 photo = ButterKnife.findById(view, R.id.photo);

Add a static import for ButterKnife.findById and enjoy even more fun.

Source: http://jakewharton.github.io/butterknife/

Question:

I have successfully replaced findViewByIds with Butterknife library. Unfortunately, one problem has occured:

final Button btnPopup = (Button) popupView.findViewById(R.id.btn_popup); //popupView.findViewById(...) problem!!!

How can I change this line of code in Butterknife: as Butterknife.bind(this); takes the whole activities Views


Answer:

Bind your popupView to your main view using

View popupView = View.inflate(getContext(), R.layout.yourPopup, null);
ButterKnife.bind(this,popupView);

Or you may want to bind it directly using

Button btnPopup = ButterKnife.findById(popupView, R.id.btn_popup);

Question:

I have this code :

@OnClick( {R.id.iv_first,R.id.iv_second} )
public void launchCards() {
    Log.i(TAG,"clicked");
}

Is there a way to know inside the launchCards() method which of the two ImageView has been clicked ?


Answer:

You can do something like this:

@OnClick({R.id.iv_first,R.id.iv_second}) 
public void launchCards(View view) {

        // Check which ImageView was clicked
        switch (view.getId()) {
          case R.id.iv_first:
              // 1 clicked
            break;
          case R.id.iv_second:
              // 2 clicked
            break;
        }
      }

Question:

Android Studio 2.3.3.

My layout xml file:

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

    <ProgressBar
        android:id="@+id/downloadProgressBar"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

</android.support.constraint.ConstraintLayout>

In my app/build.gradle:

apply plugin: 'com.android.application'
apply plugin: 'com.jakewharton.butterknife'
apply plugin: 'kotlin-kapt'
apply plugin: 'kotlin-android'

    android {
    compileSdkVersion 26
    buildToolsVersion "26.0.2"
    defaultConfig {
        applicationId "com.myproject"
        minSdkVersion 15
        targetSdkVersion 26
        versionCode 1
        versionName "1.0"

        buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
        dev {
            initWith(debug)

        }
    }

}    

dependencies {
    annotationProcessor 'com.github.bumptech.glide:compiler:4.2.0'
    annotationProcessor "com.jakewharton:butterknife-compiler:$BUTTER_KNIFE_VERSION"   
    compile "com.jakewharton:butterknife:$BUTTER_KNIFE_VERSION" 
}

Here snippet of MyActivity:

public class MyActivityextends extends AppCompatActivity  {
    @BindView(R.id.downloadProgressBar) ProgressBar downloadProgressBar;       

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.pdf_viewer_activity);
        ButterKnife.bind(this);
        ButterKnife.setDebug(true);    
        // THROW NPE!!!
        downloadProgressBar.setVisibility(View.GONE); 
     }    
}

But after start this activity I get NPE:

NullPointerException at com.myproject.MyActivity.onCreate(MyActivity.java:63)

Why? I think I correct initialize butterKnife lib. Project success build and run from Android Studio and from console.


Answer:

You are using Kotlin, so you should do

apply plugin: 'com.android.application'
//apply plugin: 'com.jakewharton.butterknife'
apply plugin: 'kotlin-android'
apply plugin: 'kotlin-kapt'

And

dependencies {
    kapt 'com.github.bumptech.glide:compiler:4.2.0'
    kapt "com.jakewharton:butterknife-compiler:$BUTTER_KNIFE_VERSION"   
    compile "com.jakewharton:butterknife:$BUTTER_KNIFE_VERSION" 
}

Question:

I add a Header and a Footer to my listview like this:

lv = (ListView) findViewById(R.id.lv_process_person)
            View header = getLayoutInflater().inflate(R.layout.activity_input_forward_department_header, null);
            View footer = getLayoutInflater().inflate(R.layout.activity_input_forward_department_footer, null);
            lv.addHeaderView(header);
            lv.addFooterView(footer);

And i use view inside header like this:

btnForward = (TextView) header.findViewById(R.id.button_forward);
    btnForward.setText("SetText");

How to use ButterKnife Liblary intead of these code? i researched but not resuilt. thank you and sorry for my english.


Answer:

You can use something similar to this example from the ButterKnife docs:

You can also perform binding on arbitrary objects by supplying your own view root.

public class FancyFragment extends Fragment {
  @BindView(R.id.button1) Button button1;
  @BindView(R.id.button2) Button button2;

  @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
    View view = inflater.inflate(R.layout.fancy_fragment, container, false);
    ButterKnife.bind(this, view);
    // TODO Use fields...
    return view;
  }
}

The class which you pass as the first argument to ButterKnife.bind() must have fields that are annotated with @BindView. The most straightforward way to do this is to create a custom View class called ListViewHeader or something more specific to your use.

Question:

I created a custom view VerticalTextView which is as given below.

public class VerticalTextView extends AppCompatTextView {

  private boolean isVerticalText = false;
  private boolean topDown = false;

  public VerticalTextView(Context context, AttributeSet attrs, int defStyle) {
    super(context, attrs, defStyle);
    if (attrs != null) {
      TypedArray array = getContext().obtainStyledAttributes(attrs, R.styleable.VerticalTextView);
      isVerticalText = array.getBoolean(R.styleable.VerticalTextView_is_vertical_text, false);
      topDown = array.getBoolean(R.styleable.VerticalTextView_top_down, false);
      array.recycle();
    }
  }

  public VerticalTextView(Context context, AttributeSet attrs) {
    this(context, attrs, 0);
  }

  public VerticalTextView(Context context) {
    super(context);
  }

  @Override
  protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    // vise versa
    if (isVerticalText) {
      int height = getMeasuredWidth();
      int width = getMeasuredHeight();
      setMeasuredDimension(width, height);
    }
  }

  public void setVerticalText(boolean verticalText) {
    isVerticalText = verticalText;
  }

  @Override
  protected void onDraw(Canvas canvas) {
    if (isVerticalText) {
      TextPaint textPaint = getPaint();
      textPaint.setColor(getCurrentTextColor());
      textPaint.drawableState = getDrawableState();

      canvas.save();

      if (topDown) {
        canvas.translate(getWidth(), 0);
        canvas.rotate(90);
      } else {
        canvas.translate(0, getHeight());
        canvas.rotate(-90);
      }

      canvas.translate(getCompoundPaddingLeft(), getExtendedPaddingTop());

      getLayout().draw(canvas);
      canvas.restore();
    } else {
      super.onDraw(canvas);
    }
  }

}  

Then I used it in LogInFragment as shown below: login_fragment.xml

<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/root"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:background="@color/color_sign_up">

    <androidx.constraintlayout.widget.Guideline
        android:id="@+id/guideline"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:orientation="horizontal"
        app:layout_constraintGuide_begin="48dp" />

    <View
        android:id="@+id/logo"
        android:layout_width="@dimen/logo_size"
        android:layout_height="@dimen/logo_size"
        android:layout_marginTop="8dp"
        android:focusable="true"
        android:focusableInTouchMode="true"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="@+id/guideline" />

    <com.google.android.material.textfield.TextInputLayout
        android:id="@+id/email_input"
        style="@style/Widget.TextInputLayout"
        android:layout_marginTop="48dp"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/logo">

        <com.google.android.material.textfield.TextInputEditText
            android:id="@+id/email_input_edit"
            style="@style/Widget.TextEdit"
            android:hint="@string/email_hint"
            android:inputType="textEmailAddress" />

    </com.google.android.material.textfield.TextInputLayout>

    <com.google.android.material.textfield.TextInputLayout
        android:id="@+id/password_input"
        style="@style/Widget.TextInputLayout"
        android:layout_marginTop="16dp"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/email_input"
        app:passwordToggleTint="@color/color_input_hint">

        <com.google.android.material.textfield.TextInputEditText
            android:id="@+id/password_input_edit"
            style="@style/Widget.TextEdit"
            android:hint="@string/password_hint"
            android:inputType="textPassword" />

    </com.google.android.material.textfield.TextInputLayout>

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="48dp"
        android:gravity="center"
        android:text="@string/forgot_password"
        android:textColor="#FFF"
        android:textSize="20sp"
        android:textStyle="bold"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/password_input" />


    <com.learn.fsrsolution.models.VerticalTextView
        android:id="@+id/caption"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:gravity="center"
        android:text="@string/log_in_label"
        android:textAllCaps="true"
        android:textColor="@color/color_label"
        android:textSize="@dimen/unfolded_size"
        android:textStyle="bold"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintVertical_bias="0.78" />

</androidx.constraintlayout.widget.ConstraintLayout>  

LogInFragment.java

public class LogInFragment extends AuthFragment {

  @BindViews(value = {R.id.email_input_edit, R.id.password_input_edit})
  protected List<TextInputEditText> views;
  @BindView(R.id.password_input)
  TextInputLayout inputLayout;
  @BindView(R.id.caption)
  VerticalTextView caption;

  @Override
  public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
    super.onViewCreated(view, savedInstanceState);
    caption.setText(getString(R.string.log_in_label));
    view.setBackgroundColor(ContextCompat.getColor(getContext(), R.color.color_log_in));
    for (TextInputEditText editText : views) {
      if (editText.getId() == R.id.password_input_edit) {
        ButterKnife.bind(this, inputLayout);
        Typeface boldTypeface = Typeface.defaultFromStyle(Typeface.BOLD);
        inputLayout.setTypeface(boldTypeface);
        editText.addTextChangedListener(new TextWatcherAdapter() {
          @Override
          public void afterTextChanged(Editable editable) {
            inputLayout.setPasswordVisibilityToggleEnabled(editable.length() > 0);
          }
        });
      }
      editText.setOnFocusChangeListener((temp, hasFocus) -> {
        if (!hasFocus) {
          boolean isEnabled = editText.getText().length() > 0;
          editText.setSelected(isEnabled);
        }
      });
    }
  }

  @Override
  public int authLayout() {
    return R.layout.login_fragment;
  }

  @Override
  @TargetApi(Build.VERSION_CODES.LOLLIPOP)
  public void fold() {
    lock = false;
    Rotate transition = new Rotate();
    transition.setEndAngle(-90f);
    transition.addTarget(caption);
    TransitionSet set = new TransitionSet();
    set.setDuration(getResources().getInteger(R.integer.duration));
    ChangeBounds changeBounds = new ChangeBounds();
    set.addTransition(changeBounds);
    set.addTransition(transition);
    TextSizeTransition sizeTransition = new TextSizeTransition();
    sizeTransition.addTarget(caption);
    set.addTransition(sizeTransition);
    set.setOrdering(TransitionSet.ORDERING_TOGETHER);
    final float padding = getResources().getDimension(R.dimen.folded_label_padding) / 2;
    set.addListener(new Transition.TransitionListenerAdapter() {
      @Override
      public void onTransitionEnd(Transition transition) {
        super.onTransitionEnd(transition);
        caption.setTranslationX(-padding);
        caption.setRotation(0);
        caption.setVerticalText(true);
        caption.requestLayout();

      }
    });
    TransitionManager.beginDelayedTransition(parent, set);
    caption.setTextSize(TypedValue.COMPLEX_UNIT_PX, caption.getTextSize() / 2);
    caption.setTextColor(Color.WHITE);
    ConstraintLayout.LayoutParams params = getParams();
    params.leftToLeft = ConstraintLayout.LayoutParams.UNSET;
    params.verticalBias = 0.5f;
    caption.setLayoutParams(params);
    caption.setTranslationX((caption.getWidth() / 8) - padding);
  }

  @Override
  public void clearFocus() {
    for (View view : views) view.clearFocus();
  }

}  

Then I used caption in AuthFragment as follows.

public abstract class AuthFragment extends Fragment {

  protected Callback callback;

  @BindView(R.id.caption)
  protected VerticalTextView caption;

  @BindView(R.id.root)
  protected ViewGroup parent;

  protected boolean lock;

  @Override
  public void onCreate(@Nullable Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setRetainInstance(true);
  }

  @Nullable
  @Override
  public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
    View root = inflater.inflate(authLayout(), container, false);
    ButterKnife.bind(this, root);
    KeyboardVisibilityEvent.setEventListener(getActivity(), isOpen -> {
      callback.scale(isOpen);
      if (!isOpen) {
        clearFocus();
      }
    });
    return root;
  }

  public void setCallback(@NonNull Callback callback) {
    this.callback = callback;
  }

  @LayoutRes
  public abstract int authLayout();

  public abstract void fold();

  public abstract void clearFocus();

  @OnClick(R.id.root)
  public void unfold() {
    if (!lock) {
      caption.setVerticalText(false);
      caption.requestLayout();
      Rotate transition = new Rotate();
      transition.setStartAngle(-90f);
      transition.setEndAngle(0f);
      transition.addTarget(caption);
      TransitionSet set = new TransitionSet();
      set.setDuration(getResources().getInteger(R.integer.duration));
      ChangeBounds changeBounds = new ChangeBounds();
      set.addTransition(changeBounds);
      set.addTransition(transition);
      TextSizeTransition sizeTransition = new TextSizeTransition();
      sizeTransition.addTarget(caption);
      set.addTransition(sizeTransition);
      set.setOrdering(TransitionSet.ORDERING_TOGETHER);
      caption.post(() -> {
        TransitionManager.beginDelayedTransition(parent, set);
        caption.setTextSize(TypedValue.COMPLEX_UNIT_PX, getResources().getDimension(R.dimen.unfolded_size));
        caption.setTextColor(ContextCompat.getColor(getContext(), R.color.color_label));
        caption.setTranslationX(0);
        ConstraintLayout.LayoutParams params = getParams();
        params.rightToRight = ConstraintLayout.LayoutParams.PARENT_ID;
        params.leftToLeft = ConstraintLayout.LayoutParams.PARENT_ID;
        params.verticalBias = 0.78f;
        caption.setLayoutParams(params);
      });
      callback.show(this);
      lock = true;
    }
  }

  protected ConstraintLayout.LayoutParams getParams() {
    return (ConstraintLayout.LayoutParams) caption.getLayoutParams();
  }

  public interface Callback {
    void show(AuthFragment fragment);

    void scale(boolean hasFocus);
  }
}

When I run that code, I get below error:

java.lang.IllegalStateException: Required view 'caption' with ID 2131230791 for field 'caption' was not found. How can I fix it?


Answer:

Sometimes butter knife doesn't work with Custom views. So try to do it manually too.

But here, why are you declaring caption property again in Login Fragment?

(@BindView(R.id.caption) VerticalTextView caption;)

AuthFragment is abstract and you are passing layout id to it from child fragment.

Then why you created another property of VerticalTextView caption; in child class too when it is already in parent class.

Question:

Here's my fragment_photo_gallery.xml file:

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

<RelativeLayout
    android:id="@+id/disconnected_view"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_centerInParent="true"
    android:visibility="gone">

    <ImageView
        android:id="@+id/disconnected_image"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerHorizontal="true"
        android:src="@drawable/ic_offline" />

    <TextView
        android:id="@+id/disconnected_title_text"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_below="@+id/disconnected_image"
        android:layout_centerHorizontal="true"
        android:layout_marginTop="8dp"
        android:fontFamily="sans-serif-medium"
        android:gravity="center"
        android:text="@string/disconnected_title_text"
        android:textAppearance="?android:textAppearanceMedium" />

    <TextView
        android:id="@+id/disconnected_subtitle_text"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_below="@+id/disconnected_title_text"
        android:layout_centerHorizontal="true"
        android:layout_marginTop="8dp"
        android:fontFamily="sans-serif"
        android:gravity="center"
        android:paddingLeft="8dp"
        android:paddingRight="8dp"
        android:text="@string/disconnected_subtitle_text"
        android:textAppearance="?android:textAppearanceSmall"
        android:textColor="#A2AAB0" />

    <Button
        android:id="@+id/disconnected_button"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_below="@id/disconnected_subtitle_text"
        android:layout_centerHorizontal="true"
        android:layout_marginTop="8dp"
        android:text="@string/disconnected_button_text" />

</RelativeLayout>

</RelativeLayout>

I bind all the stuff in the class which extends fragment:

public class PhotoGalleryFragment extends Fragment {

    ....

    @BindView(R.id.disconnected_view)
    RelativeLayout disconnectedView;

    ....

    public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        View v = inflater.inflate(R.layout.fragment_photo_gallery, container, false);
        unbinder = ButterKnife.bind(this, v);
        return v;
    }

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

    ....
}

And get NPE on this method:

private void showDisconnectedView() {
    disconnectedView.setVisibility(View.VISIBLE);
    progressBar.setVisibility(View.GONE);
}

Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'void android.widget.RelativeLayout.setVisibility(int)' on a null object reference

My build gradle looks ok so I don't know why I get such an error

implementation 'com.jakewharton:butterknife:8.8.1'
annotationProcessor 'com.jakewharton:butterknife-compiler:8.8.1'

The guy who got similar problem figured out by changing annotationProcessor to apt but in my case, it just won't ever sync.


QUICK UPDATE

The problem still happened even if I replace @BindView(R.id.disconnected_view)RelativeLayout disconnectedView; with disconnectedView = v.findViewById(R.id.disconnected_view); in my onCreateView method. So it must be not butterknife fault.


Answer:

Use Butterknife without unbinder, You need to return already inflated view rather than creating new view & inflating it.

Also apply view specific code in onViewCreated() method.

public class PhotoGalleryFragment extends Fragment {

@BindView(R.id.disconnected_view)
RelativeLayout disconnectedView;

@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
    View v = inflater.inflate(R.layout.fragment_photo_gallery, container, false);
    ButterKnife.bind(this, v);
    return v;
}

@Override
public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
    super.onViewCreated(view, savedInstanceState);
    disconnectedView.setVisibility(View.GONE);
}

Question:

Here my topActivity which extend BaseActivity

activity_top.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="schemas.android.com/apk/res/android"; 
  android:layout_width="match_parent" 
  android:layout_height="match_parent" android:orientation="vertical"> 
  <View android:id="@+id/activity_top_group_area1" 
   android:layout_width="wrap_content" 
   android:layout_height="match_parent"/>
 </LinearLayout> 

TopActivity.java

public class TopActivity extends BaseActivity {

    @BindView(R.id.activity_top_group_area1)

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

        ButterKnife.bind(this);
        # do something... but mViewClickArea1 is null here.
     }
    }

And the BaseActivity Which extend AppCompactActivity in which i do some centralize permission work

public class BaseActivity extends AppCompactActivity  {

# do some Run time Permission work that is ...
private int requestCodeM;

@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
}

@Override
public void onRequestPermissionsResult(final int requestCode, @NonNull final String[] permissions, @NonNull int[] grantResults) {
    boolean isPermissionGranted = false;
    if (requestCodeM == requestCode) {
        if (grantResults.length > 0) {
            /*--------------------------------------------------*/
            for (int i = 0; i < grantResults.length; i++) {
               if(grantResults[i] == PackageManager.PERMISSION_GRANTED){
                   isPermissionGranted=true;
               }else {
                   isPermissionGranted=false;
                   break;
               }
            }
            permissiongrantedResult(requestCode,isPermissionGranted);
        }
    }
}

public void addRequestPermission(String[] permissionRequest, int requestCode) {
    this.requestCodeM = requestCode;
    ActivityCompat.requestPermissions(ActivityWithRequestPermission.this, permissionRequest, requestCode);
}

public abstract void permissiongrantedResult(int requestCode, boolean grantStatus);`enter code here`
}

Kindly look at this.


Answer:

Try this in your code .

Change xml code to this

<?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">

<View
    android:id="@+id/activity_top_group_area1"
    android:layout_width="wrap_content"
    android:layout_height="match_parent"/>
</LinearLayout>

Check project gradle

dependencies {
    classpath 'com.android.tools.build:gradle:2.3.3'
    // add this in your code
    classpath 'com.neenbedankt.gradle.plugins:android-apt:1.8'  
}

Check app gradle

apply plugin: 'com.android.application'
apply plugin: 'android-apt'  // add this 

...
dependencies {
    compile fileTree(include: ['*.jar'], dir: 'libs')
    androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
    exclude group: 'com.android.support', module: 'support-annotations'
    })

    compile 'com.jakewharton:butterknife:8.6.0'
    // add this 
    apt 'com.jakewharton:butterknife-compiler:8.6.0
}

Question:

When I try to bind my views with Butterknife I get this IllegalStateException after every time I call ButterKnife.bind(this, fragmentView!!) method.

For example:

//...BindView section
@BindView(R.id.logoutButton)
lateinit var logoutButton: View

@BindView(R.id.closeSession)
lateinit var closeSessionButton: View

@BindView(R.id.settings)
lateinit var settingsButton: View

And I get this:

java.lang.IllegalStateException: Required view login with ID 2131362018 for field logoutButton was not found. If this view is optional add @Nullable (fields) or @Optional (methods) annotation.

The point is that I DIDN'T BIND the 'login' view as the exception says. I bounded 'logutButton'. I did have 'login' view, but in the other fragment which has no connection to fragment where the exception appears.

And this happening in every fragment, activity, or adapter or something else which needs binding views with butterknife. And every time Butterknife tries to bind, an absolutely random view for the field that comes first in declaration order (only first @BindView annotation affected, the next annotation are fine)

I'm using @Nullable annotation and it's helping perfectly (even after I deleted @Nullable annotation - fragment works fine). But I have lots of fragments and activities, so I can't check all of them and add the @Nullable annotation.

How I can find the source of this problem so that it never happens again?


Answer:

This is how i solved this:

Build -> Clean Project

And everything fine!

Question:

I want use ButterKnife in my Project. I use many EditText and for initialize this editTexts I use this code :

@BindView(R.id.registerCountryEdtTxt)
EditText countryEdt;

@BindView(R.id.registerDateBirthEdtTxt)
EditText birthDayEdt;

@BindView(R.id.registerGenderEdtTxt)
EditText genderEdt;

@BindView(R.id.registerFullnameEdtTxt)
EditText fullnameEdt;

@BindView(R.id.registerEmailEdtTxt)
EditText emailEdt;

@BindView(R.id.registerUsernameEdtTxt)
EditText usernameEdt;

@BindView(R.id.registerPasswordEdtTxt)
EditText passwordEdt;

@BindView(R.id.registerFacebookEdtTxt)
EditText facebookEdt;

For onClick I want use many views one click method, how can I use one @BindView for many views?

@OnClick({R.id.registerDateBirthInptLay, R.id.registerDateBirthEdtTxt})
void selectBirthDay() {

Answer:

You can group multiple Views into a List or array.

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

And to access these Views, just access the position:

nameViews.get(0).setText("Text");

Question:

I have a strange problem with ButterKnife's OnClick listeners. When my custom view opened below OnClick listeners are running automatically when view opened. Below code helps you to understand what my problem is.

public class UserMenuFragment extends LinearLayout {
@BindView(R.id.buttonBlockUser)
Button buttonBlockUser;
@BindView(R.id.buttonMuteUser)
Button buttonMuteUser;
@BindView(R.id.buttonHideYourPreset)
Button buttonHideYourPreset;
@BindView(R.id.buttonTurnOnNotifs)
Button buttonTurnOnNotifs;

public UserMenuFragment(Context context, AttributeSet attrs, int defStyle) {
    super(context, attrs, defStyle);
    initView();
}

public UserMenuFragment(Context context, AttributeSet attrs) {
    super(context, attrs);
    initView();
}

public UserMenuFragment(Context context) {
    super(context);
    initView();
}

private void initView() {
    View view = inflate(getContext(), R.layout.fragment_user_menu, null);
    addView(view);
    bindViewWithButterKnife(this, view);
    onButtonReportUserClicked();
    onButtonBlockUserClicked();
    onButtonMuteUserClicked();
    onButtonHideYourPresetClicked();
    onButtonCopyProfileLinkClicked();
    onButtonTurnOnNotifsClicked();
}

@OnClick(R.id.buttonReportUser)
void onButtonReportUserClicked() {
    Toast.makeText(getContext(), "User Reported!", Toast.LENGTH_SHORT).show();
}

@OnClick(R.id.buttonBlockUser)
void onButtonBlockUserClicked() {
    Toast.makeText(getContext(), "User Blocked!", Toast.LENGTH_SHORT).show();
    changeButtonText(buttonBlockUser, R.string.unblock_user_text);
}

@OnClick(R.id.buttonMuteUser)
void onButtonMuteUserClicked() {
    Toast.makeText(getContext(), "User Muted!", Toast.LENGTH_SHORT).show();
    changeButtonText(buttonMuteUser, R.string.unmute_user_text);
}

@OnClick(R.id.buttonHideYourPreset)
void onButtonHideYourPresetClicked() {
    Toast.makeText(getContext(), "User preset hided!", Toast.LENGTH_SHORT).show();
    buttonHideYourPreset.setText(getContext().getString(R.string.show_your_preset_text));
    changeButtonText(buttonHideYourPreset, R.string.show_your_preset_text);
}

@OnClick(R.id.buttonCopyProfileLink)
void onButtonCopyProfileLinkClicked() {
    Toast.makeText(getContext(), "User's profile link copied!", Toast.LENGTH_SHORT).show();
}

@OnClick(R.id.buttonTurnOnNotifs)
void onButtonTurnOnNotifsClicked() {
    Toast.makeText(getContext(), "User's notification is off now!!", Toast.LENGTH_SHORT).show();
    changeButtonText(buttonTurnOnNotifs, R.string.turn_off_notification_text);
}

private void changeButtonText(Button button, int newText) {
    button.setText(getContext().getString(newText));
}

private void bindViewWithButterKnife(UserMenuFragment whichFragment, View view) {
    ButterKnife.bind(whichFragment, view);
}

}

IMO this is happening because I called the OnClick listeners in my constructor so while view creating(after created) naturally they are running. Could somebody help me to understand where is the exact problem is and how to fix it?

My ButterKnife versions:

implementation 'com.jakewharton:butterknife:8.8.1'
annotationProcessor 'com.jakewharton:butterknife-compiler:8.8.1'

Answer:

Change initView() to :

private void initView() {
    View view = inflate(getContext(), R.layout.fragment_user_menu, null);
    addView(view);
    bindViewWithButterKnife(this, view);
}

I don't think you need to call the methods, the annotations already do the job to set the listeners, right ?

Question:

public class DailyForecastActivity extends ListActivity {

private Day[] mDays;

@InjectViews(android.R.id.list) ListView mListView;
@InjectViews(android.R.id.empty) TextView mEmptyTextView;

but when I debug , ı get error like that

Error:(25, 46) error: @InjectViews must be a List or array. (brah.mb.hanifiui.DailyForecastActivity.mListView)
Error:(26, 47) error: @InjectViews must be a List or array. (brah.mb.hanifiui.DailyForecastActivity.mEmptyTextView)

what is the error. if any information u need , ı can edit again.tnx.


Answer:

I suppose that you are using ButterKnife library. '@InjectViews' was used to inject several views as array.

eg :

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

@InjectViews should be used only on List type or on an array of view objects. Other implementations are restricted.

You can also look at working code sample here.

So, you cannot use it the way you have defined, the error clearly states that, you need to use list or array. Moreover, look into new document, the thing that you are trying to do is simply the very first example, simply use @BindView, and if you want to bind multiple similar views at once, search for @BindViews on the same page itself.

Hope It helps !

Question:

I am using ButterKnife to bind view element.

Here is my fragment layout:

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

    <Button
        android:id="@+id/ok_btn"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@string/ok" />
</LinearLayout>

My fragment:

class MyFragment : Fragment() {
    @BindView(R.id.ok_btn)
    lateinit var okBtn: Button

    ...

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)

        okBtn.setOnClickListener { view ->
            Log.d("mytag", "ok clicked!")
        }
    }
}

When I run my simple app, I get error:

Caused by: kotlin.UninitializedPropertyAccessException: lateinit property okBtn has not been initialized
E/AndroidRuntime( 5435):    at com.my.app.MyFragment.onViewCreated(MyFragment.kt:35)

Why I get this error? It sounds like the @BindView(R.id.ok_btn) does't initialize the button instance variable. What do I miss?


Answer:

where is the line like?

Butterknife.bind(this, rootView) 

not sure how it should look on Kotlin and don't forget to add unbinder you should use it with fragments according documentation

finally it will look something like...

Unbinder unbinder;
onViewCreated(){ 
  unbinder = Butterknife.bind(this, rootView); 
  //here you can set your onClickListener
}
onDestroyView(){
  unbinder.unbind()
}

adapt it for Kotlin and bravely use))

Question:

I have a project from someone else, but when I opened it there was some error. Butterknife has an error, it displays: "error: can't find findById (View, int) notation", I know that it has been replaced by @BindView, I changed findById to @BindView but only findById 2 parameters while @BindView only has 1. How do I convert it?

This is new code:

@BindView(R.id.fab_subitem_image) ImageView image;
private void addActionItem(@NonNull LayoutInflater inflater, int index,
    @NonNull final FABAction item) {
    // Inflate & Configure item
    final View subItem = inflater.inflate(R.layout.fab_subitem, mItemContainer, false);

    image.setBackgroundColor(item.mBgColor);

This is old code:

private void addActionItem(@NonNull LayoutInflater inflater, int index,
    @NonNull final FABAction item) {
    // Inflate & Configure item
    final View subItem = inflater.inflate(R.layout.fab_subitem, mItemContainer, false);
    ImageView image = ButterKnife.findById(subItem, R.id.fab_subitem_image); <--This is old code

    image.setBackgroundColor(item.mBgColor);

Answer:

You have to tell ButterKnife to generate bindings for the object that contains @BindView annotations. You should call ButterKnife.bind(this, subItem) after inflation:

@BindView(R.id.fab_subitem_image) ImageView image;

private Unbinder unbinder;

private void addActionItem(@NonNull LayoutInflater inflater, int index, @NonNull final FABAction item) {
    // Inflate & Configure item
    final View subItem = inflater.inflate(R.layout.fab_subitem, mItemContainer, false);
    // Generate bindings
    unbinder = ButterKnife.bind(this, subItem);

    image.setBackgroundColor(item.mBgColor);
    ...
}

...

@Override
public void onDestroyView(View view) {
    // Unbind when bindings are no longer needed eg. in onDestroyView of a Fragment
    unbinder.unbind()
}

See the documentation for more information.