Where should I call Interface in android? - java

I am trying to call the activity method from the adaptor class using interface.And both the activity are independent i.e. class which is calling adapter and the class where the method is defined.
Interface class
public interface AdapterCallback {
int onMethodCallback();
}
Adapter class
public class SimpleAdapter extends RecyclerView.Adapter<SimpleAdapter.ViewHolder> {
String[] goals;
Context context;
private AdapterCallback mAdapterCallback;
public SimpleAdapter(Context context, String[] goals)
{
super();
this.context=context;
this.goals=goals;
}
/* public SimpleAdapter(Context context) {
try {
} catch (ClassCastException e) {
throw new ClassCastException("Activity must implement AdapterCallback.");
}
}*/
#Override
public SimpleAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view= LayoutInflater.from(parent.getContext()).inflate(R.layout.simple_item,parent,false);
return new ViewHolder(view);
}
#Override
public void onBindViewHolder(final SimpleAdapter.ViewHolder holder, int position) {
holder.textView.setText(goals[position]);
holder.textView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
try {
mAdapterCallback = ((AdapterCallback) context);
int result=mAdapterCallback.onMethodCallback();
Toast.makeText(context,Integer.toString(result), Toast.LENGTH_SHORT).show();
} catch (ClassCastException exception) {
// do something
Log.i("In the catch","Yes");
}
}
});
}
#Override
public int getItemCount() {
return goals.length;
}
public class ViewHolder extends RecyclerView.ViewHolder {
Button textView;
public ViewHolder(View itemView) {
super(itemView);
textView=(Button) itemView.findViewById(R.id.text);
}
}
}
Method is defined in the MainActivity.class
#Override
public int onMethodCallback() {
// do something
return 2;
}
Problem:
How should I call the interface function so that indirectly it will call the function defined in the MainActivity class.
I know I need to provide the context of the MainActivity as
mAdapterCallback = ((AdapterCallback) context);
but where should I put this code.
IF i put this code in the constructor then it will not get the MainActivity class context because adapter is calling from another class.
EDIT:
public class MainActivity extends AppCompatActivity implements AdapterCallback {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab);
fab.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Snackbar.make(view, "Replace with your own action", Snackbar.LENGTH_LONG)
.setAction("Action", null).show();
}
});
}
#Override
public int onMethodCallback() {
// do something
return 2;
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.menu_main, menu);
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
//noinspection SimplifiableIfStatement
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}
public int sampleFunction()
{
return 2;
}
}
EDIT 2
Class which is calling the adaptor class
public class OtherClass extends AppCompatActivity {
RecyclerView recyclerView;
SimpleAdapter simpleAdapter;
String[] action_name={"Swimming","Yoga","SWD","IFT","Follow Diet Plan", "Diagnostic Tests","Record Temperature","Record Blood Pressure"," Record Sugar Level","Record Weight"};
#Override
protected void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.xtra);
recyclerView=(RecyclerView) findViewById(R.id.recylerview);
recyclerView.setHasFixedSize(true);
recyclerView.setLayoutManager(new LinearLayoutManager(this));
simpleAdapter=new SimpleAdapter(this, action_name);
recyclerView.setAdapter(simpleAdapter);
}
}

First you have set the interface.Write a method like this in your adapter class
AdapterCallback adapterCallback ;
public void setAdapterCallback(AdapterCallback adapterCallback){
this.adapterCallback = adapterCallback
}
Now impliment and initialize the interface where you actually requires the callback. In your case MainActivity Do like this
MainActivity extends AppCompatActivity implements AdapterCallback
now initialize your interface like this.
SimpleAdapter adpter = new SimpleAdapter()
adpter.setAdapterCallback(this); // very imp step
Now send the callback like this
holder.textView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
if(adapterCallback != null){
adapterCallback.onMethodCallback();
}
}
});
That's all you will get callback on your mainactivity..
Edit
I see you have your adapter set in another activity ..In that case you have to pass your interface object like this
AdapterCallback adapterCallback = this;
Intent intent = new Intent(context, OtherClass.class);
intent.putExtra("interface", adapterCallback);
startActivity(intent);
And retreive it in OtherClass;
Intent intent = getIntent();
AdapterCallback inter = (AdapterCallback) intent.getSerializableExtra("interface");
Also change interface to serializable .
public interface AdapterCallback extends Serializable {
int onMethodCallback();
}
And setInterface like this
simpleAdapter.setAdapterCallback(inter);
If you jsut used a fragment instead of otherclass it would have been a lot easier..
Edit
If both activities are independent then you can write a gettter and setter for your interface in Application class. Set the interface from mainActivity and get the callback in your adater..
write this in your Application class
AdapterCallback adapterCallback;
public AdapterCallback getAdapterCallback() {
return adapterCallback;
}
public void setAdapterCallback(AdapterCallback adapterCallback) {
this.adapterCallback = adapterCallback;
}
Write this in your Main
((YourApplication)getApplication()). setAdapterCallback(this);
And use this method in your click
((YourApplication) getApplication()).getAdapterCallback().onMethodCallback();

