android.support.v4.app.Fragment.setUserVisibleHint应用程序恢复的空指针

我在片段代码中的应用程序简历上遇到崩溃.我从来没有看到这个崩溃,但是我已经通过TestFlight从用户那里收到了崩溃报告.
我想有一些我错过的东西,因为代码在大多数机器上运行正常.任何帮助将不胜感激.

这是调用堆栈.

java.lang.NullPointerException
android.support.v4.app.Fragment.setUserVisibleHint in Fragment.java on Line 819
android.support.v4.app.FragmentPagerAdapter.setPrimaryItem in FragmentPagerAdapter.java on Line 130
android.support.v4.view.ViewPager.populate in ViewPager.java on Line 1066
android.support.v4.view.ViewPager.populate in ViewPager.java on Line 914
android.support.v4.view.ViewPager.onMeasure in ViewPager.java on Line 1436
android.view.View.measure in View.java on Line 15323
android.view.ViewGroup.measureChildWithMargins in ViewGroup.java on Line 4924
android.widget.LinearLayout.measureChildBeforeLayout in LinearLayout.java on Line 1421
android.widget.LinearLayout.measureVertical in LinearLayout.java on Line 698
android.widget.LinearLayout.onMeasure in LinearLayout.java on Line 579
android.view.View.measure in View.java on Line 15323
android.view.ViewGroup.measureChildWithMargins in ViewGroup.java on Line 4924
android.widget.FrameLayout.onMeasure in FrameLayout.java on Line 315
android.view.View.measure in View.java on Line 15323
android.support.v4.widget.DrawerLayout.onMeasure in DrawerLayout.java on Line 639
android.view.View.measure in View.java on Line 15323
android.view.ViewGroup.measureChildWithMargins in ViewGroup.java on Line 4924
android.widget.FrameLayout.onMeasure in FrameLayout.java on Line 315
android.view.View.measure in View.java on Line 15323
android.view.ViewGroup.measureChildWithMargins in ViewGroup.java on Line 4924
android.widget.LinearLayout.measureChildBeforeLayout in LinearLayout.java on Line 1421
android.widget.LinearLayout.measureVertical in LinearLayout.java on Line 698
android.widget.LinearLayout.onMeasure in LinearLayout.java on Line 579
android.view.View.measure in View.java on Line 15323
android.view.ViewGroup.measureChildWithMargins in ViewGroup.java on Line 4924
android.widget.FrameLayout.onMeasure in FrameLayout.java on Line 315
com.android.internal.policy.impl.PhoneWindow$DecorView.onMeasure in PhoneWindow.java on Line 2155
android.view.View.measure in View.java on Line 15323
android.view.ViewRootImpl.performMeasure in ViewRootImpl.java on Line 1854
android.view.ViewRootImpl.measureHierarchy in ViewRootImpl.java on Line 1102
android.view.ViewRootImpl.performTraversals in ViewRootImpl.java on Line 1275
android.view.ViewRootImpl.doTraversal in ViewRootImpl.java on Line 1000
android.view.ViewRootImpl$TraversalRunnable.run in ViewRootImpl.java on Line 4218
android.view.Choreographer$CallbackRecord.run in Choreographer.java on Line 725
android.view.Choreographer.doCallbacks in Choreographer.java on Line 555
android.view.Choreographer.doFrame in Choreographer.java on Line 525
android.view.Choreographer$FramedisplayEventReceiver.run in Choreographer.java on Line 711
android.os.Handler.handleCallback in Handler.java on Line 615
android.os.Handler.dispatchMessage in Handler.java on Line 92
android.os.Looper.loop in Looper.java on Line 137
android.app.ActivityThread.main in ActivityThread.java on Line 4744
java.lang.reflect.Method.invokeNative(Native Method)
java.lang.reflect.Method.invoke in Method.java on Line 511
com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run in ZygoteInit.java on Line 786
com.android.internal.os.ZygoteInit.main in ZygoteInit.java on Line 553
dalvik.system.NativeStart.main(Native Method)

