实现 RecyclerView 时出现 NullPointerException

NullPointerException while implementing RecyclerView

我正在尝试实现 RecyclerView 以显示 Fragment 中的项目列表。

片段代码:

import android.app.Activity;
import android.os.Bundle;
import android.support.v4.app.LoaderManager;
import android.support.v4.content.Loader;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Toast;

import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;

import java.lang.reflect.Type;
import java.util.List;

public class SearchFragment extends BaseFragment implements LoaderManager.LoaderCallbacks<StringBuilder> {

    private RecyclerView mRecyclerView;
    private SearchAdapter mAdapter;
    private RecyclerView.LayoutManager mLayoutManager;

    private String searchQuery;

    private User user;

    private OnFragmentInteractionListener mListener;

    public SearchFragment() {
    }

    public static SearchFragment newInstance() {
        SearchFragment fragment = new SearchFragment();
        return fragment;
    }

    public void setSearchQuery(String searchQuery) {
        this.searchQuery = searchQuery;
    }

    public void search() {
        try {
            Bundle bundle = new Bundle();
            bundle.putString(API.DISH_SEARCH_KEY, searchQuery);
            getLoaderManager().restartLoader(LoaderConstants.DISH_SEARCH_LOADER_ID, bundle, SearchFragment.this).forceLoad();
        } catch (IllegalStateException e) {
            // thrown when Fragment not attached to Activity
        }
    }

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        if (getArguments() != null) {
            user = new Gson().fromJson(getArguments().getString(API.USER_KEY), User.class);
        }
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {

        View view = inflater.inflate(R.layout.fragment_search, container, false);

        mRecyclerView = (RecyclerView) view.findViewById(R.id.my_recycler_view);

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

        search();

        return view;
    }

    @Override
    public Loader<StringBuilder> onCreateLoader(int id, Bundle bundle) {

        String searchQuery = bundle.getString(API.DISH_SEARCH_KEY);
        String url = String.format(API.DISH_SEARCH_URL, searchQuery);

        bundle.putString(API.URL_KEY, url);
        bundle.putString(API.TYPE_KEY, API.TYPE_GET);

        return new CravyAsyncLoader(getActivity(), bundle);
    }

    @Override
    public void onLoadFinished(Loader<StringBuilder> loader, StringBuilder data) {

        if (Util.isEmptyJsonResponse(data)) {
            Toast.makeText(getActivity(), "No dishes found!", Toast.LENGTH_LONG).show();
            return;
        }

        List<Dish> dishes;
        try {
            // Convert JSONArray response to List<Dish>
            Type listType = new TypeToken<List<Dish>>() {
            }.getType();
            dishes = (List<Dish>) new Gson().fromJson(data.toString(), listType);
        } catch (Exception ex) {
            Toast.makeText(getActivity(), "Something went wrong. Try again.", Toast.LENGTH_LONG).show();
            return;
        }

        if (dishes != null) {
            mAdapter = new SearchAdapter(dishes, SearchFragment.this);
            mRecyclerView.setAdapter(mAdapter);
        }
    }

    @Override
    public void onLoaderReset(Loader<StringBuilder> loader) {
    }
}

适配器:

import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentTransaction;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.LinearLayout;
import android.widget.TextView;

import com.google.gson.Gson;

import java.util.List;

public class SearchAdapter extends RecyclerView.Adapter<SearchAdapter.ViewHolder> {

    private List<Dish> mDishes;
    private Fragment fragment;

    public SearchAdapter(List<Dish> dishes, Fragment fragment) {
        mDishes = dishes;
        this.fragment = fragment;
    }

    // Provide a reference to the views for each data item
    // Complex data items may need more than one view per item, and
    // you provide access to all the views for a data item in a view holder
    public class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {

        // each data item is just a string in this case
        public LinearLayout mView;
        private Fragment fragment;

        public ViewHolder(LinearLayout itemView, Fragment fragment) {
            super(itemView);
            this.fragment = fragment;
            itemView.setClickable(true);
            itemView.setOnClickListener(this);
        }

