Search code examples
androidandroid-cursor

Using SQLite cursor to output table contents in listview in a fragment


I have MyDBHandler with a getAllDetails method that queries the database using a cursor and returns a list.

What I don't know what to do now is how to output this list in a listview in another fragment. I was told to create two XML layouts and a custom adapter but I don't know how to this exactly!

MyDBHandler class

package com.astuetz.viewpager.extensions.sample;

import android.content.ContentValues;
import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.database.Cursor;
import android.content.Context;
import android.content.ContentValues;

import java.util.ArrayList;
import java.util.List;

public class MyDBHandler extends SQLiteOpenHelper {

private static final int DATABASE_VERSION = 1;
private static final String DATABASE_NAME = "detailsDB.db";
public static final String TABLE_DETAILS = "details";
public static final String COLUMN_ID = "_id";
public static final String COLUMN_FIRSTNAME = "firstname";
public static final String COLUMN_SURNAME = "surname";
public static final String COLUMN_PHONE = "phone";
public static final String COLUMN_EMAIL = "email";
public static final String COLUMN_ADDRESS1 = "address1";
public static final String COLUMN_ADDRESS2 = "address2";

public static final String TABLE_KIN_DETAILS = "kindetails";
public static final String COLUMN_KIN_ID = "_id";
public static final String COLUMN_KIN_YOUREMAIL = "youremailkin";
public static final String COLUMN_KIN_FIRSTNAME = "firstnamekin";
public static final String COLUMN_KIN_SURNAME = "surnamekin";
public static final String COLUMN_KIN_PHONE = "phonekin";
public static final String COLUMN_KIN_EMAIL = "emailkin";
public static final String COLUMN_KIN_ADDRESS1 = "address1kin";
public static final String COLUMN_KIN_ADDRESS2 = "address2kin";

// Pass database information along to superclass
public MyDBHandler(Context context, String name, SQLiteDatabase.CursorFactory factory, int version) {
    super(context, DATABASE_NAME, factory, DATABASE_VERSION);
}

@Override
public void onCreate(SQLiteDatabase db) {
    String query = " CREATE TABLE " + TABLE_DETAILS + "("
            + COLUMN_ID + " INTEGER PRIMARY KEY AUTOINCREMENT, "
            + COLUMN_FIRSTNAME + " TEXT, "
            + COLUMN_SURNAME + " TEXT, "
            + COLUMN_PHONE + " TEXT, "
            + COLUMN_EMAIL + " TEXT, "
            + COLUMN_ADDRESS1 + " TEXT, "
            + COLUMN_ADDRESS2 + " TEXT "
            + ");";

    String query2 = " CREATE TABLE " + TABLE_KIN_DETAILS + "("
            + COLUMN_KIN_ID + " INTEGER PRIMARY KEY AUTOINCREMENT, "
            + COLUMN_KIN_YOUREMAIL + " TEXT, "
            + COLUMN_KIN_FIRSTNAME + " TEXT, "
            + COLUMN_KIN_SURNAME + " TEXT, "
            + COLUMN_KIN_PHONE + " TEXT, "
            + COLUMN_KIN_EMAIL + " TEXT, "
            + COLUMN_KIN_ADDRESS1 + " TEXT, "
            + COLUMN_KIN_ADDRESS2 + " TEXT "
            + ");";
    db.execSQL(query);
    db.execSQL(query2);
}

@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
    db.execSQL(" DROP TABLE IF EXISTS " + TABLE_DETAILS);
    db.execSQL(" DROP TABLE IF EXISTS " + TABLE_KIN_DETAILS);
    onCreate(db);
}

//Add a new row to the database
public void addDetails(Details details) {
    ContentValues values = new ContentValues();
    values.put(COLUMN_FIRSTNAME, details.getFirstname());
    values.put(COLUMN_SURNAME, details.getSurname());
    values.put(COLUMN_PHONE, details.getPhone());
    values.put(COLUMN_EMAIL, details.getEmail());
    values.put(COLUMN_ADDRESS1, details.getAddress1());
    values.put(COLUMN_ADDRESS2, details.getAddress2());
    SQLiteDatabase db = getWritableDatabase();
    db.insert(TABLE_DETAILS, null, values);
    db.close();
}

public void addKinDetails(KinDetails kinDetails){
    ContentValues values = new ContentValues();
    values.put(COLUMN_KIN_YOUREMAIL, kinDetails.getyourEmailkin());
    values.put(COLUMN_KIN_FIRSTNAME, kinDetails.getFirstnamekin());
    values.put(COLUMN_KIN_SURNAME, kinDetails.getSurnamekin());
    values.put(COLUMN_KIN_PHONE, kinDetails.getPhonekin());
    values.put(COLUMN_KIN_EMAIL, kinDetails.getEmailkin());
    values.put(COLUMN_KIN_ADDRESS1, kinDetails.getAddress1kin());
    values.put(COLUMN_KIN_ADDRESS2, kinDetails.getAddress2kin());
    SQLiteDatabase db = getWritableDatabase();
    db.insert(TABLE_KIN_DETAILS, null, values);
    db.close();
}



