Best way to respond to Button within listview within fragment - android

I have a Button in a ListViewItem in a ListView within a Fragment. I have code that successfully notifies the host Activity of the button being tapped. While the code works, I want to make sure that this is the best design pattern to use here.
Here is a summary of the code:
The Activity (MainActivity) passes a reference of itself (this) to the Fragment in a variable called mainActivityReference.
The Fragment passes this reference to the ArrayAdapter object in a variable also called mainActivityReference.
In the ArrayAdapter getView method, I set the onClickListener and call a method within the mainActivityReference with the index position of the item as a parameter as follows:
viewHolder.soundButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Log.d(TAG, "Sound button tapped at position " + position);
mainActivityReference.chooseSoundForIndex(position);
}
});
Does this seem kosher? Or should I use something like a LocalBroadcastManager?

The basic strategy of passing an "owner" object to an adapter is quite kosher, and very common. Often I will make a listener interface, and have the parent activity or fragment implement the interface. Since it is your activity that is responding to the click, you wouldn't even need to pass the reference to the fragment and then the adapter. You could just get the View's context, and check if it implements the interface. Like this:
public interface SoundChooser {
void chooseSoundForIndex(int position);
}
viewHolder.soundButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Log.d(TAG, "Sound button tapped at position " + position);
Context context = v.getContext();
if (context instanceof SoundChooser) {
((SoundChooser)context).chooseSoundForIndex(position);
} else {
Log.w(TAG, "Activity should implement SoundChooser:" + context.getClass().getName());
}
}
});

Related

Update TextView in Fragment when RecyclerView's data changes

In my Fragment, I have 2 views. A Textview and a RecyclerView. The Textview essentially displays the current size of the RecyclerView. So, when a row is removed in the adapter class, I need to update the TextView's value accordingly.
The row is removed successfully when removeBtn is clicked, but I need to update the TextView in the Fragment accordingly.
FRAGMENT
titleText.text = "SIZE (" + arrayStringList().size.toString() + ")"
//...
//...
//Set RecyclerView Adapter
mRecyclerView.layoutManager = androidx.recyclerview.widget.LinearLayoutManager(context)
val adapter = MRecyclerView(context!!, arrayStringList)
mRecyclerView.adapter = adapter
RECYCLERVIEW
holder.removeBtn{
mData.removeAt(position)
notifyItemRemoved(position)
}
Is there some sort of listener that I can put in my fragment to detect when the data changes? Or is there a way to send data from the recyclerview back to the fragment when removeBtn is clicked?
Create a interface in recyclerView class , and implement that interface in fragment . Once you click the remove button , call this interface . In Fragment class , update the text view with adapter.getItemCount.
In Adapter
interface ItemCallback{
void updateTextView();
}
This interface will be implemented in fragment class ,where you can update your textView with itemCount .
public class Fragment implements Adapter.ItemCallback{
#Override
public void updateTextView() {
tvTextView.setText(adapter.getItemCount()); // This will return the current item count of adapter
}
}
You can do this via call back. Make an interface and implement that on Fragment. And pass the reference of the interface to the adapter. When you trigger the event to delete item from recycler view call the interface method (That you implemented on Activity). And in that call back method, you need to set the value to your text view. To set value on TextView, you can call size() method and set the value whatever is returned from it. For example the List you are passing to the adapter is mData. When you get call back the call size method on the reference and set the value as mentioned below code.
titleText.setText(String.valueOf(mData.size())).
Hope this will help you.
NOTE: You need to call String.valueOf method because size method returns integer value so it needs to be cast.
"Or is there a way to send data from the recyclerview back to the fragment when removeBtn is clicked?" the answer is yes
One approach is to pass your adapter your own click listener (an interface), this way you can control the click from the fragment something like this,
A1) create an interface
public interface ItemTouchListener {
void onCardClick(View view, int position);
boolean onCardLongClick(View view, int position);
}
A2) implement this interface in your fragment
public class YourFragment extends Fragment implements ItemTouchListener
A3) implement the methods you created in your fragment
#Override
public void onCardClick(View view, int position) {
if (view.getId() == R.id.removeBtn){
//update your text
}else{
//other buttons
}
}
#Override
public boolean onCardLongClick(View view, int position) {
if (view.getId() == R.id.removeBtn){
//update your text
} else {
//other buttons
}
return true;
}
A4) create this interface in your adapter and set it to your button
private ItemTouchListener onItemTouchListener;
public YourAdapter(List<Object> list, ItemTouchListener onItemTouchListener) {
this.onItemTouchListener = onItemTouchListener;
this.list = list;
}
removeBtn = view.findViewById(R.id.removeBtn);
removeBtn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
onItemTouchListener.onCardClick(v, getAdapterPosition());
}
});
removeBtn.setOnLongClickListener(new View.OnLongClickListener() {
#Override
public boolean onLongClick(View view) {
onItemTouchListener.onCardLongClick(view, getAdapterPosition());
return true;
}
});
A5) and now when you create your adapter it will ask for the ItemTouchListener which you can give it by just passing 'this'
YourAdapter adapter = new YourAdapter(this);
A6) you may also want to give your adapter a method something like getCount which return the list size
public int getCount(){
list.size();
}
and then you can call this like myAdapter.getCount