If you have implemented interface AdapterCallback in MainActivity then call constructor of SimpleAdapter with including a new paramenter of AdapterCallback Object. Try with these change. It may helps you
String[] goals;
Context context;
private AdapterCallback mAdapterCallback;
public SimpleAdapter(Context context, AdapterCallback adapterCallback, String[] goals){
super();
this.context=context;
this.adapterCallback = adapterCallback;
this.goals=goals;
}
and remove this
mAdapterCallback = ((AdapterCallback) context);

I'm not sure just a work around try,
If u have an Util class create a method or Create a Util class and do
say
private Context mContext;
public void setContext(Context context) {
mContext = context;
}
public Context getContext(){
return mContext;
}
Then
set the context in MainActivity
like
Util.setContext(MainActivity.this);
and in SimpleAdapter class use Util.getContext() and
Context context = Util.getContext();
if(context != null && context instanceof MainActivity){
mAdapterCallback = ((AdapterCallback) context);
int result=mAdapterCallback.onMethodCallback();
}

public class SimpleAdapter extends RecyclerView.Adapter<SimpleAdapter.ViewHolder> {
String[] goals;
Context context;
private AdapterCallback mAdapterCallback;
public SimpleAdapter(Context context, String[] goals)
{
super();
this.context=context;
this.goals=goals;
}
/* public SimpleAdapter(Context context) {
try {
} catch (ClassCastException e) {
throw new ClassCastException("Activity must implement AdapterCallback.");
}
}*/
#Override
public SimpleAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view= LayoutInflater.from(parent.getContext()).inflate(R.layout.simple_item,parent,false);
return new ViewHolder(view);
}
#Override
public void onBindViewHolder(final SimpleAdapter.ViewHolder holder, int position) {
holder.textView.setText(goals[position]);
holder.textView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
try {
mAdapterCallback = ((AdapterCallback) context);
int result=mAdapterCallback.onMethodCallback();
Toast.makeText(context,Integer.toString(result), Toast.LENGTH_SHORT).show();
} catch (ClassCastException exception) {
// do something
Log.i("In the catch","Yes");
}
}
});
}
#Override
public int getItemCount() {
return goals.length;
}
public class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
Button textView;
public ViewHolder(View itemView) {
super(itemView);
textView=(Button) itemView.findViewById(R.id.text);
//for entire cell
itemView.setOnClickListener(this);
//or only for button
textView.setOnClickListener(this);
}
#Override
public void onClick(View view) {
/*
If your want clicked position you can use bellow code
*/
//int clicked_position = getAdapterPosition();
mAdapterCallback.onMethodCallback(clicked_position,goals[clicked_position]);
}
}
}
this is the way we have to use interface in android recyclerview
Edits
change your interface like bellow
public interface AdapterCallback {
void onMethodCallback(int position,String value);
}
and on your OtherClass.class like bellow
public class OtherClass extends AppCompatActivity implements AdapterCallback{
RecyclerView recyclerView;
SimpleAdapter simpleAdapter;
String[] action_name={"Swimming","Yoga","SWD","IFT","Follow Diet Plan", "Diagnostic Tests","Record Temperature","Record Blood Pressure"," Record Sugar Level","Record Weight"};
#Override
protected void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.xtra);
recyclerView=(RecyclerView) findViewById(R.id.recylerview);
recyclerView.setHasFixedSize(true);
recyclerView.setLayoutManager(new LinearLayoutManager(this));
simpleAdapter=new SimpleAdapter(this, action_name);
recyclerView.setAdapter(simpleAdapter);
}
#Override
public void onMethodCallback(int position, String value) {
System.out.println(value+" "+position);
//start activity intent here , now you have position as well as selected value
}
}

Related

Multiple OnClickListeners in Fragment with CustomAdapter