public List<Details> getAllDetails(){

    //create a new list in which we put all persons
    List<Details>detailsList = new ArrayList<>();

    SQLiteDatabase db = getWritableDatabase();
    String query = "SELECT * FROM " + TABLE_DETAILS;

    //Cursor points to a location in your results
    Cursor c = db.rawQuery(query, null);
    //Move to the first row in your results

    if (c != null) {

        c.moveToFirst();

        //Position after the last row means the end of the results
        while (!c.isAfterLast()) {

            //create new details object
            Details details = new Details();

            //Here use static declared on top of the class..don't use "" for the table column
            details.set_id(c.getColumnIndex(COLUMN_ID));
            details.setFirstname(c.getString(c.getColumnIndex(COLUMN_FIRSTNAME)));
            details.setSurname(c.getString(c.getColumnIndex(COLUMN_SURNAME)));
            details.setPhone(c.getString(c.getColumnIndex(COLUMN_PHONE)));
            details.setEmail(c.getString(c.getColumnIndex(COLUMN_EMAIL)));
            details.setAddress1(c.getString(c.getColumnIndex(COLUMN_ADDRESS1)));
            details.setAddress2(c.getString(c.getColumnIndex(COLUMN_ADDRESS2)));

            detailsList.add(details);


            c.moveToNext();
        }

        c.close();
    }

    db.close();

    //return our list of persons
    return detailsList;

}
}

Solution

  • You need to first create layout files for your fragment and the listview rows.

    For the fragment you can create a new blank fragment as follows : Note: We are using a blank fragment because its good practise to learn since it gives you more control in complex situations.

    enter image description here

    enter image description here

    In the fragment_details.xml paste the following code : Note change com.companyname to your app package name!

    <LinearLayout 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"
    tools:context="com.companyname.myapplication.FragmentDetails">
    
    
    <ListView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:id="@+id/frag_details_listView"
        android:layout_weight="1" />
    
     </LinearLayout>
    

    Create a new xml layout file and name it row_details , this will be our custom row for our listview.

    enter image description here

    And in the file row_details.xml paste the following code :

    <?xml version="1.0" encoding="utf-8"?>
    

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textAppearance="?android:attr/textAppearanceLarge"
        android:text="Large Text"
        android:id="@+id/row_details_textview_name"
        android:layout_marginTop="10dp"
        android:layout_marginLeft="10dp" />
    
    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textAppearance="?android:attr/textAppearanceSmall"
        android:text="Small Text"
        android:id="@+id/row_details_textview_id"
        android:layout_marginLeft="10dp" /> 
    
      </LinearLayout>
    

    What we need now is a custom adapter which will take care of loading the data into our listview.

    Create a new Java Class and name it DetailsAdapter, and paste the following code : Note see my comments in the code because it is very important to understand the concept behind the adapters in Android :

    public class DetailsAdapter extends ArrayAdapter<Person> {
    
    private Context context;
    
    //Constructor
    public DetailsAdapter(Context context, int resource, List<Person> objects) {
        super(context, resource, objects);
    
        this.context = context;
    }
    
    
    //The get view is the most crucial part of the adapter, here the listview asks the 
    //adapter for the row to display
    
    @Override
    public View getView(int position, View row, ViewGroup parent) {
    
        //Get an instance of our holder
        Holder holder;
    
    
        //Check if this is the first time we are creating this row for the listview
        if (row == null){
    
            //Row was null and thus we need to get components from the row_details.xml
            holder = new Holder();
    
            //get the Android's layout inflater service which will read our row_details.xml
            LayoutInflater inflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
    
            //Fill our row view with the xml layout file
            row = inflater.inflate(R.layout.row_details, null);
    
            //Fill our holder with the text view components
            holder.textViewName = (TextView)row.findViewById(R.id.row_details_textview_name);
            holder.textViewId = (TextView)row.findViewById(R.id.row_details_textview_id);
    
            //This is very imp! attach our holder to the row 
            row.setTag(holder);
    
        }else{
    
            //row was created before! thus get the holder object from the row tag
            holder = (Holder)row.getTag();
        }
    
    
        //At this point we have our row, either created from new or got it from the row tag object
        //we can now fill the data
    
        //First get our object from the list which is in the position of the listview
        //The position as you can see is passed to the getView method by the listview
        Person person = getItem(position);
    
        holder.textViewName.setText(person.getFirstname());
        holder.textViewId.setText("ID: " + person.get_id());
    
        //we are done formatting our row..return to listview to show
        return row;
    }
    
    //A holder will be resposable to hold our components to improve listview performance
    //We replicate the components we have in the row_details.xml
    private class Holder{
    
        TextView textViewName;
        TextView textViewId;
    
    
    }
    
    }
    

    At this point we are ready to rumble!!

    In the FragmentDetails java class we declare a global private List of Details...we get an instance of our listview..we get the data..create a new DetailsAdapter and attach it to the listview..

    public class FragmentDetails extends Fragment {
    
    private List<Details>detailsList = new ArrayList<>();
    
    private ListView mListView;
    
    private DetailsAdapter adapter;
    
    public FragmentDetails() {
        // Required empty public constructor
    }
    
    
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        // Inflate the layout for this fragment
        View rootView = inflater.inflate(R.layout.fragment_details, container, false);
    
        //get an instance of our listview
        mListView = (ListView)rootView.findViewById(R.id.frag_details_listView);
    
        //Get the data here!!
        MyDBHandler dbHandler = new MyDBHandler(getActivity().getApplicationContext());
        detailsList = dbHandler.getAllDetails();
    
        //Initiate our adapter
        adapter = new DetailsAdapter(getActivity().getApplicationContext(), R.layout.row_details, detailsList);
    
        //set adapter to the listview
        if(adapter != null){
            mListView.setAdapter(adapter);
        }
    
        return rootView;
    
    }
    
    
    }
    

    NOTE !!

    In your MyDbHandler class include another constructor which takes only the context as a parameter like so :

    public MyDBHandler(Context context){
        super(context, DATABASE_NAME, null, DATABASE_VERSION);
    }
    

    Your good to go ..run the project

    With this procedure you can create any type of listviews in android