View#onDetachedFromWindow

When making a custom View subclass something I often notice is overriding onAttachedToWindow and onDetachedFromWindow for lifecycle events. This isn't inherently bad, but the contents of that override could be making your View less flexible. Take this example where we are using an event bus.

public TestView(Context context) {
  super(context);
  EventBus.register(this);
}

@Override
protected void onDetachedFromWindow() {
  super.onDetachedFromWindow();
  EventBus.unregister(this);
}

This works really well if that View will always be attached, but if its removed then reattached you'd notice you no longer receive events. Thats because onAttachedToWindow and onDetatchedFromWindow need to work together here and more appropriately represent "my view does or does not have a surface to draw on", not a typical lifecycle.

In this next example, ImageView represents this quite well. It uses attach events to determine Drawable visibility states and hints the view to redraw itself if needed. The most important distinction is that the ImageView is completely reusable and does not irreparably destroy itself simply because its been detached.

@Override
protected void onAttachedToWindow() {
  super.onAttachedToWindow();
  if (mDrawable != null) {
    mDrawable.setVisible(getVisibility() == VISIBLE, false);
  }
}

@Override
protected void onDetachedFromWindow() {
  super.onDetachedFromWindow();
  if (mDrawable != null) {
    mDrawable.setVisible(false, false);
  }
}

In our event bus example, this fix is quite easy – just move the register call into onAttachedToWindow. If you need a true lifecycle matching that of an Activity or Fragment, your best bet is to pass those events through manually or by using a library like Lightcycle. Also take a close look at what that View is doing – you might be better off having the parent Controller, Activity, or Fragment do the work and passively update the view in question.