Ruby
Ruby

Reputation: 251

ListView using SimpleCursorAdapter OnItemClickListener not working

I can populate my list with the database values. My problem is that ListView layout looks like this (for example) -> ( textview, delete button )

Activity 1 || Delete_Button

Activity 2 || Delete_Button

and what i want is that when i clicked Activity 1, it will go to Activity 1 intent. or when i clicked Activity 2, it will go to Activity 2 intent. same as the delete button, if I clicked the row 1 delete button, it will delete row 1 and etc.

How to do this ? I'm new at Android.

This is my code:

 ListView listView ;
    ArrayList<String> list;

    public int goal_id;
    int i = 0;

    //database variables
    MyDBAdapter dbhandler;


    protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_set_act);
            TypefaceProvider.registerDefaultIconSets();

            Bundle extras = getIntent().getExtras();

            if (extras == null) {
                return;
            }

            goal_id = Integer.parseInt(extras.getString("goalid"));

            Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
            setSupportActionBar(toolbar);
            toolbar.setSubtitle("Activities List");
            ActionBar actionBar = getSupportActionBar();
            actionBar.setHomeAsUpIndicator(R.drawable.ic_back);
            actionBar.setDisplayHomeAsUpEnabled(true);

            FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab);
            fab.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View view) {
                    Snackbar.make(view, "Added new activity", Snackbar.LENGTH_LONG)
                            .setAction("Added new activity", null).show();

                    onCLick_addAct();
                }
            });

            dbhandler = new MyDBAdapter(this);
            populateListView();
            listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {

                @Override
                public void onItemClick(AdapterView<?> parent, View view, int position, long id) {

                    Long temp = listView.getItemIdAtPosition(position);
                    MessageTo.message(SetActActivity.this, Long.toString(temp));
                }
            });

        }

        public void populateListView(){
            Cursor cursor = dbhandler.getAllActivitiesByGoalCursor(goal_id);
            String[] actlist = new String[] {dbhandler.dbhandler.COLUMN_ACTIVITY_NAME};
            int[] actNames = new int[] {R.id.list_item_string};

            SimpleCursorAdapter myAdapter = new SimpleCursorAdapter(SetActActivity.this,R.layout.act_list,cursor,actlist,actNames,0){
            @Override
            public View getView(int position, View convertView, ViewGroup parent) {
                View v = convertView;
                ViewHolder holder;
                if (v == null) {
                    holder = new ViewHolder();
                    LayoutInflater vi = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
                    v = vi.inflate(R.layout.act_list, null);
                    holder.textView = (TextView) v.findViewById(R.id.list_item_string);
                    holder.button = (Button) v.findViewById(R.id.delete_btn);
                    v.setTag(holder);
                    holder.button.setOnClickListener(new View.OnClickListener() {
                        @Override
                        public void onClick(View v) {
                            int pos = (int) v.getTag();
                            list.remove(pos);
                            notifyDataSetChanged();
                        }
                    });
                } else {
                    holder = (ViewHolder) v.getTag();
                } 
//  holder.textView.setText(list.get(position).get("title")); //the get("title") is error. undefined

                holder.button.setTag(position);
                return v;

            }

            class ViewHolder {
                TextView textView;
                Button button;
            }
        };
        //handle listview and assign adapter
        listView = (ListView)findViewById(R.id.list);
        // Attach cursor adapter to the ListView
        listView.setAdapter(myAdapter);

    }

This one code -> it wont distinguish if i clicked the textview or the delete button. It will still implement the same function which is not what i want to happen. :(

    listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {

                    @Override
                    public void onItemClick(AdapterView<?> parent, View view, int position, long id) {

                        Long temp = listView.getItemIdAtPosition(position);
                        MessageTo.message(SetActActivity.this, Long.toString(temp));
                    }
                });

Upvotes: 2

Views: 1456

Answers (3)

Bharatesh
Bharatesh

Reputation: 9009

UPDATED : As you can't delete a row/item from cursor and also re-query Cursor every time user presses delete not a good idea.

Instead you can read all values from cursor and put it in List<Map<String,String> items and pass this object to SimpleAdapter. try below code.

    items = new ArrayList<Map<String,String>>();
    Map<String, String> item;
    cursor.moveToFirst();
    while (!cursor.isAfterLast()) {
        String name = cursor.getString(cursor.getColumnIndex("title"));//column name
        String id = cursor.getString(cursor.getColumnIndex("_id"));//column name
        item = new HashMap<>();
        item.put("title", name);
        item.put("id", id);
        items.add(item);
        cursor.moveToNext();
    }

    SimpleAdapter adapter = new SimpleAdapter(this, items, R.layout.adapter_text_button, new String[]{"title"
    }, new int[]{R.id.title}) {
        @Override

        public View getView(int position, View convertView, ViewGroup parent) {
            View v = convertView;
            ViewHolder holder;
            if (v == null) {
                holder = new ViewHolder();
                LayoutInflater vi = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
                v = vi.inflate(R.layout.adapter_text_button, null);
                holder.textView = (TextView) v.findViewById(R.id.title);
                holder.button = (Button) v.findViewById(R.id.action);
                v.setTag(holder);
                holder.button.setOnClickListener(new View.OnClickListener() {
                    @Override
                    public void onClick(View v) {
                        int pos = (int) v.getTag();
                        Map<String, String> item = items.get(pos);
                        String id = item.get("id");
                        //using this id delete the record from the database
                        items.remove(item);
                        notifyDataSetChanged();
                        Log.i("TAG", "ID " + id);
                    }
                });
            } else {
                holder = (ViewHolder) v.getTag();
            }
            Map<String, String> data = items.get(position);
            holder.textView.setText(data.get("title"));
            holder.button.setTag(position);
            return v;

        }

        class ViewHolder {
            TextView textView;
            Button button;
        }
    };

    listView.setAdapter(adapter);

Upvotes: 2

Faraz
Faraz

Reputation: 2154

You are using a focusable item (Button) in a list which is overriding the event of OnItemClickListener. The solution is to use two separate onClickListeners while creating the views in the adapter.

This issue is pretty common. See this for reference.

Now, the code for custom SimpleCursorAdapter:

public class MyAdapter extends SimpleCursorAdapter
{

    private Context mContext;
    private Context appContext;
    private int layout;
    private Cursor cr;
    private final LayoutInflater inflater;

    public MyAdapter(Context context, int layout, Cursor c, String[] from, int[] to)
    {
        super(context, layout, c, from, to);
        this.layout = layout;
        this.mContext = context;
        this.inflater = LayoutInflater.from(context);
        this.cr = c;
    }

    @Override
    public View newView(Context context, Cursor cursor, ViewGroup parent)
    {
        return inflater.inflate(layout, null);
    }

    @Override
    public void bindView(View view, final Context context, Cursor cursor)
    {
        super.bindView(view, context, cursor);
        RelativeLayout parentView = (RelativeLayout) view.findViewById(R.id.parentView);
        TextView textview = (TextView) view.findViewById(R.id.itemLayoutText);
        // Set the text using cursor with column index.
        textview.setText(cursor.getString(1));
        Button button = (Button) view.findViewById(R.id.itemLayoutBtn);
        button.setOnClickListener(new View.OnClickListener()
        {
            @Override
            public void onClick(View view)
            {
                // Use interface to send a callback to the activity
                Toast.makeText(context, "Button clicked", Toast.LENGTH_SHORT).show();
            }
        });

        parentView.setOnClickListener(new View.OnClickListener()
        {
            @Override
            public void onClick(View view)
            {
                // Use interface to send a callback to the activity
                Toast.makeText(context, "List item clicked", Toast.LENGTH_SHORT).show();
            }
        });

    }
}

Layout of list item:

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

    <TextView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_alignParentLeft="true"
        android:textAppearance="?android:textAppearanceMedium"
        android:id="@+id/itemLayoutText"/>

    <Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:id="@+id/itemLayoutBtn"
        android:text="Delete"
        android:layout_alignParentRight="true"
        />

</RelativeLayout>

Upvotes: 1

Ichigo Kurosaki
Ichigo Kurosaki

Reputation: 3843

You can simply add in your custom adapter's getView() method a setOnClickListener() for the buttons you're using.

Any data associated with the button has to be added with myButton.setTag() in the getView() and can be accessed in the onClickListener via view.getTag()

Check the solution in this link

Upvotes: 0

Related Questions