Dayem Saeed
Dayem Saeed

Reputation: 380

Can't successfully retrieve Spinner selected item text from database to fill contact list item in my app using cursor

My app has a registration screen for blood donors and the blood type field is a spinner. I save all the donor information in an SQLite database. Now I need to retrieve it and show it for a list showing all the registered blood donors with their blood types.

How can I do that?

I've attached all my code below. The main problems appear in RegisterActivity.java and DonorList.java.

RegisterActivity.java

import android.content.Intent;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.View;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Spinner;
import android.widget.Toast;

public class RegisterActivity extends AppCompatActivity {

    EditText edtname, edtnumber;
    Spinner spblood;
    Button btnregister, btnlist;

    public static SQLiteHelper sqLiteHelper;

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

        init();

        Spinner spinner = findViewById(R.id.blood_selector);
        // Create an ArrayAdapter using the string array and a default spinner layout
        ArrayAdapter<CharSequence> adapter = ArrayAdapter.createFromResource(this,
                R.array.blood_type, android.R.layout.simple_spinner_item);
        // Specify the layout to use when the list of choices appears
        adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
        // Apply the adapter to the spinner
        spinner.setAdapter(adapter);

        sqLiteHelper = new SQLiteHelper(this, "Donors.sqlite", null, 1);

        sqLiteHelper.queryData("CREATE TABLE IF NOT EXISTS DONORS (Id INTEGER PRIMARY KEY AUTOINCREMENT, name VARCHAR, number VARCHAR, blood VARCHAR)");

        btnregister.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                try {
                    sqLiteHelper.insertData(
                            edtname.getText().toString().trim(),
                            edtnumber.getText().toString().trim(),
                            spblood
                    );
                }
                catch (Exception e) {
                    e.printStackTrace();
                }
            }
        });

        btnlist.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent intent = new Intent(RegisterActivity.this, DonorList.class);
                startActivity(intent);
            }
        });

    }

    private void init() {
        edtname = findViewById(R.id.name_input);
        edtnumber = findViewById(R.id.numberinput);
        spblood = findViewById(R.id.blood_selector);
        btnregister = findViewById(R.id.register_button);
        btnlist = findViewById(R.id.list_button);
    }

}

DonorList.java

import android.database.Cursor;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v7.app.AppCompatActivity;
import android.widget.ListView;
import android.widget.Spinner;

import java.util.ArrayList;

public class DonorList extends AppCompatActivity {

    ListView listView;
    ArrayList<Donor> list;
    DonorListAdapter adapter = null;

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

        listView = (ListView) findViewById(R.id.contacts_list);
        list = new ArrayList<>();
        adapter = new DonorListAdapter(this, R.layout.activity_main, list);
        listView.setAdapter(adapter);

        Cursor cursor = RegisterActivity.sqLiteHelper.getData("SELECT * FROM DONORS");
        list.clear();
        while (cursor.moveToNext()) {
            String name = cursor.getString(1);
            String number = cursor.getString(2);
            String blood = cursor.getString(3);

            list.add(new Donor(name, number, blood));
        }

        adapter.notifyDataSetChanged();
    }
}

Donor.java

import android.widget.Spinner;

public class Donor {
    private String name;
    private String number;
    private Spinner blood;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getNumber() {
        return number;
    }

    public void setNumber(String number) {
        this.number = number;
    }

    public Spinner getBlood() {
        return blood;
    }

    public void setBlood(Spinner blood) {
        this.blood = blood;
    }

    public Donor(String name, String number, Spinner blood) {

        this.name = name;
        this.number = number;
        this.blood = blood;
    }
}

SQLiteHelper.java

import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.database.sqlite.SQLiteStatement;
import android.widget.Spinner;

public class SQLiteHelper extends SQLiteOpenHelper {

    public SQLiteHelper(Context context, String name, SQLiteDatabase.CursorFactory factory, int version) {
        super(context, name, factory, version);
    }

    public void queryData(String sql) {
        SQLiteDatabase database = getWritableDatabase();
        database.execSQL(sql);
    }

    public void insertData(String name, String number, Spinner blood) {
        SQLiteDatabase database = getWritableDatabase();
        String sql = "INSERT INTO DONORS (name, number, blood) values (?, ?, ?)";

        SQLiteStatement statement = database.compileStatement(sql);
        statement.clearBindings();

        statement.bindString(1, name);
        statement.bindString(2, number);
        statement.bindString(3, blood.getSelectedItem().toString());

        statement.executeInsert();
    }

    public Cursor getData(String sql) {
        SQLiteDatabase database = getReadableDatabase();
        return database.rawQuery(sql, null);
    }
}

DonorListAdapter.java

import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.TextView;

import java.util.ArrayList;

