【问题标题】:Can't change the tabItem ( program crashes ), when I delete one of my tabItems with code无法更改 tabItem(程序崩溃),当我用代码删除我的 tabItems 之一时
【发布时间】:2019-04-16 16:25:08
【问题描述】:

我有一个应用程序,我在其中动态创建 TabItems 并将它们添加到 TabLayout。我将向您展示下面的代码。然后我还有一种机制,当创建tabitem 时,用户可以通过单击按钮将其关闭。现在:问题发生在这里。当用户删除该tabitem 并且程序自动将用户定向到另一个选项卡时。我无法再单击在应用程序启动时创建的其他选项卡。我可以点击它们,但程序关闭并出现错误

java.lang.IllegalStateException: The application's PagerAdapter changed the adapter's contents without calling PagerAdapter#notifyDataSetChanged! Expected adapter item count: 4, found: 3 Pager

当我删除带有为点击而编写的代码的tabitem 时,所有这些都会发生。下面是我的 MainActivity.java 代码:

public class MainActivity extends AppCompatActivity implements ContactsFragment.CallBacks, UserDetailFragment.DetailCallBacks {

    android.support.v7.widget.Toolbar toolbar;

    public static List<Fragment> fragments = new ArrayList<>();
    public static List<String> fragmentsTitle = new ArrayList<>();
    ViewPager viewPager;
    TabLayout tabLayout;
    int tabposition_number;

    public List<Fragment> getFragments() {
        return fragments;
    }

    public List<String> getFragmentsTitle() {
        return fragmentsTitle;
    }

    public void addToFragments(Fragment fragment) {
        fragments.add(fragment);
    }

    public void addToFragmentsTitle(String title) {
        fragmentsTitle.add(title);
    }

    public Fragment getFragmentsWithPosition(int position) {
        return fragments.get(position);
    }

    public String getFragmentsTitleWithPosition(int position) {
        return fragmentsTitle.get(position);
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        MenuInflater menuInflater = new MenuInflater(this);
        menuInflater.inflate(R.menu.top_main_menu,menu);
        return super.onCreateOptionsMenu(menu);
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        if(item.getItemId() == R.id.remove_tab) {
            remove_tab_details(3);
        }
        return super.onOptionsItemSelected(item);
    }

    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main_page_drawer);
        this.tabLayout = findViewById(R.id.tab_layout);
        this.viewPager = findViewById(R.id.view_pager);
        tabLayout.setupWithViewPager(viewPager);
        SetUpViewPager(viewPager);
        this.toolbar = findViewById(R.id.toolbar);
        setSupportActionBar(toolbar);
        NavigationView navigationView = findViewById(R.id.navigation_view);
        navigationView.setItemIconTintList(null);

        tabLayout.addOnTabSelectedListener(new TabLayout.OnTabSelectedListener(){

            @Override
            public void onTabSelected(TabLayout.Tab tab) {

                if(tab.getPosition() > 2) {
                    tabposition_number = tab.getPosition();
                }

//                viewPager.setCurrentItem(tab.getPosition());

                if(tab.getPosition() == 1) {
                    toolbar.setBackgroundColor(ContextCompat.getColor(MainActivity.this,R.color.tab_contacts));
                    tabLayout.setBackgroundColor(ContextCompat.getColor(MainActivity.this,R.color.main_contacts));
                    if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
                        getWindow().setStatusBarColor(ContextCompat.getColor(MainActivity.this,R.color.status_contacts));
                    }
                } else if(tab.getPosition() == 2) {
                    toolbar.setBackgroundColor(ContextCompat.getColor(MainActivity.this,R.color.tab_register));
                    tabLayout.setBackgroundColor(ContextCompat.getColor(MainActivity.this,R.color.main_register));
                    if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
                        getWindow().setStatusBarColor(ContextCompat.getColor(MainActivity.this,R.color.status_register));
                    }
                } else {
                    toolbar.setBackgroundColor(ContextCompat.getColor(MainActivity.this,R.color.tab_signin));
                    tabLayout.setBackgroundColor(ContextCompat.getColor(MainActivity.this,R.color.main_signin));
                    if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
                        getWindow().setStatusBarColor(ContextCompat.getColor(MainActivity.this,R.color.status_signin));
                    }
                }
            }

            @Override
            public void onTabUnselected(TabLayout.Tab tab) {

            }

            @Override
            public void onTabReselected(TabLayout.Tab tab) {

            }
        });

        viewPager.addOnPageChangeListener(new TabLayout.TabLayoutOnPageChangeListener(tabLayout));

    }

    public void SetUpViewPager(ViewPager viewPager) {
        MyViewPagerAdapter Adapter = new MyViewPagerAdapter((getSupportFragmentManager()));
        Adapter.AddFragmentPage(new SignInFragment(),"ورود");
        Adapter.AddFragmentPage(new ContactsFragment(),"ارتباطات");
        Adapter.AddFragmentPage(new RegisterFragment(),"ثبت نام");
        Adapter.notifyDataSetChanged();
        viewPager.setAdapter(Adapter);
    }

    @Override
    public void create_user_detail_tab(UserObject userObject) {
        MyViewPagerAdapter Adapter = new MyViewPagerAdapter(getSupportFragmentManager());
        UserDetailFragment userDetailFragment = new UserDetailFragment();
        Bundle bundle = new Bundle();
        bundle.putString("name",userObject.getName());
        bundle.putString("family",userObject.getFamily());
        bundle.putString("email",userObject.getEmail());
        userDetailFragment.setArguments(bundle);
        Adapter.AddFragmentPage(userDetailFragment,userObject.getName());
        viewPager.setAdapter(Adapter);
        TabLayout.Tab tab = tabLayout.getTabAt(1);
        tab.select();
    }

    @Override
    public void delete_previous_tab(int tabposition_number) {
        remove_tab_details(tabposition_number);
        MyViewPagerAdapter myViewPagerAdapter = new MyViewPagerAdapter(getSupportFragmentManager());
        myViewPagerAdapter.notifyDataSetChanged();
    }

    @Override
    public void changeTabItem(boolean mustdelete) {
        ContactsFragment contactsFragment = new ContactsFragment();
        if(tabposition_number > 2 && mustdelete) {
            contactsFragment.setTextView(tabposition_number,mustdelete);
            TabLayout.Tab tab = tabLayout.getTabAt(1);
            tab.select();
        }
    }

    public class MyViewPagerAdapter extends FragmentPagerAdapter {


        public MyViewPagerAdapter(FragmentManager manager) {
            super(manager);
        }

        public void removeTabPage(int position) {
                fragments.remove(position);
                fragmentsTitle.remove(position);
                MyViewPagerAdapter myViewPagerAdapter = new MyViewPagerAdapter(getSupportFragmentManager());
                myViewPagerAdapter.notifyDataSetChanged();
                myViewPagerAdapter.notifyDataSetChanged();
        }

        public void AddFragmentPage(Fragment frag,String title) {
            MainActivity.this.addToFragments(frag);
            MainActivity.this.addToFragmentsTitle(title);
            MyViewPagerAdapter myViewPagerAdapter = new MyViewPagerAdapter(getSupportFragmentManager());
            myViewPagerAdapter.notifyDataSetChanged();
        }

        public Fragment getItem(int position) {
            return MainActivity.this.getFragmentsWithPosition(position);
        }

        public CharSequence getPageTitle(int position) {
            return MainActivity.this.getFragmentsTitleWithPosition(position);
        }


        public int getCount() {
            return fragments.size();
        }
    }

    public void remove_tab_details(int tab_to_delete) {
        //            TabLayout.Tab tab = tabLayout.getTabAt(2);
//            tab.select();
        tabLayout.removeTabAt(tab_to_delete);
        MyViewPagerAdapter Adapter = new MyViewPagerAdapter(getSupportFragmentManager());
        Adapter.removeTabPage(tab_to_delete);
        Adapter.notifyDataSetChanged();
    }



}

