2016-02-14 43 views
0

我正在使用包含一系列片段的ViewPager爲我的Android應用創建介紹部分。該片段的代碼是:ViewPager使用片段時出錯,「指定的孩子已經有父級」

package testing.testmusic; 

import android.graphics.Bitmap; 
import android.os.Bundle; 
import android.support.v4.app.Fragment; 
import android.view.LayoutInflater; 
import android.view.View; 
import android.view.ViewGroup; 
import android.widget.FrameLayout; 
import android.widget.ImageView; 

import butterknife.Bind; 
import butterknife.ButterKnife; 

public class IntroPageFragment extends Fragment { 
    /** 
    * Used during logging to identify this class. 
    */ 
    private static final String TAG = "[IntroPageFragment]"; 

    /** 
    * Used to prevent premature attempts to update the UI. 
    */ 
    private boolean viewsBoundToInstanceVariables = false; 

    /** 
    * Holds and displays a {@code Bitmap} at the top of the screen. This {@code View} is drawn in 
    * front of {@code backImageHolder} but behind {@code contentHolder} by default. 
    */ 
    @Bind(R.id.intro_fragment_imageFront) protected ImageView frontImageHolder; 

    /** 
    * Holds and displays a {@code Bitmap} at the top of the screen. This {@code View} is drawn 
    * behind both {@code backImageHolder} and {@code contentHolder} by default. 
    */ 
    @Bind(R.id.intro_fragment_imageBack) protected ImageView backImageHolder; 

    /** 
    * Displays custom content at the centre of the screen. This {@code View} is drawn in front of 
    * both {@code backImageHolder} and {@code contentHolder} by default. 
    */ 
    @Bind(R.id.intro_fragment_content) protected FrameLayout contentHolder; 

    /** 
    * The image to display in {@code frontImageHolder}. 
    */ 
    private Bitmap frontImage = null; 

    /** 
    * The image to display in {@code backImageHolder}. 
    */ 
    private Bitmap backImage = null; 

    /** 
    * The content to display in {@code contentHolder}. 
    */ 
    private View content = null; 

    /** 
    * Constructs a new IntroPageFragment instance. Avoid calling this method directly, instead 
    * call {@link #newInstance()}. 
    */ 
    public IntroPageFragment() {} 

    /** 
    * @return a new IntroPageFragment instance. 
    */ 
    public static IntroPageFragment newInstance() { 
     return new IntroPageFragment(); 
    } 

    @Override 
    public View onCreateView(final LayoutInflater inflater, final ViewGroup container, 
      final Bundle savedInstanceState) { 

     final View fragmentRoot = inflater.inflate(R.layout.fragment_intro_page, container, false); 
     ButterKnife.bind(this, fragmentRoot); 
     viewsBoundToInstanceVariables = true; 
     updateViewsToReflectData(); 
     return fragmentRoot; 
    } 

    /** 
    * Displays the provided image at the top of the screen. The image will be drawn in front of 
    * any image supplied to {@link #setBackImage(Bitmap)}, but behind any {@code Views} supplied 
    * to {@link #setContent(View)} (by default). 
    * 
    * @param frontImage the image to display 
    * @return this {@code IntroPageFragment} to allow method chaining 
    */ 
    public IntroPageFragment setFrontImage(final Bitmap frontImage) { 
     this.frontImage = frontImage; 
     updateViewsToReflectData(); 
     return this; 
    } 

    /** 
    * @return the ImageView which holds the image supplied to {@link #setFrontImage(Bitmap)} 
    */ 
    public ImageView getFrontImageHolder() { 
     return frontImageHolder; 
    } 

    /** 
    * Displays the provided image at the top of the screen. The image will be drawn in behind of 
    * any image supplied to {@link #setBackImage(Bitmap)}, and behind any {@code Views} supplied 
    * to {@link #setContent(View)} (by default). 
    * 
    * @param backImage the image to display 
    * @return this {@code IntroPageFragment} to allow method chaining 
    */ 
    public IntroPageFragment setBackImage(final Bitmap backImage) { 
     this.backImage = backImage; 
     updateViewsToReflectData(); 
     return this; 
    } 

