Customizing onClickItem listner - ListActivity - android

I am creating a contact list view, diplaying user name,user email and user id. Now while clicking on particular item i want to post some event to server based on the user id. How to get the user id inside the onClickItem listener, as user id is long value. i am able to get the user name that means the text but not the user id.

listView has onCLicklistener that has parameter position.If you are using arrayList to inflate ListView then you can use this positon to get corresponding object.

You can try to set the user id to tag using View.setTag and View.getTag. There are two version available choose the one you need. This way you can attach the user id as tag and then get it back.
http://developer.android.com/reference/android/view/View.html#setTag(int, java.lang.Object)
You code should look like:
view.setTag(Long.valueOf(id));
.....
onClickListener(..) {
Long id = (Long)view.getTag();
}

You should make your own bean class which contains your userid and put it in List (or ArrayList)
then create an adapter by creating a class extending ArrayAdapter (for instance) to bind your list of this bean class
register a listener either using onItemClickListener or View listener in your row if you inflate your custom layout.
get the position and use it to retrieve your userid on your bean list.
Here's my snippet
public class ListActivity extends Activity implements OnItemClickListener {
private Context context;
private RowAdapter adapter;
private ArrayList<Row> rowList = new ArrayList<Row>();
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
context = ListActivity.this;
initRows();
adapter = new RowAdapter(context, rowList);
ListView listView = (ListView) findViewById(R.id.listView);
listView.setAdapter(adapter);
listView.setOnItemClickListener(this);
}
private void initRows() {
Row row = new Row(1);
rowList.add(row);
row = new Row(2);
rowList.add(row);
}
public class Row {
long userid = 0;
public Row(long userid) {
this.userid = userid;
}
public long getUserid() {
return userid;
}
public void setUserid(long userid) {
this.userid = userid;
}
}
public class RowAdapter extends ArrayAdapter<Row> {
private Context context;
public RowAdapter(Context context, ArrayList<Row> bindList) {
super(context, R.layout.row_layout, bindList);
this.context = context;
}
#Override
public View getView(final int position, View convertView, ViewGroup parent) {
View view = convertView;
if(view == null) {
LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
view = inflater.inflate(R.layout.row_layout, null);
}
//if you use some additional View you can retrieve your position using this
Button button = view.findViewById(R.id.button);
button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
updateSelected(position);
}
});
return view;
}
}
//or if you rather just listen on row click then you can retrieve your position using this
#Override
public void onItemClick(AdapterView<?> arg0, View view, int position, long arg3) {
updateSelected(position);
}
private void updateSelected(int position) {
rowList.get(position).getUserid();
//have it your way
}
}

Related

How to pass data from custom Android ListView ArrayAdapter (when it has multiple onClickEventListeners) back to its fragment/activity