        @Override
        public void onClick(View v) {
            TextView textView = (TextView) v.findViewById(R.id.dish_id);
            String id = textView.getText().toString();

            Dish dish = getDishById(id);
            Bundle bundle = new Bundle();
            bundle.putString(API.DISH_KEY, new Gson().toJson(dish));

            // Create new fragment and transaction
            DishDetailsFragment dishDetailsFragment = DishDetailsFragment.newInstance(bundle);

            FragmentTransaction transaction = fragment.getFragmentManager().beginTransaction();

            // Replace whatever is in the fragment_container view with this fragment,
            // and add the transaction to the back stack
            transaction.replace(R.id.content, dishDetailsFragment);
            transaction.addToBackStack(null);

            // Commit the transaction
            transaction.commit();
        }
    }

    // Create new views (invoked by the layout manager)
    @Override
    public SearchAdapter.ViewHolder onCreateViewHolder(ViewGroup parent,
                                                       int viewType) {
        LinearLayout view = (LinearLayout) LayoutInflater.from(parent.getContext())
                .inflate(R.layout.search_list_item, parent, false);
        return new ViewHolder(view, fragment);
    }

    // Replace the contents of a view (invoked by the layout manager)
    @Override
    public void onBindViewHolder(ViewHolder holder, int position) {
        // - get element from your dataset at this position
        // - replace the contents of the view with that element

        ((TextView) holder.mView.findViewById(R.id.dish_id)).setText(mDishes.get(position).getId());
        ((TextView) holder.mView.findViewById(R.id.dish_name)).setText(mDishes.get(position).getName());
        ((TextView) holder.mView.findViewById(R.id.restaurant_name)).setText(mDishes.get(position).getRestaurantId());
        try {
            ((TextView) holder.mView.findViewById(R.id.price)).setText(String.valueOf(mDishes.get(position).getPrice().getValue()));
        } catch (Exception ex) {
            ((TextView) holder.mView.findViewById(R.id.price)).setText("No Price Available");
        }
    }

    // Return the size of your dataset (invoked by the layout manager)
    @Override
    public int getItemCount() {
        return mDishes.size();
    }

    public Dish getDishById(String id) {
        for (Dish dish : mDishes) {
            if (dish.getId().equals(id))
                return dish;
        }
        return null;
    }
}

我在 Adapter

中遇到错误
    ((TextView) holder.mView.findViewById(R.id.dish_id)).setText(mDishes.get(position).getId());

错误:

java.lang.NullPointerException: Attempt to invoke virtual method 'android.view.View android.widget.LinearLayout.findViewById(int)' on a null object reference
        at com.fonduetech.cravy.adapter.SearchAdapter.onBindViewHolder(SearchAdapter.java:87)
        at com.fonduetech.cravy.adapter.SearchAdapter.onBindViewHolder(SearchAdapter.java:21)
        at android.support.v7.widget.RecyclerView$Adapter.bindViewHolder(RecyclerView.java:4138)
        at android.support.v7.widget.RecyclerView$Recycler.getViewForPosition(RecyclerView.java:3448)
        at android.support.v7.widget.RecyclerView$Recycler.getViewForPosition(RecyclerView.java:3340)
        at android.support.v7.widget.LinearLayoutManager$LayoutState.next(LinearLayoutManager.java:1810)
        at android.support.v7.widget.LinearLayoutManager.layoutChunk(LinearLayoutManager.java:1306)
        at android.support.v7.widget.LinearLayoutManager.fill(LinearLayoutManager.java:1269)
        at android.support.v7.widget.LinearLayoutManager.onLayoutChildren(LinearLayoutManager.java:523)
        at android.support.v7.widget.RecyclerView.dispatchLayout(RecyclerView.java:1988)
        at android.support.v7.widget.RecyclerView.onLayout(RecyclerView.java:2237)
        at android.view.View.layout(View.java:15671)
        at android.view.ViewGroup.layout(ViewGroup.java:5038)
        at android.widget.FrameLayout.layoutChildren(FrameLayout.java:579)
        at android.widget.FrameLayout.onLayout(FrameLayout.java:514)
        at android.view.View.layout(View.java:15671)
        at android.view.ViewGroup.layout(ViewGroup.java:5038)
        at android.widget.FrameLayout.layoutChildren(FrameLayout.java:579)
        at android.widget.FrameLayout.onLayout(FrameLayout.java:514)
        at android.view.View.layout(View.java:15671)
        at android.view.ViewGroup.layout(ViewGroup.java:5038)
        at android.support.design.widget.CoordinatorLayout.layoutChild(CoordinatorLayout.java:1000)
        at android.support.design.widget.CoordinatorLayout.onLayoutChild(CoordinatorLayout.java:710)
        at android.support.design.widget.ViewOffsetBehavior.onLayoutChild(ViewOffsetBehavior.java:42)
        at android.support.design.widget.AppBarLayout$ScrollingViewBehavior.onLayoutChild(AppBarLayout.java:982)
        at android.support.design.widget.CoordinatorLayout.onLayout(CoordinatorLayout.java:723)
        at android.view.View.layout(View.java:15671)
        at android.view.ViewGroup.layout(ViewGroup.java:5038)
        at android.support.v4.widget.DrawerLayout.onLayout(DrawerLayout.java:907)
        at android.view.View.layout(View.java:15671)
        at android.view.ViewGroup.layout(ViewGroup.java:5038)
        at android.widget.FrameLayout.layoutChildren(FrameLayout.java:579)
        at android.widget.FrameLayout.onLayout(FrameLayout.java:514)
        at android.view.View.layout(View.java:15671)
        at android.view.ViewGroup.layout(ViewGroup.java:5038)
        at android.widget.LinearLayout.setChildFrame(LinearLayout.java:1703)
        at android.widget.LinearLayout.layoutVertical(LinearLayout.java:1557)
        at android.widget.LinearLayout.onLayout(LinearLayout.java:1466)
        at android.view.View.layout(View.java:15671)
        at android.view.ViewGroup.layout(ViewGroup.java:5038)
        at android.widget.FrameLayout.layoutChildren(FrameLayout.java:579)
        at android.widget.FrameLayout.onLayout(FrameLayout.java:514)
        at android.view.View.layout(View.java:15671)
        at android.view.ViewGroup.layout(ViewGroup.java:5038)
        at android.widget.LinearLayout.setChildFrame(LinearLayout.java:1703)
        at android.widget.LinearLayout.layoutVertical(LinearLayout.java:1557)
        at android.widget.LinearLayout.onLayout(LinearLayout.java:1466)
        at android.view.View.layout(View.java:15671)
        at android.view.ViewGroup.layout(ViewGroup.java:5038)
        at android.widget.FrameLayout.layoutChildren(FrameLayout.java:579)
        at android.widget.FrameLayout.onLayout(FrameLayout.java:514)
        at android.view.View.layout(View.java:15671)
        at android.view.ViewGroup.layout(ViewGroup.java:5038)
        at android.view.ViewRootImpl.performLayout(ViewRootImpl.java:2086)
        at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:1843)
        at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:1061)
        at android.view.ViewR

我尝试调试应用程序。它将 mView 显示为 null。为什么?

   public ViewHolder(LinearLayout itemView, Fragment fragment) {
        super(itemView);
        this.fragment = fragment;
        this.mView = itemView; //this line is missing
        itemView.setClickable(true);
        itemView.setOnClickListener(this);
    }

你用过 Android Studio 吗??

如果是,只需将其包含在 build.grade 中:

compile 'com.android.support:cardview-v7:21.0.+'
compile 'com.android.support:recyclerview-v7:21.0.+'

然后只需同步成绩或只需按顶部的 gradle 按钮即可。我想这会给你一些结果

如果您的 RecyclerView 适配器没有数据意味着您没有调用 setAdapter 那么它是 return 错误。

因此默认情况下,如果您有数据,则必须将 RecyclerView 设置为不可见 属性,然后先设置数据,然后设置 RecyclerView 的可见 属性。