无法在RecyclerView中获得片段中的onClick事件

时间:2018-07-24 06:58:50

标签: java android android-studio android-fragments recyclerview-layout

我正在使用Json来获取应用程序的数据和图像。图像显示在连接到MainActivity的片段(Tab1.java)内的RecyclerView中。我想以这种方式进行设置,以便当用户单击RecyclerView中的图像时,将启动一个新的Activity(ViewImage.java),并在其中显示该图像。

到目前为止,我已经能够获取Json数据并将其显示在回收者视图中。图像显示完美,但是当我尝试设置“ setItemOnClickListener”时,应用程序开始崩溃(我在 Tab1.java 中用注释标记了该行)。

Tab1.java

/*
 * A simple {@link Fragment} subclass.
 * Activities that contain this fragment must implement the
 * {@link Tab1.OnFragmentInteractionListener} interface
 * to handle interaction events.
 * Use the {@link Tab1#newInstance} factory method to
 * create an instance of this fragment.
 */
public class Tab1 extends Fragment implements CardAdapter.OnItemClickListener{
    // TODO: Rename parameter arguments, choose names that match
    // the fragment initialization parameters, e.g. ARG_ITEM_NUMBER
    private static final String ARG_PARAM1 = "param1";
    private static final String ARG_PARAM2 = "param2";

    // TODO: Rename and change types of parameters
    private String mParam1;
    private String mParam2;

    public static final String EXTRA_URL = "imageUrl";

    private RecyclerView mRecyclerView;
    private CardAdapter mCardAdapter;
    private ArrayList<Card> mCardList;

    TextView textView;

    private OnFragmentInteractionListener mListener;

    public Tab1() {
        // Required empty public constructor
    }

    /*
     * Use this factory method to create a new instance of
     * this fragment using the provided parameters.
     *
     * @param param1 Parameter 1.
     * @param param2 Parameter 2.
     * @return A new instance of fragment Tab1.
     */
    // TODO: Rename and change types and number of parameters
    public static Tab1 newInstance(String param1, String param2) {
        Tab1 fragment = new Tab1();
        Bundle args = new Bundle();
        args.putString(ARG_PARAM1, param1);
        args.putString(ARG_PARAM2, param2);
        fragment.setArguments(args);
        return fragment;
    }

//    @Override
    public void onCreate(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        if (getArguments() != null) {
            mParam1 = getArguments().getString(ARG_PARAM1);
            mParam2 = getArguments().getString(ARG_PARAM2);
        }
    }

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

        mRecyclerView = v.findViewById(R.id.recycler_view);
        mRecyclerView.setHasFixedSize(true);
        mRecyclerView.setLayoutManager(new LinearLayoutManager(getActivity()));

        mCardList = new ArrayList<>();

        /*
         * Retrofit code to fetch the Json data
         */
        Retrofit retrofit = new Retrofit.Builder()
                .baseUrl(ApiService.BASE_URL)
                .addConverterFactory(GsonConverterFactory.create())
                .build();

        ApiService service = retrofit.create(ApiService.class);
        Call<JsonResponse> call = service.getPopulationData();
        final StringBuffer flagData = new StringBuffer();

        call.enqueue(new Callback<JsonResponse>(){
            @Override
            public void onResponse(Call<JsonResponse> call, Response<JsonResponse> response) {
                ArrayList<Worldpopulation> population=new ArrayList(response.body()
                        .getWorldpopulation());

                for (Worldpopulation j : population) {
                    String countryName = j.getCountry();
                    String imageUrl = j.getFlag();
                    int rank = j.getRank();

                    mCardList.add(new Card(imageUrl, countryName, rank));
                }

                mCardAdapter = new CardAdapter(getActivity(), mCardList);
                mRecyclerView.setAdapter(mCardAdapter);

                // This particular line of code is causing the application to crash.
                // And I cannot figure out how this is supposed to be implemented.
                mCardAdapter.setItemOnClickListener((CardAdapter.OnItemClickListener) getContext());

            }

            @Override
            public void onFailure(Call<JsonResponse> call, Throwable t) {
                Log.d("JSONError", t.getMessage());
            }
        });