    /** 
    * @return the ImageView which holds the image supplied to {@link #setBackImage(Bitmap)} 
    */ 
    public ImageView getBackImageHolder() { 
     return backImageHolder; 
    } 

    /** 
    * Adds the provided content to a FrameLayout at the centre of the screen. The content will be 
    * drawn in front of any images supplied to {@link #setFrontImage(Bitmap)} and {@link 
    * #setBackImage (Bitmap)} (by default). 
    * 
    * @param content the content to display on this page 
    * @return this {@code IntroPageFragment} to allow method chaining 
    */ 
    public IntroPageFragment setContent(final View content) { 
     this.content = content; 
     updateViewsToReflectData(); 
     return this; 
    } 

    /** 
    * @return the FrameLayout which displays the content supplied to {@link #setContent(View)} 
    */ 
    public FrameLayout getContentHolder() { 
     return contentHolder; 
    } 

    /** 
    * Updates all views to use the images and content supplied to {@link #setFrontImage(Bitmap)}, 
    * {@link #setBackImage(Bitmap)} and {@link #setContent(View)}. 
    */ 
    public void updateViewsToReflectData() { 
     if (viewsBoundToInstanceVariables) { 
      frontImageHolder.setImageBitmap(frontImage); 
      backImageHolder.setImageBitmap(backImage); 
      contentHolder.removeAllViews(); 

      if (content != null) { 
       contentHolder.addView(content); 
       contentHolder.invalidate(); 
      } 
     } 
    } 
} 

片段佈局是:

<?xml version="1.0" encoding="utf-8"?> 
<android.support.v4.view.ViewPager 
     android:id="@+id/intro_activity_viewpager" 
     xmlns:android="http://schemas.android.com/apk/res/android" 
     xmlns:tools="http://schemas.android.com/tools" 
     android:layout_width="match_parent" 
     android:layout_height="match_parent" 
     android:fitsSystemWindows="false" 
     tools:context="testing.testmusic.IntroActivity"> 
</android.support.v4.view.ViewPager> 

如預期的應用程序啓動並顯示片段,然而通過頁面滾動時,第三滾動(向前或向後,那並不噸有所作爲)導致以下錯誤:

FATAL EXCEPTION: main 
Process: testing.testmusic, PID: 12404 
java.lang.IllegalStateException: The specified child already has a parent. You must call removeView() on the child's parent first. 
at android.view.ViewGroup.addViewInner(ViewGroup.java:4309) 
at android.view.ViewGroup.addView(ViewGroup.java:4145) 
at android.view.ViewGroup.addView(ViewGroup.java:4086) 
at android.view.ViewGroup.addView(ViewGroup.java:4059) 
at testing.testmusic.IntroPageFragment.updateViewsToReflectData(IntroPageFragment.java:158) 
at testing.testmusic.IntroPageFragment.onCreateView(IntroPageFragment.java:80) 
at android.support.v4.app.Fragment.performCreateView(Fragment.java:1962) 
at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1067) 
at android.support.v4.app.FragmentManagerImpl.attachFragment(FragmentManager.java:1426) 
at android.support.v4.app.BackStackRecord.run(BackStackRecord.java:728) 
at android.support.v4.app.FragmentManagerImpl.execPendingActions(FragmentManager.java:1613) 
at android.support.v4.app.FragmentManagerImpl.executePendingTransactions(FragmentManager.java:570) 
at android.support.v4.app.FragmentPagerAdapter.finishUpdate(FragmentPagerAdapter.java:141) 
at android.support.v4.view.ViewPager.populate(ViewPager.java:1106) 
at android.support.v4.view.ViewPager.populate(ViewPager.java:952) 
at android.support.v4.view.ViewPager$3.run(ViewPager.java:251) 
at android.view.Choreographer$CallbackRecord.run(Choreographer.java:858) 
at android.view.Choreographer.doCallbacks(Choreographer.java:670) 
at android.view.Choreographer.doFrame(Choreographer.java:603) 
at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:844) 
at android.os.Handler.handleCallback(Handler.java:739) 
at android.os.Handler.dispatchMessage(Handler.java:95) 
at android.os.Looper.loop(Looper.java:148) 
at android.app.ActivityThread.main(ActivityThread.java:5417) 
at java.lang.reflect.Method.invoke(Native Method) 
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:726) 
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:616) 