首先,我在活动的OnResume函数中设置视图寻呼机.

private void initialiseViewPager()
{
    mLoginFragment = new WeakReference<LoginFragment>(new LoginFragment());
    Bundle loginBundle = new Bundle();
    loginBundle.putInt("SpinnerIndex",HDMSLiveSession.getInstance().getSpinnerPosition());
    loginBundle.putString("UserName",HDMSLiveSession.getInstance().getUsername());
    loginBundle.putString("Password",HDMSLiveSession.getInstance().getpassword());
    loginBundle.putInt("Mode",HDMSLiveSession.getInstance().getConnectionMode().ordinal());
    loginBundle.putBoolean("LoggedIn",HDMSLiveSession.getInstance().isLoggedIn());
    loginBundle.putBoolean("Connected",HDMSLiveSession.getInstance().isConnected());
    loginBundle.putString("LoginResult",HDMSLiveSession.getInstance().getLoginResult());
    loginBundle.putString("System",HDMSLiveSession.getInstance().getSystem());
    loginBundle.putInt("code",HDMSLiveSession.getInstance().getAccessCode());
    loginBundle.putLong("bytesSent",mCurrentSB);
    loginBundle.putLong("bytesReceived",mCurrentRB);
    loginBundle.putLong("nbytesSent",mNCurrentSB);
    loginBundle.putLong("nbytesReceived",mNCurrentRB);
    loginBundle.putInt("appid",mApp.getApplicationInfo().uid);
    loginBundle.putString(mWebSocketAddresspreference,mConnect.getWebSocketURL());
    loginBundle.putString(mAPIAddresspreference,mLogin.getLiveServerURL());
    loginBundle.putBoolean(mAutoLoginPreference,mAutoLoginEnabled);
    loginBundle.putBoolean(mAutoConnectPreference,mLogin.isAutoConnectEnabled());
    loginBundle.putInt(mAutoReconnectTimePreference,mConnect.getAutoReconnectTime());
    loginBundle.putInt(mMaxAutoReconnectionAttemptsPreference,mConnect.getMaxAutoReconnectionAttempts());
    loginBundle.putInt(mPingResponseTimePreference,mConnect.getPingResponseTime());
    loginBundle.putInt(mAutopingTimePreference,mConnect.getAutopingTime());
    loginBundle.putInt(mCurrentPingPreference,mConnect.getCurrentPing());
    loginBundle.putInt(mAutoReconnectAttemptsPreference,mConnect.getAutoReconnectAttempts());
    loginBundle.putInt(mAutoReconnectTotalAttemptsPreference,mConnect.getAutoReconnectTotalAttempts());
    loginBundle.putBoolean(mPlayListMessagePreference,messageSubscriptionContains(mPlayListMessage));
    loginBundle.putBoolean(mAutopageSwapPreference,mAutopageSwap);
    loginBundle.putBoolean(mWifiCheckedPreference,mWifiChecked);
    loginBundle.putBoolean(mAutoWebCheckedPreference,mConnect.isAutoWebChecked());
    loginBundle.putBoolean(mGatewayCheckedPreference,mGatewayChecked);
    loginBundle.putBoolean(mDHS1CheckedPreference,mDNS1Checked);
    loginBundle.putBoolean(mHDMSLiveCheckedPreference,mHDMSLiveChecked);
    loginBundle.putBoolean(mGoogleCheckedPreference,mGoogleChecked);
    loginBundle.putBoolean(mHDMSCheckedPreference,mHDMSChecked);
    loginBundle.putBoolean(mParrotCheckedPreference,mParrotChecked);
    loginBundle.putBoolean(mLocalIPCheckedPreference,mLocalIPChecked);
    loginBundle.putString(mLocalIPPreference,mLocalIP);
    loginBundle.putInt(mMaxImagesFromWebPreference,mMaxImagesFromWeb);
    loginBundle.putInt(mMaxPingAttemptsPreference,mConnect.getMaxPingAttempts());
    loginBundle.putInt(mFailedPingsPreference,mConnect.getFailedPings());
    loginBundle.putBoolean("AutoLogin",mLogin.isAutoLogin());
    loginBundle.putBoolean("wasLoggedIn",HDMSLiveSession.getInstance().wasLoggedIn());
    mLoginFragment.get().setArguments(loginBundle);

    mBAUFragment = new WeakReference<BAUFragment>(new BAUFragment());
    Bundle bauBundle = new Bundle();
    bauBundle.putBoolean("jump",mJumpToCurrent);
    bauBundle.putInt("place",mBAUPosition);
    bauBundle.putBoolean(mBAUExpandedPreference,mBAUExpanded);
    mBAUFragment.get().setArguments(bauBundle);
    mPlayerFragment = new WeakReference<PlayerFragment>(new PlayerFragment());

    mListFragment = new WeakReference<ListFragment>(new ListFragment());
    Bundle listBundle = new Bundle();
    listBundle.putInt(mListModePreference,mListMode);
    mListFragment.get().setArguments(listBundle);

    mSearchFragment = new WeakReference<SearchFragment>(new SearchFragment());
    Bundle searchBundle = new Bundle();
    searchBundle.putInt(mSearchModePreference,mSearchMode);
    searchBundle.putString("searchQueryA",mSearchTextA);
    searchBundle.putString("searchQueryS",mSearchTextS);
    searchBundle.putString("titleLast",mTitleLast);
    searchBundle.putString("artistLast",mArtistLast);
    searchBundle.putString("listLast",mListLast);
    searchBundle.putString("yearLast",mYearLast);
    searchBundle.putString("genreLast",mGenreLast);
    mSearchFragment.get().setArguments(searchBundle);

    mVideoFragment = new WeakReference<VideoFragment>(new VideoFragment());
    Bundle videoBundle = new Bundle();
    videoBundle.putInt(mVideoOutputPreference,mVideoOutput);
    mVideoFragment.get().setArguments(videoBundle);

    List<Fragment> fragments = new Vector<Fragment>();
    fragments.add(mVideoFragment.get());
    fragments.add(mPlayerFragment.get());
    fragments.add(mBAUFragment.get());
    fragments.add(mListFragment.get());
    fragments.add(mSearchFragment.get());
    fragments.add(mLoginFragment.get());
    mPagerAdapter  = new ViewPagerAdapter(getSupportFragmentManager(),fragments);

    mViewPager = (ViewPager)findViewById(R.id.contentViewPager);
    mViewPager.setAdapter(mPagerAdapter);
    mViewPager.setonPagechangelistener(this);
    mViewPager.setVisibility(View.VISIBLE);

    ActivityManager am = (ActivityManager) getSystemService(ACTIVITY_SERVICE);
    if (am.getMemoryClass() >= 32)
        mViewPager.setoffscreenPageLimit(Fragments.Max.ordinal());

    mLastFragment = -1;
    Updatedisplay();
}

