【问题标题】:RecyclerView onListItemClick to create new intentRecyclerView onListItemClick 创建新意图
【发布时间】:2014-12-19 02:44:54
【问题描述】:

所以,在最新更新之前,我使用 onListItemClick 监听器,它工作正常,但现在我尝试使用 RecyclerView,我不确定如何为每个项目实现 onClick,这将打开一个新活动..

这是我曾经拥有的

public class SermonsFragment extends Fragment {

    @Override
    public void onListItemClick(ListView list, View v, int position, long id) {
        Intent mediaStreamIntent = new Intent(getActivity(), MediaStreamPlayer.class);
        mediaStreamIntent.putExtra("sermon_details", (android.os.Parcelable) list.getItemAtPosition(position));
        startActivity(mediaStreamIntent);
    }
}

但现在,我创建了一个布道适配器,而不是使用 listview,它看起来像这样

public class SermonListAdapter extends RecyclerView.Adapter<SermonListAdapter.ViewHolder>{
    private ArrayList<Sermon> mDataset;

    // 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
    //Note: need to remove static class no idea why
    public class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener{
        // each data item is just a string in this case
        public View mView;
        public ViewHolder(View v) {
            super(v);
            v.setOnClickListener(this);
            mView = v;
        }

        @Override
        public void onClick(View v) {
            Log.d("SermonsListAdapter.java.debug", "itemClick " + mDataset.get(getPosition()).getName());

        }
    }

    // Provide a suitable constructor (depends on the kind of dataset)
    public SermonListAdapter(ArrayList<Sermon> myDataset) {
        mDataset = myDataset;
    }

    // Create new views (invoked by the layout manager)
    @Override
    public SermonListAdapter.ViewHolder onCreateViewHolder(ViewGroup parent,
                                                   int viewType) {
        // create a new view
        View v = LayoutInflater.from(parent.getContext())
                .inflate(R.layout.sermon_cardview, parent, false);
        // set the view's size, margins, paddings and layout parameters

        ViewHolder vh = new ViewHolder(v);
        return vh;
    }

    // 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 title = (TextView) holder.mView.findViewById(R.id.sermon_title);
        TextView series = (TextView) holder.mView.findViewById(R.id.sermon_series);
        TextView pastor = (TextView) holder.mView.findViewById(R.id.sermon_pastor);
        TextView sermonDate = (TextView) holder.mView.findViewById(R.id.sermon_date);

        title.setText(mDataset.get(position).getName());
        series.setText(mDataset.get(position).getSeries());
        pastor.setText(mDataset.get(position).getPastor());
        sermonDate.setText(mDataset.get(position).getSermonDate());

    }

和片段差不多,只是我不能再使用onListItemClick了

    public class SermonsFragment extends Fragment {
        private static final int MAX_SERMONS_LIST = 20;
        private ArrayAdapter<Sermon> listAdapter;
        private String imageUrl;
        private static String sermonListJSONUrl = “http://someurl”;

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

        @Override
        public void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setRetainInstance(true);

            //Check if there is internet, if yes call JSONParser
            ConnectionDetector myConnection = new ConnectionDetector(getActivity().getApplicationContext());
            Boolean isInternetOnline = false;
            isInternetOnline = myConnection.isConnectingToInternet();

            if(isInternetOnline) {
                //Call JSONParser Asynchronously to get sermonList in JSON Format
                new callJSONParserAsync().execute(sermonListJSONUrl);
            }
        }

        @Override
        public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
            View rootView = inflater.inflate(R.layout.fragment_sermons, container, false);
            mRecyclerView = (RecyclerView) rootView.findViewById(R.id.my_recycler_view);
            return rootView;
        }

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

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

            //Just an Empty Class
            ArrayList<Sermon> mySermon = new ArrayList<Sermon>();

            //specify an adapter
            mAdapter = new SermonListAdapter(mySermon);
            mRecyclerView.setAdapter(mAdapter);
        }

