ViewPager 中的片段在 getView() 中返回 null

Posted

技术标签:

【中文标题】ViewPager 中的片段在 getView() 中返回 null【英文标题】:Fragment inside ViewPager returning null in getView() 【发布时间】:2013-10-07 02:33:49 【问题描述】:

在我的应用程序中,我有一个 ViewPager,在该 ViewPager 中大约有 17 个片段。我已经为纵向和横向设计了布局。 当我旋转屏幕时,getView() 方法返回一个空对象,不知道为什么会这样,我使用了setRetainInstance(true),但还是一样,我使用PagerStateFragmentAdapter 作为我的适配器实施。

为什么会发生这种情况?

提前谢谢你。

编辑

MainActivity

public class MainActivity extends FragmentActivity implements ViewPagerController
    public static final String READ_TYPE = "Read_type";
    private static final String TAG = MainActivity.class.getSimpleName();
    private int mReadType;
    private ViewPager mBookPager;

    @Override
    public void goToNextPage() 
        // TODO Auto-generated method stub
        int currentPage = mBookPager.getCurrentItem();
        if(currentPage+1 < mBookPager.getAdapter().getCount())
            FragmentPagerAdapter adapter = (FragmentPagerAdapter)mBookPager.getAdapter();
            BookPageFragment bookPage = (BookPageFragment)adapter.getItem(currentPage);
            bookPage.setCurrentPage(false);

            bookPage = (BookPageFragment)adapter.getItem(currentPage+1);
            bookPage.setCurrentPage(true);
            mBookPager.setCurrentItem(currentPage+1, true);
        
    

    @Override
    public void goToPreviousPage() 
        // TODO Auto-generated method stub
        int currentPage = mBookPager.getCurrentItem();
        if(currentPage >= 0)
            mBookPager.setCurrentItem(currentPage-1,true);
        
    

    @Override
    public void onBackPressed() 
        // TODO Auto-generated method stub
        finish();
        overridePendingTransition(R.anim.anim_move_to_right,R.anim.anim_from_left_to_right);
    

    @Override
    protected void onDestroy() 
        // TODO Auto-generated method stub
        Log.i(TAG,"onDestroy");
        mBookPager.removeAllViews();
        mBookPager = null;
        super.onDestroy();
    

    @Override
    protected void onCreate(Bundle arg0) 
        // TODO Auto-generated method stub
        super.onCreate(arg0);
        setContentView(R.layout.main_layout);
        overridePendingTransition(R.anim.anim_from_right_to_left, R.anim.anim_move_to_left);
        initReadType();
        mBookPager = (ViewPager)findViewById(R.id.mainLayout_mainViewPager);
        initViewPager();

    

    private void initReadType()
        mReadType = getIntent().getIntExtra(READ_TYPE, -1);
    

    private void initViewPager()
        BookPagerAdapter mPagerAdapter = new BookPagerAdapter(getSupportFragmentManager(),mReadType);
        ((BookPageFragment)mPagerAdapter.getItem(0)).setCurrentPage(true);
        mBookPager.setAdapter(mPagerAdapter);
        mBookPager.setOnPageChangeListener(mOnPageChangeListener);
    

    private OnPageChangeListener mOnPageChangeListener = new OnPageChangeListener()

        @Override
        public void onPageScrollStateChanged(int arg0) 
            // TODO Auto-generated method stub

        

        @Override
        public void onPageScrolled(int arg0, float arg1, int arg2) 
            // TODO Auto-generated method stub

        

        @Override
        public void onPageSelected(int selection) 
            // TODO Auto-generated method stub
            BookPagerAdapter bookAdapter = (BookPagerAdapter)mBookPager.getAdapter();
            BookPageFragment fragment = (BookPageFragment)bookAdapter.getItem(selection);
            if(selection > 0)
                bookAdapter.getItem(selection - 1).onPause();
