11

What's the best practice for calling : -

Butterknife.unbind()

in a custom Android view please?

aprofromindia
  • 1,111
  • 1
  • 13
  • 27

4 Answers4

26

Yes, onDetachedFromWindow is the right function as mentioned in NJ's answer because this is where view no longer has a surface for drawing.

But the usage is incorrectly mentioned in the answer. The right approach involves binding in onFinishInflate():

@Override
protected void onFinishInflate() {
    super.onFinishInflate();
    unbinder = ButterKnife.bind(this);
}

and unbinding in onDetachedFromWindow:

@Override
protected void onDetachedFromWindow() {
    super.onDetachedFromWindow();
    // View is now detached, and about to be destroyed
    unbinder.unbind();
}
Community
  • 1
  • 1
Wahib Ul Haq
  • 4,185
  • 3
  • 44
  • 41
  • is it necesary to bind when in a custom view ? i dont unbind in a fragment why do i need to do this in the view ? im just wondering if its required for clean up or why bother unbinding ? – j2emanue Mar 28 '17 at 18:18
  • @j2emanue If you need to null out views and null out listeners then you better call unbind in a custom view. It's not needed but a recommended approach. You should also unbind in Fragment. Jake Wharton mentioned the reason here: ` There can be a case when fragment's view is destroyed, but the fragment instance is still present. For example, when fragment goes into the back stack - onDestroyView() is called, but onDestroy() is not.` source: https://github.com/JakeWharton/butterknife/issues/291 – Wahib Ul Haq Mar 28 '17 at 22:14
  • @j2emanue Here is better explanation why to nullify views in `onDestroyView();` http://stackoverflow.com/a/26370042/1307690 @WahibUlHaq I'm not shure if you have to do this in `onDetachedFromView()` because your custom view at this point will not be yet null, and if you try to change childs of this after unbind you`l get NullPointerException – Roman Nazarevych Apr 20 '17 at 10:55
  • I wonder then if it's better to unbind in oncreateview just before you bind? – j2emanue Apr 20 '17 at 16:23
10

Try in onDetachedFromWindow()

Unbinder unbinder;
unbinder = Butterknife.bind(this, root);

and in onDetachedFromWindow you need to call unbinder.unbind();

@Override
protected void onDetachedFromWindow() {
    super.onDetachedFromWindow();
    // View is now detached, and about to be destroyed
   unbinder.unbind()
}
N J
  • 27,217
  • 13
  • 76
  • 96
  • 1
    That's the right approach, although be careful with that, because `onDetachedFromWindow` callback does not necessarily have to mean that the `View` is about to be destroyed (e.g. if it's a part of `RecyclerView`). – Bartek Lipinski May 30 '16 at 08:50
  • 1
    @BartekLipinski What is the right approach for custom view in a ViewHolder. Calling unbind in onDetachedFromWindow() is not possible. – erdna Aug 02 '16 at 10:18
1

onDetachedFromWindow won't always work, like if the custom view is within a RecyclerView. Adding that in fact actually crashed my app. Honestly, it worked fine without unbinding it.

PKDev
  • 21
  • 4
0

Warning!

If you set attributes with app:attribute="value" in XML, you will lose their values when reading with:

@Override
protected void onFinishInflate() {
    super.onFinishInflate();
    unbinder = ButterKnife.bind(this);

    TypedValue typedValue = new TypedValue();
    TypedArray typedArray = getContext().obtainStyledAttributes(typedValue.data, R.styleable.YourStyleable);
    try {
        int number = typedArray.getResourceId(R.styleable.YourStyleable_number, 0);
        image.setImageResource(number);

        String text = typedArray.getString(R.styleable.YourStyleable_text);
        text.setText(text);
    } finally {
        typedArray.recycle();
    }
}

Their values will be 0 and null. Initialize them in custom view's constructor.

A reason is using obtainStyledAttributes(typedValue.data instead of obtainStyledAttributes(attrs.

See: Magic with obtainStyledAttributes method.

CoolMind
  • 26,736
  • 15
  • 188
  • 224