Problem: I am trying to implement three different OnClickListeners via floating action buttons into every item of a recycler view. Each of the three FABs does something different so they need different OnClickListeners. I think I am able to instantiate one with my current adapter setup, but I would like to be able to access all three in the fragment via something like this:
mRecyclerView2.addItemDecoration(itemDecoration2);
mLayoutManager2 = new GridLayoutManager(mContext, 3);
mRecyclerView2.setLayoutManager(mLayoutManager2);
mAdapter2 = new photo_adapter2(mContext, arrayList2);
mRecyclerView2.setAdapter(mAdapter2);
mAdapter2.floatingActionButtonDelete.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
int position = mRecyclerView2.getChildAdapterPosition(v);
photo_item2 item = mAdapter2.getDataSet().get(position);
final String key = item.getMatchId();
}
});
mAdapter2.floatingActionButtonView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
int position = mRecyclerView2.getChildAdapterPosition(v);
photo_item2 item = mAdapter2.getDataSet().get(position);
final String key = item.getMatchId();
}
});
mAdapter2.floatingActionButtonChat.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
int position = mRecyclerView2.getChildAdapterPosition(v);
photo_item2 item = mAdapter2.getDataSet().get(position);
final String key = item.getMatchId();
}
});
I get the following error when I move to the fragment:
java.lang.NullPointerException: Attempt to invoke virtual method 'void com.google.android.material.floatingactionbutton.FloatingActionButton.setOnClickListener(android.view.View$OnClickListener)' on a null object reference
at com.example.firetest.Tabs.MatchProcess.MatchFragment.onCreateView
Adapter:
public class photo_adapter2 extends RecyclerView.Adapter<photo_adapter2.ViewHolder> {
ImageView imageView;
FloatingActionButton floatingActionButtonDelete;
FloatingActionButton floatingActionButtonChat;
FloatingActionButton floatingActionButtonView;
private Uri imageUri;
private ArrayList<photo_item2> mDataSet;
private Context mContext;
private OnItemClickListener mListener;
public ArrayList<photo_item2> getDataSet() {
return mDataSet;
}
public void setDataSet(ArrayList<photo_item2> mDataSet) {
this.mDataSet = mDataSet;
}
public ImageView getImageView() {
return imageView;
}
public void setImageView(ImageView imageView) {
this.imageView = imageView;
}
public Context getContext() {
return mContext;
}
public void setContext(Context mContext) {
this.mContext = mContext;
}
public Uri getImageUri() {
return imageUri;
}
public void setImageUri(Uri imageUri) {
this.imageUri = imageUri;
}
public interface OnItemClickListener {
void onItemClick(int position);
}
public void setOnItemClickListener(OnItemClickListener listener) {
mListener = listener;
}
public photo_adapter2(Context context, ArrayList<photo_item2> DataSet) {
mDataSet = DataSet;
mContext = context;
}
public ArrayList<photo_item2> DataSet() {
return mDataSet;
}
public static class ViewHolder extends RecyclerView.ViewHolder {
public ImageView mImageView;
public FloatingActionButton floatingActionButtonDelete;
public FloatingActionButton floatingActionButtonView;
public FloatingActionButton floatingActionButtonChat;
public RelativeLayout mLinearLayout;
private int adapterPositionOnCLick;
public ViewHolder(View v, final OnItemClickListener listener) {
super(v);
mImageView = (ImageView) v.findViewById(R.id.tv);
floatingActionButtonDelete = (FloatingActionButton) v.findViewById(R.id.floatingActionButtonDelete);
floatingActionButtonChat = (FloatingActionButton) v.findViewById(R.id.floatingActionButtonChat);
floatingActionButtonView = (FloatingActionButton) v.findViewById(R.id.floatingActionButtonView);
floatingActionButtonDelete.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (listener != null) {
adapterPositionOnCLick = getAdapterPosition();
if (adapterPositionOnCLick != RecyclerView.NO_POSITION) ;
listener.onItemClick(adapterPositionOnCLick);
}
}
});
floatingActionButtonChat.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (listener != null) {
adapterPositionOnCLick = getAdapterPosition();
if (adapterPositionOnCLick != RecyclerView.NO_POSITION) ;
listener.onItemClick(adapterPositionOnCLick);
}
}
});
floatingActionButtonView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (listener != null) {
adapterPositionOnCLick = getAdapterPosition();
if (adapterPositionOnCLick != RecyclerView.NO_POSITION) ;
listener.onItemClick(adapterPositionOnCLick);
}
}
});
mLinearLayout = (RelativeLayout) v.findViewById(R.id.ll);
}
public ImageView getImageView() {
return mImageView;
}
public void setImageView(ImageView mImageView) {
this.mImageView = mImageView;
}
}
#Override
public photo_adapter2.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View v = LayoutInflater.from(mContext).inflate(R.layout.photo_custom_view_card, parent, false);
ViewHolder vh = new ViewHolder(v, (OnItemClickListener) mListener);
return vh;
}
#Override
public void onBindViewHolder(final ViewHolder holder, final int position) {
final photo_item2 photo_item = mDataSet.get(position);
}
#Override
public int getItemCount() {
return mDataSet.size();
}
}
How would I go about creating three onClickListeners like this? How should I modify my current fragment and adapter set up to achieve that? Please let me know if there is anything else I should add to my post.
I think, you can create an interface onFabClickListener to dispatch the original onClick event on the FloatingActionButton to your Activity or Fragment. If three FloatingActionButtons are only way to interact with the row of RecyclerView, then I guess you don't even need to handle onItemClick()(or one which handle onclick of row overall).
The interface onFabClickListener.java may look like this :
// is supposed to handle every fab click of every viewholder
public interface OnFabClickListener {
// view to know which fab was click and position to know the position
// of viewholder that was clicked
void onFabClick(View view, int position);
}
Then your Adapter class may look like this :
public class photo_adapter2 extends RecyclerView.Adapter<photo_adapter2.ViewHolder> {
// you all other variable declarations
private ArrayList<photo_item2> mDataSet;
private Context mContext;
private OnFabClickListener mListener;
// your all other required methods definition
public void setOnFabClickListener(OnFabClickListener listener) {
mListener = listener;
}
public ArrayList<photo_item2> getDataSet() {
return mDataSet;
}
public void setDataSet(ArrayList<photo_item2> mDataSet) {
this.mDataSet = mDataSet;
}
public photo_adapter2(Context context) {
mContext = context;
}
#NonNull
#Override
public photo_adapter2.ViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View v = LayoutInflater.from(mContext).inflate(R.layout.photo_custom_view_card, parent, false);
return new ViewHolder(v, mListener);
}
#Override
public void onBindViewHolder(#NonNull final ViewHolder holder, final int position) {
final photo_item2 photo_item = mDataSet.get(position);
// do you stuff here
}
#Override
public int getItemCount() {
return mDataSet.size();
}
public static class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
private OnFabClickListener listener;
public ViewHolder(View v, final OnFabClickListener listener) {
super(v);
// your all other view initialization
//setting our listener object
this.listener = listener;
// your all other views declaration
FloatingActionButton floatingActionButtonDelete = v.findViewById(R.id.floatingActionButtonDelete);
FloatingActionButton floatingActionButtonChat = v.findViewById(R.id.floatingActionButtonChat);
FloatingActionButton floatingActionButtonView = v.findViewById(R.id.floatingActionButtonView);
// setting onclicklisteners on them
// our view holder class is gonna handle all of the onclick
floatingActionButtonDelete.setOnClickListener(this);
floatingActionButtonChat.setOnClickListener(this);
floatingActionButtonView.setOnClickListener(this);
}
#Override
public void onClick(View view) {
// if the view is a floating action button and listener is not equal to null
if (view instanceof FloatingActionButton && listener != null) {
if (getAdapterPosition() != RecyclerView.NO_POSITION) {
// for every on click listened here we will dispatch it to our activity or fragment which
// is required to respond to those events
listener.onFabClick(view, getAdapterPosition());
}
}
}
// your all other methods definition
}
}
Then now a sample MainActivity which implements our custom onFabClickListener will receive the appropriate onclick events handled and dispatched initially by our photo_adapter2 class may look like this:
public class MainActivity extends AppCompatActivity implements OnFabClickListener {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Toolbar toolbar = findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
// declare and initialize the recyclerview
RecyclerView rcView = ......
// declare and initialize the requiredadapter
photo_adapter2 adapter = .....
// set the data using setDataSet() or you can skip this if you
// already passed the dataset in the constructor
adapter.setDataSet(yourDataSet);
// set this class as the onFabClickListener(you forgot this one I guess)
adapter.setOnFabClickListener(this);
// set the adapter to the recyclerview
rcView.setAdapter(adapter);
}
#Override
public void onFabClick(View view, int position) {
int id = view.getId();
switch (id) {
case R.id.floatingActionButtonDelete:
// you can now do your stuff here
break;
case R.id.floatingActionButtonChat:
// for eg get the item associated with the viewholder of whose fab was clicked
photo_item2 item = mAdapter2.getDataSet().get(position);
break;
case R.id.floatingActionButtonView:
break;
}
}
}
Note:
According to Material Design Specifications, it is not recommended to use more than one FloatingActionButton in the single screen(Activity/Fragment). It represents the most important single frequent action that is performed by the user. Instead, I think you should switch to MaterialButton and if you are using Fab just to get this circular look, you need to switch immediately. You can specify the materialButtonStyle attribute in your styles.xml file to get a circular look.
Check your XML file where all three floating action buttons are created, make sure you have them all created, with the respective names that you accessing from the view. The NullPointerException is telling you that one of your floating action button's are pointed to something that doesn't yet exist.

