2014-11-02 28 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; 
}