RecyclerView Start上的NullPointerExecption

时间:2016-01-04 03:34:26

标签: android user-interface android-fragments android-viewpager android-recyclerview

我有一个包含三个片段的视图寻呼机(A-> B-> C):

片段A 有两个edittexts和一个保存按钮; 片段B 有一个工具栏和一个可滚动的textview; Fragment C 有一个设置为LinearLayout的RecyclerView。

在应用启动时,我滑动到片段B,然后在ListFragment(片段C)的视图适配器getItemCount()上获得NPE。这发生在物理测试设备(API 21)上,但不在任何仿真器上(API 18-23)。

可能是什么原因?

编辑:添加 HomeActivity.class 界面方法:

@Override
public ArrayList<String> getList() {
    titleSharedPref = getSharedPreferences(TITLE_PREF, Context.MODE_PRIVATE);
    try {
        this.songArrayList = (ArrayList<String>) ObjectSerializer
                .deserialize(titleSharedPref.getString(TITLE_PREF, ObjectSerializer.serialize(new ArrayList<String>())));
    } catch (IOException e) {
        e.printStackTrace();
    } catch (ClassNotFoundException e) {
        e.printStackTrace();
    }
    return this.songArrayList;
}

ListFragment.class

public class ListFragment extends Fragment {

    private RecyclerView recyclerView;
    private SongRecyclerViewAdapter recyclerViewAdapter;
    private FragmentCommunicator communicator;

    public ListFragment() {
        // Required empty constructor
    }

    public static ListFragment newInstance() {
        return new ListFragment();
    }

    @Override
    public void onAttach(Context context) {
        super.onAttach(context);
        if (context instanceof FragmentCommunicator) {
            communicator = (FragmentCommunicator) context;
        } else {
            throw new RuntimeException(context.toString()
                + " must implement FragmentCommunicator");
        }
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                         Bundle savedInstanceState) {
        View view = inflater.inflate(R.layout.fragment_song_list, container, false);

        // Set the adapter
        if (view instanceof RecyclerView) {
            Context context = view.getContext();
            recyclerView = (RecyclerView) view;
            recyclerView.setLayoutManager(new LinearLayoutManager(context));
            recyclerViewAdapter = new SongRecyclerViewAdapter(communicator.getList(), communicator);
            recyclerView.setAdapter(recyclerViewAdapter);
        }

        ItemTouchHelper.SimpleCallback simpleItemCallBack = new ItemTouchHelper.SimpleCallback(0, ItemTouchHelper.LEFT){
            @Override
            public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target) {
                return false;
            }

            @Override
            public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) {
                int pos = viewHolder.getAdapterPosition();
                if (communicator.remove(pos)) {
                    recyclerViewAdapter.notifyItemRemoved(pos);
                    recyclerViewAdapter.notifyItemRangeChanged(pos, recyclerViewAdapter.getItemCount());
                }
            }
        };
        ItemTouchHelper itemTouchHelper = new ItemTouchHelper(simpleItemCallBack);
        itemTouchHelper.attachToRecyclerView(recyclerView);

        return view;
    }

    /**
     * {@link RecyclerView.Adapter} that can display a {@link ArrayList} and makes a call to the
     * specified {@link FragmentCommunicator}.
     */
    public class SongRecyclerViewAdapter extends RecyclerView.Adapter<SongRecyclerViewAdapter.ViewHolder> {

        private final ArrayList<String> mValues;
        private final FragmentCommunicator communicator;

        public SongRecyclerViewAdapter(ArrayList<String> items, FragmentCommunicator communicator) {
            this.mValues = items;
            this.communicator = communicator;
        }

        @Override
        public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
            return new ViewHolder(LayoutInflater.from(parent.getContext()).inflate(R.layout.list_item, parent, false));
        }

        public class ViewHolder extends RecyclerView.ViewHolder {
            public final View mView;
            public final TextView mContentView;
            public String mItem;

            public ViewHolder(View view) {
                super(view);
                mView = view;
                mContentView = (TextView) view.findViewById(R.id.content);
            }

            @Override
            public String toString() {
                return super.toString() + " '" + mContentView.getText() + "'";
            }
        }

        @Override
        public void onBindViewHolder(final ViewHolder holder, final int position) {
            holder.mItem = mValues.get(position);
            holder.mContentView.setText(holder.mItem);
            holder.mView.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    if (null != communicator) {
                        // Notify the active callbacks interface (the activity, if the
                        // fragment is attached to one) that an item has been selected.
                        communicator.respond(holder.mItem, HomeActivity.MODE_PICK);
                    }
                }
            });
        }

        @Override
        public int getItemCount() {
            return mValues.size();
        }
    }

    @Override
    public void onDetach() {
        super.onDetach();
        // kill
        communicator = null;
        recyclerViewAdapter = null;
    }
}

编辑:删除了第二个问题:adding ViewPager listener.

谢谢大家!

2 个答案:

答案 0 :(得分:2)

首先,您应该认真考虑清理碎片代码。我建议您将viewholder和adapter解压缩到自己的类中。通过将代码隔离到特定的需求区域,这将极大地帮助您完成代码。

其次,考虑在视图中进行视图工作,而不是在适配器的onBindViewHolder()方法中。您可以创建一个名为populateViews()的方法,然后传入将填充视图中视图的数据。

第三,您确定数据实际上是传递给RecyclerView吗?我的猜测是,不,你可能没有传递数据,因此它正在抛出一个NPE。请记住,FragmentPagerAdapter将尝试启动至少三个片段 - 可见的片段,左侧的片段和右侧的片段。在您的情况下,当您滑动到片段B时,它正在尝试填充片段C中的RecyclerView,但您还没有任何数据。

至于如何将数据从片段A传递到片段B,而无需用户点击某些内容......只需将片段A的EditTexts内容传递给Activity,然后将该数据发送到片段B.您可以间隔执行此操作(例如,在输入每个字符后)或用户暂停时,或者当FragmentPagerAdapter开始您可以使用的滑动时甚至还有回调。

答案 1 :(得分:0)

@ rf43感谢您的帮助。 这是我的HTC One M7测试设备的设备特定问题。我手动卸载调试apk(安装完毕)并再次安装。现在我的应用程序按设计工作。设备一定存在内存问题。