跟蹤導致方法updateViewsToReflectDataIntroPageFragment,具體地contentHolder.addView(content)。我不明白爲什麼會出現此錯誤,因爲contentHolder.removeAllViews()總是直接在前面調用。爲什麼會發生此錯誤?

萬一有幫助,這是我的活動代碼:

package testing.testmusic; 

     import android.graphics.Bitmap; 
     import android.os.Bundle; 
     import android.support.v4.view.ViewPager; 
     import android.support.v7.app.AppCompatActivity; 
     import android.widget.ImageView; 

     import butterknife.Bind; 
     import butterknife.ButterKnife; 

     public class IntroActivity extends AppCompatActivity { 
      /** 
      * Used during logging to identify this class. 
      */ 
      private static final String TAG = "[IntroActivity]"; 

      /** 
      * Displays an interactive multi-page intro screen to the user. 
      */ 
      @Bind(R.id.intro_activity_viewpager) protected ViewPager viewPager; 

      /** 
      * Adapts the elements of {@code fragments} to views in {@code viewPager}. 
      */ 
      private IntroPageAdapter adapter = new IntroPageAdapter(getSupportFragmentManager()); 

      @Override 
      protected void onCreate(Bundle savedInstanceState) { 
       super.onCreate(savedInstanceState); 
       setContentView(R.layout.activity_introduction); 
       ButterKnife.bind(this); 
       viewPager.setAdapter(adapter); 
       createPages(); 
      } 

      /** 
      * Populates {@code fragments} with the pages to display in {@code viewPager}. 
      */ 
      private void createPages() { 
       Bitmap rainbow = BitmapHelper 
         .decodeSampledBitmapFromResource(getResources(), R.raw.rainbow, 100, 100); 
       Bitmap frontDots = BitmapHelper 
         .decodeSampledBitmapFromResource(getResources(), R.raw.front, 1000, 1000); 
       Bitmap backDots = BitmapHelper 
         .decodeSampledBitmapFromResource(getResources(), R.raw.back, 1000, 1000); 

       for (int i = 0; i < 10; i++) { 
        IntroPageFragment page = IntroPageFragment.newInstance(); 
        page.setFrontImage(frontDots); 
        page.setBackImage(backDots); 
        ImageView content = new ImageView(this); 
        content.setImageBitmap(rainbow); 
        page.setContent(content); 
        adapter.addPage(page); 
       } 
      } 
     } 

,這裏是我的適配器代碼:

package testing.testmusic; 

import android.support.v4.app.Fragment; 
import android.support.v4.app.FragmentManager; 
import android.support.v4.app.FragmentPagerAdapter; 

import java.util.ArrayList; 
import java.util.List; 

public class IntroPageAdapter extends FragmentPagerAdapter { 
    List<IntroPageFragment> fragments; 

    public IntroPageAdapter(FragmentManager fm) { 
     super(fm); 
     this.fragments = new ArrayList<>(); 
    } 

    @Override 
    public Fragment getItem(int position) { 
     return fragments.get(position); 
    } 

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

    public void addPage(IntroPageFragment page) { 
     if (page != null) { 
      fragments.add(page); 
      notifyDataSetChanged(); 
     } 
    } 

    public void removePage(IntroPageFragment page) { 
     fragments.remove(page); 
     notifyDataSetChanged(); 
    } 
} 
+0

你可以在這裏檢查:http://stackoverflow.com/questions/13559353/how-to-solve-for-viewpager-the-specified-child-alr伊迪 - 有-A-家長您,絕 –

回答

0

改變方法updateViewsToReflectData以下解決了這一問題:

public void updateViewsToReflectData() { 
     if (viewsBoundToInstanceVariables) { 
      frontImageHolder.setImageBitmap(frontImage); 
      backImageHolder.setImageBitmap(backImage); 
      contentHolder.removeAllViewsInLayout(); 

      if (content != null) { 
       if (content.getParent() == null) { 
        contentHolder.addView(content); 
        contentHolder.invalidate(); 
       } 
      } 
     } 
    } 
相關問題