问题描述
我有一个应用程序,我在其中动态创建 TabItem 并将它们添加到 TabLayout
.我将向您展示下面的代码.然后我还有一个机制,当创建 tabitem
时,用户可以通过单击按钮关闭它.现在:问题发生在这里.当用户删除该 tabitem
时,程序会自动将用户定向到另一个选项卡.我无法再单击在应用程序开始时创建的其他选项卡.我可以点击它们,但程序因错误而关闭
I have an application in which I create TabItems dynamically and I add them to the TabLayout
. I'll show you the code below. then I also have a mechanism that when a tabitem
is created, the user can close it with a click of a button. NOW: the problem happens here. when the user deletes that tabitem
and program automatically directs the user to another tab. I can no longer click on the other tabs that I created at the start of the application. I Can click on them, but the program closes with the error
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 代码:
and all of this happens when I delete a tabitem
with a code written for a click. below is my MainActivity.java code :
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 的代码(当用户单击列表视图片段中的一项时创建该代码.
and the code for UserDetailFragment ( which creates when the user click on one of the items in a listview fragment .
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);
}
最后但并非最不重要的是:该列表项的代码,当用户单击其项时创建动态选项卡:
and last but not least : the code for that list item that creates dynamic tabs when user clicks on its items :
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;
}
}
所以...有人可以帮我吗?问题很简单,为什么错误 The application's PagerAdapter 改变了适配器的内容而没有调用 PagerAdapter#notifyDataSetChanged!预期的适配器项数:4,发现:3
移除 tabitem 时出现,我该如何解决?
So... can anyone help me please? the problem is simple, why the error The application's PagerAdapter changed the adapter's contents without calling PagerAdapter#notifyDataSetChanged! Expected adapter item count: 4, found: 3
appears when a tabitem is removed, how can I solve it?
推荐答案
我解决了我的问题,但是通过 hack,您会看到错误是因为:TabItems
are counting and indexing from 0, but因为我的页面是动态创建的,所以我设置了我的 FragmentPagerAdapter
的 getCount()
方法返回 ArrayList;片段
size ,与 fragments.size()
,另一方面,ArrayList
的大小不计为 0.所以对于 3 个元素,而是0 1 2 或数字 2,返回数字 3.
I solved my Problem, But with a hack, you see the error was because: TabItems
are counting and indexing from 0, but as my pages are dynamically creating, I set thegetCount()
method of my FragmentPagerAdapter
to return the ArrayList<Fragment> fragments
size , with fragments.size()
, on the other hand, the size of an ArrayList
doesn't count 0. so for 3 elements, instead of 0 1 2, or number 2, it returns to number 3.
回到正题,我不得不在我的 ArrayList 中添加 null,在我的 ArrayList 标题中添加一个 null,这样当我删除最后一个 TabItem
时,程序不再崩溃,并且为了更方便,当用户关闭所有 Tabs
时,每次用户打开(添加)一个新的 tab
时,我调用 fragments.removeAll(Collections.singleton(null)));
为 TabTitles Too 清除我插入的每个空元素.
so back to business, I was compelled to add null to my ArrayList and one null to my ArrayList titles, so this way when I removed my last TabItem
, program doesn't crash anymore, and to be more convenient, when a user closes all Tabs
, everytime user opens ( adds ) a new tab
, I call fragments.removeAll(Collections.singleton(null));
to clear every null element i have inserted, for the TabTitles Too .
无论如何,为你们加油,我相信这对于那些想要创建此类应用程序的人来说是一个很好的教程,因为我已经包含了我的所有代码.请竖起大拇指.谢谢.
anyway cheers you guys, I'm sure this would be a good tutorial for those who want to create such applications because I've included all of my codes. please give a thumbs up. thanks.
这篇关于无法更改 tabItem(程序崩溃),当我用代码删除我的 tabItems 之一时的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!