2014-11-02 138 views
17

我想在我的片段中使用RecyclerView。它显示了罚款,第一个选项卡,但是当我刷到第二个选项卡,然后回到第一个我得到以下错误:为什么我在我的RecyclerView上得到空引用

java.lang.NullPointerException: Attempt to invoke virtual method 'void android.support.v7.widget.RecyclerView$LayoutManager.stopSmoothScroller()' on a null object reference

有谁知道为什么我会得到这个错误?似乎有一个电话是我在片段切换之前丢失的,但我无法弄清楚。

为片段寻呼机适配器:

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使用样板I类创建:

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(); 

} 

EDIT

错误堆栈跟踪:

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) 
+0

你能粘贴错误日志吗? – MrMins 2014-11-02 18:13:10

+0

请检查我的更新。 – 2014-11-02 18:14:40

+1

我不认为你的RecyclerView是空的。它看起来更像是别的东西_inside_ RecyclerView为空。可能是Google代码的错误。 – Karakuri 2014-11-02 18:29:09

回答

20

基本上,你的布局管理被处置之前,你已经回收完成它。

从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是否为空。我向一个我一直在努力的应用程序扔了一个非常黑客的修复程序,但不应该将它用作长期解决方案,因为它非常黑客,但我有一个紧迫的截止日期,所以我只需要捕获空指针异常。我剪掉了我的处理程序,因为它是特定应用程序。

我烫只是创建一个自定义视图扩展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所有引用。如果您确实使用它,请在Android修补此问题后将其删除,因为这有点破绽。

  • 如果您使用XML recylerview不要忘了相应更改的XML文件,而不是com.your.package.HotFixRecyclerViewandroid.support.v7.widget.RecyclerView
+0

谢谢你的代码,但我最终回到使用我以前使用过的Listview和viewholder模式。我只是试图让我的手与Recyclerview bc肮脏,它是一个很好的部件。尽管我会接受答案。 – 2014-11-13 20:36:29

+1

你知道他们会解决这个问题吗? https://code.google.com/p/android/issues/detail?id=79244 – ichaki5748 2015-01-11 11:45:39

+0

据我所知,它仍然标记为“状态:未来发布” – 2015-01-11 17:13:36

1

阅读张贴伊萨克的bug,最好的解决办法似乎是分配布局只要视图膨胀,管理者就会立即进行操作。

对我来说,我只需要指定它的onCreate来解决这个问题:

mLayoutManager = new LinearLayoutManager(this); 
mRecyclerView.setLayoutManager(mLayoutManager); 
+0

你是对的,你必须分配的LayoutManager“如果”RecyclerView膨胀。 – 2015-06-30 14:53:49

+0

在onCreateView()中实例化RecyvlerView时,如何在onCreate()中将layoutManager分配给RecyclerView() – 2016-10-25 06:46:58

3

看来,如果你在你的布局有RecyclerView并加载它在活动,这是一个必须为它设置一个LayoutManager,否则它会在试图销毁它时抛出这个异常。我刚刚遇到了这个错误,这是我解决它的方式:

我的活动显示了一对TextView或RecyclerView中的元素,具体取决于项目的数量:如果它是一个项目集合,我使用了RecyclerView;如果只有一个项目,它显示在TextView上,我将RecyclerView的可见性设置为GONE

然后,在第一种情况下,我打电话给myRecyclerView.setLayoutManager(myLayoutManager),但在另一种情况下,我没有,因为我不打算使用它。在这两种情况下,包含RecyclerView的Activity都完美显示。但是,关闭它时,异常在第二种情况下被抛出,因为RecyclerView虽然没有被使用,但是当试图处置它时,它似乎不能。所以我在这两种情况下都分配了LayoutManager,尽管我没有使用它,这解决了这个问题。

下面是从我的活动代码:

ItemsAdapter adapter; 
RecyclerView myRecyclerView = findViewById(R.id.my_recycler_view); 
RecyclerView.LayoutManager layoutManager = new LinearLayoutManager(this); 

if (items.size() > 1){ 
    adapter = new ItemsAdapter(this, R.layout.item_layout, items); 
    myRecyclerView.setLayoutManager(layoutManager); 
    myRecyclerView.setAdapter(adapter); 
} else { 
    tv_field1.setText(items.get(0).getField1()); 
    tv_field2.setText(items,get(0).getField2()); 
    myRecyclerView.setVisibility(View.GONE); 

    //This is what I had to add 
    myRecyclerView.setLayoutManager(layoutManager); 
} 
2

,因为它已经膨胀pref.xml。你应该删除它:

@Override 
public View onCreateView(LayoutInflater inflater, ViewGroup container, 
         Bundle savedInstanceState) { 
    mRootView = inflater.inflate(R.layout.xxx, container, false); 
    return mRootView; 
}