App is crashing when i click on any item in recyclerview - java

I was creating a recycler view and trying to create a toast when any item is clicked on using interface(i'm doing for first time). But my app is crashing when i click any item in recycler view.
Here is my main java file code.
package com.example.creatingrecyclerview;
import androidx.appcompat.app.AppCompatActivity;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import android.os.Bundle;
import android.view.View;
import android.widget.Toast;
public class MainActivity extends AppCompatActivity implements newsOnCkicked {
RecyclerView r;
String arr[]={"1","2","3","4","1","1","1","1","1","1","1","1","1","1","1","1","1","1","1","1","1","1","1","1","1","1","1"};
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
r=findViewById(R.id.rv);
r.setLayoutManager(new LinearLayoutManager(this));
CustomAdapter c=new CustomAdapter(arr,this);
r.setAdapter(c);
}
#Override
public void onClick(View view) {
}
#Override
public String onItemClicked(String s) {
Toast.makeText(this, "Item clicked is "+ s, Toast.LENGTH_SHORT).show();
return null;
}
}
And this is my customadapter java code.
package com.example.creatingrecyclerview;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import androidx.recyclerview.widget.RecyclerView;
public class CustomAdapter extends RecyclerView.Adapter<CustomAdapter.ViewHolder> {
private String[] localDataSet;
private newsOnCkicked k;
/**
* Provide a reference to the type of views that you are using
* (custom ViewHolder).
*/
public static class ViewHolder extends RecyclerView.ViewHolder {
private final TextView textView;
public ViewHolder(View view) {
super(view);
// Define click listener for the ViewHolder's View
textView = (TextView) view.findViewById(R.id.textView2);
}
public TextView getTextView() {
return textView;
}
}
/**
* Initialize the dataset of the Adapter.
*
* #param dataSet String[] containing the data to populate views to be used
* by RecyclerView.
*/
public CustomAdapter(String[] dataSet,newsOnCkicked k) {
localDataSet = dataSet;
this.k=k;
}
// Create new views (invoked by the layout manager)
#Override
public ViewHolder onCreateViewHolder(ViewGroup viewGroup, int viewType) {
// Create a new view, which defines the UI of the list item
View view = LayoutInflater.from(viewGroup.getContext())
.inflate(R.layout.mylayout, viewGroup, false);
RecyclerView.ViewHolder v=new ViewHolder(view);
view.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View vi) {
k.onItemClicked(localDataSet[v.getAdapterPosition()]);
}
});
return new ViewHolder(view);
}
// Replace the contents of a view (invoked by the layout manager)
#Override
public void onBindViewHolder(ViewHolder viewHolder, final int position) {
// Get element from your dataset at this position and replace the
// contents of the view with that element
viewHolder.getTextView().setText(localDataSet[viewHolder.getAdapterPosition()]);
}
// Return the size of your dataset (invoked by the layout manager)
#Override
public int getItemCount() {
return localDataSet.length;
}
}
interface newsOnCkicked extends View.OnClickListener {
String onItemClicked(String s);
}
Please help me find the error in the code. It will be great:)

You have to set you click listener with viewHolder . copy the code below and paste then run
public class CustomAdapter extends RecyclerView.Adapter<CustomAdapter.ViewHolder> {
private String[] localDataSet;
private newsOnCkicked k;
/**
* Provide a reference to the type of views that you are using
* (custom ViewHolder).
*/
public static class ViewHolder extends RecyclerView.ViewHolder {
private final TextView textView;
public ViewHolder(View view) {
super(view);
// Define click listener for the ViewHolder's View
textView = (TextView) view.findViewById(R.id.textView2);
}
public TextView getTextView() {
return textView;
}
}
/**
* Initialize the dataset of the Adapter.
*
* #param dataSet String[] containing the data to populate views to be used
* by RecyclerView.
*/
public CustomAdapter(String[] dataSet,newsOnCkicked k) {
localDataSet = dataSet;
this.k=k;
}
// Create new views (invoked by the layout manager)
#Override
public ViewHolder onCreateViewHolder(ViewGroup viewGroup, int viewType) {
// Create a new view, which defines the UI of the list item
View view = LayoutInflater.from(viewGroup.getContext())
.inflate(R.layout.mylayout, viewGroup, false);
return new ViewHolder(view);
}
// Replace the contents of a view (invoked by the layout manager)
#Override
public void onBindViewHolder(ViewHolder viewHolder, final int position) {
// Get element from your dataset at this position and replace the
viewHolder.itemView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View vi) {
k.onItemClicked(localDataSet[viewHolder.getAdapterPosition()]);
}
});
viewHolder.getTextView().setText(localDataSet[viewHolder.getAdapterPosition()]);
}
// Return the size of your dataset (invoked by the layout manager)
#Override
public int getItemCount() {
return localDataSet.length;
}
}
interface newsOnCkicked extends View.OnClickListener {
String onItemClicked(String s);
}
if still get problem comment below with error log.