public class DonorListAdapter extends BaseAdapter {

    private Context context;
    private int layout;
    private ArrayList<Donor> donorList;

    public DonorListAdapter(Context context, int layout, ArrayList<Donor> donorList) {
        this.context = context;
        this.layout = layout;
        this.donorList = donorList;
    }

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

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

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

    private class ViewHolder {
        TextView txtname, txtnumber, txtblood;
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {

        View row = convertView;
        ViewHolder holder = new ViewHolder();

        if (row == null) {
            LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
            if (inflater != null) {
                row = inflater.inflate(layout, null);
            }

            if (row != null) {
                holder.txtname = row.findViewById(R.id.name_input);
            }
            if (row != null) {
                holder.txtnumber = row.findViewById(R.id.numberinput);
            }
            if (row != null) {
                holder.txtblood = (TextView) row.findViewById(R.id.blood_selector);
            }
            if (row != null) {
                row.setTag(holder);
            }
        }
        else {
            holder = (ViewHolder) row.getTag();
        }

        Donor donor = donorList.get(position);

        holder.txtname.setText(donor.getName());
        holder.txtnumber.setText(donor.getNumber());
        holder.txtblood.setText(donor.getBlood().toString());

        return row;
    }
}

activity_main.xml

<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.lumen.dayem.blooddonor.MainActivity">


    <ListView
        android:id="@+id/contacts_list"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:choiceMode="singleChoice">

    </ListView>

</LinearLayout>

activity_register.xml

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

    <EditText
        android:id="@+id/name_input"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:hint="@string/person_name"
        android:ems="10"
        android:inputType="textCapWords"
        android:layout_marginBottom="5sp" />

    <EditText
        android:id="@+id/numberinput"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:hint="@string/hint"
        android:ems="10"
        android:inputType="phone"
        android:layout_marginBottom="5sp" />

    <TextView
        android:id="@+id/blood"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="@string/blood_type"
        android:layout_marginBottom="10sp"/>

    <Spinner
        android:id="@+id/blood_selector"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:entries="@array/blood_type"
        android:prompt="@string/blood_select"
        android:layout_marginBottom="5sp"/>

    <Button
        android:id="@+id/register_button"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@string/register" />

    <Button
        android:id="@+id/list_button"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@string/show_donors" />

</LinearLayout>

contact_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">

    <TextView
        android:id="@+id/contact_name"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:text="@string/contact_name"
        android:textSize="22sp"/>

    <TextView
        android:id="@+id/contact_number"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:textAppearance="?android:textAppearanceSmall"
        android:text="@string/contact_number"
        android:layout_alignParentTop="true"
        android:layout_alignParentLeft="true"
        android:layout_alignParentStart="true"
        android:layout_marginLeft="29sp"
        android:layout_marginStart="29sp"
        android:layout_marginTop="31sp" />

    <TextView
        android:id="@+id/contact_blood"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:textAppearance="?android:textAppearanceMedium"
        android:text="@string/blood_type"
        android:layout_alignParentTop="true"
        android:layout_alignParentLeft="true"
        android:layout_alignParentStart="true"
        android:layout_marginLeft="300sp"
        android:layout_marginStart="300sp"
        android:layout_marginTop="30sp"/>

</RelativeLayout>

Upvotes: 0

Views: 70

Answers (1)

B&#246; macht Blau
B&#246; macht Blau

Reputation: 13009

Your class Donor seems to have a field blood of type Spinner. I changed the type to String because a data class should not contain any Views:

public class Donor
{
    private String name;
    private String number;
    private String blood;

   // Getters and Setters here...

   public Donor(String name, String number, String blood) {
        this.name = name;
        this.number = number;
        this.blood = blood;
    }
}

The SQLiteHelper should have a static getInstance() method so you can avoid having it as a static field in RegisterActivity. Also, I think that the database setup should be encapsulated. The Activity does not need to know anything about the database implementation. So I moved the DDL to the SQLiteHelper's onCreate() and dropped queryData(). For the same reason, I changed getData(String sql) to getDonors(). Lastly, insertData() should take data as parameters not Views. So one should not pass the Spinner but the selected item's value.

My version of SQLiteHelper.java:

public class SQLiteHelper extends SQLiteOpenHelper{
    private static SQLiteHelper sqliteHelper;
    private static String dbName = "Donors.sqlite";
    private static int version = 1;

    private static final String CREATE_TABLE_DONORS = "CREATE TABLE IF NOT EXISTS DONORS (Id INTEGER PRIMARY KEY AUTOINCREMENT, name VARCHAR, number VARCHAR, blood VARCHAR)";

    /**
     * We use the application Context under the hood because this helps to avoid Exceptions
     * @param ctx
     */
    private SQLiteHelper(Context ctx){
        super(ctx.getApplicationContext(), dbName, null, version);
    }