Recycler Adapter callback nullpointer

i have recycler adapter like this
public class ShopUsersAdapter extends RecyclerView.Adapter<ShopUsersAdapter.MyViewHolder> implements View.OnClickListener {
private List<ShopUsersRecyclerModel> user_list;
private Context context;
private AdminCheckLocActivity activity;
private AdapterCallback mAdapterCallback;
public class MyViewHolder extends RecyclerView.ViewHolder {
public TextView user;
public TextView type;
private ImageButton btn_loc;
public MyViewHolder(View view) {
super(view);
user = (TextView) view.findViewById(R.id.txt_text);
type =(TextView)view.findViewById(R.id.txt_count);
btn_loc=(ImageButton)view.findViewById(R.id.btn_loc);
}
}
#Override
public ShopUsersAdapter.MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View itemView = LayoutInflater.from(parent.getContext())
.inflate(R.layout.map_pop_up_item, parent, false);
context=parent.getContext();
itemView.setOnClickListener(this);
return new ShopUsersAdapter.MyViewHolder(itemView);
}
#Override
public void onClick(View v) {
}
public ShopUsersAdapter(List<ShopUsersRecyclerModel> user_list, AdminCheckLocActivity activity) {
this.user_list = user_list;
this.activity=activity;
this.mAdapterCallback = ((AdapterCallback) context);
}
#Override
public void onBindViewHolder(final ShopUsersAdapter.MyViewHolder holder, int position) {
final ShopUsersRecyclerModel user = user_list.get(position);
holder.user.setText(user.getUser_info());
if (user.getUser_type()==3){holder.type.setText("TV Pro.");}
if (user.getUser_type()==4){holder.type.setText("B. Esya Pro.");}
holder.btn_loc.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
mAdapterCallback.onMethodCallback(user.getUser_info());
}
});
}
#Override
public int getItemCount() {
return user_list.size();
}
public interface AdapterCallback {
void onMethodCallback(String userName);
}
}
but i get error
NullPointer at
mAdapterCallback.onMethodCallback(user.getUser_info());
my activity code;
#Override
public void onMethodCallback(final String userName) {
Toast.makeText(this,userName,Toast.LENGTH_LONG).show();
}
and i implement this like ;
implements ShopUsersAdapter.AdapterCallback
userInfo data is not null, i check this. but i need this callback all of my recyclers please help me.
I suggest changing your adapter's constructor to directly receive a callback:
public ShopUsersAdapter(List<ShopUsersRecyclerModel> user_list, AdminCheckLocActivity activity, AdapterCallback callback) {
this.user_list = user_list;
this.activity=activity;
this.mAdapterCallback = callback;
}
You can also make sure your callback isn't null when you're utilizing it:
holder.btn_loc.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
// This should be optional for your case
// but it can be useful if you're ever in a situation
// where the callback isn't always available
if(mAdapterCallback != null){
mAdapterCallback.onMethodCallback(user.getUser_info());
}
}
});
And within your Activity, make sure to pass in the callback as an argument when you create your Adapter instance:
// Use 'this' since your Activity implements the callback
ShopUsersAdapter adapter = new ShopUsersAdapter(myList, myActivity, this);

