我正在尝试在片段中使用RecyclerView。对于第一个选项卡,它显示得很好,但是当我滑动到第二个选项卡然后又回到第一个选项卡时,出现以下错误:
java.lang.NullPointerException:尝试在空对象引用上调用虚拟方法“ void android.support.v7.widget.RecyclerView $ LayoutManager.stopSmoothScroller()”
有谁知道为什么我会收到此错误?在片段切换之前,似乎有一个电话丢失了,但我无法弄清楚。
片段的寻呼机适配器:
public class PagerAdapter extends FragmentPagerAdapter { private final String[] TITLES = {"Header 0", "Header 1" }; public PagerAdapter(FragmentManager fm){ super(fm); } @Override public CharSequence getPageTitle(int position){ return TITLES[position]; } @Override public int getCount() { return TITLES.length; } @Override public Fragment getItem(int position){ switch(position){ case 0: return new FragmentOne(); case 1: return new FragmentTwo(); default: return new FragmentOne(); } } }
FragmentOne和FragmentTwo使用我创建的样板类:
public class FragmentOne extends Base { ... code for displaying content in the RecyclerView. Just contains my custom Adapter for the RecyclerView ... }
基础:
public abstract class Base extends Fragment { public View mView; public RecyclerView mDataView; public ProgressBar mProgressBar; public Context mContext; private RecyclerView.LayoutManager mLayoutManager; public Base() { } @Override public View onCreateView(LayoutInflater _i, ViewGroup _vg, Bundle savedInstanceBundle){ mView = _i.inflate(R.layout.f_base, null); mDataView = (RecyclerView) mView.findViewById(R.id.data); mProgressBar = (ProgressBar)mView.findViewById(R.id.loading); mLayoutManager = new LinearLayoutManager(mContext); mDataView.setLayoutManager(mLayoutManager); mContext = this.getActivity(); return mView; } @Override public void onStart() { super.onStart(); init(); doWork(); } public abstract void init(); public abstract void doWork(); }
编辑
错误堆栈跟踪:
11-02 12:49:44.171 3708-3708/com.nitrox.digitune E/AndroidRuntime﹕ FATAL EXCEPTION: main Process: com.nitrox.digitune, PID: 3708 java.lang.NullPointerException: Attempt to invoke virtual method 'void android.support.v7.widget.RecyclerView$LayoutManager.stopSmoothScroller()' on a null object reference at android.support.v7.widget.RecyclerView.stopScrollersInternal(RecyclerView.java:1159) at android.support.v7.widget.RecyclerView.stopScroll(RecyclerView.java:1151) at android.support.v7.widget.RecyclerView.onDetachedFromWindow(RecyclerView.java:1356) at android.view.View.dispatchDetachedFromWindow(View.java:13441) at android.view.ViewGroup.dispatchDetachedFromWindow(ViewGroup.java:2837) at android.view.ViewGroup.dispatchDetachedFromWindow(ViewGroup.java:2834) at android.view.ViewGroup.dispatchDetachedFromWindow(ViewGroup.java:2834) at android.view.ViewGroup.removeViewInternal(ViewGroup.java:4163) at android.view.ViewGroup.removeViewInternal(ViewGroup.java:4136) at android.view.ViewGroup.removeView(ViewGroup.java:4068) at android.support.v4.view.ViewPager.removeView(ViewPager.java:1326) at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1045) at android.support.v4.app.FragmentManagerImpl.detachFragment(FragmentManager.java:1280) at android.support.v4.app.BackStackRecord.run(BackStackRecord.java:724) at android.support.v4.app.FragmentManagerImpl.execPendingActions(FragmentManager.java:1489) at android.support.v4.app.FragmentManagerImpl.executePendingTransactions(FragmentManager.java:486) at android.support.v4.app.FragmentPagerAdapter.finishUpdate(FragmentPagerAdapter.java:141) at android.support.v4.view.ViewPager.populate(ViewPager.java:1073) at android.support.v4.view.ViewPager.populate(ViewPager.java:919) at android.support.v4.view.ViewPager$3.run(ViewPager.java:249) at android.view.Choreographer$CallbackRecord.run(Choreographer.java:767) at android.view.Choreographer.doCallbacks(Choreographer.java:580) at android.view.Choreographer.doFrame(Choreographer.java:549) at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:753) at android.os.Handler.handleCallback(Handler.java:739) at android.os.Handler.dispatchMessage(Handler.java:95) at android.os.Looper.loop(Looper.java:135) at android.app.ActivityThread.main(ActivityThread.java:5221) at java.lang.reflect.Method.invoke(Native Method) at java.lang.reflect.Method.invoke(Method.java:372) at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:899) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:694)
基本上,在回收者完成之前要先处理LayoutManager。
从Android来源:
@Override protected void onDetachedFromWindow() { super.onDetachedFromWindow(); if (mItemAnimator != null) { mItemAnimator.endAnimations(); } mFirstLayoutComplete = false; stopScroll(); mIsAttached = false; if (mLayout != null) { mLayout.onDetachedFromWindow(this, mRecycler); } removeCallbacks(mItemAnimatorRunner); }
问题出在stopScroll尝试调用mLayout.stopSmoothScroller();时。而不检查mLayout是否为null。
我为正在开发的应用程序添加了一个非常骇人的补丁,但我不建议将其用于长期解决方案,因为这是一个很大的难题。如果像我一样,您的截止日期很紧,那么最好只是捕获空指针异常并忽略它。
我的修补程序只是创建一个扩展RecyclerView的自定义视图:
import android.content.Context; import android.support.v7.widget.RecyclerView; import android.util.AttributeSet; public class HotFixRecyclerView extends RecyclerView { public HotFixRecyclerView( Context context ) { super( context ); } public HotFixRecyclerView( Context context, AttributeSet attrs ) { super( context, attrs ); } public HotFixRecyclerView( Context context, AttributeSet attrs, int defStyle ) { super( context, attrs, defStyle ); } @Override public void stopScroll() { try { super.stopScroll(); } catch( NullPointerException exception ) { /** * The mLayout has been disposed of before the * RecyclerView and this stops the application * from crashing. */ } } }
然后将所有引用从RecyclerView更改为HotFixRecyclerView。如果您确实使用过,请在Android修复此问题后将其删除,因为这有点hack。
com.your.package.HotFixRecyclerView
android.support.v7.widget.RecyclerView