【问题标题】:How to open a new activity when an item of a fragment with RecyclerView is clicked while passing the data of the clicked custom list item?在传递单击的自定义列表项的数据时单击带有 RecyclerView 的片段的项目时如何打开新活动?
【发布时间】:2019-08-11 07:57:19
【问题描述】:

我已经制作了一个自定义 Place 对象和 Place Adapter。我使用了 Parcelable,但是当我单击 Fragments 的任何项目时没有任何反应

尝试使用 Parcelable,但单击任何项​​目均无响应。

放置对象

public class Place implements Parcelable {


/** String resource ID for the name of the place */
private int mPlaceID;

private int mImageResourceId;

private int mNearestStation;

private int mSiteInfo;

public Place(int placeID, int imageResourceId, int NearestStation, int 
SiteInfo) {
    mPlaceID = placeID;
    mImageResourceId = imageResourceId;
    mNearestStation = NearestStation;
    mSiteInfo = SiteInfo;
}

protected Place(Parcel in) {
    mImageResourceId = in.readInt();
    mPlaceID = in.readInt ();
    mNearestStation = in.readInt ();
    mSiteInfo = in.readInt ();

}

public static final Creator<Place> CREATOR = new Creator<Place>() {
    @Override
    public Place createFromParcel(Parcel in) {
        return new Place (in);
    }

    @Override
    public Place[] newArray(int size) {
        return new Place[size];
    }
};

/**
 * Get the string resource ID for the name of the place.
 */
public int getPlaceName() {
    return mPlaceID;
}

/**
 * Return the image resource ID of the place.
 */
public int getImageResourceId() {
    return mImageResourceId;
}

public int getNearestStation() {
    return mNearestStation;
}

public int getSiteInfo() {
    return mSiteInfo;
}

@Override
public int describeContents() {
    return 0;
}

@Override
public void writeToParcel(Parcel parcel, int i) {
    parcel.writeInt(mImageResourceId);
    parcel.writeInt(mPlaceID);
    parcel.writeInt ( mNearestStation );
    parcel.writeInt ( mSiteInfo );
}

}

放置适配器

public class PlaceAdapter extends 
RecyclerView.Adapter<PlaceAdapter.PlaceViewHolder> {

Context mContext;
List<Place> mData;

public static class PlaceViewHolder extends RecyclerView.ViewHolder{

    public TextView mTextView;
    public ImageView mImageView;

    public PlaceViewHolder(@NonNull View itemView) {
        super ( itemView );
        mTextView = itemView.findViewById ( R.id.ImageViewText );
        mImageView = itemView.findViewById ( R.id.ImageView );

    }
}

public PlaceAdapter(Context mContext, List<Place> mData){

    this.mContext = mContext;
    this.mData = mData;

}

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

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


    holder.mTextView.setText ( mData.get ( position ).getPlaceName () );
    holder.mImageView.setImageResource ( mData.get ( position 
).getImageResourceId () );

}

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

public interface OnPlaceListener{

    void onPlaceClick(int position);
}

}

这是我点击项目的片段之一

public class MonumentsFragment extends Fragment implements 
PlaceAdapter.OnPlaceListener {

private RecyclerView mRecyclerView;

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

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


    final List<Place> places = new ArrayList<> ();

    Place place1 = new Place(R.string.monument1, 
R.drawable.windsor_castle, R.string.monument1S, R.string.monument1I);
    places.add(place1);

    Place place2 = new Place(R.string.monument2, 
R.drawable.trafalgar_square,R.string.monument2S, R.string.monument2I);
    places.add(place2);

    Place place3 = new Place(R.string.monument3, 
R.drawable.buckingham_palace,R.string.monument3S, R.string.monument3I);
    places.add(place3);

    Place place4 = new Place(R.string.monument4, 
R.drawable.bank_of_england,R.string.monument4S, R.string.monument4I);
    places.add(place4);

    Place place5 = new Place(R.string.monument5, 
R.drawable.kensington_palace,R.string.monument5S, R.string.monument5I);
     places.add(place5);

    Place place6 = new Place(R.string.monument6, 
R.drawable.london_wall,R.string.monument6S, R.string.monument6I);
    places.add(place6);


    mRecyclerView = (RecyclerView) rootView.findViewById ( 
R.id.recycler_view );
    PlaceAdapter placeAdapter = new PlaceAdapter ( getContext (), places 
);

    mRecyclerView.setLayoutManager ( new LinearLayoutManager ( getActivity 
() ) );
    mRecyclerView.setAdapter ( placeAdapter );

    return rootView;



}

@Override
public void onPlaceClick(int position) {
    Intent intent = new Intent( MonumentsFragment.this.getActivity () 
,SelectedPlaceActivity.class );
    intent.putExtra("Place Item", position);
    startActivity ( intent );
}


}

这是我想在点击时打开的 Activity

public class SelectedPlaceActivity extends AppCompatActivity {

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView( R.layout.selected_place);

    Intent intent = getIntent();

    if (intent!=null) {
        Place currentPlace = intent.getParcelableExtra("Place Item");


        int imageRes = currentPlace.getImageResourceId ();

        int placeName = currentPlace.getPlaceName ();

        int nearestStation = currentPlace.getNearestStation ();

        int moreInfo = currentPlace.getSiteInfo ();

        ImageView placeImage = findViewById (R.id.selected_place_image );
        TextView namePlace = findViewById ( R.id.selected_place_name );
        TextView station = findViewById ( R.id.nearest_station );
        TextView information = findViewById ( R.id.more_info );


        placeImage.setImageResource(imageRes);
        namePlace.setText(placeName);
        station.setText(nearestStation);
        information.setText ( moreInfo );
    }

}
}