        // Inflate the layout for this fragment
        return v;
    }

    // TODO: Rename method, update argument and hook method into UI event
    public void onButtonPressed(Uri uri) {
        if (mListener != null) {
            mListener.onFragmentInteraction(uri);
        }
    }

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

    @Override
    public void onDetach() {
        super.onDetach();
        mListener = null;
    }

    @Override
    public void onItemClick(int position) {
        Intent imagePreview = new Intent(getActivity(), ViewImage.class);
        Card clickedItem = mCardList.get(position);

        imagePreview.putExtra(EXTRA_URL, clickedItem.getImageUrl());

        startActivity(imagePreview);
    }

    /*
     * This interface must be implemented by activities that contain this
     * fragment to allow an interaction in this fragment to be communicated
     * to the activity and potentially other fragments contained in that
     * activity.
     * <p>
     * See the Android Training lesson <a href=
     * "http://developer.android.com/training/basics/fragments/communicating.html"
     * >Communicating with Other Fragments</a> for more information.
     */
    public interface OnFragmentInteractionListener {
        // TODO: Update argument type and name
        void onFragmentInteraction(Uri uri);
    }
}

CardAdapter.java

public class CardAdapter extends RecyclerView.Adapter<CardAdapter.CardViewHolder> {
  private Context mContext;
  private ArrayList<Card> mCardList;
  private OnItemClickListener mListener;

  public interface OnItemClickListener {
    void onItemClick(int position);
  }

  public void setItemOnClickListener(OnItemClickListener listener) {
    mListener = listener;
  }

  public CardAdapter(Context context, ArrayList<Card> cardList) {
    mContext = context;
    mCardList = cardList;
  }

  @Override
  public CardViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
    View v = LayoutInflater.from(mContext).inflate(R.layout.card, parent, false);
    return new CardViewHolder(v);
  }

  @Override
  public void onBindViewHolder(CardViewHolder holder, int position) {
    Card currentItem = mCardList.get(position);

    String imageUrl = currentItem.getImageUrl();
    String countryName = currentItem.getCountryName();
    int rank = currentItem.getRank();

    holder.mTextViewCountry.setText(countryName);
    holder.mTextViewRank.setText("Rank: " + rank);

    Picasso.get().load(imageUrl).fit().centerInside().into(holder.mImageView);
  }

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

  public class CardViewHolder extends RecyclerView.ViewHolder {
    public ImageView mImageView;
    public TextView mTextViewCountry;
    public TextView mTextViewRank;

    public CardViewHolder(View itemView) {
      super(itemView);
      mImageView = itemView.findViewById(R.id.image_view);
      mTextViewCountry = itemView.findViewById(R.id.text_view_country_name);
      mTextViewRank = itemView.findViewById(R.id.text_view_rank);

      itemView.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
          if (mListener != null) {
            int position = getAdapterPosition();
            if (position != RecyclerView.NO_POSITION) {
              mListener.onItemClick(position);
            }
          }
        }
      });
    }
  }
}

ViewImage.java

public class viewimage extends appcompatactivity {

  @override
  protected void oncreate(bundle savedinstancestate) {
    super.oncreate(savedinstancestate);
    setcontentview(r.layout.activity_view_image);
    // imageview where the image is to be displayed in this activity
    imageview imageview = findviewbyid(r.id.fullscreenimage);

    bundle bundle = getintent().getextras();
    if (bundle != null) {
      string imageurl = bundle.getstring("extra_url");
      if (imageurl != null) {
        picasso.get().load(imageurl).fit().centerinside().into(imageview);
      }
    }
  }
}

1 个答案:

答案 0 :(得分:3)

您已经知道RecyclerView类中不再提供此方法。

我在onClick中实现RecyclerView事件的方法是这样的:

class MyAdapter extends RecyclerView.Adapter<MyViewHolder> {

    interface OnClickListener {
        void onClick(Item item);
    }

    private final List<Item> dataset;
    private final OnClickListener l; 

    public MyAdapter(List<Item> data, OnClickListener listener) {
        this.dataset = data;
        this.l = listener;
    }

    @Override MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        View v = //inflate layout
        MyClick click = new MyClick() {
            onClick(int position) {
                if (l != null) {
                    l.onClick(dataset.get(position));
                }
            }
        };
        return new MyViewHolder(click, v);
    }

    static class MyViewHolder {
        final MyClick l;

        public MyViewHolder(MyClick listener, View view) {
            super(view);
            l = listener;
            // inflate views
            view.setOnClickListener(new OnClickListener() {
                if (l != null) {
                    l.onClick(getAdapterPosition());
                }
            });
        }

        interface MyClick {
            void onClick(int position);
        }
    }
}

class MyActivity extends AppCompatActivity {

    @Override void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        // set layout
        MyAdapter adapter = new MyAdapter(getData(), new OnClickListener() {
            @Override onClick(Item item) {
                // do stuff with item
            }
        });
    }
}