#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));
очистить каждый вставленный мной нулевой элемент, для заголовков таблиц тоже.
в любом случае, приветствую вас, ребята, я уверен, что это будет хорошим руководством для тех, кто хочет создавать такие приложения, потому что я включил все свои коды. пожалуйста, поднимите большой палец вверх. Спасибо.