//              bookAdapter.getItem(selection - 1).onDestroy();
            
            if(selection + 1 < bookAdapter.getCount() && (bookAdapter.getItem(selection + 1) != null))
                bookAdapter.getItem(selection + 1).onPause();
            
            fragment.setCurrentPage(true);
            fragment.onResume();
        

    ;

    public static class BookPagerAdapter extends FragmentStatePagerAdapter
        private List<Fragment> mBookPagesList;
        private int mReadType;

        public BookPagerAdapter(FragmentManager fm,int readType) 
            super(fm);
            // TODO Auto-generated constructor stub
            mReadType = readType;
            initPages();
        

        @Override
        public Fragment getItem(int position) 
            // TODO Auto-generated method stub
            return mBookPagesList.get(position);
        

        @Override
        public int getCount() 
            // TODO Auto-generated method stub
            return mBookPagesList.size();
        

        private void initPages()
            mBookPagesList = new ArrayList<Fragment>();
            mBookPagesList.add(FirstPageFragment.newInstance(mReadType));
            mBookPagesList.add(SecondPageFragment.newInstance(mReadType));
            mBookPagesList.add(ThirdPageFragment.newInstance(mReadType));
            mBookPagesList.add(FourthPageFragment.newInstance(mReadType));
            mBookPagesList.add(FifthPageFragment.newInstance(mReadType));
            mBookPagesList.add(SixthPageFragment.newInstance(mReadType));
            mBookPagesList.add(SeventhPageFragment.newInstance(mReadType));
            mBookPagesList.add(EigthPageFragment.newInstance(mReadType));
            mBookPagesList.add(NinethPageFragment.newInstance(mReadType));
            mBookPagesList.add(TenthPageFragment.newInstance(mReadType));
            mBookPagesList.add(EleventhPageFragment.newInstance(mReadType));
            mBookPagesList.add(TwelvethPageFragment.newInstance(mReadType));
            mBookPagesList.add(ThirteenthPageFragment.newInstance(mReadType));
            mBookPagesList.add(FourteenthPageFragment.newInstance(mReadType));
            mBookPagesList.add(FifteenthPageFragment.newInstance(mReadType));
            mBookPagesList.add(SixteenthPageFragment.newInstance(mReadType));
            mBookPagesList.add(SeventeenthPageFragment.newInstance(mReadType));
            mBookPagesList.add(CreditsPageFragment.newInstance(mReadType));
        
    

BookPageFragment

public abstract class BookPageFragment extends Fragment
public static final String TAG = BookPageFragment.class.getSimpleName();

public static final int AUTO_PLAY = 1;
public static final int READ_WITH_ME = 2;
public static final int READ_TO_MYSELF = 3;

private ViewPagerController mPageController;
protected final static String READ_TYPE_KEY = "readType";

private boolean mIsCurrentPage;

private int mCurrentWordIndex;
private MediaPlayer mMediaPlayer;
private BookPage mBookPage;
private SpeechController mSpeechController;

private TextHighlightController mCurrentHighlightController;
protected List<TextHighlightController> mHighlighters;
private int mCurrentHighlightIndex;

public abstract int getJsonId();
public abstract int getAudioResourceId();
protected abstract int[] getParagraphsTextView();
protected abstract int[] getParagraphsStringRes();
protected abstract int[] getPopupButtonsId();

public BookPageFragment()
    mIsCurrentPage = false;
    mCurrentHighlightIndex = 0;


public void endAudioPlayback()
    if(getReadTypeFromArgs() == AUTO_PLAY)
        mPageController.goToNextPage();
    


private void loadHighlighters()
    int[] paragraphsTextViews = getParagraphsTextView();
    int[] stringRes = getParagraphsStringRes();
    for(int i=0;i<paragraphsTextViews.length;i++)
        int currentParagraph = paragraphsTextViews[i];
        int stringId = stringRes[i];
        TextView paragraph = (TextView)getView().findViewById(currentParagraph);
        TextHighlightController controller = TextHighlightController.newInstance(getActivity(), paragraph, stringId);
        addHighlighter(controller);
    


public final void highlightNextWord()
    if(!mCurrentHighlightController.highlightNextWord())
        mCurrentHighlightIndex++;
        if(mCurrentHighlightIndex < mHighlighters.size())
            mCurrentHighlightController = mHighlighters.get(mCurrentHighlightIndex);
            mCurrentHighlightController.highlightNextWord();
        
    


@Override
public void onAttach(Activity activity) 
    // TODO Auto-generated method stub
    super.onAttach(activity);
    Log.i(TAG,"onAttach");
    try
        mPageController = (ViewPagerController)activity;
    catch(ClassCastException e)
        throw new IllegalArgumentException("Activity not implementing ViewPagerController");
    


@Override
public void onCreate(Bundle savedInstanceState) 
    // TODO Auto-generated method stub
    super.onCreate(savedInstanceState);
    Log.i(TAG,"onCreate");


@Override
public void onDetach() 
    // TODO Auto-generated method stub
    super.onDetach();
    resetAll();
    Log.i(TAG,"onDetach");


public void goToNextPage()
    mPageController.goToNextPage();


