Search code examples
javaandroidlistviewandroid-sqlite

how can i code public class for SimpleCursorAdapter?


I am new to android and I need to use ListView for my project. I use a sample from the internet which has no public class for ListView so I am not able to code flexible. how can I code public class for this.

public class LIGHTS extends AppCompatActivity {

    ListView users_list;
    private DatabaseManager dbManager;
    private SimpleCursorAdapter adapter;
    private DatabaseHelper dbHelper;

    final String[] from = new String[]{dbHelper._ID, dbHelper.TITLE, dbHelper.DESC};
    final int[] to = new int[]{R.id.id, R.id.KEYCODE, R.id.NAME};

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_lights);
        startconnection();

        dbManager = new DatabaseManager(this);
        dbManager.open();
        Cursor cursor = dbManager.fetch();

        users_list = findViewById(R.id.users_list);

        adapter = new SimpleCursorAdapter(this, R.layout.adapter, cursor, from, to, 0);
        users_list.setAdapter(adapter);}

and the fetch() is in below code in dbmanager:

    public Cursor fetch() {
        String[] columns = new String[]{dbHelper._ID, dbHelper.TITLE, dbHelper.DESC};
        Cursor cursor = database.query(dbHelper.TABLE_NAME, columns, null, null, null, null, null);
        if (cursor != null) {
            cursor.moveToFirst();
        }
        return cursor;
    }