How pass data from RecyclerView to activity

I need to pass data from recyclerView adapter to main activity on click on image of recyclerview. Can someone help?
public class VideoAdapter extends RecyclerView.Adapter<VideoAdapter.VideoHolder> {
private ArrayList<Video> mData;
private ArrayList<Video> mData2;
private Activity mACtivity;
public VideoAdapter(ArrayList<Video> data, ArrayList<Video> data2, Activity activity) {
this.mData = data;
this.mData2 = data2;
this.mACtivity = activity;
}
#Override
public VideoHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.anteprima_list_item, parent, false);
//view.setOnClickListener(mOnClickListener);
return new VideoHolder(view);
}
#Override
public void onBindViewHolder(VideoHolder holder, int position) {
Video video = mData.get(position);
final Video video2 = mData2.get(position);
holder.setTitolo(video.getTitolo());
holder.setSottoTitolo(video.getSottotitolo());
holder.setData(video.getData());
holder.setData(video.getData());
/* holder.setAddress(restaurant.getAddress());
holder.setCost("Average cost for 2: " + restaurant.getCurrency() + restaurant.getCost());
holder.setRating(restaurant.getRating());*/
Glide.with(mACtivity)
.load(video2.getPic())
.into(holder.restaurantImageView);
holder.restaurantImageView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
// handle click event here
System.out.println("PIC"+video2.getPic());
}
});
}
#Override
public int getItemCount() {
if (mData == null)
return 0;
return mData.size();
}
public class VideoHolder extends RecyclerView.ViewHolder {
ImageView restaurantImageView;
TextView restaurantNameTextView;
TextView restaurantAddressTextView;
TextView restaurantRatingTextView;
TextView costTextView;
TextView distanceTextView;
LinearLayout linearlayout;
public VideoHolder(View itemView) {
super(itemView);
linearlayout=(LinearLayout) itemView.findViewById((R.id.linearlayout));
restaurantImageView = (ImageView) itemView.findViewById(R.id.imageview_restaurant);
restaurantNameTextView = (TextView) itemView.findViewById(R.id.textview_restaurant_name);
restaurantAddressTextView = (TextView) itemView.findViewById(R.id.restaurant_address_textview);
distanceTextView = (TextView) itemView.findViewById(R.id.restaurant_distance_textview);
/* costTextView = (TextView) itemView.findViewById(R.id.cost_for_two_textview);
restaurantRatingTextView = (TextView) itemView.findViewById(R.id.rating);*/
}
public void setTitolo(String titolo) {
restaurantNameTextView.setText(titolo);
}
public void setSottoTitolo(String sottotitolo) {
restaurantAddressTextView.setText(sottotitolo);
}
public void setData(String data) {
distanceTextView.setText(data);
}
/* public void setPic(String pic) {
distanceTextView.setText(pic);
}
public void setCost(String cost) {
costTextView.setText(cost);
}
public void setDistance(String distance) {
distanceTextView.setText(distance);
}*/
}
}
Create a listener Interface and let your MainActivity implement it. That way you can call your callback method in your onClick method.
Interface:
public interface OnImageClickListener {
void onImageClick(String imageData);
}
MainActivity:
public class MainActivity implements OnImageClickListener {
#Override
public void onImageClick(String imageData) {
// handle image data
}
//...
}
Your VideoAdapter:
//...
private OnImageClickListener onImageClickListener;
public VideoAdapter(ArrayList<Video> data, ArrayList<Video> data2, Activity activity, OnImageClickListener onImageClickListener) {
this.mData = data;
this.mData2 = data2;
this.mACtivity = activity;
this.onImageClickListener = onImageClickListener;
}
//...
#Override
public void onBindViewHolder(VideoHolder holder, int position) {
//...
holder.restaurantImageView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
onImageClickListener.onImageClick(video2.getPic());
}
});
//...
}
//...
If you want to pass value from onclick to your Parent activity, use onMethodCallback in your MainActivity:
public class MainActivity extends Activity implements AdapterCallback {
private MyAdapter mMyAdapter;
#Override
public void onMethodCallback(String yourValue) {
// get your value here
}
#Override
protected void onCreate(final Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
this.mMyAdapter = new MyAdapter(this);
}
}
In your Adapter:
public class MyAdapter extends RecyclerView.Adapter<MyAdapter.ViewHolder> {
private AdapterCallback mAdapterCallback;
public MyAdapter(Context context) {
try {
this.mAdapterCallback = ((AdapterCallback) context);
} catch (ClassCastException e) {
throw new ClassCastException("Activity must implement AdapterCallback.");
}
}
#Override
public void onBindViewHolder(final MyAdapter.ViewHolder viewHolder, final int i) {
// simple example, call interface here
// not complete
viewHolder.itemView.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
mAdapterCallback.onMethodCallback();
}
});
}
public static interface AdapterCallback {
void onMethodCallback(String yourValue);
}
}
If you are working with kotlin, the solution is much simpler.
Original Answer here
pass the lamda val itemClick: (Int) -> Unit to your adapter.
class MyRecyclerViewAdapter(params , val itemClick: (Int) -> Unit): RecyclerView.Adapter<RecyclerView.ViewHolder>() {
internal inner class MyViewHolder(view: View) : RecyclerView.ViewHolder(view) {
...
itemView.setOnClickListener( {itemClick(layoutPosition)} )
}
}
In your Activity use the returned value position
val myAdapter = MyRecyclerViewAdapter(params) { position ->
// do something
}
Write interface in your adapter like bellow :
interface clickItemListener {
void onItemClick(String order);
}
And your constructor should be :
privat clickItemListener clickItemListeners;
public VideoAdapter(ArrayList<Video> data, ArrayList<Video> data2, Activity activity, clickItemListener clickItemListeners) {
this.mData = data;
this.mData2 = data2;
this.mACtivity = activity;
this.clickItemListeners = clickItemListeners;
}
Then you can pass to Activity :
yourLayout.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
clickItemListeners.onItemClick(yourValue);
}
});
And implement your interface in your activity like bellow :
public class yourActivity extends AppCompatActivity implements
YourAdapter.clickItemListener{
#Override
public void onItemClick(String order) {
//You can get your value here
}
}
Remember that you should pass activity to adapter like bellow :
YourAdapter adapter = new YourAdapter (... , ... , ... , activity.this);