    /**
     * SQLiteHelper as a Singleton
     * @param ctx any Context
     * @return x
     */
    public static SQLiteHelper getInstance(Context ctx)
    {
        if(sqliteHelper == null){
            sqliteHelper = new SQLiteHelper(ctx);
        }
        return sqliteHelper;
    }

    @Override
    public void onCreate(SQLiteDatabase db)
    {
        db.execSQL(CREATE_TABLE_DONORS);
    }

    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion)
    {
        // necessary if you have a new database version
    }

    public void insertData(String name, String number, String blood) {
        SQLiteDatabase database = getWritableDatabase();
        String sql = "INSERT INTO DONORS (name, number, blood) values (?, ?, ?)";

        SQLiteStatement statement = database.compileStatement(sql);
        statement.clearBindings();

        statement.bindString(1, name);
        statement.bindString(2, number);
        statement.bindString(3, blood);

        statement.executeInsert();
    }

    public Cursor getDonors() {
        String sql = "SELECT * FROM DONORS";
        SQLiteDatabase database = getReadableDatabase();
        return database.rawQuery(sql, null);
    }
}

The updated RegisterActivity.java (note that I got rid of the local variable spinner and only used spblood):

public class RegisterActivity extends AppCompatActivity
{
    private EditText edtname, edtnumber;
    private Spinner spblood;
    private Button btnregister, btnlist;
    private SQLiteHelper sqLiteHelper;

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

        init();

        ArrayAdapter<CharSequence> adapter = ArrayAdapter.createFromResource(this,
                R.array.blood_type, android.R.layout.simple_spinner_item);
        adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
        spblood.setAdapter(adapter);

        sqLiteHelper = SQLiteHelper.getInstance(this);

        btnregister.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                try {
                        sqLiteHelper.insertData(
                        edtname.getText().toString().trim(),
                        edtnumber.getText().toString().trim(),
                        spblood.getSelectedItem().toString()
                    );
                }
                catch (Exception e) {
                    e.printStackTrace();
                }
            }
        });

        btnlist.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent intent = new Intent(RegisterActivity.this, DonorList.class);
                startActivity(intent);
            }
        });
    }

    private void init() {
        edtname = findViewById(R.id.name_input);
        edtnumber = findViewById(R.id.numberinput);
        spblood = findViewById(R.id.blood_selector);
        btnregister = findViewById(R.id.register_button);
        btnlist = findViewById(R.id.list_button);
    }
}

The changes to DonorList and the Adapter are due to the changes I made to SQLiteHelper and Donor. In addition to that, you need to pass the resource id of the list row to the Adapter's Constructor not the resource id of the Activity's layout. Similarly, the R.id.... values for the TextViews in the list row have to match those in contact_item.xml

DonorList.java

public class DonorList extends AppCompatActivity
{
    private ListView listView;
    private ArrayList<Donor> list;
    private DonorListAdapter adapter = null;

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

        listView = (ListView) findViewById(R.id.contacts_list);
        list = new ArrayList<>();
        adapter = new DonorListAdapter(this, R.layout.contact_item, list);
        listView.setAdapter(adapter);

        Cursor cursor = SQLiteHelper.getInstance(this).getDonors();
        list.clear();
        while (cursor.moveToNext()) {
            String name = cursor.getString(1);
            String number = cursor.getString(2);
            String blood = cursor.getString(3);

            list.add(new Donor(name, number, blood));
        }

        adapter.notifyDataSetChanged();
    }
}

And finally, the Adapter:

public class DonorListAdapter extends BaseAdapter
{

    private Context context;
    private int layout;
    private ArrayList<Donor> donorList;

    public DonorListAdapter(Context context, int layout, ArrayList<Donor> donorList) {
        this.context = context;
        this.layout = layout;
        this.donorList = donorList;
    }

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

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

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

    private class ViewHolder {
        TextView txtname, txtnumber, txtblood;
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {

        View row = convertView;
        if (row == null) {
            ViewHolder holder = new ViewHolder();
            row = LayoutInflater.from(context).inflate(layout, null);
            holder.txtname = (TextView)row.findViewById(R.id.contact_name);
            holder.txtnumber = (TextView)row.findViewById(R.id.contact_number);
            holder.txtblood = (TextView) row.findViewById(R.id.contact_blood);
            row.setTag(holder);
        }

        ViewHolder viewHolder = (ViewHolder) row.getTag();
        Donor donor = donorList.get(position);

        viewHolder.txtname.setText(donor.getName());
        viewHolder.txtnumber.setText(donor.getNumber());
        viewHolder.txtblood.setText(donor.getBlood());
        return row;
    }
}

Enjoy!

Upvotes: 1

Related Questions