How to Get a callback for activity started from inside arrayadapter for listview in Android?

How to start an activity from inside ArrayAdapter and get a call back when the activity is finished(just like onActivityResult)?
Following code is on post execute of an asynctask that is started on the button click of a button displayed in each listview row.
((Activity) mContext).startActivityForResult(intent, AppConstants.DUMMY_CONSTANT);
If it's possible, try using this instead:
listView.setOnItemClickListener(new OnItemClickListener() { ... });
Edit. You can also create interface, implement it in your acitvity and pass it to your adapter
My Pscudoe code:-- Create call back method using interface
and make call back wherever you want
MyListener listener;
public interface MyListener {
// TODO: Update argument type and name
void onClick(View view, int position);
}
#Override
public void onClick(View view) {
listener.onCardClick(view, getPosition());
}
From Listview onitem:---

Send an event from Listview (which is in a Fragment) to an existing activity via the Fragment

I have a ListView which is in a Fragment. Each row display a set of 4 buttons.
Each button has an OnClickListener defined in the Adapter Class. Everything is working well and i can diplay the ID of the clicked button.
My problem is how the send this ID to the activity (who hold the Fragment where the ListView is defined) via this Fragment. I'm stuck since 1 week till now !!!
Please remember that this activity is already existing and she is the one who already launched the fragment.
Write one method in the Activity class,
public void setButtonClick(int buttonId){
// do your task
}
and from your adapter class
((YourActivity)fragment.getActivity()).setButtonClick(id);
But you need to pass fragment instance to the adapter using its constructor.
New Edits as per your code posted here,
class ArticleSetAdapter{
// Variables
private ArticleFragment context;
// Constructor
public ArticleSetAdapter(ArticleFragment context, ArrayList<ArrayList<Article>> articleSetArray) {
super(context.getActivity(), 0, articleSetArray);
this.context = context;
}
and in your adapter onClick,
// the OnClickListener handler method
private View.OnClickListener mOnClickListener = new View.OnClickListener() {
#Override
public void onClick(View v) {
Integer artID = (Integer) ((Button) v).getTag();
((youractivity.class)context.getActivity())..setButtonClick(artID)
makeText(getContext(), "CLICK: " + artID, Toast.LENGTH_SHORT).show();
}
};
Hope this will help you.

Android create interface listener for onClick in Adapter

in my application i'm create simple interface to detect after click on adapter items into parent activity.after create interface and method into adapter i can not how to use this interface to call listener, for example:
Interface Class:
public interface IOnClickListListener {
public void onClick(boolean click);
}
summurized Adapter:
private static class ViewHolder {
public ViewHolder(View view) {
}
public void fill(final ArrayAdapter<SubjectListStructure> adapter, final SubjectListStructure item, final int position) {
root.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
/* call interface to listen that */
}
});
}
}
public void setOnClickListener(IOnClickOnNiyazmandihaListListener l){
iOnClickOnNiyazmandihaListListener = l;
}
in this adapter after click on item, my interface must be call. now i want to listen that into activity by this code:
subjects_adapter.setOnClickListener(new IOnClickOnNiyazmandihaListListener() {
#Override
public void onClick(boolean click) {
Toast.makeText(G.currentActivity,"ddddd", Toast.LENGTH_SHORT).show();
}
});
now how to call listener into adapter ?
if you want to trigger/invoke the callback, simply call
boolean click = true
iOnClickOnNiyazmandihaListListener.onLogin(click)
from the adapter class
In my honest opinion, if you intend to register the click event inside an adapter, you must pass the position of item which was clicked, instead of passing a boolean value to check if item was clicked or not. In this way, you will get a number of options to handle the clicked item callback.
Here is a simple implementation from my side according to your use-case.
Your interface class just require a small change as follows:
public interface IOnClickListListener {
public void onClick(int positionOfItem);
}
Inside your adapter class, at the onClick() of your root's setOnClickListener, you must call the interface's method in the following way, considering iOnClickOnNiyazmandihaListListener is a member variable of your adapter class
iOnClickOnNiyazmandihaListListener.onClick(position)
where position is passed as a parameter to setOnClickListener and it is the actual position of item clicked.
In this way, wherever you want this onClick() method to be called, you have to provide implementation of the interface in that class, about what you want to do with the clicked position when onClick() is triggered.
So whenever any list item is clicked, your custom implementation of the onClick() method will be used, and the code which you put inside that implemented method will be called.
Example:
Suppose you implemented this interface in an activity, then it tell you to override the onClick() method of your interface inside that activity, i.e. to provide onClick() implementation
So implementation of onClick() would look similar as follows:
#Override
void onClick(int position){
// do what you want to do with clicked item's position
Toast.makeText(this, "Item at position:" + position + " clicked", Toast.LENGTH_LONG).show();
}
For that, your class must have implements IOnClickOnNiyazmandihaListListener as its starting line.

