简体   繁体   中英

RecyclerView OnClick resulting in NullPointerException

I am using a RecyclerView to display information in a Fragment as a list with ImageViews and TextViews. I gave the ImageViews an OnClickListener to get the position and with that the drawable id to display the image in a larger ImageView. This works fine for all the RecyclerView rows which are displayed at the start of the Fragment, but as soon as i click on an ImageView from a row, which i needed to scroll to, i get a NullPointerException with the massage:

java.lang.NullPointerException: Attempt to invoke virtual method 'android.view.View android.view.View.findViewById(int)' on a null object reference

The displayed information changes depending on a Spinner in the previews Fragment. The variable is given to the Fragment via the Activity using a fragmentManager.region(d).

The infromationFragment's code is as follwed:

public class Info_Material extends Fragment implements View.OnClickListener {

Button button_back;
Communicator communicator;
static ImageView image_large;


static private RecyclerView recyclerView;
private Information_List_Adapter adapter;

static ArrayList<String> holz_;
static ArrayList<String> land_;
static ArrayList<Integer> blatt_;
static ArrayList<Integer> baum_;
static ArrayList<Integer> frucht_;

String region_;

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

    holz_ = new ArrayList<>();
    land_ = new ArrayList<>();
    blatt_ = new ArrayList<>();
    baum_ = new ArrayList<>();
    frucht_ = new ArrayList<>();

    holz_.add(getString(R.string.));
    land_.add("");
    blatt_.add(R.drawable.);
    baum_.add(R.drawable.);
    frucht_.add(R.drawable.);

    if (region_wahl.equals(getString(a))){
        holz_.addAll(Arrays.asList());
        land_.addAll(Arrays.asList());
        blatt_.addAll(Arrays.asList());
        baum_.addAll(Arrays.asList());
        frucht_.addAll(Arrays.asList());
    }
    if (region_wahl.equals(getString(b))){
        holz_.addAll(Arrays.asList());
        land_.addAll(Arrays.asList());
        blatt_.addAll(Arrays.asList());
        baum_.addAll(Arrays.asList());
        frucht_.addAll(Arrays.asList());
    }

    recyclerView= (RecyclerView) view.findViewById(R.id.materialInfoList);
    adapter = new Information_List_Adapter(getActivity(),getData());
    recyclerView.setAdapter(adapter);
    recyclerView.setLayoutManager(new LinearLayoutManager(getActivity()));

    button_back = (Button) view.findViewById(R.id.back_I_M);
    button_back.setOnClickListener(this);

    image_large= (ImageView) view.findViewById(R.id.image_large);
    image_large.setOnClickListener(this);

    return view;
}

public static List<Information_List> getData() {
    List<Information_List> data = new ArrayList<>();

    for(int i=0;i<holz_.size() && i<blatt_.size() && i<baum_.size() && i<frucht_.size();i++) {
        Information_List current = new Information_List();
        current.blattID=blatt_.get(i);
        current.baumID=baum_.get(i);
        current.fruchtID=frucht_.get(i);
        current.holz=holz_.get(i);
        data.add(current);
    }
    return data;
}



@Override
public void onActivityCreated(Bundle savedInstanceState) {
    super.onActivityCreated(savedInstanceState);

}

public void setCommunicator (Communicator communicator) {
    this.communicator = communicator;
}

@Override
public void onClick(View view) {
    if(view.getId()==R.id.back_I_M){
        String d;
        d = "back";
        communicator.finish_I_M(d);
    }
    if(view.getId()==R.id.image_large){
        image_large.setImageDrawable(null);
    }
}


public void region (String d) {

    region_ = d;

}

static void enlarge (int position,String data){
    ImageView imageView=null;
    if(data.equals("blatt")){
        imageView = (ImageView)recyclerView.getChildAt(position).findViewById(R.id.info_list_blatt);
    }
    if(data.equals("baum")){
        imageView = (ImageView)recyclerView.getChildAt(position).findViewById(R.id.info_list_baum);
    }
    if(data.equals("frucht")){
        imageView = (ImageView)recyclerView.getChildAt(position).findViewById(R.id.info_list_frucht);
    }

    BitmapDrawable drawable = (BitmapDrawable) imageView.getDrawable();

    image_large.setImageDrawable(drawable);
}