以及 UserDetailFragment 的代码(当用户单击列表视图片段中的一项时创建。

public class UserDetailFragment extends Fragment {

    View view;
    DetailCallBacks detailCallBacks;

    public UserDetailFragment() {}

    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        view = inflater.inflate(R.layout.user_detail_fragment,null);
        return view;
    }

    @Override
    public void onResume() {
        super.onResume();
        final Bundle bundle = getArguments();
        String name = (String) bundle.get("name");
        String family = (String)bundle.get("family");
        String email = (String)bundle.get("email");
        TextView nameFamilytv = view.findViewById(R.id.user_detail_name_and_family);
        String nameAndfamily = name + " " + family;
        nameFamilytv.setText(nameAndfamily);
        TextView emailtv = view.findViewById(R.id.user_detail_email);
        emailtv.setText(email);
        Button closebtn = view.findViewById(R.id.detail_close_button);
        closebtn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                detailCallBacks.changeTabItem(true);
            }
        });
    }

    @Override
    public void onAttach(Context context) {
        super.onAttach(context);
        detailCallBacks = (DetailCallBacks)context;
    }

    public interface DetailCallBacks {
        public void changeTabItem(boolean mustdelete);
    }

最后但并非最不重要的是:当用户单击其项目时,该列表项的代码会创建动态选项卡:

public class ContactsFragment extends ListFragment {

    CallBacks callBacks;
    View view;
    public static int came_fromTabItem;
    public static boolean do_delete;