我的 cardview xml 看起来像这样

<!-- A CardView that contains a TextView -->
<android.support.v7.widget.CardView
    xmlns:card_view="http://schemas.android.com/apk/res-auto"
    android:id="@+id/card_view"
    android:layout_margin="5dp"
    android:layout_width="match_parent"
    android:layout_height="100dp"
    card_view:cardCornerRadius="1dp">

    <LinearLayout android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical">
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:textAppearance="?android:attr/textAppearanceLarge"
            android:id="@+id/sermon_title" />
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:textAppearance="?android:attr/textAppearanceSmall"
            android:id="@+id/sermon_series" />
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:textAppearance="?android:attr/textAppearanceSmall"
            android:id="@+id/sermon_pastor" />
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:textAppearance="?android:attr/textAppearanceSmall"
            android:id="@+id/sermon_date" />
    </LinearLayout>
</android.support.v7.widget.CardView>

我在尝试创建新意图时遇到此错误

12-18 22:31:48.469  31887-31887/org.ifgfseattle.ifgfseattle E/AndroidRuntime﹕ FATAL EXCEPTION: main
    Process: org.ifgfseattle.ifgfseattle, PID: 31887
    android.util.AndroidRuntimeException: Calling startActivity() from outside of an Activity  context requires the FLAG_ACTIVITY_NEW_TASK flag. Is this really what you want?
            at android.app.ContextImpl.startActivity(ContextImpl.java:1232)
            at android.app.ContextImpl.startActivity(ContextImpl.java:1219)
            at android.content.ContextWrapper.startActivity(ContextWrapper.java:322)
            at org.ifgfseattle.ifgfseattle.adapter.SermonListAdapter$1.onClick(SermonListAdapter.java:81)
            at android.view.View.performClick(View.java:4756)
            at android.view.View$PerformClick.run(View.java:19749)
            at android.os.Handler.handleCallback(Handler.java:739)
            at android.os.Handler.dispatchMessage(Handler.java:95)
            at android.os.Looper.loop(Looper.java:135)
            at android.app.ActivityThread.main(ActivityThread.java:5221)
            at java.lang.reflect.Method.invoke(Native Method)
            at java.lang.reflect.Method.invoke(Method.java:372)
            at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:899)
            at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:694)