Related

How to set OnClick For a Recycler View Item Toast with position

I have Just Created a recycler View that contains Cards All I want to setOnCLick for this recycler view toast with a position item Click as It's ma first time to use a recycler view I always use a list View with a setOnItemClickListner so
Here's my Adapter Class
package abtech.waiteriano.com.retailstar.adapters;
import android.content.Context;
import android.support.v7.widget.CardView;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import java.util.List;
import abtech.waiteriano.com.retailstar.R;
public class RVAdapter extends RecyclerView.Adapter<RVAdapter.PersonViewHolder> {
public static class PersonViewHolder extends RecyclerView.ViewHolder {
CardView cv;
Context c;
TextView InvoiceNumber;
TextView InvoiceType;
TextView InvoiceDate;
TextView Status;
TextView CustomerID;
PersonViewHolder(View itemView) {
super(itemView);
cv = (CardView)itemView.findViewById(R.id.cv);
InvoiceNumber = (TextView)itemView.findViewById(R.id.invoiceNo);
InvoiceType = (TextView)itemView.findViewById(R.id.tvType);
InvoiceDate = (TextView)itemView.findViewById(R.id.tvDate);
Status = (TextView)itemView.findViewById(R.id.statusTv);
CustomerID = (TextView)itemView.findViewById(R.id.cutomerId);
}
}
List<Invoice> Invoices;
RVAdapter(List<Invoice> Invoices){
this.Invoices = Invoices;
}
#Override
public void onAttachedToRecyclerView(RecyclerView recyclerView) {
super.onAttachedToRecyclerView(recyclerView);
}
#Override
public PersonViewHolder onCreateViewHolder(ViewGroup viewGroup, int i) {
View v = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.item, viewGroup, false);
PersonViewHolder pvh = new PersonViewHolder(v);
return pvh;
}
#Override
public void onBindViewHolder(PersonViewHolder personViewHolder, int i) {
personViewHolder.InvoiceNumber.setText(Invoices.get(i).invoiceNo);
personViewHolder.InvoiceType.setText(Invoices.get(i).invoiceType);
personViewHolder.InvoiceDate.setText(Invoices.get(i).invoiceDate);
personViewHolder.Status.setText(Invoices.get(i).status);
personViewHolder.CustomerID.setText(Invoices.get(i).cutomerId);
}
#Override
public int getItemCount() {
return Invoices.size();
}
}
and here's the fragment class which contains the recycler VIew
package abtech.waiteriano.com.retailstar.adapters;
import android.net.Uri;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import java.util.ArrayList;
import java.util.List;
import abtech.waiteriano.com.retailstar.R;
/**
* A simple {#link Fragment} subclass.
* Activities that contain this fragment must implement the
* {#link InvoiceFragment.OnFragmentInteractionListener} interface
* to handle interaction events.
* Use the {#link InvoiceFragment#newInstance} factory method to
* create an instance of this fragment.
*/
public class InvoiceFragment extends Fragment {
// TODO: Reinvoice_number parameter arguments, choose invoice_numbers that match
View rootView;
private List<Invoice> Invoices;
private RecyclerView rv;
// the fragment initialization parameters, e.g. ARG_ITEM_NUMBER
private static final String ARG_PARAM1 = "param1";
private static final String ARG_PARAM2 = "param2";
// TODO: Reinvoice_number and change types of parameters
private String mParam1;
private String mParam2;
private OnFragmentInteractionListener mListener;
public InvoiceFragment() {
// 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 InvoiceFragment.
*/
// TODO: Reinvoice_number and change types and number of parameters
public static InvoiceFragment newInstance(String param1, String param2) {
InvoiceFragment fragment = new InvoiceFragment();
Bundle args = new Bundle();
args.putString(ARG_PARAM1, param1);
args.putString(ARG_PARAM2, param2);
fragment.setArguments(args);
return fragment;
}
#Override
public void onCreate(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) {
// Inflate the layout for this fragment
rootView = inflater.inflate(R.layout.fragment_invoice, container, false);
rv=(RecyclerView)rootView.findViewById(R.id.rv);
LinearLayoutManager llm = new LinearLayoutManager(getContext());
rv.setLayoutManager(llm);
rv.setHasFixedSize(true);
initializeData();
initializeAdapter();
return rootView;
}
private void initializeData(){
Invoices = new ArrayList<>();
Invoices.add(new Invoice("204", "Regular","15/5/2017","Regular","100200000194"));
Invoices.add(new Invoice("205", "Regular","20/5/2017","Regular","100200000195"));
Invoices.add(new Invoice("206", "Regular","30/5/2017","Regular","100200000196"));
Invoices.add(new Invoice("207", "Regular","5/6/2017","Regular","100200000197"));
Invoices.add(new Invoice("208", "Regular","10/6/2017","Regular","100200000198"));
Invoices.add(new Invoice("209", "Regular","15/6/2017","Regular","100200000199"));
Invoices.add(new Invoice("210", "Regular","20/6/2017","Regular","100200000200"));
Invoices.add(new Invoice("211", "Regular","25/6/2017","Regular","100200000201"));
Invoices.add(new Invoice("212", "Regular","30/6/2017","Regular","100200000202"));
}
private void initializeAdapter(){
RVAdapter adapter = new RVAdapter(Invoices);
rv.setAdapter(adapter);
}
// TODO: Reinvoice_number method, update argument and hook method into UI event
public void onButtonPressed(Uri uri) {
if (mListener != null) {
mListener.onFragmentInteraction(uri);
}
}
#Override
public void onDetach() {
super.onDetach();
mListener = null;
}
/**
* 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 invoice_number
void onFragmentInteraction(Uri uri);
}
}
All you have to do is implement onClickListener in your PersonViewHolder class inside your recyclerview adapter like this:
Make a Constructor
Set onClickListener on the itemview
Make toast in onClick function for the clicked item
Final edit will look like this -
public class RVAdapter extends RecyclerView.Adapter<RVAdapter.PersonViewHolder> {
private Context mContext;
public RVAdapter(Context context) {
mContext = context;
}
public static class PersonViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
CardView cv;
Context c;
TextView InvoiceNumber;
TextView InvoiceType;
TextView InvoiceDate;
TextView Status;
TextView CustomerID;
PersonViewHolder(View itemView) {
super(itemView);
cv = (CardView)itemView.findViewById(R.id.cv);
InvoiceNumber = (TextView)itemView.findViewById(R.id.invoiceNo);
InvoiceType = (TextView)itemView.findViewById(R.id.tvType);
InvoiceDate = (TextView)itemView.findViewById(R.id.tvDate);
Status = (TextView)itemView.findViewById(R.id.statusTv);
CustomerID = (TextView)itemView.findViewById(R.id.cutomerId);
//set OnclickListener
itemView.setOnClickListener(this);
}
#Override
public void onClick(View view) {
int position = getAdapterPosition();
//Do whatever you what with the position
Toast.makeText(mContext, "Clicked Position"+position, Toast.LENGTH_SHORT).show();
}
}
List<Invoice> Invoices;
RVAdapter(List<Invoice> Invoices){
this.Invoices = Invoices;
}
#Override
public void onAttachedToRecyclerView(RecyclerView recyclerView) {
super.onAttachedToRecyclerView(recyclerView);
}
#Override
public PersonViewHolder onCreateViewHolder(ViewGroup viewGroup, int i) {
View v = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.item, viewGroup, false);
PersonViewHolder pvh = new PersonViewHolder(v);
return pvh;
}
#Override
public void onBindViewHolder(PersonViewHolder personViewHolder, int i) {
personViewHolder.InvoiceNumber.setText(Invoices.get(i).invoiceNo);
personViewHolder.InvoiceType.setText(Invoices.get(i).invoiceType);
personViewHolder.InvoiceDate.setText(Invoices.get(i).invoiceDate);
personViewHolder.Status.setText(Invoices.get(i).status);
personViewHolder.CustomerID.setText(Invoices.get(i).cutomerId);
}
#Override
public int getItemCount() {
return Invoices.size();
}
}
You can get context from constructor then make toast inside onBindViewHolder() :
Context context;
RVAdapter(Context context, List<Invoice> Invoices){
this.Invoices = Invoices;
this.context = context;
}
#Override
public void onBindViewHolder(PersonViewHolder personViewHolder, int position) {
personViewHolder.InvoiceNumber.setText(Invoices.get(i).invoiceNo);
personViewHolder.InvoiceType.setText(Invoices.get(i).invoiceType);
personViewHolder.InvoiceDate.setText(Invoices.get(i).invoiceDate);
personViewHolder.Status.setText(Invoices.get(i).status);
personViewHolder.CustomerID.setText(Invoices.get(i).cutomerId);
holder.itemView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Toast.makeToast(context, "Clicked position is : "+position, Toast.LENGTH_SHORT);
}
});
}
Inside your fragment :
RVAdapter adapter = new RVAdapter(getActivity(), Invoices);

Unable to resolve "startActivity()" when trying to use it from RecyclerView's onClickListener()

I am new to android programming and trying to implement the RecyclerView. Please forgive me if the question is redundant but I could not find my answer anywhere else. So, I'm finally posting my question.
import android.content.Context;
import android.content.Intent;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import java.util.List;
public class QueriesAdapter extends RecyclerView.Adapter<QueriesAdapter.QueryViewHolder> {
private List<Query> list;
private Context mContext;
// 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
public class QueryViewHolder extends RecyclerView.ViewHolder{
// each data item is just a string in this case
protected TextView questionTextView;
public QueryViewHolder (View view)
{
super(view);
this.questionTextView = (TextView) view.findViewById(R.id.list_item_question);
}
}
// Provide a suitable constructor (depends on the kind of dataset)
public QueriesAdapter(Context context, List<Query> myDataset) {
mContext = context;
list = myDataset;
}
// Create new views (invoked by the layout manager)
#Override
public QueriesAdapter.QueryViewHolder onCreateViewHolder(ViewGroup parent,
int viewType) {
// create a new view
View v = LayoutInflater.from(parent.getContext())
.inflate(R.layout.list_item, parent, false);
// set the view's size, margins, paddings and layout parameters
QueryViewHolder vh = new QueryViewHolder(v);
return vh;
}
// Replace the contents of a view (invoked by the layout manager)
#Override
public void onBindViewHolder(QueryViewHolder holder, int position) {
// - get element from your dataset at this position
// - replace the contents of the view with that element
holder.questionTextView.setText(list.get(position).mQuery);
holder.questionTextView.setTag(holder);
}
View.OnClickListener clickListener = new View.OnClickListener(){
#Override
public void onClick(View v) {
QueryViewHolder viewHolder = (QueryViewHolder)v.getTag();
int position = viewHolder.getPosition();
Query q = list.get(position);
Intent i = new Intent(mContext, Answer.class);
i.putExtra("QueryId", q.id);
i.putExtra("question", q.mQuery);
i.putExtra("answer", q.mAnswer);
startActivity(i);
//This line is showing error that it cannot resolve startActivity() function, I think that I did not pass the context properly.
//Anyway, help me on this.
}
};
// Return the size of your dataset (invoked by the layout manager)
#Override
public int getItemCount() {
return list.size();
}
}
Now, this is a part of my MainActivity which I used to instantiate the QueriesAdapter Class(a Custom Adapter)
mAdapter = new QueriesAdapter(this, list);
You must use mContext to start a method which is default in the Activity try with mContext.startActivity(i)
You need to implement in the following way. Define a click listener in RecyclerView adapter class so that event can be consumed in corresponding Activity or Fragment. This helps making the events to handle easier
public class ListViewNotifyAdapter extends RecyclerView.Adapter <...>{
//defining a click listner
private static MyClickListener myClickListener;
//usual methods and variables goes here
public void setOnItemClickListener(MyClickListener myClickListener) {
this.myClickListener = myClickListener;
}
//interface for click
public interface MyClickListener {
public void onItemClick(int position, View v);
}
//view holder
public static class NotificationObjectHolder extends RecyclerView.ViewHolder implements View.OnClickListener{
TextView txtEventAlias;
TextView txtTime;
TextView txtLogMessage;
public NotificationObjectHolder(View viewItem){
super(viewItem);
txtEventAlias=(TextView)viewItem.findViewById(R.id.txtEventAlias);
txtTime=(TextView)viewItem.findViewById(R.id.txtTime);
txtLogMessage=(TextView)viewItem.findViewById(R.id.txtLogMessage);
itemView.setOnClickListener(this);
}
#Override
public void onClick(View v) {
myClickListener.onItemClick(getPosition(), v);
}
}
}
Now in the class which you have implemented the RecyclerView do like the following
#Override
public void onResume() {
super.onResume();
((ListViewNotifyAdapter) mAdapter).setOnItemClickListener(
new ListViewNotifyAdapter.MyClickListener() {
#Override
public void onItemClick(int position, View v) {
showAlert(position);
}
});
}
void showAlert(int position){
//action for the item click
}
Use mContext.startActivity(i);.

recyclerview onclicklistener java.lang.IndexOutOfBoundsException: Invalid index 0, size is 0

when I dynamic remove an item, or when I refresh the adapter(swipe to fresh) i get these erros:
recyclerview onclicklistener java.lang.IndexOutOfBoundsException: Invalid index 0, size is 0
Really can't figure out why this is happening, Really Appreciate any feed back.
MainActivity:
adapter.setOnItemClickListener(new OnItemClickListener() {
#Override
public void onItemClick(View view, int position) {
GroupModel selectedList = mGroupModels.get(position);
if (selectedList != null) {
Log.d(TAG, "setAdpterListner > view.getId: " + view.getId() +
" | P: " + position +
" | data ID: " + selectedList.getGroupName()
//" | viewID: " + viewID
);
Intent intent = new Intent(this, DetailsActivity.class);
String listId = selectedList.getGroupID();
String listName = selectedList.getGroupName();
intent.putExtra(Constant.KEY_LIST_ID, listId);
intent.putExtra(Constant.KEY_LIST_NAME, listName);
startActivity(intent);
}
}
});
Adapter:
public class GroupListAdapter extends RecyclerView.Adapter<GroupListAdapter.StatusViewHolder> {
Context context;
private List<GroupModel> mGroupModels;
private static OnItemClickListener listener;
public GroupListAdapter(Context context, List<GroupModel> groupList) {
this.context = context;
this.mGroupModels = groupList;
}
public void setOnItemClickListener(OnItemClickListener listener) {
GroupListAdapter.listener = listener;
}
#Override
public StatusViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.single_group_list, parent, false);
return new StatusViewHolder(view);
}
#Override
public void onBindViewHolder(StatusViewHolder holder, int position) {
final GroupModel data = mGroupModels.get(position);
holder.text_view_list_name.setText(data.getGroupName());
}//end onBindViewHolder
#Override
public int getItemCount() {
return mGroupModels.size();
}
public class StatusViewHolder extends RecyclerView.ViewHolder {
public TextView text_view_list_name;
public TextView created_by;
public StatusViewHolder(final View itemView) {
super(itemView);
text_view_list_name = (TextView) itemView.findViewById(R.id.text_view_list_name);
created_by = (TextView) itemView.findViewById(R.id.created_by);
// Setup the click listener
itemView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (listener != null)
listener.onItemClick(itemView, getLayoutPosition());
}
});
}
}//end StatusViewHolder
}//end GroupListAdapter
UPDATE:
I taken into consideration Yurii Tsap Feedback. I check the code again. I think the problem is somewhere below:
Whenever I swipe to Fresh, and If i click on the list straight way, the app Crash with the error from above.
mSwipeRefreshLayout.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
#Override
public void onRefresh() {
// Refresh items
mRecyclerView.invalidate();
adapter = null;
initGetGroupList();
mSwipeRefreshLayout.setRefreshing(false);
}
});
In the API call
...
GroupModel groupModel = new GroupModel(groupID, groupName, groupCreatedBy);
mGroupModels.add(groupModel);
}
updateUI(true);
if (adapter == null) {
adapter = new GroupListAdapter(MainActivity.this, mGroupModels);
mRecyclerView.setAdapter(adapter);
setAdapterListener(adapter);
}
The problem is definitely not in the static listener. And also the listener is just an interface callback(related to the comment above) not a AdapterView.OnItemClickListener(). I think the problem is somewhere behind this code, maybe you are clearing the item list somewhere else or something like that?
And also as for me in your case it's better to use getAdapterPosition() instead of getLayoutPosition().
As mentioned in docs :
If LayoutManager needs to call an external method that requires the adapter position of the item, it can use getAdapterPosition() or RecyclerView.Recycler.convertPreLayoutPositionToPostLayout(int).
Make OnItemClickListener non static .Like
private OnItemClickListener listener;
your code have alot of problem
i will explain my way to handle recycle view
very simple adapter
package com.pentavalue.ongo.transportway.adapter;
import android.app.Activity;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.ProgressBar;
import android.widget.RelativeLayout;
import com.pentavalue.ongo.R;
import com.pentavalue.ongo.Utilts.ImageLoaderHelper;
import com.pentavalue.ongo.register.model.Vechiles;
import com.pentavalue.ongo.widget.ArabicTextView;
import java.util.ArrayList;
/**
* Created by hamada on 19/09/2015.
*/
public class TransportTypeAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
public LayoutInflater inflater = null;
Activity activity;
ArrayList<Vechiles> vechileList;
ImageLoaderHelper imageLoaderHelper;
public TransportTypeAdapter(Activity activity, ArrayList<Vechiles> vechileList) {
this.activity = activity;
this.vechileList = vechileList;
imageLoaderHelper = new ImageLoaderHelper(activity, null);
inflater = LayoutInflater.from(activity);
}
#Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View vi = inflater.inflate(R.layout.single_transport_item, parent, false);
RecyclerView.ViewHolder vh = new VechileListHolder(vi);
return vh;
}
#Override
public void onBindViewHolder(RecyclerView.ViewHolder viewHolder, int pos) {
VechileListHolder mHolder = (VechileListHolder) viewHolder;
mHolder.renderDate(vechileList.get(pos));
}
#Override
public int getItemCount() {
if (vechileList != null)
return this.vechileList.size();
else
return 0;
}
public class VechileListHolder extends RecyclerView.ViewHolder implements
View.OnClickListener {
ArabicTextView vecName;
RelativeLayout img_layout;
ProgressBar progress;
ImageView imgView;
public VechileListHolder(View vi) {
super(vi);
vi.setOnClickListener(this);
img_layout = (RelativeLayout) vi.findViewById(R.id.img_layout);
vecName = (ArabicTextView) vi.findViewById(R.id.TVVecName);
progress = (ProgressBar) vi.findViewById(R.id.progress);
imgView = (ImageView) vi.findViewById(R.id.imgView);
}
public void renderDate(Vechiles item) {
imageLoaderHelper.loadImage(imgView, progress, item.getImg());
vecName.setText(item.getVecName());
}
#Override
public void onClick(View v) {
if (mItemClickListener != null)
mItemClickListener.onItemClickListener(getPosition(), v);
}
}
public void setOnItemClickListener(ItemClickListener itemClick) {
this.mItemClickListener = itemClick;
}
public ItemClickListener mItemClickListener;
public interface ItemClickListener {
public void onItemClickListener(int pos, View v);
}
public void updateList(ArrayList<Vechiles> vechileList) {
this.vechileList = vechileList;
notifyDataSetChanged();
}
public void removeItem(int pos){
this.vechileList.remove(pos);
notifyItemRemoved(pos);
}
}
and in Fragment or activity can
#Override
public void onActivityCreated(#Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
initListView();
}
private void initRecycleView(){
listView = (RecyclerView) v.findViewById(R.id.listView);
listView.getItemAnimator().setAddDuration(1000);
listView.getItemAnimator().setChangeDuration(1000);
listView.getItemAnimator().setMoveDuration(1000);
listView.getItemAnimator().setRemoveDuration(1000);
listView.setLayoutManager(new GridLayoutManager(getActivity(), 3));
listView.setAdapter(new TransportTypeAdapter(getActivity(), vecList));
}
then after data back from API can update adapter with new data by use method update
((VechileListHolder ) listView.getAdapter).updateList( vechileList);
in case went to remove any item by using Pos can do call method that in adapter removeItem(pos)
((VechileListHolder ) listView.getAdapter).removeItem(1);
hope this code help you