Why are we using interface to set onClick for View Holders for recycler view in the MainActivity

I am going through a tutorial which is using the Recycler View to display a list of weather for each day for a week.
There are two classes which I am confused in:
ForecastAdapter and MainActivity
Here is the code for the above two classes:
ForecastAdapter.java
public class ForecastAdapter extends RecyclerView.Adapter<ForecastAdapter.ForecastAdapterViewHolder> {
private String[] mWeatherData;
final private ForecastAdapterOnClickListener mClickHandler;
//Why do we need to create an interface here.
public interface ForecastAdapterOnClickListener {
void onClick(String weatherForDay);
}
public ForecastAdapter(ForecastAdapterOnClickListener forecastAdapterOnClickListener) {
mClickHandler = forecastAdapterOnClickListener;
}
public class ForecastAdapterViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener{
public final TextView mWeatherTextView;
public ForecastAdapterViewHolder(View view) {
super(view);
mWeatherTextView = (TextView) view.findViewById(R.id.tv_weather_data);
view.setOnClickListener(this);
}
#Override
public void onClick(View v) {
int adapterPosition = getAdapterPosition();
String weatherForDay = mWeatherData[adapterPosition];
//Why are we calling onClick from mClickHandler here. Why can't we just display Toast here.
mClickHandler.onClick(weatherForDay);
/*Why can't we just display the Toast from here like this:
Toast.makeText(v.getContext(), weatherForDay, Toast.LENGTH_SHORT).show()
*/
}
}
#Override
public ForecastAdapterViewHolder onCreateViewHolder(ViewGroup viewGroup, int viewType) {
Context context = viewGroup.getContext();
int layoutIdForListItem = R.layout.forecast_list_item;
LayoutInflater inflater = LayoutInflater.from(context);
boolean shouldAttachToParentImmediately = false;
View view = inflater.inflate(layoutIdForListItem, viewGroup, shouldAttachToParentImmediately);
return new ForecastAdapterViewHolder(view);
}
#Override
public void onBindViewHolder(ForecastAdapterViewHolder forecastAdapterViewHolder, int position) {
String weatherForThisDay = mWeatherData[position];
forecastAdapterViewHolder.mWeatherTextView.setText(weatherForThisDay);
}
#Override
public int getItemCount() {
if (null == mWeatherData) return 0;
return mWeatherData.length;
}
public void setWeatherData(String[] weatherData) {
mWeatherData = weatherData;
notifyDataSetChanged();
}
}
MainActivity.java
//Why are implementing ForecastAdapterOnClickListener here?
public class MainActivity extends AppCompatActivity implements ForecastAdapter.ForecastAdapterOnClickListener{
private RecyclerView mRecyclerView;
private ForecastAdapter mForecastAdapter;
private TextView mErrorMessageDisplay;
private ProgressBar mLoadingIndicator;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_forecast);
mRecyclerView = (RecyclerView) findViewById(R.id.recyclerview_forecast);
mErrorMessageDisplay = (TextView) findViewById(R.id.tv_error_message_display);
LinearLayoutManager layoutManager
= new LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false);
mRecyclerView.setLayoutManager(layoutManager);
mRecyclerView.setHasFixedSize(true);
mForecastAdapter = new ForecastAdapter(this);
mRecyclerView.setAdapter(mForecastAdapter);
mLoadingIndicator = (ProgressBar) findViewById(R.id.pb_loading_indicator);
loadWeatherData();
}
private void loadWeatherData() {
showWeatherDataView();
String location = SunshinePreferences.getPreferredWeatherLocation(this);
new FetchWeatherTask().execute(location);
}
#Override
public void onClick(String weatherForDay) {
Context context = this;
Toast.makeText(context, weatherForDay, Toast.LENGTH_SHORT)
.show();
}
private void showWeatherDataView() {
mErrorMessageDisplay.setVisibility(View.INVISIBLE);
mRecyclerView.setVisibility(View.VISIBLE);
}
private void showErrorMessage() {
mRecyclerView.setVisibility(View.INVISIBLE);
mErrorMessageDisplay.setVisibility(View.VISIBLE);
}
public class FetchWeatherTask extends AsyncTask<String, Void, String[]> {
#Override
protected void onPreExecute() {
super.onPreExecute();
mLoadingIndicator.setVisibility(View.VISIBLE);
}
#Override
protected String[] doInBackground(String... params) {
if (params.length == 0) {
return null;
}
String location = params[0];
URL weatherRequestUrl = NetworkUtils.buildUrl(location);
try {
String jsonWeatherResponse = NetworkUtils
.getResponseFromHttpUrl(weatherRequestUrl);
String[] simpleJsonWeatherData = OpenWeatherJsonUtils
.getSimpleWeatherStringsFromJson(MainActivity.this, jsonWeatherResponse);
return simpleJsonWeatherData;
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
#Override
protected void onPostExecute(String[] weatherData) {
mLoadingIndicator.setVisibility(View.INVISIBLE);
if (weatherData != null) {
showWeatherDataView();
mForecastAdapter.setWeatherData(weatherData);
} else {
showErrorMessage();
}
}
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.forecast, menu);
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
int id = item.getItemId();
if (id == R.id.action_refresh) {
mForecastAdapter.setWeatherData(null);
loadWeatherData();
return true;
}
return super.onOptionsItemSelected(item);
}
}
The adapter, view holder and recycler view is working as expected. We are now supposed to implement Click Handling on the rows of the recycler view. Whenever a particular row is clicked, we are supposed to display a toast.
As you can see, we are implementing OnClickListener in the ForecastAdapterViewHolder and in the onClick function we are calling the onClick of the interface "ForecastAdapterOnClickListener".
In the MainActivity.java, we are implementing this "ForecastAdapterOnClickListener" and then displaying the toast.
Why can't we just display the toast in the onClick that is defined for the "ForecastAdapterViewHolder" class. I have tried it and it works. What is the point of doing what is being done in the code?
Is there some advantage in setting the click listener like that?
Because you'll have to display information afterwards and isn't role of ViewHolder neither Adapter. Activity/fragment must do that.
It's to keep your code organized.

