In order to detect finish of app bar collapsing I called addOnOffsetChangedListener
. In listener's onOffsetChanged
I catch and handle the moment of collapsing done. Then I need to stop listen for offset changes.
In most examples here is call of removeOnOffsetChangedListener(this)
from inside of onOffsetChanged
. But looking in AppBarLayout.java I see:
private void dispatchOffsetUpdates(int offset) {
// Iterate backwards through the list so that most recently added listeners
// get the first chance to decide
if (mListeners != null) {
for (int i = 0, z = mListeners.size(); i < z; i++) {
final OnOffsetChangedListener listener = mListeners.get(i);
if (listener != null) {
listener.onOffsetChanged(this, offset);
}
}
}
}
So if there is more than one listener installed, calling removeOnOffsetChangedListener(this)
naturally results in IndexOutOfBoundsException
.
Have I missed something? Is there safe way to 'unsubscribe' from listening for offset updates?
Interestingly, this wouldn't be a problem if their code actually did what the comment says. Anyway, we can defer the removal by putting the call to removeOnOffsetChangedListener()
in a Runnable
, and posting it to the AppBarLayout
in onOffsetChanged()
, instead of calling it directly there.
For example:
AppBarLayout.OnOffsetChangedListener listener = new AppBarLayout.OnOffsetChangedListener() {
@Override
public void onOffsetChanged(final AppBarLayout abl, int offset) {
abl.post(new Runnable() {
@Override
public void run() {
abl.removeOnOffsetChangedListener(listener);
}
}
);
}
};