簡體   English   中英

為什么我在我的 RecyclerView 上得到一個空引用

[英]Why am I getting a null reference on my RecyclerView

我正在嘗試在我的片段中使用 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 在你的回收者完成之前就被處理掉了。

來自安卓源:

@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 是否為空。

我為我一直在開發的應用程序拋出了一個非常hacky的修補程序,但我不建議將其用作長期解決方案,因為它非常麻煩。 如果像我一樣你的截止日期很緊,最好只捕獲空指針異常並忽略它。

我的熱修復只是創建一個擴展 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 修補此問題后將其刪除,因為它有點像黑客。

  • 如果您使用 recylerview inn XML,請不要忘記相應地更改您的 XML 文件以使用com.your.package.HotFixRecyclerView而不是android.support.v7.widget.RecyclerView

似乎如果您的布局中有一個 RecyclerView 並且您將它加載到 Activity 中,則必須為其設置一個 LayoutManager ,否則它會在嘗試銷毀它時拋出此異常。 我剛剛遇到了這個錯誤,這是我解決它的方法:

我的活動根據項目的數量在一對 TextView 或 RecyclerView 中顯示元素:如果它是項目的集合,我使用 RecyclerView; 如果只有一項,它會顯示在 TextViews 上,我將 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);
}

閱讀 Isaak 發布的錯誤,最好的解決方案似乎是在視圖膨脹后立即分配布局管理器。

就我而言,我只需將它分配給 onCreate 即可解決問題:

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

因為它已經膨脹了 pref.xml 。 你應該刪除這個:

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

就我而言,我在錯誤的適配器上使用了notifyDataSetChanged()

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM