ListView subobject clickable confilct

After asking a question and spending 15 days to solve this, i am looking for help and solution here again. In MainActivity i have created Json Downloading Task which is downloading data from http and with CustomListAdapter.class i populate the listview. Everything works. Now, in the listview i have 2 textview's which i want to be clickable, one of them is "Accept", that textview is just in xml it's not populated with Adapter or Json. "Accept" should work like this "Change the text to Accepted and change color" and its working like everything else. BUT when i click on first "Accept"(Position 0) in listview it changes other listview items (Position 4,9). It's like i clicked textviews on Position 4,9. On first image is before clicking the "Accept" and second on is afer clicking.

before clicking /// after clicking

 public class MainActivity extends Activity {

protected static final String TAG = null;
public ArrayList<FeedItem> feedList;
public ListView feedListView;
private ProgressBar progressbar;
 private CustomListAdapter adap;
 private LayoutInflater mInflater;


@Override 
public void onCreate(Bundle savedInstanceState)
{
      super.onCreate(savedInstanceState);
      setContentView(R.layout.activity_main); 
      feedListView= (ListView) findViewById(R.id.custom_list);

      mInflater = (LayoutInflater) getSystemService(Activity.LAYOUT_INFLATER_SERVICE);
      String url = "...";
      new DownloadFilesTask().execute(url);

      getActionBar().setIcon(R.drawable.angel);
      progressbar = (ProgressBar)findViewById(R.id.progressBar);


       public void updateList() {
    adap = new CustomListAdapter(this, feedList);

           feedListView.setAdapter(adap);

            }


      public class DownloadFilesTask extends AsyncTask<String, Integer, Void> {


      ///....  

CustomListAdapter.class

    public class CustomListAdapter extends BaseAdapter  
 {

private ArrayList<FeedItem> listData;
private LayoutInflater layoutInflater;
private Context mContext;
private ArrayList<String> data;
protected ListView feedListView;
ArrayList<HashMap<String,String>> list;

public CustomListAdapter(Context context, ArrayList<FeedItem> listData)
{
    this.listData = listData;
    layoutInflater = (LayoutInflater) context
            .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
    mContext = context;
    data = new ArrayList<String>();
    for (int i = 0; i < 10; i++) {
        data.add("Sample Text " + String.valueOf(i));
    }
}


@Override
public int getCount()
{
    return listData.size();
}

@Override
public Object getItem(int position)
{
    return listData.get(position);
}

@Override
public long getItemId(int position)
{
    return position;
}


public View getView( int position, View convertView, ViewGroup parent)
{
 final ViewHolder holder;
 View row=convertView;
    if ((row == null) || (row.getTag()==null)) {

     convertView = layoutInflater.inflate(R.layout.list_row_layout, null);
     holder = new ViewHolder();
     holder.headlineView = (TextView)convertView.findViewById(R.id.name);
     holder.reportedDateView = (TextView) convertView.findViewById(R.id.confid);
     holder.accept= (TextView) convertView.findViewById(R.id.acceptTV);

     convertView.setTag(holder);



    }
    else
    {
        holder = (ViewHolder) convertView.getTag();

    }

   final FeedItem newsItem = (FeedItem) listData.get(position);
    holder.accept.setFocusable(true);

    holder.accept.setClickable(true);
    holder.headlineView.setText(Html.fromHtml(newsItem.getTitle()));
    holder.reportedDateView.setText(Html.fromHtml(newsItem.getContent()));

    holder.accept.setOnClickListener(new View.OnClickListener() {

        @Override
        public void onClick(View arg0) {


                    holder.accept.setText(Html.fromHtml(newsItem.getContent()));
        }
    });



    return convertView;
}




static class ViewHolder
{

    TextView accept;
    TextView headlineView;
    TextView reportedDateView;
    ImageView imageView;
    FeedItem newsItem;

}

You need to understand how listview recycle mechanism works

How ListView's recycling mechanism works

Use a Model Class. Assume you already have the below

public class FeedItem {

String title,content;

public String getTitle() {
    return title;
}

public void setTitle(String title) {
    this.title = title;
}

public String getContent() {
    return content;
}

public void setContent(String content) {
    this.content = content;
}

}

In getView

holder.accept.setText(listData.get(position).getContent()); 
holder.accept.setTag(position);
holder.accept.setOnClickListener(mClickListener);

Then

private OnClickListener mClickListener = new OnClickListener() {
public void onClick(View v) {
    int pos = (Integer) v.getTag();
    FeedItem newsItem = (FeedItem) listData.get(pos);
    newsItem.setContent("Accepted");
    CustomListadapter.this.notifyDataSetChanged();
}
};

Exaplanation :

You use a model class which has getters and setters.

You setTag to the button with position. In onClick you get the tag ie position and change the content accordingly. You refresh listview by calling notifyDataSetChanged on the adapter.

For the benefit of others here's a example

public class MainActivity extends Activity {

   ArrayList<Holder> list = new ArrayList<Holder>();
   ListView lv;
   CustomListAdapter cus;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        lv = (ListView) findViewById(R.id.listView1);
        for(int i=0;i<10;i++)
        {
            Holder h = new Holder();
            h.setTitle("Title"+i);
            h.setContent("Content"+i);
            h.setColor(Color.BLACK);
            list.add(h);
        }
        cus = new CustomListAdapter(this,list);
        lv.setAdapter(cus);
    }
}

Model class Holder

public class Holder {

    String title,content;
    int color;

    public int getColor() {
return color;

    public void setColor(int color) {
this.color = color;
    }

    public String getTitle() {
        return title;
    }

    public void setTitle(String title) {
        this.title = title;
    }

    public String getContent() {
        return content;
    }

    public void setContent(String content) {
        this.content = content;
    }

}

CustomListAdapter

public class CustomListAdapter extends BaseAdapter{

    LayoutInflater inflater;
    ArrayList<Holder> list;
    public CustomListAdapter(MainActivity mainActivity, ArrayList<Holder> list) {
        inflater = LayoutInflater.from(mainActivity);
        this.list =list;
    }
    @Override
    public int getCount() {
        // TODO Auto-generated method stub
        return list.size();
    }
    @Override
    public Object getItem(int position) {
        // TODO Auto-generated method stub
        return position;
    }
    @Override
    public long getItemId(int position) {
        // TODO Auto-generated method stub
        return position;
    }
    public View getView(int position, View convertView, ViewGroup parent) { 
        ViewHolder holder; 
        if (convertView == null) { 
            convertView = inflater.inflate(R.layout.list_item, 
                    parent, false);
            holder = new ViewHolder(); 
            holder.tv = (TextView) convertView.findViewById(R.id.textView1); 
            holder.b = (Button) convertView.findViewById(R.id.button1);
           convertView.setTag(holder); 
       } else { 
           holder = (ViewHolder) convertView.getTag(); 
       } 
       Holder h = list.get(position);
       holder.tv.setText(h.getTitle());
       holder.b.setText(h.getContent());
       holder.b.setTextColor(h.getColor());
       holder.b.setOnClickListener(mClickListener); 
       holder.b.setTag(position);
       return convertView; 
}
     private OnClickListener mClickListener = new OnClickListener() {

            public void onClick(View v) {
                int pos = (Integer) v.getTag();
                Holder h = (Holder) list.get(pos);
                h.setContent("Accepted");
                    h.setColor(Color.BLUE);
                CustomListAdapter.this.notifyDataSetChanged();

            }

            };
    static class ViewHolder
    {
        TextView tv;
        Button b;
    }
}

list_item.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent" >

    <Button
        android:id="@+id/button1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentRight="true"
        android:layout_alignParentTop="true"
        android:layout_marginRight="40dp"
        android:text="Button" />

    <TextView
        android:id="@+id/textView1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignBottom="@+id/button1"
        android:layout_alignParentLeft="true"
        android:layout_marginLeft="22dp"
        android:text="TextView" />

</RelativeLayout>

activity_main.xml

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context=".MainActivity" >
    <ListView
        android:id="@+id/listView1"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        >
    </ListView>

</RelativeLayout>

Snap

Button at row 1 and 5 is clicked so it is changed to Accepted and is Blue.

enter image description here


getView(...){
if ((row == null) || (row.getTag()==null)) {
 // some code
}else{
 // some code
}
holder.accept.setTag(position);

// some more code

if(newsItem.isSelected()){
holder.accept.setText("accepted");
}else{
holder.accept.setText("accept");
}

//handling click
holder.accept.setOnClickListener(new View.OnClickListener() {

    @Override
    public void onClick(View arg0) {

                int position = (Integer)arg0.getTag();
                // change backing dataset here instead.
                FeedItem m = listData.get(position);
                // declare a boolean 'selected' in FeedItem 
                // toggle the previous selection
                m.setSelected(! m.isSelected());
                // call notifydatasetChanged
                CustomListAdapter.this.notifyDataSetChanged();

    }
});

// some more code
}


class FeedItem{
// some data member

boolean selected = false;
public boolean isSelected(){
return selected;
}

public void setSelected(boolean status){
selected = status;
}
}