Solution

  • Here's an example based upon your code that handles clicking a button for each item in the list.

    If you click a switch then it displays the id of the item via a toast.

    This utilises a Custom Adapter based upon (extends) the CursorAdapter class.

    First the layout adapter.xml used for the item (should have the basics of your's and includes a switch who's id is the_switch) :-

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout
        xmlns:android="http://schemas.android.com/apk/res/android"
        android:orientation="horizontal"
        android:layout_width="match_parent"
        android:layout_height="match_parent">
        <TextView
            android:id="@+id/id"
            android:layout_width="0dp"
            android:layout_weight="1"
            android:layout_height="wrap_content" />
        <TextView
            android:id="@+id/KEYCODE"
            android:layout_width="0dp"
            android:layout_weight="2"
            android:layout_height="wrap_content" />
        <TextView
            android:id="@+id/NAME"
            android:layout_width="0dp"
            android:layout_weight="6"
            android:layout_height="wrap_content" />
        <Switch
            android:id="@+id/the_switch"
            android:layout_width="0dp"
            android:layout_weight="1"
            android:layout_height="wrap_content"
            android:focusable="false"
            />
    </LinearLayout>
    

    The Activity Lights.java is now :-

    public class Lights extends AppCompatActivity {
    
        ListView users_list, alt_users_list;
        private DatabaseManager dbManager;
        private MyCustomCursorAdapter adapter;
        //private DatabaseManager dbHelper; //?????? a second not needed
        Cursor cursor;
        Context mContext;
    
        //<<<<<<<<<< Not needed although could be passed
        //final String[] from = new String[]{DatabaseManager._ID, DatabaseManager.TITLE, DatabaseManager.DESC};
        //final int[] to = new int[]{R.id.id, R.id.KEYCODE, R.id.NAME};
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            mContext = this;
            setContentView(R.layout.activity_lights);
            startconnection(); //?????? dummied out
            users_list = findViewById(R.id.users_list);
            alt_users_list = findViewById(R.id.alt_users_list);
    
            dbManager = new DatabaseManager(this);
            dbManager.open();
            manageListView(); //Handles the ListView
        }
    
        // Moved here handles list refresh if called (e.g. in onResume)
        private void manageListView() {
            cursor = dbManager.fetch();
            //Setup the adapter if not already setup else swaps (refreshes) the cursor
            if (adapter == null) {
                adapter = new MyCustomCursorAdapter(this, cursor);
                users_list.setAdapter(adapter);
                users_list.setOnItemClickListener(new AdapterView.OnItemClickListener() {
                    @Override
                    public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
                        Toast.makeText(mContext,"You clicked on the item with an ID of " + String.valueOf(id),Toast.LENGTH_SHORT).show();
                    }
                });
            } else {
                adapter.swapCursor(cursor);
            }
        }
        private void startconnection(){}
    
        @Override
        protected void onDestroy() {
            super.onDestroy();
            // Close the Cursors when done with them
            cursor.close();
        }
    
        @Override
        protected void onResume() {
            super.onResume();
            // Refresh the listviews when returning to the activity
            manageListView();
        }
    }
    
    • Comments try to explain changes (basically it is quite similar).
    • The biggest change is that the setting up of the listview has been moved to a method of it's own, which also handles refreshing the listview (redisplaying it after the underlying data has been changed).
    • The instantiation of the adapter is also simpler than for the SimpleCursorAdapter (the layout and column to view handling coded in the adapter).

    The adapter myCustomAdapter.java is :-

    public class MyCustomCursorAdapter extends CursorAdapter {
    
        public MyCustomCursorAdapter(Context context, Cursor c) {
            super(context, c, 0);
        }
    
        @Override
        public View getView(int position, View convertView, ViewGroup parent) {
            View view = super.getView(position, convertView, parent);
            if (position % 2 == 0) {
                view.setBackgroundColor(0xFFAAAAFF);
            } else {
                view.setBackgroundColor(0xAAAAAAFF);
            }
            return view;
        }
    
        @Override
        public View newView(Context context, Cursor cursor, ViewGroup parent) {
            return LayoutInflater.from(context).inflate(R.layout.adapter,parent,false);
        }
    
        @Override
        public void bindView(View view, Context context, Cursor cursor) {
            ((TextView)view.findViewById(R.id.id)).setText(cursor.getString(cursor.getColumnIndex(DatabaseManager._ID)));
            ((TextView)view.findViewById(R.id.KEYCODE)).setText(cursor.getString(cursor.getColumnIndex(DatabaseManager.TITLE)));
            ((TextView)view.findViewById(R.id.NAME)).setText(cursor.getString(cursor.getColumnIndex(DatabaseManager.DESC)));
    
            Switch thisswitch = view.findViewById(R.id.the_switch);
            thisswitch.setTag(cursor.getString(cursor.getColumnIndex(DatabaseManager._ID)));
            thisswitch.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
                @Override
                public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
                    Toast.makeText(buttonView.getContext(),
                            "You clicked the switch for ID " + (String) buttonView.getTag() +
                                    " the status is now " + (new Boolean(isChecked)).toString(),
                            Toast.LENGTH_SHORT)
                            .show()
                    ;
                }
            });
        }
    }
    
    • bindView has primarily been used it :-
      • binds the values from the columns of the cursor to the views for each item
      • and in this case sets the tag of the switch to the id and then adds an onCheckChangedListener for the Button.
    • bindView has the advantage that the cursor and context are passed to it.
    • getView can also be used, it has the advantage of having the position of the item in the list passed.
    • In this case it has been used to alternate the background colour for each item.

    Result

    Here's a screen shot showing the toast (note testing data was added to the underlying database, so this will obviously vary from yours) :-

    enter image description here

    Additional

    It might be that you need to handle the switch check change in the owning activity.

    The following changes show a basic means, via an interface, of handling the switch event in the activity, rather than in the adapter.

    First the interface myOnCheckedChangedInterface.java

    public interface myOnCheckedChangedInterface {
        void myOnCheckedChangedHandler(String id, boolean check_status);
    }
    

    Second change Lights.java by adding the handler method myOnCheckedChangedHandler

    @Override
    public void myOnCheckedChangedHandler(String id, boolean check_status) {
        Toast.makeText(
                this,
                "You changed the status for the row with an id of " + id +
                        " the status is now " + new Boolean(check_status).toString(),
                Toast.LENGTH_SHORT).show();
    }
    
    • Ignore the error that the method doesn't override method from it's superclass.

    Third change the Class declaration to implement the interface by adding implements myOnCheckedChangedInterface as per :-

    public class Lights extends AppCompatActivity implements myOnCheckedChangedInterface {
    

    Lastly change MyCustomCursorAdapter to be able to call the myOnCheckedChangedHandler

    e.g.

    public class MyCustomCursorAdapter extends CursorAdapter {
        Lights calling_activity; //<<<<<<<<<<@@@@@@@@@@@ ADDED for interface
    
        public MyCustomCursorAdapter(Context context, Cursor c) {
            super(context, c, 0);
            this.calling_activity = (Lights) context; //<<<<<<<<<<@@@@@@@@@@@ ADDED for interface
        }
    
        @Override
        public View getView(int position, View convertView, ViewGroup parent) {
            View view = super.getView(position, convertView, parent);
            if (position % 2 == 0) {
                view.setBackgroundColor(0xFFAAAAFF);
            } else {
                view.setBackgroundColor(0xAAAAAAFF);
            }
            return view;
        }
    
        @Override
        public View newView(Context context, Cursor cursor, ViewGroup parent) {
            return LayoutInflater.from(context).inflate(R.layout.adapter,parent,false);
        }
    
        @Override
        public void bindView(View view, Context context, Cursor cursor) {
            ((TextView)view.findViewById(R.id.id)).setText(cursor.getString(cursor.getColumnIndex(DatabaseManager._ID)));
            ((TextView)view.findViewById(R.id.KEYCODE)).setText(cursor.getString(cursor.getColumnIndex(DatabaseManager.TITLE)));
            ((TextView)view.findViewById(R.id.NAME)).setText(cursor.getString(cursor.getColumnIndex(DatabaseManager.DESC)));
    
            Switch thisswitch = view.findViewById(R.id.the_switch);
            thisswitch.setTag(cursor.getString(cursor.getColumnIndex(DatabaseManager._ID)));
            thisswitch.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
                @Override
                public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
                    /**
                    Toast.makeText(buttonView.getContext(),
                            "You clicked the switch for ID " + (String) buttonView.getTag() +
                                    " the status is now " + (new Boolean(isChecked)).toString(),
                            Toast.LENGTH_SHORT)
                            .show()
                    **/
                    calling_activity.myOnCheckedChangedHandler((String)buttonView.getTag(),isChecked); //<<<<<<<<<<@@@@@@@@@@@ ADDED for interface
                }
            });
        }
    }
    
    • See commments with //<<<<<<<<<<@@@@@@@@@@@ ADDED for interface for changes
    • The original Toast has been commented out as it is no longer needed
    • Note this isn't the tidiest way as the Adapter is tied to a Lights activity, it's just meant to be a simple example.