GridviewLayoutManager with headers

I am working on an app
I have implemented a working recycler view that receives a jsonarray, passes the data to a string array.
I now want to add section headers to the layout manager.
I have read two schools of thought on this:
- Change the spansize of the view to match the total columns of the grid
- create a custom adapter that loads a different view if the item is a section header.
Im not sure which way to go with this and its starting to confuse me
I have a list of data in an array which includes both headers and grid data (myDataset), i have also created another array with the mapping for the dataset in (myDatamap). In myDatamap i have a list of field types (1 for header and 0 for griddata. I was hoping to pass both arrays to the adaptor and for it decide if its a header or a griditem and then load the appropriate view.
I am leaning more towards loading a different view for the header items, allowing for me to customise the layout of the header easier.
Here is my adaptor code
package com.example.alex.recyclerview2;
import java.util.ArrayList;
import android.content.Context;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;
import com.squareup.picasso.Picasso;
public class MyAdapter extends RecyclerView.Adapter<MyAdapter.ViewHolder> {
private ArrayList<String> mDataset;
private ArrayList<Integer> mDatamap;
private Context context;
// 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
public class ViewHolder extends RecyclerView.ViewHolder {
// each data item is just a string in this case
public TextView txtHeader;
public TextView txtFooter;
public ImageView imgImage;
public ViewHolder(View v) {
super(v);
txtHeader = (TextView) v.findViewById(R.id.firstLine);
txtFooter = (TextView) v.findViewById(R.id.secondLine);
imgImage = (ImageView) v.findViewById(R.id.icon);
}
}
public void add(int position, String item) {
mDataset.add(position, item);
notifyItemInserted(position);
}
public void remove(String item) {
int position = mDataset.indexOf(item);
mDataset.remove(position);
notifyItemRemoved(position);
}
// Provide a suitable constructor (depends on the kind of dataset)
public MyAdapter(ArrayList<String> myDataset, ArrayList<Integer> myDatamap) {mDataset = myDataset;myDatamap=mDatamap; }
// Create new views (invoked by the layout manager)
#Override
public MyAdapter.ViewHolder onCreateViewHolder(ViewGroup parent,
int viewType) {
// create a new view
View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.sub_layout, parent, false);
context = v.getContext();
// 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
final String name = mDataset.get(position);
Picasso.with(context).load("http://www.500kgiveaway.co.uk/" + name).resize(200,200).into(holder.imgImage);
// holder.txtHeader.setText(mDataset.get(position));
holder.txtHeader.setText(name);
holder.txtHeader.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
remove(name);
}
});
holder.txtFooter.setText("Footer: " + mDataset.get(position));
}
// Return the size of your dataset (invoked by the layout manager)
#Override
public int getItemCount() {
return mDataset.size();
}
}
ive not had much interest in this post but here is the answer
i hope this help someone else
What i have done is implemented a custom view adaptor to manage the item types
import android.content.Context;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;
import com.squareup.picasso.Picasso;
import java.util.ArrayList;
public class ElementsAdapter extends RecyclerView.Adapter<ElementsAdapter.ViewHolder> {
private ArrayList<String> mDataset;
private ArrayList<Integer> mDatamap;
public Context context;
private static final int VIEW_HEADER = 0;
private static final int VIEW_NORMAL = 1;
private View headerView;
private int datasetSize;
public class ViewHolder extends RecyclerView.ViewHolder {
// each data item is just a string in this case
public TextView txtHeader;
public TextView txtFooter;
public ImageView imgImage;
//header
public TextView headertext;
public ViewHolder(View v, int viewType) {
super(v);
switch (viewType){
case 1:
txtHeader = (TextView) v.findViewById(R.id.firstLine);
txtFooter = (TextView) v.findViewById(R.id.secondLine);
imgImage = (ImageView) v.findViewById(R.id.icon);
case 0:
headertext = (TextView) v.findViewById(R.id.headertext);
}
}
}
public ElementsAdapter(ArrayList<String> myDataset, ArrayList<Integer> myDatamap) {
mDataset = myDataset;
mDatamap = myDatamap;
}
#Override
public int getItemViewType(int position) {
return isHeader(position) == 1 ? VIEW_HEADER : VIEW_NORMAL;
}
#Override
public int getItemCount() {
return mDataset.size();
}
#Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
if (viewType == VIEW_HEADER) {
// create a new view
View sub_view = LayoutInflater.from(parent.getContext()).inflate(R.layout.header, parent, false);
Context context = sub_view.getContext();
// set the view's size, margins, paddings and layout parameters
ViewHolder vh = new ViewHolder(sub_view,viewType);
return vh;
// return new HeaderViewHolder(headerView);
} else {
// create a new view
View sub_view = LayoutInflater.from(parent.getContext()).inflate(R.layout.sub_layout, parent, false);
context = sub_view.getContext();
// set the view's size, margins, paddings and layout parameters
ViewHolder vh = new ViewHolder(sub_view, viewType);
return vh;
}
}
#Override
public void onBindViewHolder(ViewHolder viewHolder, int position) {
if (isHeader(position) == 1) {
// - get element from your dataset at this position
// - replace the contents of the view with that element
final String name = mDataset.get(position);
// holder.txtHeader.setText(mDataset.get(position));
viewHolder.headertext.setText(name);
} else {
// - get element from your dataset at this position
// - replace the contents of the view with that element
final String name = mDataset.get(position);
Picasso.with(context).load("http://www.500kgiveaway.co.uk/"+name).resize(200,200).into(viewHolder.imgImage);
// holder.txtHeader.setText(mDataset.get(position));
viewHolder.txtHeader.setText(name);
viewHolder.txtHeader.setOnClickListener(new View.OnClickListener()
{
#Override
public void onClick (View v){
//remove(name);
}
}
);
viewHolder.txtFooter.setText("Footer: "+mDataset.get(position));
}
//ViewHolder holder = (ViewHolder) viewHolder;
//holder.textView.setText("Position " + (position - 1));
}
public int isHeader(int position) {
return mDatamap.get(position) ==1 ? 1:0;}
}
Why don't you use both solutions? If you set the span size you can easily set a textview or whatever you want the header to be.
gridLayoutManager.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() {
#Override
public int getSpanSize(int position) {
return adapter.isHeader(position) ? gridLayoutManager.getSpanCount() : 1;
}
});
Then in the adapter have a general class Item that says if the item is a header and has some information about the real item that should be shown, in my case since I have image paths for showing images and titles for headers I just use a attribute text but you can use something like int realPositionInTheirLists since headers titles and images paths are in two separate lists:
private static class Item {
public boolean isHeader;
public String text;
public Item(String text, boolean isHeader) {
this.isHeader = isHeader;
this.text = text;
}
}
Then you have something like this on the methods that tell which type of item it is:
#Override
public int getItemViewType(int position) {
return mItems.get(position).isHeader ? VIEW_TYPE_HEADER : VIEW_TYPE_CONTENT;
}
public boolean isHeader(int position) {
return mItems.get(position).isHeader;
}
Then finally on the two methods that inflate the view and bind the data you inflate the view that you want depending on whether it is a header or not and bind the data using the Item class:
#Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view;
if (viewType == VIEW_TYPE_HEADER) {
view = LayoutInflater.from(parent.getContext())
.inflate(R.layout.grid_header, parent, false);
} else {
view = LayoutInflater.from(parent.getContext())
.inflate(R.layout.grid_item, parent, false);
}
return new ViewHolder(view);
}
#Override
public void onBindViewHolder(ViewHolder holder, int position) {
final Item item = mItems.get(position);
holder.bindItem(item, position);
}
Being the holder.bindItem a method of the ViewHolder class. There you can choose however you want to separate both views.

