【问题标题】:Android: Why is onTabSelected being called when tabs are created?Android:为什么在创建选项卡时调用 onTabSelected?
【发布时间】:2014-08-30 00:21:18
【问题描述】:

当操作栏有选项卡时,我注意到当活动加载到屏幕上时会调用 onTabSelected。每当发生方向变化时,它也会被调用。我的代码根据选择的选项卡查询数据库,并将查询结果显示到加载的布局中。

我的问题是保存标签状态时,当前选中的标签为1或更高,在恢复状态时,由于onTabSelected默认在0标签上调用,当恢复状态标签为1或更高时会再次调用。这使得选项卡 0 上的数据库查询毫无用处。

如何配置在创建选项卡时不调用 onTabSelected 的 android,或者至少检测到此调用是默认调用而不是用户触发的?

@Override
public void onTabSelected(Tab tab, FragmentTransaction ft) {
    int tabPos = tab.getPosition();
    switch(tabPos) {
    case 0:
        // query database and display result
        break;
    case 1:
        // a different query and display result
        break;
    case 2: ...
    }
}

@Override
public void onRestoreInstanceState(Bundle savedInstanceState) {
    if(savedInstanceState.containsKey(STATE_SELECTED_TAB)) {
        getActionBar().setSelectedNavigationItem(savedInstanceState.getInt(STATE_SELECTED_TAB));
    }
    super.onRestoreInstanceState(savedInstanceState);
}

@Override
public void onSaveInstanceState(Bundle outState) {
    outState.putInt(STATE_SELECTED_TAB, getActionBar().getSelectedNavigationIndex());
    super.onSaveInstanceState(outState);
}

增加了复杂性: 当当前选中的选项卡为0,方向发生变化时,仍然会调用两次onTabSelected!一次是在最初创建选项卡时,第二次当 onRestoreState 恢复保存的选项卡选择状态时,即使它是 0。

我原本以为 onTabSelected 被调用了两次,但我错了。这是我的片段 onCreateView 被调用了两次,片段事务中的一些错误在方向更改时两次添加了相同的片段。 onTabSelected 被调用一次,恢复状态调用 onTabReselected 在恢复的 tab 也是 0 时也会被调用。


在搜索 SO 和谷歌之后,我发现这个问题有类似的问题原因。 Creating ActionBar tab also calling its selectTab functions

【问题讨论】:

    标签: android android-activity tabs


    【解决方案1】:

    因此,在查看了 Google Android 网站上关于 ActionBar 的参考文档后,addTab 方法是默认负责调用 onTabSelected 的方法。

    public abstract void addTab (ActionBar.Tab tab)
    

    添加一个选项卡以在选项卡式导航模式下使用。该选项卡将添加到列表的末尾。如果这是要添加的第一个选项卡,它将成为选定的选项卡。

    参数
    标签     要添加的标签

    顺便说一句,存在其他不调用 onTabSelected 的重载方法。

    public abstract void addTab (ActionBar.Tab tab, boolean setSelected)
    

    所以我改用了这些替代方法,它解决了问题。 但是,一旦显示选项卡,第一个选项卡可能会显示为已选中,即使它不是。点击它会调用 onTabSelected 而不是 onTabReselected。

    【讨论】:

    • 它可以工作,显然我们只需要对 ActionBar 中的单个选项卡设置 true (创建阶段)。 onTabSelected 将在 setSelected 设置为 true 添加的每个选项卡上触发。
    • 当时我正在调用 addOnTabSelectedListener
    【解决方案2】:

    我是这样解决的:

    tabLayout.addOnTabSelectedListener之前致电setupWithViewPager

    tabLayout.setupWithViewPager(viewPager)
    
    tabLayout.addOnTabSelectedListener(object :  TabLayout.OnTabSelectedListener {
                override fun onTabSelected(tab: TabLayout.Tab?) {....}
    .....
    }
    

    因为当你调用 setupWithViewPager 时,它会在内部调用 setOnTabSelectedListener(新 ViewPagerOnTabSelectedListener(viewPager));

    所以你最好在将 tabSelect Listener 添加到 tabLayout 之前调用它

    【讨论】:

      【解决方案3】:

      我认为你可以做到这一点(请忽略任何错字:-)):

      public class MainActivity extends FragmentActivity {
      
      boolean isConfigChanged;
      int savedTabIndex;
      @Override
      protected void onCreate(Bundle savedInstanceState) {
          super.onCreate(savedInstanceState);
          setContentView(R.layout.activity_main);
           if(savedInstanceState != null){
              if(savedInstanceState.containsKey(STATE_SELECTED_TAB)) {
                  savedTabIndex = savedInstanceState.getInt(STATE_SELECTED_TAB);
                //getActionBar().setSelectedNavigationItem(savedTabIndex); actually you do not need this
              }
              isConfigChanged = true;
          }
      
         // here add actionbar tabs
      
      //...}
      

      在:

      下面的代码检查如果configuration 更改并且用户选择的选项卡是not zero 所以这是默认调用并忽略但如果isConfigChanged == true 并且用户选择的选项卡是0 你must query DB 或者isConfigChanged == false 你必须查询数据库,因为这是第一次加载该应用程序。快速播放可能适合您的需求。

         @Override
         public void onTabSelected(Tab tab, FragmentTransaction ft) {
          if(isConfigChanged && savedTabIndex != 0){
             isConfigChanged = false;
             return;
           }
          isConfigChanged = false;
          int tabPos = tab.getPosition();
          switch(tabPos) {
          case 0:
              // query database and display result
              break;
          case 1:
              // a different query and display result
              break;
          case 2: ...
          }
        }
      

      删除onRestore

      @Override
      public void onSaveInstanceState(Bundle outState) {
          outState.putInt(STATE_SELECTED_TAB, getActionBar().getSelectedNavigationIndex());
          super.onSaveInstanceState(outState);
      }
      

      【讨论】:

      • 我认为你正在做一些事情。但是,我做了更多的测试,问题比我最初想象的要复杂。例如,如果当前选项卡为 0 并且方向发生变化,则调用两次 onTabSelected !一次创建选项卡时,第二次 onRestoreState 恢复选项卡 0 选择。我喜欢你的想法,我必须对我刚才提到的这个增加的复杂性进行改进。
      • 只需放置另一个标志并将其更改为case 0: 的块,这样第二次就会忽略。
      • 我不会阻止您编辑您的答案,请务必这样做。我只是想告诉你这种情况。
      • 我找到了一个更简单的解决方案。我已将其发布为答案。但感谢您的投入。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-02-03
      • 2013-11-15
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多