animate activity start in Android

I need to animate my Activity when it starts up. The Activity is started from a BaseAdapter class. I tried using overridePendingTransition() but I can't seem to use that in the on click event. How can I over come this?
holder.userpic.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
Log.d(" ", " value " + obj.get(position).get_post_id());
Intent appInfo = new Intent("android.intent.action.Profile");
appInfo.putExtra("pk", obj.get(position).get_foodie_id());
context.startActivity(appInfo);
overridePendingTransition(R.anim.full_side_up,0); // cant use this
}
});
You need to attach the Context as:
context.overridePendingTransition(R.anim.full_side_up,0);
Or you can use the transition in onResume method inside the new Activity:
#Override
public void onResume() {
super.onResume();
overridePendingTransition(R.anim.full_side_up,0);
}
Let me know if this works.
overridePendingTransition is a method of the Activity class. You would have to hold a reference to an activity.
An alternative would be specifying your listener in XML using onClick attribute as follows:
<ImageView
id="#+id/user_pic"
...
onClick="onClickUserPic" />
Then you create method onClickUserPic(View) inside your activity (which contains the ListView filled by your adapter class):
public void onClickUserPic(View view) {
int position = (Integer)view.getTag(); // here is stored position in list
Log.d(" ", " value " + obj.get(position).get_post_id());
Intent appInfo = new Intent("android.intent.action.Profile");
appInfo.putExtra("pk", obj.get(position).get_foodie_id());
context.startActivity(appInfo);
overridePendingTransition(R.anim.full_side_up,0);
}
Note that this method has to be inside this and any other activity which contains the clickable image view. If it weren't, you would get a NoSuchMethodException on click.
Finally add this line to your adapter:
holder.userpic.setTag(Integer.valueOf(position)); // save position for reference
Also make sure that you have access to obj from inside the activity.

Categories

Resources