public void goToPreviousPage()
    mPageController.goToPreviousPage();


public void setCurrentPage(boolean isCurrentPage)
    mIsCurrentPage = isCurrentPage;


public boolean isCurrentPage()
    return mIsCurrentPage;


@Override
public void onStart() 
    // TODO Auto-generated method stub
    super.onStart();
    Log.i(TAG,"onStart");


@Override
public void onResume() 
    // TODO Auto-generated method stub
    Log.i(TAG,"onResume");
    super.onResume();
    resetAll();
    configureBookPage();


public final void startWithAutoPlay()
    disablePopupButtons();
    initAudioPlayback();


public final void startWithRead()
    initAudioPlayback();


private long prevWordStartTime = 0;
public final long getNextWordStart()
    long wordStart=-1;
    if(mCurrentWordIndex < mBookPage.getWordList().size())
        Word currentWord = mBookPage.getWordList().get(mCurrentWordIndex);
        wordStart = currentWord.getStartTime() - prevWordStartTime;
        wordStart = wordStart + currentWord.getWordLength() - 25;
        prevWordStartTime = currentWord.getEndTime();
        mCurrentWordIndex++;
    
    return wordStart;


public final long getNextWordLength()
    long wordLength;
    if(mCurrentWordIndex < mBookPage.getWordList().size())
        Word currentWord = mBookPage.getWordList().get(mCurrentWordIndex);
        if(mCurrentWordIndex == 0)
            wordLength= currentWord.getStartTime();
        else
            wordLength = currentWord.getWordLength();
        
        mCurrentWordIndex++;
    else
        wordLength = -1;
    
    return wordLength;


public final void startPlayback()
    mMediaPlayer = MediaPlayer.create(getActivity(), getAudioResourceId());
    mMediaPlayer.start();


@Override
public void onPause() 
    // TODO Auto-generated method stub
    Log.i(TAG,"onPause");
    mIsCurrentPage = false;
    if(mSpeechController != null)
        mSpeechController.stopHighlighting();
    
    if(mMediaPlayer != null)
        try
            mMediaPlayer.stop();
            mMediaPlayer.release();
        catch(Exception e)

        
    
    resetHighlighters();
    resetAll();
    super.onPause();


@Override
public void onStop() 
    // TODO Auto-generated method stub
    super.onStop();
    Log.i(TAG,"onStop");


protected void addHighlighter(TextHighlightController controller)
    if(mHighlighters == null)
        mHighlighters = new ArrayList<TextHighlightController>();
    
    mHighlighters.add(controller);


private void resetHighlighters()
    if(mHighlighters != null)
        for(TextHighlightController controller : mHighlighters)
            controller.reset();
        
    
    mCurrentHighlightIndex = 0;
    mCurrentWordIndex = 0;


private void resetAll()
    mCurrentWordIndex = 0;
    mCurrentHighlightIndex = 0;
    if(mMediaPlayer != null)
        try
            mMediaPlayer.reset();
        catch(Exception e)

        
    
    if(mCurrentHighlightController != null)
        mCurrentHighlightController.reset();
    
    if(mSpeechController != null)
        Message msg = mSpeechController.obtainMessage(SpeechController.END_AUDIO);
        mSpeechController.sendMessage(msg);
    
    if(mHighlighters != null)
        for(TextHighlightController controller : mHighlighters)
            controller.reset();
        
    


private void initAudioPlayback()
    if(getJsonId() != 0)
        initHighlightersList();
        loadJson();
        mSpeechController = new SpeechController(this);
        Message msg = mSpeechController.obtainMessage(SpeechController.START_AUTO_PLAY);
        mSpeechController.sendMessageDelayed(msg, 1000);
    


private void disablePopupButtons()
    if(getView() != null)
        int[] buttonsId = getPopupButtonsId();
        for(int currentButtonId : buttonsId)
            getView().findViewById(currentButtonId).setVisibility(View.INVISIBLE);
        
    


private void initHighlightersList()
    loadHighlighters();
    if(mHighlighters != null)
        mCurrentHighlightController = mHighlighters.get(mCurrentHighlightIndex);


private void loadJson()
    Gson gson = new Gson();
    InputStream jsonStream = getResources().openRawResource(getJsonId());
    InputStreamReader jsonReader = new InputStreamReader(jsonStream);
    mBookPage = gson.fromJson(jsonReader, BookPage.class);


