Не удается изменить TabItem (сбой программы), когда я удаляю один из моих TabItems с помощью кода

#android #android-layout #android-fragments #android-viewpager

#Android #android-макет #android-фрагменты #android-viewpager #android-layout

Вопрос:

У меня есть приложение, в котором я динамически создаю TabItems и добавляю их в TabLayout . Я покажу вам код ниже. тогда у меня также есть механизм, который при tabitem создании a пользователь может закрыть его одним нажатием кнопки. ТЕПЕРЬ: проблема возникает здесь. когда пользователь удаляет это 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
  

и все это происходит, когда я удаляю a 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 amp;amp; 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 (который создается, когда пользователь нажимает на один из элементов во фрагменте listview .

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

Итак … кто-нибудь может мне помочь, пожалуйста? проблема проста, почему ошибка The application's PagerAdapter changed the adapter's contents without calling PagerAdapter#notifyDataSetChanged! Expected adapter item count: 4, found: 3 появляется при удалении элемента tabitem, как я могу ее решить?

Комментарии:

1. Ваша проблема связана с тем фактом, что вы создаете новые MyViewPagerAdapter экземпляры повсюду. Создайте один раз и только изменяйте и уведомляйте об этом

Ответ №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();
  

Комментарии:

1. что ж, я сделал это, как вы можете видеть в моем MainActivity.java коде файла, в методе MyViewPagerAdapter -> getCount() , который я написал return fragments.size() , который является фрагментом, который я добавляю и удаляю к нему фрагменты. очевидно, что когда я удаляю фрагмент из фрагментов, размер уменьшается, и, следовательно, 4 должно стать 3, или это не правильная функция?

2. не могли бы вы, пожалуйста, объяснить, что вы имеете в виду, и поблагодарить вас за ваш ответ, вы читали мой MainActivity.java код? можете ли вы объяснить , что я должен делать ?

3. да, я прочитал это, но ваш код написан не очень хорошо, вам следует создать класс, который расширяет PagerAdapter отдельно , попытаться сделать ваш код более чистым, и самое главное, вам нужно добавить некоторые параметры в ваш конструктор viewpagerdapter, например tab item

4. Спасибо , я расскажу , что я могу сделать , посмотрим , сработает это или нет.

5. извините, что беспокою вас, Исмаил, но как мне написать и использовать этот конструктор? , извините, я новичок, вы можете расширить его немного больше или добавить код к своему ответу? что — нибудь короткое , например , пример . спасибо тебе , тааакая каша , за то , что помог мне , брат .

Ответ №2:

Я решил свою проблему, но с помощью взлома вы видите, что ошибка была вызвана тем, что: TabItems подсчитываются и индексируются с 0, но поскольку мои страницы создаются динамически, я установил getCount() метод my FragmentPagerAdapter для возврата ArrayList<Fragment> fragments размера fragments.size() , с другой стороны, размер an ArrayList не учитывает 0. итакдля 3 элементов вместо 0 1 2 или числа 2 он возвращается к числу 3.

итак, вернемся к делу, я был вынужден добавить null в свой ArrayList и один null в свои заголовки ArrayList, поэтому, когда я удалил свой последний TabItem , программа больше не зависает, и, чтобы быть более удобным, когда пользователь закрывает все Tabs , каждый раз, когда пользователь открывает (добавляет) новый tab , я вызываючтобы fragments.removeAll(Collections.singleton(null)); очистить каждый вставленный мной нулевой элемент, для заголовков таблиц тоже.

в любом случае, приветствую вас, ребята, я уверен, что это будет хорошим руководством для тех, кто хочет создавать такие приложения, потому что я включил все свои коды. пожалуйста, поднимите большой палец вверх. Спасибо.