2014-11-02 3 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 использовать класс шаблонный, который я создал:

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

+0

, пожалуйста, проверьте мое обновление. –

+1

Я не думаю, что ваш RecyclerView имеет значение NULL. Это больше похоже на что-то еще _inside_ RecyclerView равно null. Может быть ошибкой с кодом Google. – Karakuri

ответ

20

В принципе, ваш 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 равно нулю. Я бросил togeather очень хакерское исправление для приложения, над которым я работал, но НЕ должен использоваться как долгосрочное решение, так как это очень хак, но у меня был ограниченный срок, поэтому мне просто пришлось поймать исключение нулевого указателя , Я вырезал обработчик, потому что он был специфичным для приложения.

Моего исправления было просто создать собственный вид, расширяющий 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 запустит эту проблему, поскольку это немного взломан.

  • В случае, если вы используете recylerview на XML Не забудьте изменить файл XML в соответствии с com.your.package.HotFixRecyclerView вместо android.support.v7.widget.RecyclerView
+0

спасибо за код, но я просто вернусь к использованию шаблона Listview и зрителя, который я использовал раньше. Я просто пытался заполонить руки с помощью Recyclerview bc, это такой хороший виджет. Однако я соглашусь с ответом. –

+1

Вы понимаете, они собираются исправить это и когда? https://code.google.com/p/android/issues/detail?id=79244 – ichaki5748

+0

Насколько я знаю, он по-прежнему отмечен как «Status: FutureRelease» –

1

Чтения ошибки, отправленный Айзек, наилучшее решение, как представляется, присваивая Layout Менеджер, как только вид завышен.

В моем случае, я только должен был назначить его на OnCreate, чтобы решить эту проблему:

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

Вы правы, вам нужно назначить LayoutManager «если», то RecyclerView завышен. –

+0

Как определить layoutManager для RecyclerView в onCreate(), когда RecyvlerView создается в onCreateView() –

3

кажется, что если у вас есть RecyclerView в макете, и вы загрузите его в деятельности, это должен установить для него LayoutManager, иначе он выбросит это исключение при попытке его уничтожить.Я только что испытал эту ошибку, и это так, как я ее решил:

Моя активность показала элементы в паре TextViews или в RecyclerView в зависимости от количества элементов: если это был набор элементов, я использовал RecyclerView; если был только один элемент, он отображался в TextViews, и я установил видимость RecyclerView на GONE.

Затем, в первом случае, я позвонил myRecyclerView.setLayoutManager(myLayoutManager), но в другом случае я этого не сделал, потому что я не собирался его использовать. В обоих случаях активность, содержащая RecyclerView, была отлично отображена. Но при его закрытии исключение было выбрано во втором случае, потому что 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; 
}