除非是具有小内存堆的设备,否则所有碎片都将被保留.目前有6个片段,崩溃发生时只有4个内存.所以我知道碎片的数量不是问题.我确实尝试将视图寻呼机设置设置为认值,唯一的区别是速度,因为应用程序需要在用户刷新时加载碎片.当应用程序暂停时,所有碎片都将被销毁.

@Override
protected void onSaveInstanceState(Bundle outState)
{
    FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
    if (mLoginFragment.get() != null)
        ft.remove(mLoginFragment.get());
    if (mPlayerFragment.get() != null)
        ft.remove(mPlayerFragment.get());
    if (mBAUFragment.get() != null)
        ft.remove(mBAUFragment.get());
    if (mListFragment.get() != null)
        ft.remove(mListFragment.get());
    if (mSearchFragment.get() != null)
        ft.remove(mSearchFragment.get());
    if (mVideoFragment.get() != null)
        ft.remove(mVideoFragment.get());
    ft.commit();

    mLoginFragment = new WeakReference<LoginFragment>(null);
    mPlayerFragment = new WeakReference<PlayerFragment>(null);
    mBAUFragment = new WeakReference<BAUFragment>(null);
    mListFragment = new WeakReference<ListFragment>(null);
    mSearchFragment = new WeakReference<SearchFragment>(null);
    mVideoFragment = new WeakReference<VideoFragment>(null);
    mPagerAdapter = null;
    mViewPager = null;

    mFragmentsLoaded = 0;
    mLastFragment = -1;
}

