Android调用onNavigationItemSelected为时已晚,无法防范它

时间:2014-02-16 11:49:37

标签: android android-actionbar

即使我是常客,这是我在Stackoverflow上的第一个问题,所以请保持温和。 ;)

我有一个可以使用视图寻呼机或操作栏下拉列表横向导航的活动。为了实现这一点,我附加了一个OnPageChangeListener和一个OnNavigationListener来在操作栏导航时更新视图寻呼机,反之亦然。

为了避免无限循环(寻呼机监听器设置操作栏,导航监听器得到通知并设置寻呼机,寻呼机获得通知并设置操作栏等),我获得了一个锁并在我的开始检查事件处理程序(布尔字段inhibited)。

由于我知道后续更新将异步发生,通过Android在消息队列上发布布局请求,我也会异步释放锁定,将其包装在Runnable中并将其发布到队列中。

我的期望是,我的runnable被放置在队列之后框架发布的所有消息,以更新操作栏微调器,查看寻呼机以及它认为需要的任何其他内容这样做,因为这些都应该在致电pager.setCurrentItemnavigationAdapter.notifyDataSetChangedsetSelectedNavigationItem时发布。 (期望也会反映在//注释中。)但是,在运行此代码时,我发现在已经释放锁之后,我会从OnNavigationListener调用我的回调。

我的问题是,此延迟通话来自何处以及我如何优雅地阻止它(没有像postDelayed之类的丑陋黑客)?

以下是我的听众的代码:

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));
    }

}

如果需要可以发布更多代码但不想发送垃圾邮件......

0 个答案:

没有答案