Harts
Harts

Reputation: 4103

RecyclerView onListItemClick to create new intent

so, before latest update, I use onListItemClick listener and it works fine, but now I tried to use RecyclerView, and I'm not sure how to implement onClick for each item, that will open up a new activity..

this is what I used to have

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);
    }
}

but now, instead of using listview I create a sermon adapter and it looks like this

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());

    }

and the fragment is more or less the same, it's just I can't use onListItemClick anymore

    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);
        }

I have the cardview xml look like this

<!-- 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>

I've got this error when try to create new intent

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)

Upvotes: 3

Views: 21337

Answers (1)

DSS
DSS

Reputation: 7259

You could implement an onClick on the view in the onBindViewHolder method of yours inside the adpater.

  1. Assign an id to the view that holds the item cell
  2. Get the view just the way you have for the textviews
  3. set an onClick to the root inside the method like this:

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

EDIT:

This is how you assign an id in the xml

<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>

This is how you define the views (or probably instantiate them)

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);
    }

That's your custom viewholder, so declare the TextViews just the way we declare variables.. your onBindView method wil therefore look like this now:

 @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);
          }
    });
}

I really have no idea why there is difference between the two, may be its because you are intializing the views inside onbind instead of the viewholder constructor.

You could also refer to this

EDIT 2: (2nd method)

Change you adapter to the following:

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

In the onClick do this:

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

In the fragment class create a public method with the name sendToNextAcitivity with the same param definition and then call the next intent.

3rd method

Create an interface in the adapter, create a set method for the interface, implement the interface in the fragment and then initialize it, and then pass it to the set method of the adapter.

then use this:

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

Upvotes: 15

Related Questions