I need to PASS THE DATA (videoId) from inside this custom ArrayAdapter back to the fragment that holds it when the user clicks on the favorite button.
I also need to PASS THE DATA of the song's position back to the fragment if the user clicks the layout of the song. (Both onclicks defined below.)
Previously, the position of the song was passed to the containing fragment SelectSongFragment via this method:
mListView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> adapterView, View view, int i, long l) {
//pass data to main activity
//TODO THIS NO LONGER RUNS
String songUrl = urlCleaner.parseIntoUrl(mSongs.getSong(i).getVideoId(), false);
passData(songUrl);
}
});
After I added the onclick Listeners to the arrayAdapter, mListView.setOnItemClickListener stopped working, and now I have no way to pass any data back! Check my custom ArrayAdapter below, and look for "HELP NEEDED HERE" Thanks very much!
public class SelectSongArrayAdapter extends ArrayAdapter<Song> implements AppInfo {
private ArrayList<Song> songs;
private ArrayList<String> mFavoriteSongs;
private boolean isFavorite = false;
private Song song;
/**
* Override the constructor for ArrayAdapter
* The only variable we care about now ArrayList<PlatformVersion> objects
* it is the list of the objects we want to display
*
* #param context
* #param resource
* #param objects
*/
public SelectSongArrayAdapter(Context context, int resource, ArrayList<Song> objects, ArrayList<String> favoriteSongVideoIds) {
super(context, resource, objects);
this.songs = objects;
this.mFavoriteSongs = favoriteSongVideoIds;
}
/**
* Primary functionality to create a list in the view of songs and song detail lines.
*
* #param position
* #param convertView
* #param parent
* #return
*/
public View getView(int position, View convertView, ViewGroup parent) {
// assign the view we are converting to a local variable
View view = convertView;
/*
Check to see if view null. If so, we have to inflate the view
"inflate" basically mean to render or show the view
*/
if (view == null) {
LayoutInflater inflater = (LayoutInflater) getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
view = inflater.inflate(R.layout.detail_line_song, null);
}
song = songs.get(position);
// obtain a reference to the widgets in the defined layout "wire up the widgets from detail_line"
TextView songTitle = (TextView) view.findViewById(R.id.songTitle);
TextView songDescription = (TextView) view.findViewById(R.id.songDescription);
View viewSongLayout = view.findViewById(R.id.songLayout); //For when user clicks left side of view
final ImageButton favoriteStarButton = (ImageButton) view.findViewById(R.id.favorite);
//Find out if song is favorite or not:
isFavorite = false;
for (String songId : mFavoriteSongs) {
if (song.getVideoId().equals(songId)) {
//Is not a favorite song. Do nothing
} else {
//Is a favorite song
isFavorite = true;
break;
}
}
//TODO Testing with multiple favorite songs.
songTitle.setText(song.getDisplayName());
songDescription.setText(song.getDescription());
favoriteStarButton.setPressed(isFavorite); //Changes star color
//Add Listeners
favoriteStarButton.setOnClickListener(new View.OnClickListener() { //Star button click
#Override
public void onClick(View v) {
isFavorite = !isFavorite;
if (isFavorite) {
//Add to favoriteVideoIds
/************************************************
HELP NEEDED HERE:
NEED TO PASS DATA (song.getVideoId()) BACK TO THE FRAGMENT SOMEHOW TO
REMOVE SONG FROM FAVORITES LIST OF SONGS STORED IN THE ACTIVITY
NOT HERE IN THE ARRAYADAPTER)
********************************************************************/
} else {
//remove from favoriteVideoIds
/************************************************
HELP NEEDED HERE:
NEED TO PASS DATA (song.getVideoId()) BACK TO THE FRAGMENT SOMEHOW TO
ADD SONG TO FAVORITES LIST OF SONGS STORED IN THE ACTIVITY
NOT HERE IN THE ARRAYADAPTER)
********************************************************************/
}
v.setPressed(isFavorite); //Changes star color
//redraw view
v.invalidate();
}
});
//Listener for when song is clicked (left side of listview)
viewSongLayout.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
/******************************************************************
SAME PROBLEM HERE. NEED TO PASS DATA (POSITION) OF THE SONG THAT WAS CLICKED BACK TO THE FRAGMENT.
********************************/
return view;
}
}
You can create an interface for your click events :
interface ClickEvents {
void onFavoriteStarButtonClick(boolean isFavorite, int position);
void onViewSongLayoutClick(int position);
}
Specify an instance of ClickEvents as an argument inside your ArrayAdapter constructor :
private ClickEvents clickEvents;
public SelectSongArrayAdapter(Context context, int resource, ArrayList<Song> objects, ArrayList<String> favoriteSongVideoIds, ClickEvents clickEvents) {
super(context, resource, objects);
this.songs = objects;
this.mFavoriteSongs = favoriteSongVideoIds;
this.clickEvents = clickEvents;
}
Call the appropriate methods of ClickEvents inside your onClick methods :
favoriteStarButton.setOnClickListener(new View.OnClickListener() { //Star button click
#Override
public void onClick(View v) {
isFavorite = !isFavorite;
clickEvents.onFavoriteStarButtonClick(isFavorite, position);
}
});
viewSongLayout.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
clickEvents.onViewSongLayoutClick(position);
}
}
Finally pass an implementation of ClickEvents to your adapter as a parameter :
final ClickEvents clickEvents = new ClickEvents() {
#Override
public void onFavoriteStarButtonClick(boolean isFavorite, int position) {
// FavoriteStarButton clicked
}
#Override
public void onViewSongLayoutClick(int position) {
// ViewSongLayout clicked
}
};
final SelectSongArrayAdapter selectSongArrayAdapter = new SelectSongArrayAdapter(getContext(), resource, objects, favoriteSongVideoIds, clickEvents);

Delete Custom Row In ListView