这是我的观点寻呼机代码.

package com.hdms.manager.Fragments;

/**
 * Created by bradj on 8/10/13.
 *
 */
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentPagerAdapter;
import android.support.v4.app.FragmentTransaction;
import android.view.View;

import java.util.List;

public class ViewPagerAdapter extends FragmentPagerAdapter
{
    private final List<Fragment> mFragments;
    FragmentManager mFragmentManager;

    public ViewPagerAdapter(FragmentManager aFragmentManager,List<Fragment> aFragments)
    {
        super(aFragmentManager);

        mFragmentManager = aFragmentManager;
        mFragments = aFragments;
    }

    @Override
    public Fragment getItem(int aPosition)
    {
        return mFragments.get(aPosition);
    }

    @Override
    public long getItemId(int aPosition)
    {
        return aPosition;
    }

    @Override
    public void destroyItem(android.view.ViewGroup aContainer,int aPosition,java.lang.Object aObject)
    {
        if (aPosition <= getCount() && aObject != null)
        {
            FragmentTransaction trans = mFragmentManager.beginTransaction();
            trans.remove((Fragment) aObject);
            trans.commit();
        }
    }

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

解决方法

最后!我现在能够可靠地重新创建这个错误

要重新创建错误,关闭活动/应用程序,并快速重新打开页面与片段.您可能需要尝试几次,因为在我的测试中,我不得不在30秒内重新打开应用程序.不同速度设备的时间可能会更慢或更快.

问题是我只显式创建了Fragment(使用new)一次,并保留了对该实例的引用,以便我可以重用它.对此问题的一个简单的解决方案是始终返回Fragment的Fragment的新实例FragmentPagerAdapter.getItem(…),如下所示.

public class ViewPagerAdapter extends FragmentPagerAdapter {
    ...

    @Override
    public Fragment getItem(int position) {
        switch (position) {
            case 0: return mMyFragment; // Error. Has the edge-case crash.
            case 1: return new MyFragment(); // Works.
            default: return new MyDefaultFragment();
        }
    }
}

对于OP的具体情况,使用列表< Fragment>持有引用可能与上述相同的问题案例.

ps – 根问题可能与Fragment生命周期有关,并尝试在销毁它时再次使用它.

pps – 另一种重新创建错误方法是在足够的选项卡之间快速切换,以使Fragment想要被破坏,从缓存中释放一些内存,然后快速返回.认情况下,FragmentPagerAdapter仅将一个片段缓存到“左”和“右”.因此,根据您的缓存限制,您必须至少有三个选项卡以这种方式重新创建错误.

ppps – 此解决方案修复了用于android.app.Fragment.setUserVisibleHint(Fragment.java:997)的NullPointerException,并且也适用于android.support.v4.app.Fragment.setUserVisibleHint.

相关文章

Android性能优化——之控件的优化 前面讲了图像的优化,接下...
前言 上一篇已经讲了如何实现textView中粗字体效果,里面主要...
最近项目重构,涉及到了数据库和文件下载,发现GreenDao这个...
WebView加载页面的两种方式 一、加载网络页面 加载网络页面,...
给APP全局设置字体主要分为两个方面来介绍 一、给原生界面设...
前言 最近UI大牛出了一版新的效果图,按照IOS的效果做的,页...