private void configureBookPage()
    int currentReadType = getReadTypeFromArgs();
    Log.i(TAG,"GotReadType");
    switch(currentReadType)
    case AUTO_PLAY:
        if(mIsCurrentPage)
            startWithAutoPlay();
        
        break;
    case READ_WITH_ME:
        if(mIsCurrentPage)
            startWithRead();
        
        break;
    case READ_TO_MYSELF:
        //Should do Nothing
        break;
    default:
        throw new IllegalArgumentException("You must select one of the reading types of BookPageFragment");
    


protected int getReadTypeFromArgs()
    return getArguments().getInt(READ_TYPE_KEY);

LOGCAT

    09-30 22:56:37.602: E/androidRuntime(7640): FATAL EXCEPTION: main
09-30 22:56:37.602: E/AndroidRuntime(7640): java.lang.NullPointerException
09-30 22:56:37.602: E/AndroidRuntime(7640):     at com.mobimanage.kagadventures.fragment.BookPageFragment.loadHighlighters(BookPageFragment.java:68)
09-30 22:56:37.602: E/AndroidRuntime(7640):     at com.mobimanage.kagadventures.fragment.BookPageFragment.initHighlightersList(BookPageFragment.java:275)
09-30 22:56:37.602: E/AndroidRuntime(7640):     at com.mobimanage.kagadventures.fragment.BookPageFragment.initAudioPlayback(BookPageFragment.java:257)
09-30 22:56:37.602: E/AndroidRuntime(7640):     at com.mobimanage.kagadventures.fragment.BookPageFragment.startWithRead(BookPageFragment.java:149)
09-30 22:56:37.602: E/AndroidRuntime(7640):     at com.mobimanage.kagadventures.fragment.BookPageFragment.configureBookPage(BookPageFragment.java:298)
09-30 22:56:37.602: E/AndroidRuntime(7640):     at com.mobimanage.kagadventures.fragment.BookPageFragment.onResume(BookPageFragment.java:140)
09-30 22:56:37.602: E/AndroidRuntime(7640):     at com.mobimanage.kagadventures.MainActivity$1.onPageSelected(MainActivity.java:136)
09-30 22:56:37.602: E/AndroidRuntime(7640):     at android.support.v4.view.ViewPager.scrollToItem(ViewPager.java:567)
09-30 22:56:37.602: E/AndroidRuntime(7640):     at android.support.v4.view.ViewPager.setCurrentItemInternal(ViewPager.java:551)
09-30 22:56:37.602: E/AndroidRuntime(7640):     at android.support.v4.view.ViewPager.onTouchEvent(ViewPager.java:2008)
09-30 22:56:37.602: E/AndroidRuntime(7640):     at android.view.View.dispatchTouchEvent(View.java:7253)
09-30 22:56:37.602: E/AndroidRuntime(7640):     at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2168)
09-30 22:56:37.602: E/AndroidRuntime(7640):     at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:1903)
09-30 22:56:37.602: E/AndroidRuntime(7640):     at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2174)
09-30 22:56:37.602: E/AndroidRuntime(7640):     at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:1917)
09-30 22:56:37.602: E/AndroidRuntime(7640):     at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2174)
09-30 22:56:37.602: E/AndroidRuntime(7640):     at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:1917)
09-30 22:56:37.602: E/AndroidRuntime(7640):     at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2174)
09-30 22:56:37.602: E/AndroidRuntime(7640):     at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:1917)
09-30 22:56:37.602: E/AndroidRuntime(7640):     at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2174)
09-30 22:56:37.602: E/AndroidRuntime(7640):     at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:1917)
09-30 22:56:37.602: E/AndroidRuntime(7640):     at com.android.internal.policy.impl.PhoneWindow$DecorView.superDispatchTouchEvent(PhoneWindow.java:2215)
09-30 22:56:37.602: E/AndroidRuntime(7640):     at com.android.internal.policy.impl.PhoneWindow.superDispatchTouchEvent(PhoneWindow.java:1458)
09-30 22:56:37.602: E/AndroidRuntime(7640):     at android.app.Activity.dispatchTouchEvent(Activity.java:2410)
09-30 22:56:37.602: E/AndroidRuntime(7640):     at com.android.internal.policy.impl.PhoneWindow$DecorView.dispatchTouchEvent(PhoneWindow.java:2163)
09-30 22:56:37.602: E/AndroidRuntime(7640):     at android.view.View.dispatchPointerEvent(View.java:7433)
09-30 22:56:37.602: E/AndroidRuntime(7640):     at android.view.ViewRootImpl.deliverPointerEvent(ViewRootImpl.java:3220)
09-30 22:56:37.602: E/AndroidRuntime(7640):     at android.view.ViewRootImpl.deliverInputEvent(ViewRootImpl.java:3165)
09-30 22:56:37.602: E/AndroidRuntime(7640):     at android.view.ViewRootImpl.doProcessInputEvents(ViewRootImpl.java:4292)
09-30 22:56:37.602: E/AndroidRuntime(7640):     at android.view.ViewRootImpl.enqueueInputEvent(ViewRootImpl.java:4271)
09-30 22:56:37.602: E/AndroidRuntime(7640):     at android.view.ViewRootImpl$WindowInputEventReceiver.onInputEvent(ViewRootImpl.java:4363)
09-30 22:56:37.602: E/AndroidRuntime(7640):     at android.view.InputEventReceiver.dispatchInputEvent(InputEventReceiver.java:179)
09-30 22:56:37.602: E/AndroidRuntime(7640):     at android.os.MessageQueue.nativePollOnce(Native Method)
09-30 22:56:37.602: E/AndroidRuntime(7640):     at android.os.MessageQueue.next(MessageQueue.java:125)
09-30 22:56:37.602: E/AndroidRuntime(7640):     at android.os.Looper.loop(Looper.java:124)
09-30 22:56:37.602: E/AndroidRuntime(7640):     at android.app.ActivityThread.main(ActivityThread.java:5227)
09-30 22:56:37.602: E/AndroidRuntime(7640):     at java.lang.reflect.Method.invokeNative(Native Method)
09-30 22:56:37.602: E/AndroidRuntime(7640):     at java.lang.reflect.Method.invoke(Method.java:511)
09-30 22:56:37.602: E/AndroidRuntime(7640):     at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:795)
09-30 22:56:37.602: E/AndroidRuntime(7640):     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:562)
09-30 22:56:37.602: E/AndroidRuntime(7640):     at dalvik.system.NativeStart.main(Native Method)