I have two classes that I'm working with. Contacts and CustomAdapter. In my Contacts Class I have an onActivityResult() method, which gets data from a different activity and places it in a Custom ListView using my CustomAdapter Class. The data gets added fine. Each row consists of a name, email, phone number AND a Button Widget. My question is, I would like to be able to press this Button and have that specific row be deleted. I've tried a number of different things but nothing seems to be working.
I placed the code below. If anyone has any suggestions on the best way to do this, I would greatly appreciate it. Thank you.
onActivityResult in Contacts Class:
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if(requestCode == REQUEST_CODE){
if(resultCode == RESULT_OK){
String name = data.getStringExtra("name");
String phone = data.getStringExtra("phone");
final String email = data.getStringExtra("email");
//These are array lists declared earlier
phoneNums.add(phone);
names.add(name);
emails.add(email);
customAdapter = new CustomAdapter(Contacts.this,names,phoneNums,emails);
contactList.setAdapter(customAdapter);
contactList.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
names.remove(position);
phoneNums.remove(position);
phoneNums.remove(position);
//This method is still not being recognized
contactList.getAdapter().notifyDataSetChanged()
//This one is but the app is crashing when I click on any of the rows
contactList.getAdapter().notify()
}
});
}
}
}
Custom Adapter Entire Class:
public class CustomAdapter extends BaseAdapter implements View.OnClickListener {
private Context context;
private ArrayList<String>phoneNumbers;
private ArrayList<String>names;
private ArrayList<String>emails;
private static LayoutInflater inflater = null;
public CustomAdapter(Context c,ArrayList<String>n,ArrayList<String>nums,ArrayList<String>e){
context = c;
phoneNumbers = nums;
names = n;
emails = e;
inflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
}
#Override
public int getCount() {
return names.size();
}
#Override
public Object getItem(int position) {
return position;
}
#Override
public long getItemId(int position) {
return (long)position;
}
#Override
public View getView(final int position, final View convertView, ViewGroup parent) {
View view = convertView;
if (view == null){
view = inflater.inflate(R.layout.contacts_custom_row,null);
Button deleteBtn = (Button)view.findViewById(R.id.customRowDeleteButton);
TextView name = (TextView)view.findViewById(R.id.customRowContactName);
TextView phone = (TextView)view.findViewById(R.id.customRowContactNumber);
TextView email = (TextView)view.findViewById(R.id.customRowContactEmail);
name.setText(names.get(position));
phone.setText(phoneNumbers.get(position));
email.setText(emails.get(position));
deleteBtn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
//SHOULD I PLACE CODE TO DELETE THE ROW IN HERE?
}
});
}
return view;
}
Basically what you need is one List<>to rule the size of you List (i believe yours is the names. For that, your getItem(int position) has to return names.size(). To delete a specific row, you just need to delete the index of names that you want, and call notifyDataSetChanged() in your adapter after that.

How to handle an event that is trigged by a button from inside of a listadapter item?

Suppose we have a list with several items. Each item has several fragments and a label within. When a user clicks on each label I need to change the text of the button1 that is out of the list view. How can I receive that label click event from inside of the list item and change a view that is out of the list view and list adapter.
I know how to handle internal events of the list view adapter inside the adapter. It's as simple as assigning the event handlers in GetView() method but they are not available out of the list.
Thanks for any help
Solved
I created a custom event and EventAgrs. When user clicks the label I invoke this event and in the main activity I handle the event and change the text of buton1. It was easier than I thought. In GetView() I assign the click event to the label_Click() event handler.
GetView(){
.
.
label.Click += label_Click();
.
.
}
In label_Click() I invoke the custom event that I have implemented before:
private void label_Click()(object sender, EventArgs e)
{
LabelClickedEvent.Invoke(sender, new LabelClickEventArgs("aaa", "bbb"));
}
In the list Adapter I declared this custom event: (For more information please look at this guide)
public event LabelClickedEventHandler LabelClickedEvent;
public delegate void LabelClickedEventHandler(object, sender,LabelClickEventArgs args);
public class LabelClickEventArgs : EventArgs
{
public string param1 { get; set; }
public string param2 { get; set; }
public LabelClickEventArgs(string param1 , string param2 )
{
this.param1 = param1 ;
this.param2 = param2 ;
}
}
In the main activity I simply assigned the event to my event handler and did whatever is needed.
listAdapter.LabelClickedEvent += listAdapter_LabelClickedEvent;
.
.
void listAdapter_LabelClickedEvent(object sender, TheListAdapter.LabelClickEventArgs args)
{
sendButton.Text = args.param1;
}
Hope it helps someone.
I do not know the proper way, but one way to do would be to implement the label item's OnClickListener() in the adapter, pass the reference of Button 1 to your adapter while creating an adapter, and then manipulate button 1 from OnClickListener().
public class MyAdapter extends BaseAdapter {
private Activity activity;
private ArrayList data;
private Button button1;
/************* CustomAdapter Constructor *****************/
public MyAdapter(Activity activity, ArrayList data, Button button1) {
this.data = data;
this.button1 = button1;
this.activity = activity;
inflater = (LayoutInflater) this.activity.
getSystemService(Context.LAYOUT_INFLATER_SERVICE);
}
public int getCount() {
if (data.size()<=0)
return 1;
return data.size();
}
public Object getItem(int position) {
return position;
}
public long getItemId(int position) {
return position;
}
public static class ViewHolder{
public TextView label1;
}
public View getView(int position, View convertView, ViewGroup parent) {
View vi = convertView;
ViewHolder holder;
if (convertView==null) {
vi = inflater.inflate(R.layout.list_item, null);
holder = new ViewHolder();
holder.label1 = (TextView)vi.findViewById(R.id.tvLabel1);
holder.label1.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
this.button1.setText("Label 1 clicked");
}
});
vi.setTag(holder);
} else {
holder = (ViewHolder)vi.getTag();
}
// show the data in the list view
return vi;
}
}
Suppose you have a button 1 in MainActivity outside list view, so when you create adapter in MainActivity
on your MainActivity's onCreate method do following:
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// define and initialize your data
Button button1 = (Button)findViewById(R.id.button1);
MyAdapter adapter = new MyAdapter(this, data, button1);
...
}