【问题讨论】:

    标签: android android-intent android-cardview android-recyclerview


    【解决方案1】:

    您可以在 adpater 中的 onBindViewHolder 方法中的视图上实现 onClick

    1. 为包含项目单元格的视图分配一个 ID
    2. 以文本视图的方式获取视图
    3. 将 onClick 设置为方法内的根,如下所示:

      @Override
      public void onBindViewHolder(ViewHolder holder, int position) {
          viewHolder.relLayout.setOnClickListener(new OnClickListener(){
              public void onClick(View v) {
                   // perform your operations here 
              }
          });
      }
      

    编辑:

    这是您在 xml 中分配 id 的方式

    <LinearLayout android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:id="@+id/lnrLayout"  ---------->> This is new
        android:orientation="vertical">
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:textAppearance="?android:attr/textAppearanceLarge"
            android:id="@+id/sermon_title" />
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:textAppearance="?android:attr/textAppearanceSmall"
            android:id="@+id/sermon_series" />
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:textAppearance="?android:attr/textAppearanceSmall"
            android:id="@+id/sermon_pastor" />
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:textAppearance="?android:attr/textAppearanceSmall"
            android:id="@+id/sermon_date" />
    </LinearLayout>
    

    这是您定义视图(或可能实例化它们)的方式

    public ViewHolder(View mView) {
            super(view);
            title = (TextView) holder.mView.findViewById(R.id.sermon_title);
            series = (TextView) holder.mView.findViewById(R.id.sermon_series);
            pastor = (TextView) holder.mView.findViewById(R.id.sermon_pastor);
            sermonDate = (TextView) holder.mView.findViewById(R.id.sermon_date)
            lnrLayout = (LinearLayout)holder.mView.findViewById(R.id.lnrLayout);
        }
    

    那是你的自定义视图,所以像我们声明变量一样声明 TextViews.. 你的 onBindView 方法现在看起来像这样:

     @Override
    public void onBindViewHolder(ViewHolder holder, int position) {
        holder.title.setText(mDataset.get(position).getName());
        holder.series.setText(mDataset.get(position).getSeries());
        holder.pastor.setText(mDataset.get(position).getPastor());
        holder.sermonDate.setText(mDataset.get(position).getSermonDate());
        holder.lnrLayout.setOnClickListener(new OnClickListener(){
              public void onClick(View v) {
                 // on click action here
                 //-- use context to start the new Activity
                Intent mediaStreamIntent = new Intent(mContext, MediaStreamPlayer.class);
                mediaStreamIntent.putExtra("sermon_details", (android.os.Parcelable) mDataset.get(position));
                mContext.startActivity(mediaStreamIntent);
              }
        });
    }
    

    我真的不知道为什么两者之间存在差异,可能是因为您正在初始化 onbind 内部的视图而不是 viewholder 构造函数。

    您也可以参考this

    编辑 2:(第二种方法)

    将您的适配器更改为以下内容:

    // Provide a suitable constructor (depends on the kind of dataset)
    public SermonListAdapter(ArrayList<Sermon> myDataset, Fragment fragment) {
        mDataset = myDataset;
        mFragment = fragment;
    }
    

    在 onClick 中这样做:

    if(mFragment != null && mFragment instanceof SermonFragment) {
          ((SermonFragment)mFragment).sendToNextActivity(position); -> you can pass any data you wsh to
     }
    

    在片段类中创建一个名为 sendToNextAcitivity 且具有相同参数定义的公共方法,然后调用下一个意图。

    第三种方法

    在adapter中创建接口,为接口创建set方法,在fragment中实现接口然后初始化,然后传给adapter的set方法。

    然后使用这个:

    if(mListener!= null) {
             mListener.sendToNextActivity(position); -> you can pass any data you wsh to
         }
    

    【讨论】:

    • 这里有几个问题:实现单击 onBindViewHolder 与公共类 ViewHolder 扩展 RecyclerView.ViewHolder 有什么区别吗?正如您现在所看到的,我在 ViewHolder 类中有它,当我尝试创建意图时,它会给出语法错误。还有你如何为视图分配一个ID?真正的初学者,需要一步一步的教程..谢谢
    • @Harts - 如果有帮助,请参阅链接
    • 所以,我到此为止了,lnrLayoutCardView.setOnClickListener(new View.OnClickListener(){ public void onClick(View v) { // 此处点击操作 Log.d("SermonsListAdapter. java.debug", "Test"); Intent mediaStreamIntent = new Intent(getActivity(), MediaStreamPlayer.class); mediaStreamIntent.putExtra("sermon_details", (android.os.Parcelable) mDataset.get(position)); startActivity( mediaStreamIntent); } });我不能使用 getactivity 和启动活动,它说无法解析方法
    • 你需要上下文而不是 getActivity ......你可以在适配器的构造函数中获取......然后将它存储在本地上下文 obj 中......并使用那个。
    • flag_new_task 基本上将新活动创建为堆栈中的新活动..所以按下后退按钮不会引导您进入上一个屏幕,而是退出应用程序,如果那是唯一的屏幕(nt当然)..你做的另一种方式是,在适配器中传递对片段的引用,然后将位置传递给片段类,然后从片段开始一个新的活动..等待@Harts检查编辑。 .
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-10-02
    • 2013-06-18
    • 1970-01-01
    • 1970-01-01
    • 2020-08-14
    • 1970-01-01
    • 2021-05-20
    相关资源
    最近更新 更多