【问题讨论】:

你能发布相应的代码吗? 完成!有代码 没关系。需要播种您的 PagerStateFragmentAdapter。 为了帮助我们需要查看代码以供我们分析,而不仅仅是您认为相关的代码。我们也需要查看 logcat。 有logcat,它说错误在'loadHighlighters'中,当我调试时我看到getView()它返回null 【参考方案1】:

而不是使用getItem来获取当前页面使用

(BookPageFragment) mBookPagerAdapter.instantiateItem(mBookPager, mBookPager.getCurrentItem());

这会返回一个对实际有视图的现有片段的引用。

【讨论】:

小建议:第一个mBookPager是适配器,第二个是viewPager 这个问题是双重的,但是:首先,它依赖于重写的 instantiateItem(),根据实现,它可能不仅仅是返回前一个片段,而是创建一个新片段。其次,不推荐将 View 作为第一个参数的调用。 -- 我找到了一个可行的解决方案,我会把它作为答案发布。 你救了我的命 :-)【参考方案2】:

如果您像往常一样在页面适配器中跟踪片段,请向其中添加以下函数:

private SparseArray<PageType> fragments;
...
public PageType getFragment(int position) 
  return fragments.get(position);

然后您可以使用它来查询片段。 getView() 已经可以正常工作了:

PageType page = (PageType) pagesAdapter.getFragment(pager.getCurrentItem());
View view = page.getView().findViewById(R.id.whatever);
view.invalidate();

【讨论】:

这真的有效吗? Androd 可能决定销毁一个片段,它仍然在您的片段数组中,然后重新创建它,然后您的数组中有一个过时的版本。不过,我还不确定这是否会发生。【参考方案3】:

对于android.support.v4.app.FragmentManager,setRetainInstance 会被忽略。

对我有用的解决方案是在调用 super.OnCreate 之前删除我活动的 onCreate 中保存的片段。

if(savedInstanceState != null) 
    savedInstanceState.remove("android:support:fragments");

这对我有用,就像我期望 setRetainInstance(true); 在片段本身中工作一样。

我找到了这个解决方案here

*请注意,如果您从任何片段调用 DialogFragment,如果您使用此解决方案,它们将在方向更改时关闭。

【讨论】:

以上是关于ViewPager 中的片段在 getView() 中返回 null的主要内容,如果未能解决你的问题,请参考以下文章

片段中的getView()导致抛出异常,不确定原因

单击按钮时刷新片段视图

ViewPager2 中的片段在返回父片段时被重新创建

如何解决片段中的 Viewpager 问题?

替换 Viewpager 中的片段 [重复]

viewpager 中的片段,未找到视图错误