How to detect change in listview from mainactivity

Summary: I need a way to trigger my calculate() function within my main activity when an item is added or removed from my ListView
Background:
My android application fills a listview with list items. A list item contains a textview and an imagebutton (delete) that removes the item from the list on click. I use a custom adapter to keep track of changes in the list. This all works fine.
In my main acticity, some calculations take place based on the values in the list in a function called calulate(). I want to call this function whenever an item is added or deleted from the list. However, I don't know if this is possible and how to implement such a function.
I noticed that it is possible to add an observer using registerDataSetObserver() that will be notified when notifyDataSetChanged() is called. However, I'm not sure if this is what I need and how to implement this. Any help or suggestions are more than welcome.
Here is my CustomListAdapter:
public class CustomListAdapter extends BaseAdapter {
static final String TAG = "CustomListAdapter";
private Context context;
ArrayList <String> listArray;
LayoutInflater inflater;
public CustomListAdapter(Context context, List <String> inputArray) {
super();
this.context = context;
this.listArray = (ArrayList<String>) inputArray;
}
#Override
public int getCount() {
return listArray.size(); // total number of elements in the list
}
#Override
public String getItem(int i) {
return listArray.get(i); // single item in the list
}
#Override
public long getItemId(int i) {
return i; // index number
}
#Override
public View getView(int position, View convertView, final ViewGroup parent) {
View V = convertView;
if(V == null) {
LayoutInflater vi = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
V = vi.inflate(R.layout.selected_drug_list_item, null);
}
//place text in textview
String listItem = listArray.get(position);
TextView textView = (TextView) V.findViewById(R.id.selectedDrugName);
textView.setText(listItem);
ImageButton deleteSelectedDrugButton = (ImageButton) V.findViewById(R.id.deleteSelectedDrugButton);
deleteSelectedDrugButton.setTag(position);
//Listener for the delete button. Deletes item from list.
deleteSelectedDrugButton.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View view) {
//re
Integer index = (Integer) view.getTag();
listArray.remove(index.intValue());
notifyDataSetChanged();
}
});
return V;
}
public void add(String input) {
listArray.add(input);
notifyDataSetChanged();
Log.v(TAG, input + " added to list");
}
public void remove(String input){
listArray.remove(input);
notifyDataSetChanged();
Log.v(TAG, input + " added to list");
}
}
Here is how my ListView is initialized in my onCreate() method.
selectionListView = (ListView) findViewById(R.id.selectionListView);
selectionAdapter = new CustomListAdapter(this,myListItems);
selectionListView.setAdapter(selectionAdapter);
If any other code fragment is required, I'll happily provide it.
You may create Interfece that will be implemented by Your Main Activity and passed to Adapter (eg. in constructor)
public interface SomeInterface
{
public void foo();
}
Add SomeInterface object in Your Adapter
SomeInterface responder=null;
public CustomListAdapter(Context context, List <String> inputArray, SomeInterface responder) {
super();
this.context = context;
this.listArray = (ArrayList<String>) inputArray;
this.responder=responder;
}
public void add(String input) {
listArray.add(input);
notifyDataSetChanged();
Log.v(TAG, input + " added to list");
responder.foo();
}
public void remove(String input){
listArray.remove(input);
notifyDataSetChanged();
Log.v(TAG, input + " added to list");
responder.foo();
}
and implements SomeInterface in Your MainActivity
public class MainActivity extends Activity implements SomeInterface
{
...
public void foo()
{
//do whatever
}
private initializeAdapter()
{
CustomListAdapter adapter=new Adapter(this, someArray, this);
}
}
You can create a callback interface with a simple method, like stuffHappened(). Then, let your activity implement that interface. Now you can add a constructor argument which has as type the callback interface, pass the activity in, keep it as a member variable on the adapter and call the stuffHappened() method whenever you need to send feedback to your activity.