public interface Communicator {

    void finish_I_M (String data);

}

}

The AdapterClass:

public class Information_List_Adapter extends RecyclerView.Adapter <Information_List_Adapter.MyViewHolder> {

private Context context;
private LayoutInflater inflater;
List<Information_List> data = Collections.emptyList();

public Information_List_Adapter(Context context, List<Information_List> data) {
    this.context=context;
    inflater= LayoutInflater.from(context);
    this.data=data;
}

@Override
public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
    View view = inflater.inflate (R.layout.custom_info_material_row,parent,false);
    MyViewHolder holder = new MyViewHolder(view);

    return holder;
}

@Override
public void onBindViewHolder(MyViewHolder holder, int position) {

    holder.holz.setText(Info_Material.holz_.get(position));
    holder.land.setText(Info_Material.land_.get(position));
    holder.blattID.setImageResource(Info_Material.blatt_.get(position));
    holder.baumID.setImageResource(Info_Material.baum_.get(position));
    holder.fruchtID.setImageResource(Info_Material.frucht_.get(position));

}

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

class MyViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener{

    TextView holz;
    TextView land;
    ImageView blattID;
    ImageView baumID;
    ImageView fruchtID;

    public MyViewHolder(View itemView) {
        super(itemView);
        holz= (TextView) itemView.findViewById(R.id.info_list_holz);
        land = (TextView) itemView.findViewById(R.id.info_list_land);
        blattID = (ImageView) itemView.findViewById(R.id.info_list_blatt);
        baumID = (ImageView) itemView.findViewById(R.id.info_list_baum);
        fruchtID = (ImageView) itemView.findViewById(R.id.info_list_frucht);

        blattID.setOnClickListener(this);
        baumID.setOnClickListener(this);
        fruchtID.setOnClickListener(this);
    }

    @Override
    public void onClick(View v) {
        if(v.getId()==R.id.info_list_blatt){
            Info_Material.enlarge(getAdapterPosition(),"blatt");
        }
        if(v.getId()==R.id.info_list_baum){
            Info_Material.enlarge(getAdapterPosition(),"baum");
        }
        if(v.getId()==R.id.info_list_frucht){
            Info_Material.enlarge(getAdapterPosition(),"frucht");
        }
    }
}

}

As stated above, this method works fine for all initially created rows when starting the Fragment, but as soon, as a newly created row (not initially shown on the screen) is clicked the app crashes with said NullPointerException.

Since i am still pretty new to Java programming i don't really have an idea where i could start looking for the mistake, so i would appreciate any hint on where the error might occur.

Thanks in advance.

In your enlarge method, you are attempting to call findViewById on a null reference.

This code:

(ImageView)recyclerView.getChildAt(position)

is returning null so you cannot use findViewById on it.

Also see this question: What is a NullPointerException, and how do I fix it?

As a final note, you will find it infinitely more manageable to move your data arrays into the Adapter instead of calling from the Adapter back to your Fragment every time you want some data.

try this,

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

@Override
public void onBindViewHolder(MyViewHolder holder, int position) {

    holder.holz.setText(Info_Material.holz_.get(position));
    holder.land.setText(Info_Material.land_.get(position));
    holder.blattID.setImageResource(Info_Material.blatt_.get(position));
    holder.baumID.setImageResource(Info_Material.baum_.get(position));
    holder.fruchtID.setImageResource(Info_Material.frucht_.get(position));

 holder.blattID.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                Info_Material.enlarge(position,"blatt");

                }
            });

}

it's better to handle all this in adapter. make recyclerview static is not good solution. maybe you want to use fragment or activity in other places.

as recyclerview recycle the views and only bind view that visible to user, it's better to change the List data and notify your adapter that some of your views have been changed.

How to update RecyclerView Adapter Data?

beside this you have wrong structure. you have to store your row data in "List < Information_List > data" and do not use those arrays list from fragment: (holz_ land_ blatt_ baum_ frucht_ )

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM