Android calls onNavigationItemSelected too late to guard against it <p>Even though I am a frequent reader, this is my first question on Stackoverflow, so be gentle. ;)</p> <p>I have an activity that can be navigated laterally using a view pager or an action bar drop down list. To achieve this, I have attached an OnPageChangeListener and an OnNavigationListener to update the view pager when navigating by the action bar and vice versa. </p> <p>In order to avoid an infinite loop (pager listener setting action bar, navigation listener gets notified and sets pager, pager gets notified and sets action bar, etc.), I acquire a lock and check for this in the beginning of my event handler (the boolean field <code>inhibited</code>). </p> <p>Since I know that the consequent updates will happen asynchronously, by means of Android posting layout requests on the message queue, I release the lock asynchronously as well by wrapping it in a <code>Runnable</code> and posting it to the queue.</p> <p>My expectation would be that this my runnable gets placed on the queue <em>after</em> all the messages posted by the framework to update the action bar spinner, view pager and whatever else it is that it thinks it needs to be doing, since these should all be posted during the calls to <code>pager.setCurrentItem</code>, <code>navigationAdapter.notifyDataSetChanged</code> and <code>setSelectedNavigationItem</code>. (An expectation that is also reflected in the // comment.) However, when running this code, I find my callback is invoked from the OnNavigationListener after the lock is already released. </p> <p>My question is, where does this delayed call come from and how can I <em>elegantly</em> prevent it (that is without ugly hacks like <code>postDelayed</code> or the like)?</p> <p>Here is the code for my Listener:</p> <pre><code>private class NavigationListener implements OnPageChangeListener, OnNavigationListener { private boolean inhibited = false; protected void inhibit() { inhibited = true; } protected void release() { inhibited = false; } private void moveToPosition(int monthId) { if (!inhibited) { try { inhibit(); pager.setCurrentItem(pagerAdapter.getIndex(monthId), true); navigationAdapter.notifyDataSetChanged(); getActionBar().setSelectedNavigationItem(navigationAdapter.getPositionForMonth(monthId)); } finally { // Need to release asynchronously because calling setCurrentItem and notifyDataSetChanged will // (asynchronously) refresh the UI and cause calls to their respective listeners. Therefore, simply // releasing the lock would result in an infinite loop. // When posting this runnable, any posts from setting the pager page and refreshing the spinner data // will already have been posted, so the release call is guaranteed to be behind them in the message queue. // Likewise, it is sure to be executed before the user can produce more input events, that is, any additional // swipe gestures or selections will be added to the message queue after the release call. pager.post(new Runnable() { @Override public void run() { release(); } }); } } } public boolean onNavigationItemSelected(int itemPosition, long itemId) { int month = (int) itemId; moveToPosition(month); /* more irrelevant code here */ return true; } public void onPageScrollStateChanged(int arg0) {} public void onPageScrolled(int arg0, float arg1, int arg2) {} public void onPageSelected(int position) { moveToPosition(pagerAdapter.getMonthId(position)); } } </code></pre> <p>Can post more code if required but didn't want to spam the question....</p>