ViewPager實現可滑動的Fragment,滑動頁面時報錯的解決方案
阿新 • • 發佈:2019-01-31
1. 主Activity和主佈局,線性佈局中只有一個ViewPager控制元件:
MainActivity.java
activity.xml
2. 三個繼承Fragment的類和對應佈局:
FragmentOne.java
FragmentTwo.java
FragmentThree.java
fragment_one.xml
fragment_two.xml
fragment_three.xml
3. 繼承FragmentPagerAdapter的類,用於管理ViewPager控制元件:
MyPagerAdapter.java
以上是實驗的環境,本人想要實現如下的效果:
1. 問題描述
但是,在左右滑動Fragment時,會報錯:
Caused by: java.lang.IllegalStateException: The specified child already has a parent. You must call removeView() on the child's parent first.
2. 部分程式碼
在FragmentOne的onCreateView方法中,我是按如下程式碼寫的。注意紅字部分,我對view進行了判斷,如果為空才建立。這是為了防止多次呼叫onCreateView而創建出多個view。
@Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { if(view == null) {//<span style="color:#ff0000;">注意這裡,view是私有成員變數。</span> view = inflater.inflate(R.layout.fragment_one, container, false); Log.i("my", "s"); } Log.i("my", "FragmentOne.onCreateView"); return view; }
MyPagerAdapter.java程式碼如下。我只重寫了構造建構函式和getItem(int arg0), getCount()兩個方法。
package guoweidong.android.test06; import java.util.ArrayList; import java.util.List; import android.support.v4.app.Fragment; import android.support.v4.app.FragmentManager; import android.support.v4.app.FragmentPagerAdapter; import android.util.Log; import android.view.ViewGroup; public class MyPagerAdapter extends FragmentPagerAdapter{ private List<Fragment> list; private FragmentManager fm; public MyPagerAdapter(FragmentManager fm) { super(fm); this.fm = fm; list = new ArrayList<Fragment>(); } public MyPagerAdapter(FragmentManager fm, List<Fragment> list) { super(fm); this.fm = fm; this.list = list; } @Override public Fragment getItem(int arg0) { // TODO Auto-generated method stub return list.get(arg0); } @Override public int getCount() { // TODO Auto-generated method stub return list.size(); } }
3. 問題發現
在FragmentPagerAdapter中有兩個方法:public Object instantiateItem(ViewGroup container, int position);
public void destroyItem(ViewGroup container, int position, Object object);
這兩個方法中第一個是用來將Fragment通過FragmentManager新增到ViewPager中的;第二個是用來將Fragment移除ViewPager的。在我們左右滑動Fragment時,在ViewPager中始終只保留兩個Fragment,剩餘的Fragment會移除ViewPager,但是並不會將此Fragment移除FragmentManager。
我們考慮一個問題:當Fragment被移除ViewPager後,又重新呼叫instantiateItem方法新增到ViewPager,但是在instantiateItem方法中不光新增到ViewPager,還新增到FragmentManager中,這就帶來了重複新增問題。
4. 解決方案
方案一: 刪掉FragmentOne的onCreateView的if判斷語句,得到下面程式碼:@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
view = inflater.inflate(R.layout.fragment_one, container, false);
return view;
}
這樣每次返回的view都是新建的,所以不存在重複新增問題。但是這麼做,會不斷增加FragmentManager的負擔。
方案二:
複寫FragmentViewPager的instantiateItem和destroyItem方法,使它不重複新增Fragment。
在MyPagerAdapter中新增下面的方法:
@Override
public Object instantiateItem(ViewGroup container, int position) {
String name = ""+ container.getId() + position;
Fragment fragment = fm.findFragmentByTag(name);
Log.i("my", name);
if(fragment != null) {
fm.beginTransaction()
.attach(fragment)
.commit();
Log.i("my", "attach");
} else {
fragment = getItem(position);
fm.beginTransaction()
.add(container.getId(), fragment, name)
.commit();
}
return fragment;
}
@Override
public void destroyItem(ViewGroup container, int position, Object object) {
// TODO Auto-generated method stub
String name = ""+ container.getId() + position;
Fragment fragment = fm.findFragmentByTag(name);
if(fragment != null) {
fm.beginTransaction()
.detach(fragment);
}
}