点击片段中的任何项目均无响应

【问题讨论】:

    标签: android android-fragments onclick onclicklistener


    【解决方案1】:

    您尚未将侦听器分配给项目的onClick,并将侦听器传递给适配器的构造函数。请按照以下步骤操作。

    第 1 步PlaceAdapter 类中声明侦听器,并通过如下所示的构造函数为其赋值。

    // declare the listener
    OnPlaceListener mListener;
    
    // pass the listener along with Context and the List
    public PlaceAdapter(Context mContext, List<Place> mData, OnPlaceListener listener){
    
        this.mContext = mContext;
        this.mData = mData;
        // assign the listener
        this.mListener = listener;
    
    }
    

    第 2 步 您需要在 onBindViewHolder 方法中将侦听器分配给 itemView 的 onClick

    @Override
    public void onBindViewHolder(@NonNull PlaceViewHolder holder, int
            position) {
        // assign the listener here
        holder.itemView.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(final View v) {
                mListener.onPlaceClick(position);
            }
        });
        holder.mTextView.setText ( mData.get ( position ).getPlaceName () );
        holder.mImageView.setImageResource ( mData.get ( position
        ).getImageResourceId () );
    
    }
    

    第 3 步 在片段中将监听器传递给适配器。

    PlaceAdapter placeAdapter = new PlaceAdapter(getContext(), places, this);
    

    另外,我注意到您正在将位置传递给意图。相反,您需要传递与该位置相关的 Place 对象

    @Override
    public void onPlaceClick(int position) {
        Intent intent = new Intent( MonumentsFragment.this.getActivity ()
                ,SelectedPlaceActivity.class );
        intent.putExtra("Place Item", places.get(position));
        startActivity ( intent );
    }
    

    注意您需要声明 List outisde onCreateView 才能从 onPlaceClick 方法访问它。

    public class MonumentsFragment extends Fragment implements
            PlaceAdapter.OnPlaceListener {
    
        private RecyclerView mRecyclerView;
        // Declare the list here
        private List<Place> places;
    
        public MonumentsFragment() {
            // Required empty public constructor
        }
    
        @Override
        public View onCreateView(LayoutInflater inflater, ViewGroup container,
                Bundle savedInstanceState) {
            View rootView = inflater.inflate( R.layout.places_list, container,
                    false);
            // initialize the list 
            places = new ArrayList<>();
    
            Place place1 = new Place(R.string.monument1, 
                                     R.drawable.windsor_castle, R.string.monument1S, R.string.monument1I);
            places.add(place1);
    
            // rest of the code
    

    【讨论】:

    • 我遵循了所有步骤,但在最后一个步骤中,当我尝试编写 places.get(position) 时,它显示未解决的“位置”。这也是我得到的另一个错误 -java.lang.RuntimeException: Unable to start activity ComponentInfo{com.example.tourguide/com.example.tourguide.ui.main.SelectedPlaceActivity}: java.lang.NullPointerException: Attempt to invoke virtual空对象引用上的方法“int com.example.tourguide.ui.main.Place.getImageResourceId()”
    • @VihaanMisra 确保您在现有项目上调用方法。因此,请检查您是否提供了正确的指针并将正确的项目传递给方法调用。并且不要害怕对这一切进行研究,网络上充满了类似这样的已经回答的问题。
    • 嘿,非常感谢,你太棒了!你编码多久了,我才刚刚开始,我真的很想能够解决别人的问题。你有什么建议让我成为一个真正伟大的程序员,因为很多时候我只是茫然无措,不知道该怎么做。再次感谢伙计!
    【解决方案2】:

    要能够点击您的RecyclerView 中的项目,您需要在该项目上提供setOnClickListener。例如,您可以在适配器的 onCreateViewHolder 内执行此操作。

    public ExampleAdapter.ExampleViewHolder onCreateViewHolder(@NonNull ViewGroup viewGroup, int i) {
        View view = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.example_item, viewGroup, false);
        final ExampleViewHolder holder = new ExampleViewHolder(view);
    
        holder.itemView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                // actions that you need to perform
            }
        });
    
        return holder;
    }
    

    如果您需要获取项目位置,您可以使用holder.getAdapterPosition()。如果您需要更多解释,请提供有关所需结果的更多详细信息。

    如果您为此使用内部接口,则可以使用listener.onPlaceClick(holder.getAdapterPosition()) 并覆盖所需的方法来打开新活动,或者将代码放入适配器并使用mData.get() 获取intent 的对象。您可以从v 获取context

    --- 更新---

    为了能够从RecyclerViewAdapter 类开始活动,您需要传递上下文。有两种方法,您可以从View 获取它或在构造函数中分配上下文。

     holder.itemView.setOnClickListener(new View.OnClickListener() {
                @Override
          public void onClick(View v) {
              Intent intent = new Intent (v.getContext(), *needed_activity_class*);
              // put all that you need in intent
              v.getContext().startActivity(intent);
          }
     });
    

    【讨论】:

    • 我需要在单击 MuseumsFragment 项目时打开 SelectedPlaceActivity 并传递与自定义数组“Place”的每个项目相关联的一个图像视图 ID 和三个文本视图 ID
    • @VihaanMisra 检查第二个答案,它已经得到了您正在寻找的详细信息
    • 有没有一种方法可以在不使用内部接口的情况下这样做,因为它让我感到困惑,所以我可以毫无问题地删除它?我需要声明一个新的意图,然后开始所需的活动。我是初学者,所以如果您也可以提供代码,这对我很有帮助。谢谢!
    • @VihaanMisra 给我一点时间来更新答案。
    猜你喜欢
    • 2021-01-12
    • 2021-04-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多