    public ContactsFragment() { }
    ArrayList<UserObject> userObjects;
    BroadcastReceiver broadcastReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            userObjects = intent.getParcelableArrayListExtra(Intent_Service.SERVICE_PAYLOAD);
            ArrayAdapter<UserObject> userObjectArrayAdapter = new UserArrayAdapter(context,0,userObjects);
            setListAdapter(userObjectArrayAdapter);
        }
    };

    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        Intent intent = new Intent(getActivity(), Intent_Service.class);
        getActivity().startService(intent);

        LocalBroadcastManager.getInstance(getActivity().getApplicationContext()).
                registerReceiver(broadcastReceiver,new IntentFilter(Intent_Service.SERVICE_MESSAGE));
    }

    public void setTextView(int position,Boolean mustDelete) {
        came_fromTabItem = position;
        do_delete = mustDelete;
    }

    @Override
    public void onResume() {
        super.onResume();
        if(came_fromTabItem > 2 && do_delete) {
                final Handler handler = new Handler();
                handler.postDelayed(new Runnable() {
                  @Override
                  public void run() {
                      callBacks.delete_previous_tab(came_fromTabItem);
                      do_delete = false;
                      Toast.makeText(getActivity().getApplicationContext(),String.valueOf(came_fromTabItem),Toast.LENGTH_LONG).show();
                  }
    }, 2000);

        }
    }

    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        this.view = inflater.inflate(R.layout.fragment_contacts,null);
        return this.view;
    }

    public void onListItemClick(ListView l, View v, int position, long id) {
        UserObject userObject = userObjects.get(position);
        callBacks.create_user_detail_tab(userObject);
    }

    public interface CallBacks {
        public void create_user_detail_tab(UserObject userObject);
        public void delete_previous_tab(int positions);
    }

    @Override
    public void onAttach(Context context) {
        super.onAttach(context);
        this.callBacks = (CallBacks)context;
    }
}

那么...有人可以帮帮我吗?问题很简单,为什么移除一个tabitem时会出现The application's PagerAdapter changed the adapter's contents without calling PagerAdapter#notifyDataSetChanged! Expected adapter item count: 4, found: 3这个错误,请问如何解决?

【问题讨论】:

  • 您的问题源于您在各处创建新的MyViewPagerAdapter 实例。创建一个,一次,只修改和通知

标签: android android-layout android-fragments android-viewpager


【解决方案1】:

出现问题是因为您删除了一个选项卡项目,而您的分页器仍然有 4 个项目计数,您必须使分页器项目计数动态,并在删除一个项目后调用 notifyDataSetChanged()

这是一个例子

public class MyPagerAdapter extends FragmentPagerAdapter {

int nbrItem;

public ProfilPagerAdapter(FragmentManager fm,String token,Int nbrItem) {
    super(fm);
    this.nbrItem= nbrItem;

  }

@Override
public Fragment getItem(int position) {
     switch(position) {
        case 0 :
            new SignInFragment();    
        case 1 :
            new ContactsFragment()
        case 2 :
            new RegisterFragment()    

    }
    return null;
}

@Override
public int getCount() {

    return nbrItem;
}

   public void setNbrItem(int nbrItem) {
    this.nbrItem= nbrItem;
}

现在,当您删除一个项目时,您会将新的项目数量传递给您的适配器

getAdapter().setNbrItem(2);
getAdapter().notifyDataSetChanged();

【讨论】:

  • 我做到了,正如您在我的MainActivity.java 文件代码中看到的那样,在MyViewPagerAdapter -> getCount() 方法中,我写了return fragments.size(),这是我的片段向其中添加和删除片段。显然,当我从片段中删除一个片段时,大小会减小,因此 4 必须变为 3,或者它不是正确的功能吗?
  • 您能解释一下您的意思吗,谢谢您的回复,您阅读我的MainActivity.java 代码了吗?你能解释一下我应该怎么做吗?
  • 是的,我读过,但是你的代码写得不好,你应该单独创建扩展pagerAdapter的类,尽量让你的代码更干净,最重要的是你必须添加一些参数您的 viewpagerapter 构造函数,例如选项卡项
  • 谢谢,我来看看能不能行。
  • 很抱歉打扰您 ismail ,但是我如何编写和使用该构造函数? ,对不起,我是初学者,您可以将其扩展一点,或者将代码添加到您的答案中吗?一些简短的例子。谢谢你帮助我兄弟。
【解决方案2】:

我解决了我的问题,但是通过 hack,您会看到错误是因为:TabItems 正在从 0 开始计数和索引,但是由于我的页面是动态创建的,因此我将 getCount() 我的 FragmentPagerAdapter 方法返回 ArrayList&lt;Fragment&gt; fragments 大小,另一方面,fragments.size() 的大小不计为 0。所以对于 3 个元素,而不是 0 1 2 ,或数字 2,它会返回到数字 3。

所以回到正题,我不得不在我的 ArrayList 中添加一个 null 并在我的 ArrayList 标题中添加一个 null,所以当我删除我的最后一个 TabItem 时,程序不会再崩溃,并且更方便,当用户关闭所有 Tabs 时,每次用户打开(添加)一个新的 tab 时,我都会调用 fragments.removeAll(Collections.singleton(null)); 来清除我插入的每个空元素,用于 TabTitles Too。

无论如何,为你们欢呼,我相信这对于那些想要创建此类应用程序的人来说是一个很好的教程,因为我已经包含了我的所有代码。请竖起大拇指。谢谢。

【讨论】:

    猜你喜欢
    • 2011-11-18
    • 2016-03-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-08-04
    相关资源
    最近更新 更多