How to create interface between Fragment and adapter?

I have fragment with ListView, say MyListFragment, and custom CursorAdapter.
I'm setting onClickListener in this adapter for the button in the list row.
public class MyListAdapter extends CursorAdapter {
public interface AdapterInterface {
public void buttonPressed();
}
...
#Override
public void bindView(final View view, final Context context, final Cursor cursor) {
ViewHolder holder = (ViewHolder) view.getTag();
...
holder.button.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
// some action
// need to notify MyListFragment
}
});
}
}
public MyListFragment extends Fragment implements AdapterInterface {
#Override
public void buttonPressed() {
// some action
}
}
I need to notify fragment when the button is pressed. How to invoke this interface?
Help, please.
Make a new constructor and an instance variable:
AdapterInterface buttonListener;
public MyListAdapter (Context context, Cursor c, int flags, AdapterInterface buttonListener)
{
super(context,c,flags);
this.buttonListener = buttonListener;
}
When the Adapter is made, the instance variable will be given the proper reference to hold.
To call the Fragment from the click:
public void onClick(View v) {
buttonListener.buttonPressed();
}
When making the Adapter, you will have to also pass your Fragment off to the Adapter. For example
MyListAdapter adapter = new MyListAdapter (getActivity(), myCursor, myFlags, this);
since this will refer to your Fragment, which is now an AdapterInterface.
Keep in mind that on orientation of the Fragment changes, it will most likely be recreated. If your Adapter isn't recreated, it can potentially keep a reference to a nonexistent object, causing errors.
Using Eventbus:
Examples:
https://github.com/kaushikgopal/RxJava-Android-Samples/tree/master/app/src/main/java/com/morihacky/android/rxjava/rxbus
or
https://github.com/greenrobot/EventBus
Using Interfaces:
I understand the current answer but needed a more clear example. Here is an example of what I used with an Adapter(RecyclerView.Adapter) and a Fragment.
Create Callback Interface:
public interface AdapterCallback {
void onMethodCallback();
}
Passing in Callback/Fragment:
This will implement the interface that we have in our Adapter. In this example, it will be called when the user clicks on an item in the RecyclerView.
In your Fragment:
public class MyFragment extends Fragment implements AdapterCallback {
private MyAdapter mMyAdapter;
#Override
public void onMethodCallback() {
// do something
}
#Override
public void onCreate(final Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
this.mMyAdapter = new MyAdapter(this); // this class implements callback
}
}
Use the Callback in your Adapter:
In the Fragment, we initiated our Adapter and passed this as an argument to the constructer. This will initiate our interface for our callback method. You can see that we use our callback method for user clicks.
public class MyAdapter extends RecyclerView.Adapter<MyAdapter.ViewHolder> {
private AdapterCallback mAdapterCallback;
public MyAdapter(AdapterCallback callback) {
this.mAdapterCallback = callback;
}
#Override
public void onBindViewHolder(final MyAdapter.ViewHolder viewHolder, final int i) {
// simple example, call interface here
// not complete
viewHolder.itemView.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
mAdapterCallback.onMethodCallback();
}
});
}
}
or Use the Fragment in your Adapter:
public class MyAdapter extends RecyclerView.Adapter<MyAdapter.ViewHolder> {
private AdapterCallback mAdapterCallback;
public MyAdapter(Fragment fragment) {
try {
this.mAdapterCallback = ((AdapterCallback) fragment);
} catch (ClassCastException e) {
throw new ClassCastException("Fragment must implement AdapterCallback.");
}
}
#Override
public void onBindViewHolder(final MyAdapter.ViewHolder viewHolder, final int i) {
// simple example, call interface here
// not complete
viewHolder.itemView.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
try {
mAdapterCallback.onMethodCallback();
} catch (ClassCastException exception) {
// do something
}
}
});
}
}
Follow the 2 steps below for receive callback from Adapter in Fragment (or Activity)
First: In your Adapter
public class ListAdapter extends RecyclerView.Adapter < RecyclerListAdapter.ItemViewHolder > {
...
private ListAdapterListener mListener;
public interface ListAdapterListener { // create an interface
void onClickAtOKButton(int position); // create callback function
}
public RecyclerListAdapter(Context mContext, ArrayList < Items > listItems, ListAdapterListener mListener) { // add the interface to your adapter constructor
...
this.mListener = mListener; // receive mListener from Fragment (or Activity)
}
...
public void onBindViewHolder(final ItemViewHolder holder, final int position) {
holder.btnOK.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
// use callback function in the place you want
mListener.onClickAtOKButton(position);
}
});
...
}
...
}
Second: In your Fragment (or Activity), there are 2 ways for implement callback method
Way 1
public MyListFragment extends Fragment {
...
public void onViewCreated(View view, #Nullable Bundle savedInstanceState) {
...
ListAdapter adapter = new ListAdapter(getActivity(), listItems, new ListAdapter.ListAdapterListener() {
#Override
public void onClickAtOKButton(int position) {
Toast.makeText(getActivity(), "click ok button at" + position, Toast.LENGTH_SHORT).show();
}
});
...
}
}
Way 2
public MyListFragment extends Fragment implements ListAdapter.ListAdapterListener {
...
public void onViewCreated(View view, #Nullable Bundle savedInstanceState) {
ListAdapter adapter = new ListAdapter (getActivity(), listItems, this);
...
}
#Override
public void onClickAtOKButton(int position) {
Toast.makeText(getActivity(), "click ok button at" + position, Toast.LENGTH_SHORT).show();
}
}
This is very similar to the way an activity and a fragment should communicate. In the constructor of your adapter, pass a reference of your fragment, cast it to your interface and just call yourReference.buttonPressed() on your onClick method.
a solution for NPE is first to make conctractor in your Fragment like that
public MyFragment MyFragment(){
return this;
}
then initialize your listener is adapter like that
Lisener lisener = new MyFragment();
Make a constructor like that:
public MyAdapter(Activity activity,AlertMessageBoxOk alertMessageBoxOk) {
this.mActivity = activity;
mAlertMessageBoxOk = alertMessageBoxOk;
}
call the interface from adapter use any event
mAlertMessageBoxOk.onOkClick(5);
after that implement AlertMessageBoxOk interface to your fragment like this,
class MyFragment extends Fragment implements AlertMessageBoxOk {
#Override
public void onOkClick(int resultCode) {
if(resultCode==5){
enter code here
}
}
}

Categories