我在片段代码中的应用程序的简历上崩溃了.我自己从未见过这次崩溃,但我通过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函数中设置了view pager.
private void initialiseViewPager() { mLoginFragment = new WeakReference(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 (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 (new PlayerFragment()); mListFragment = new WeakReference (new ListFragment()); Bundle listBundle = new Bundle(); listBundle.putInt(mListModePreference, mListMode); mListFragment.get().setArguments(listBundle); mSearchFragment = new WeakReference (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 (new VideoFragment()); Bundle videoBundle = new Bundle(); videoBundle.putInt(mVideoOutputPreference, mVideoOutput); mVideoFragment.get().setArguments(videoBundle); List fragments = new Vector (); 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个时发生了崩溃.所以我知道碎片的数量不是问题.我确实尝试将View Viewrs设置保留为默认值,唯一的区别是速度,因为应用程序需要在用户滑动时加载片段.当应用暂停时,所有片段都会被销毁.
@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(null); mPlayerFragment = new WeakReference (null); mBAUFragment = new WeakReference (null); mListFragment = new WeakReference (null); mSearchFragment = new WeakReference (null); mVideoFragment = new WeakReference (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 ListmFragments; FragmentManager mFragmentManager; public ViewPagerAdapter(FragmentManager aFragmentManager, List 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(); } }
Anonsage.. 8
最后!我现在能够可靠地重新创建此错误!
要重新创建错误,请关闭活动/应用程序,然后使用片段快速重新打开页面.您可能需要尝试几次,因为在我的测试中,我必须在大约30ms内重新打开应用程序.对于不同速度的设备,此时间可能更慢或更快.
问题是我只显式创建了Fragment(using new
)一次,并保留了对该实例的引用,以便我可以重用它.解决此问题的一个简单方法是始终返回new
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的特定情况,使用List
保持引用可能与上面的问题相同.
ps - 根问题可能与Fragment生命周期有关,并且在它被销毁时尝试再次使用它.
pps - 重新创建错误的另一种方法是在足够的选项卡之间快速切换,以便破坏Fragment以从缓存中释放一些内存,然后快速返回到它.默认情况下,FragmentPagerAdapter仅将一个片段缓存到"左"和"右".因此,根据您的缓存限制,您必须至少有三个选项卡才能以这种方式重新创建错误.
ppps - 此解决方案修复了NullPointerException,android.app.Fragment.setUserVisibleHint(Fragment.java:997)
也应该适用于android.support.v4.app.Fragment.setUserVisibleHint
.
最后!我现在能够可靠地重新创建此错误!
要重新创建错误,请关闭活动/应用程序,然后使用片段快速重新打开页面.您可能需要尝试几次,因为在我的测试中,我必须在大约30ms内重新打开应用程序.对于不同速度的设备,此时间可能更慢或更快.
问题是我只显式创建了Fragment(using new
)一次,并保留了对该实例的引用,以便我可以重用它.解决此问题的一个简单方法是始终返回new
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的特定情况,使用List<Fragment>
保持引用可能与上面的问题相同.
ps - 根问题可能与Fragment生命周期有关,并且在它被销毁时尝试再次使用它.
pps - 重新创建错误的另一种方法是在足够的选项卡之间快速切换,以便破坏Fragment以从缓存中释放一些内存,然后快速返回到它.默认情况下,FragmentPagerAdapter仅将一个片段缓存到"左"和"右".因此,根据您的缓存限制,您必须至少有三个选项卡才能以这种方式重新创建错误.
ppps - 此解决方案修复了NullPointerException,android.app.Fragment.setUserVisibleHint(Fragment.java:997)
也应该适用于android.support.v4.app.Fragment.setUserVisibleHint
.