How to let OnClick in ListView's Adapter call Activity's function

I have an Android application with a ListView in it, the ListView will setup fine but now I want a image in the ListView to be clickable. I do this by using 2 classes, the Activity class (parent) and an ArrayAdapter to fill the list. In the ArrayAdapter I implement a OnClickListener for the image in the list that I want to be clickable.
So far it all works.
But now I want to run a function from the activity class when the onClick, for the image in the list, is run but I do not know how. Below are the 2 classes that I use.
First the Activity class:
public class parent_class extends Activity implements OnClickListener, OnItemClickListener
{
child_class_list myList;
ListView myListView;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
// setup the Homelist data
myList = new child_class_list (this, Group_Names, Group_Dates);
myListView = (ListView) findViewById(R.id.list);
// set the HomeList
myListView.setAdapter( myList );
myListView.setOnItemClickListener(this);
}
void function_to_run()
{
// I want to run this function from the LiscView Onclick
}
public void onItemClick(AdapterView<?> arg0, View arg1, int arg2, long arg3)
{
// do something
}
}
And the ArrayAdapter from where I want to call a function from the Activity class:
public class child_class_list extends ArrayAdapter<String>
{
// private
private final Context context;
private String[] mName;
private String[] mDate;
public child_class_list (Context context, String[] Name, String[] Date)
{
super(context, R.layout.l_home, GroupName);
this.context = context;
this.mName = Name;
this.mDate = Date;
}
#Override
public View getView(int position, View convertView, ViewGroup parent)
{
LayoutInflater inflater = (LayoutInflater) context
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View rowView = inflater.inflate(R.layout.l_home, parent, false);
ImageView selectable_image = (ImageView) rowView.findViewById(R.id.l_selectable_image);
selectable_image.setOnClickListener(new OnClickListener()
{
public void onClick(View v)
{
// I want to run the function_to_run() function from the parant class here
}
}
);
// get the textID's
TextView tvName = (TextView) rowView.findViewById(R.id.l_name);
TextView tvDate = (TextView) rowView.findViewById(R.id.l_date);
// set the text
tvName.setText (mName[position]);
tvDate.setText (mDate[position]);
return rowView;
}
}
If anyone knows how to run the function in the activity class from the arrayadapter or how to set the image onClickListener in the Activity Class I would greatly apriciate the help.
Inside onClick() Do something like this:
((ParentClass) context).functionToRun();
Just for clarity to expand on provided answers
In a BaseAdapter you can get the parent class by calling this.getActivity();If you then typecast this to the actual activity class you can then call a function as per #AdilSoomro answer below so you actually end up with something like this
public class MyAdapter extends BaseAdapter<Long> {
public MyAdapter(Activity activity,
TreeStateManager<Long> treeStateManager, int numberOfLevels) {
super(activity, treeStateManager, numberOfLevels);
}
#Override
public void handleItemClick(final View view, final Object id) {
((MyActivity) this.activity).someFunction();
}
}
Then just declare someFunction in MyActivity to do what you want
protected void someFunction(){
// Do something here
}

Categories

Resources