How do you use an OnClickListener in a recycler view? [duplicate]

This question already has answers here:
RecyclerView onClick
(49 answers)
Closed 7 years ago.
What i'm basically trying to do is make the objects that show up in the recycler view clickable to a certain TextView id because i'm making a program that shows an album cover and its title next to it in a list. I need to be able to click on each one of the boxes that the recycler view makes and have a TextView pop up with the other information (author, published date, hit songs, etc) when its clicked on and then a back button (if possible) to go back to the album list. I've been looking at this for hours and cant figure out how to make an OnclickListener work for it. If you know how or have any suggestions id be glad to hear them. Thank you!
package com.albumlist.albumlist;
import android.content.Context;
import android.content.Intent;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;
public class MyAdapter extends RecyclerView.Adapter<MyAdapter.ViewHolder> {
private AlbumData[] itemsData;
public MyAdapter(AlbumData[] itemsData){
this.itemsData = itemsData;
}
public static class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
private TextView txtViewTitle;
private ImageView imgViewIcon;
public ViewHolder(View itemLayoutView) {
super(itemLayoutView);
itemLayoutView.setOnClickListener(this);
txtViewTitle = (TextView) itemLayoutView.findViewById(R.id.album_title);
imgViewIcon = (ImageView) itemLayoutView.findViewById(R.id.album_icon);
}
#Override
public void onClick(View v) {
}
}
#Override
public MyAdapter.ViewHolder onCreateViewHolder(ViewGroup parent,int viewType) {
View itemLayoutView = LayoutInflater.from(parent.getContext())
.inflate(R.layout.data_layout, null);
ViewHolder viewHolder = new ViewHolder(itemLayoutView);
return viewHolder;
}
#Override
public void onBindViewHolder(ViewHolder viewHolder, int position) {
viewHolder.txtViewTitle.setText(itemsData[position].getTitle());
viewHolder.imgViewIcon.setImageResource(itemsData[position].getImageUrl());
}
#Override
public int getItemCount() {
return itemsData.length;
}
}
The concept is well summed up by Xaver Kapeller in the comments. If you are looking for a simple way to manage your RecyclerView interaction similar to the traditional interactions of a ListView, check out BigNerdRanch's recyclerview-multiselect library on GitHub. They have a sample app that you can explore, which implements series of OnClickListeners and OnLongClickListeners with added capabilities of multi-selection.
Here's a snippet of how BigNerdRanch implements listeners in a Fragment across an Adapter and a ViewHolder, which in this case is actually an extension of the library's own SwappingHolder.
public CrimeHolder(View itemView) {
super(itemView, mMultiSelector);
mTitleTextView = (TextView) itemView.findViewById(R.id.crime_list_item_titleTextView);
mDateTextView = (TextView) itemView.findViewById(R.id.crime_list_item_dateTextView);
mSolvedCheckBox = (CheckBox) itemView.findViewById(R.id.crime_list_item_solvedCheckBox);
itemView.setOnClickListener(this);
itemView.setLongClickable(true);
itemView.setOnLongClickListener(this);
}
public void bindCrime(Crime crime) {
mCrime = crime;
mTitleTextView.setText(crime.getTitle());
mDateTextView.setText(crime.getDate().toString());
mSolvedCheckBox.setChecked(crime.isSolved());
}
#Override
public void onClick(View v) {
if (mCrime == null) {
return;
}
if (!mMultiSelector.tapSelection(this)) {
selectCrime(mCrime);
}
}
#Override
public boolean onLongClick(View v) {
((AppCompatActivity) getActivity()).startSupportActionMode(mDeleteMode);
mMultiSelector.setSelected(this, true);
return true;
}
}
private class CrimeAdapter extends RecyclerView.Adapter<CrimeHolder> {
#Override
public CrimeHolder onCreateViewHolder(ViewGroup parent, int pos) {
View view = LayoutInflater.from(parent.getContext())
.inflate(R.layout.list_item_crime, parent, false);
return new CrimeHolder(view);
}
#Override
public void onBindViewHolder(CrimeHolder holder, int pos) {
Crime crime = mCrimes.get(pos);
holder.bindCrime(crime);
Log.d(TAG, "binding crime" + crime + "at position" + pos);
}
#Override
public int getItemCount() {
return mCrimes.size();
}
}

Categories

Resources