An Android Sqlite Adapter that Works for Fundometer and StoreNav

I will be the first to admit that when I first started working on Fundometer in late 2013, I didn’t really know how SQLite worked in Android. I had never used it before. Through both online examples and my own tinkering, I learned a lot. All of the testing I did on StoreNav provided an even better opportunity to find something that worked and I could use for everything I needed to. If you search online for Android SQLite adapters, you will find all sorts of different solutions. The need to transfer StoreNav have to my business partner really spurred me too find the best method and use that as much as possible to route all my apps. I think I’ve done it now. Here is an example of what I’ve put together (some things have been changed to protect the integrity of our available apps).

1. The main menu list activity

 package com.gbapps.databaseexample;

import java.util.ArrayList;
import android.os.Bundle;
import android.preference.PreferenceManager;
import com.gbapps.databaseexample.R;

import android.app.AlertDialog;
import android.app.ListActivity;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.SharedPreferences;
import android.database.Cursor;
import android.util.Log;
import android.view.ContextMenu;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.ContextMenu.ContextMenuInfo;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.ListView;
import android.widget.SimpleCursorAdapter;
import android.widget.Toast;
import android.widget.AdapterView.AdapterContextMenuInfo;

public class Welcome extends ListActivity {

 private static final int RESULT_SETTINGS = 1;
 private static final int ACTIVITY_CREATE=0;
 private static final int ACTIVITY_EDIT=1;
 
 private ThermometersDbAdapter mDbHelper;
 private ListView thermsList;
 private ArrayList<Long> mItems; 
 int countThermometers;
 int shouldRate;
 
 @Override
 public void onCreate(Bundle savedInstanceState) {
 super.onCreate(savedInstanceState);
 setContentView(R.layout.activity_welcome); //Standard way of linking the xml layout to the activity
 thermsList = (ListView) findViewById(android.R.id.list);
 mItems = new ArrayList<Long>();
 mDbHelper = new ThermometersDbAdapter (this, mItems); //Creating an instance of ThermometersDbAdapter
 mDbHelper.open();
 fillData(); //Populating the list from the database (see method below)
 registerForContextMenu(getListView()); //Build-in method to allow for a long-press menu on the list
 Button b = (Button) findViewById(R.id.topbutton);
 countThermometers = thermsList.getCount(); //Get the number of thermometers
 mDbHelper.close(); 
 // Log.d("Initial MSG", "database closed");
 b.setOnClickListener(new OnClickListener() {
 // If the user clicks on the button, start the process to add a thermometer (defined in method below)
 @Override
 public void onClick(View v) {
 AddThermometers();
 }
 });
 }
 
 private void AddThermometers() {
 countThermometers = thermsList.getCount();
 // Log.d("Creating thermometer, you will have:", String.valueOf(countThermometers));
 if (premiumAllowed()!=true){
//TODO: DIALOG HERE PROMPTING THE USER TO UPGRADE
// AlertDialog.Builder builder = new AlertDialog.Builder(Welcome.this);
 Toast.makeText(this, "Thermometer limit reached", Toast.LENGTH_SHORT);
/* builder.setMessage(R.string.dialog_upgrade);
 builder.setCancelable(true);
 
 builder.setPositiveButton(R.string.dialog_upgrade_positive, new android.content.DialogInterface.OnClickListener() {
 @Override
 public void onClick(DialogInterface dialog, int which) {
 dialog.cancel();
 Intent appButton = new Intent(Welcome.this, UpgradeActivity.class);
 startActivity(appButton);
 }});
 
 builder.setNegativeButton(R.string.dialog_upgrade_negative, new android.content.DialogInterface.OnClickListener() {
 @Override
 public void onClick(DialogInterface dialog, int which) {
 dialog.cancel();
 }});
 AlertDialog alertDialog = builder.create();
 
 // show it
 alertDialog.show(); 
 */} else {
 createReminder();
 countThermometers = thermsList.getCount();
 } 
 } 
 
 @Override
 protected void onResume(){
 super.onResume();
 fillData(); 
 // Log.d("Initial MSG", "database closed (onResume)");
 }

 private void fillData() {
 //Fills the list view (all of the real work is done in the Adapter class)
 // Log.d("Welcome Method MSG", "fillData started");
 mDbHelper.open();
 thermsList.setAdapter(mDbHelper);
 }

 @Override
 protected void onListItemClick(ListView l, View v, int position, long id) {
 // Called when an item on the list is tapped
 super.onListItemClick(l, v, position, id);
 String item = l.getItemAtPosition(position).toString();
 Log.d("SELECT: on item click pos:", String.valueOf(position));
 Log.d("SELECT: on item click id:", String.valueOf(id));
 Log.d("onListItemClick MSG", item+" selected");
 Long Coord = mDbHelper.fetchReminderFromName(id);
 if (Coord != null){
 Long completion = Coord;
 
 Intent i = new Intent(this, SetupNewActivity.class);
 Log.d("thermID Selected", String.valueOf(completion));
 i.putExtra(ThermometersDbAdapter.KEY_ROWID, completion);
 startActivityForResult(i, ACTIVITY_EDIT);
 } else {
 Toast.makeText(this, R.string.error_database, Toast.LENGTH_SHORT).show();
 }
 }
 
 @Override
 public boolean onCreateOptionsMenu(Menu menu) {
 // Inflate the menu; this adds items to the action bar if it is present.
 getMenuInflater().inflate(R.menu.welcome, menu);
 return true;
 }
 
 @Override
 public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) {
 super.onCreateContextMenu(menu, v, menuInfo);
 getMenuInflater().inflate(R.menu.list_menu_item_longpress, menu);
 }

 @Override
 public boolean onMenuItemSelected(int featureId, MenuItem item) {
 switch(item.getItemId()) {
 case R.id.menu_insert:
 AddThermometers();
 return true;
 case R.id.action_settings:
// Intent i = new Intent(this, SettingsActivity.class); // SETTINGS ACTIVITY NOT CREATED YET
 // startActivityForResult(i, RESULT_SETTINGS);
 return true;
 }
 return super.onMenuItemSelected(featureId, item);
 }

 private void createReminder() {
 Intent i = new Intent(this, SetupNewActivity.class);
 startActivityForResult(i, ACTIVITY_CREATE);
 
 }
 
 @Override
 protected void onActivityResult(int requestCode, int resultCode, Intent intent){
 super.onActivityResult(requestCode, resultCode, intent);
 
 fillData();
 }
 
 @Override
 public boolean onContextItemSelected(final MenuItem item) {

 switch(item.getItemId()) {
 case R.id.menu_edit:
 //edit the entry in the edit activity
 AdapterContextMenuInfo info2 =
 (AdapterContextMenuInfo) item.getMenuInfo();
 Long Coord = mDbHelper.fetchReminderFromName(info2.id); //Get the database ID from the list ID
 if (Coord != null){
 
 Intent i = new Intent(this, SetupNewActivity.class); //Create an intent to start the setup activity
 i.putExtra(ThermometersDbAdapter.KEY_ROWID, Coord);
 Log.d("Edit ID Selected", String.valueOf(Coord));
 startActivityForResult(i, ACTIVITY_EDIT); //Start the activity based on the intent
 
 } else {
 Toast.makeText(this, R.string.error_database, Toast.LENGTH_SHORT).show();
 }

 return true;
 
 
 case R.id.menu_delete:
 //delete the entry
 Log.d("InputMSG", "button delete pressed");
 
 // Create an alert to confirm the user really wants to delete the entry
 AlertDialog.Builder builder = new AlertDialog.Builder(this);
 builder.setMessage(R.string.dialog_delete);
 builder.setCancelable(true);
 
 builder.setPositiveButton(R.string.dialog_delete_positive, new android.content.DialogInterface.OnClickListener() {
 @Override
 public void onClick(DialogInterface dialog, int which) {
 // if yes, get the row id and tell the Adapter to delete the entry
 AdapterContextMenuInfo info =
 (AdapterContextMenuInfo) item.getMenuInfo();
 Long Coord = mDbHelper.fetchReminderFromName(info.id); //Get the database ID from the list ID
 Log.d("Delete ID Selected", String.valueOf(info.id));
 Log.d("Delete ID Selected 2", String.valueOf(Coord));
 mDbHelper.open();
 mDbHelper.deleteReminder(Coord);
 fillData();
 dialog.cancel();
 }});
 
 builder.setNegativeButton(R.string.dialog_delete_negative, new android.content.DialogInterface.OnClickListener() {
 @Override
 public void onClick(DialogInterface dialog, int which) {
 //If no, cancel the dialog and do nothing
 dialog.cancel();
 }});
 AlertDialog alertDialog = builder.create();
 
 // show the alert
 alertDialog.show(); 
 return true;
 }
 return super.onContextItemSelected(item);
 }
 
 boolean premiumAllowed(){
 //In a real app, this would call an in-app purchase related method
 return true; 
 }
}

2. The display/setup activity

package com.gbapps.databaseexample;

import java.util.ArrayList;
import com.gbapps.databaseexample.R;

import android.os.Bundle;
import android.app.Activity;
import android.content.Intent;
import android.content.SharedPreferences;
import android.database.Cursor;
import android.graphics.Bitmap;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ImageView;
import android.widget.Spinner;
import android.widget.TextView;
import android.widget.Toast;
import android.widget.AdapterView.OnItemSelectedListener;

public class SetupNewActivity extends Activity implements OnItemSelectedListener {

 private EditText mTitleText;
 private Button mConfirmButton;
 private EditText mMaxText;
 private EditText mCurrText;
 ThermometersDbAdapter mDbHelper;
 private Long mRowId;
 String mThermname;
 String mBkgname;
 Spinner spinner;
 Spinner spinner2;
 ArrayList<String> thermometers_available;
 ArrayList<String> backgrounds_available;
 ArrayAdapter<String> adapter;
 ArrayAdapter<String> adapter2;

 
 @Override
 protected void onCreate(Bundle savedInstanceState) {
 super.onCreate(savedInstanceState);
 
 mDbHelper = new ThermometersDbAdapter(this);
 setContentView(R.layout.activity_setup_new); //Standard way of linking the xml layout to the activity
 registerAllViews();
 
 mRowId = savedInstanceState != null
 ? savedInstanceState.getLong(ThermometersDbAdapter.KEY_ROWID) : null;
 
 registerButtonListenersAndSetDefautText();
 }
 
 private void registerAllViews() {
 
 //defining the buttons
 mConfirmButton = (Button) findViewById(R.id.confirm);
 mTitleText = (EditText) findViewById(R.id.title);
 mMaxText = (EditText) findViewById(R.id.max);
 mCurrText = (EditText) findViewById(R.id.curr);
 
 //Adding options to the dropdown spinners
 thermometers_available = new ArrayList<String>();
 thermometers_available.add("red");
 thermometers_available.add("yellow");
 thermometers_available.add("blue");

 backgrounds_available = new ArrayList<String>();
 backgrounds_available.add("bkg_white");
 backgrounds_available.add("bkg_dark_grey");
 backgrounds_available.add("bkg_silver");
 backgrounds_available.add("bkg_goldscale");
 backgrounds_available.add("bkg_redscale");
 backgrounds_available.add("bkg_sky_blue");
 
 spinner = (Spinner) findViewById(R.id.spinner1);
 spinner.setOnItemSelectedListener(this);
 spinner2 = (Spinner) findViewById(R.id.spinner2);
 spinner2.setOnItemSelectedListener(this);
 // Create an ArrayAdapter using the string array and a default spinner layout
 adapter = new ArrayAdapter<String>(this,
 android.R.layout.simple_spinner_item, thermometers_available);
 adapter2 = new ArrayAdapter<String>(this,
 android.R.layout.simple_spinner_item, backgrounds_available);
 // Specify the layout to use when the list of choices appears
 adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
 adapter2.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
 // Apply the adapter to the spinner
 spinner.setAdapter(adapter);
 spinner2.setAdapter(adapter2);
 }

 private void setRowIdFromIntent() {
 if (mRowId == null) {
 Bundle extras = getIntent().getExtras();
 mRowId = extras != null ? extras.getLong(ThermometersDbAdapter.KEY_ROWID) : null;
 }
 }
 
 @Override
 protected void onPause() {
// Log.d("Setup OnPause", "onPause initiated");
 if (mTitleText.getText().toString().matches("")){
 mTitleText.setText("0");}
 if (mMaxText.getText().toString().matches("")){
 mMaxText.setText("0");}
 if (mCurrText.getText().toString().matches("")){
 mCurrText.setText("0");}
 // dbHelper Close() moved to saveState
 super.onPause();
 /*Log.d("Setup OnPause", "before save state");
 saveState(); not necessary here because it is called from onSaveInstanceState
 Log.d("Setup OnPause", "state saved");*/
 } 
 
 @Override
 protected void onResume(){
 super.onResume();
 mDbHelper.open();
 registerAllViews();
 registerButtonListenersAndSetDefautText();
 setRowIdFromIntent();
 try {
 populateFields();
 } catch (java.text.ParseException e) {
 Log.e("ReminderEditActivity", e.getMessage(), e);
 e.printStackTrace();
 }
 }

 private void registerButtonListenersAndSetDefautText() {
 //Defines what happens when the confirm button is clicked
 mConfirmButton.setOnClickListener(new View.OnClickListener() {
 @Override
 public void onClick(View v) {
 if (mTitleText.getText().toString().matches("") || mMaxText.getText().toString().matches("") || 
 mCurrText.getText().toString().matches("")){
 Toast.makeText(SetupNewActivity.this, "Please ensure all entries are filled", Toast.LENGTH_SHORT).show();
 
 if (mTitleText.getText().toString().matches("")){
 mTitleText.setText("0");}
 if (mMaxText.getText().toString().matches("")){
 mMaxText.setText("0");}
 if (mCurrText.getText().toString().matches("")){
 mCurrText.setText("0");}
 
 } 
 saveState();
 setResult(RESULT_OK);
 Toast.makeText(SetupNewActivity.this, getString(R.string.task_saved_message), Toast.LENGTH_SHORT).show();
 mDbHelper.close();
 finish();
 }
 });
 }
 
 private void populateFields() throws java.text.ParseException {
 // populates the forms if mRowId is not null (i.e. if this is an existing entry) ---------------POPULATE FIELDS-----------------
 if (mRowId != null) {
 Log.d("MRowId in Setup", String.valueOf(mRowId));
 Cursor reminder = mDbHelper.fetchReminder(mRowId);
 if (reminder.moveToFirst()){
 startManagingCursor(reminder);
 //Sets the text of the title using the Cursor by getting the column index
 mTitleText.setText(reminder.getString(
 reminder.getColumnIndexOrThrow(ThermometersDbAdapter.KEY_TITLE)));
// Log.d("Pop fields Title Text check", mTitleText.getText().toString());
 mMaxText.setText(reminder.getString(
 reminder.getColumnIndexOrThrow(ThermometersDbAdapter.KEY_MAX)));//
// Log.d("Pop fields Max Text check", mMaxText.getText().toString());
 mCurrText.setText(reminder.getString(
 reminder.getColumnIndexOrThrow(ThermometersDbAdapter.KEY_CURR)));
// Log.d("Pop fields Curr Text check", mCurrText.getText().toString());
 
 //Setting the dropdown spinner text to match previously made selection
 String sp1text = reminder.getString(
 reminder.getColumnIndexOrThrow(ThermometersDbAdapter.KEY_THERM_NAME));
// Log.d("Pop fields SPINNER check", sp1text);
 spinner.setSelection(adapter.getPosition(sp1text));
 spinner2.setSelection(adapter2.getPosition(reminder.getString(
 reminder.getColumnIndexOrThrow(ThermometersDbAdapter.KEY_BKG_NAME))));
// Log.d("Pop fields SPINNER check", "Risky spinner code finished");

 Log.d("Populate Fields", "Populate fields complete");
 stopManagingCursor(reminder);
 }else {
 Toast.makeText(this, R.string.error_database , Toast.LENGTH_SHORT).show();
 }
 }
 }
 
 @Override
 protected void onSaveInstanceState(Bundle outState) { //Called automatically when the app state needs to be saved (i.e, another screen is opened)
// Log.d("Setup OnSaveInstanceState", "state save started");
 super.onSaveInstanceState(outState);
 saveState();
 outState.putLong(ThermometersDbAdapter.KEY_ROWID, mRowId); //Saves the current rowId so the screen loads properly when the user comes back to it
 }
 
 private void saveState() {
 //------------------------------------------------ SAVE STATE METHOD ----------------------

 String title = mTitleText.getText().toString();
 String max = mMaxText.getText().toString();
 String curr = mCurrText.getText().toString();
 try {
 float Nummax = Float.parseFloat(mMaxText.getText().toString());
 float Numcurr = Float.parseFloat(mCurrText.getText().toString());
 max = String.valueOf(Nummax);
 curr = String.valueOf(Numcurr);
 } catch (Exception e) {
 e.printStackTrace();
 }
 max =max.replace(",", ".");
 curr = curr.replace(",", ".");
 String thermname = mThermname;
 String bkgname = mBkgname;
// Log.d("Setup SaveState thermname", mThermname);
// Log.d("Setup SaveState bkg", mBkgname);
 
 if (mRowId == null) {
// Log.d("Setup SaveState", "mRowId is null so item is new");
 Toast.makeText(this, "creating new entry " + title + max+ curr, Toast.LENGTH_LONG).show();
 // if the mRowId is null, it means that no row Id could be found in saved instance state or the intent
 //therefore the task is considered new
 long id = mDbHelper.createReminder(title, max, curr, thermname, bkgname, "CurrentPhotoPath");
 //a new task is created in the database
 if (id > 0) {
 
 mRowId = id;
 }
 } else {
// Log.d("Setup SaveState", "mRowId is not null, update reminder");
 Toast.makeText(this, "adding to existing entry", Toast.LENGTH_SHORT).show();
 mDbHelper.updateReminder(mRowId, title, max, curr, thermname, bkgname, "CurrentPhotoPath");
 }
 mDbHelper.close();
 } 
 
 @Override
 public boolean onCreateOptionsMenu(Menu menu) {
 // Inflate the menu; this adds items to the action bar if it is present.
 getMenuInflater().inflate(R.menu.setup_new, menu);
 return true;
 }

 @Override
 public void onItemSelected(AdapterView<?> parent, View view, 
 int pos, long id) {
 // An item was selected. You can retrieve the selected item using
 
 Spinner spinner = (Spinner) parent;
 if(spinner.getId() == R.id.spinner1)
 {
// Log.d("Spinner Interface pos1", String.valueOf(pos));
 mThermname = parent.getItemAtPosition(pos).toString();
// Log.d("Spinner Interface", "Thermometer selected is");
// Log.d("Spinner Interface", mThermname); 
 return; 
 }
 else if(spinner.getId() == R.id.spinner2)
 {
 mBkgname = parent.getItemAtPosition(pos).toString(); //Background has no effect in this example
// Log.d("Spinner Interface", "Background selected is");
// Log.d("Spinner Interface", mBkgname); 
 return; 
 }
 }

 @Override
 public void onNothingSelected(AdapterView<?> arg0) {
 // TODO Auto-generated method stub
 }
 @Override
 public boolean onMenuItemSelected(int featureId, MenuItem item) {
 switch(item.getItemId()) {
 case android.R.id.home:
 Intent intent = new Intent(this, Welcome.class);
 intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
 startActivity(intent);
 return true;
 case R.id.action_settings:
// Intent i = new Intent(this, SettingsActivity.class); // Settings activity not created in this example
// startActivityForResult(i, RESULT_SETTINGS);
 return true;
 
 }
 return super.onMenuItemSelected(featureId, item);
 }
}

3. The database adapter

package com.gbapps.databaseexample;

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

import android.app.Activity;
import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.SQLException;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
//import android.util.Log;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;


public class ThermometersDbAdapter extends BaseAdapter {
 private static final String DATABASE_NAME = "data";
 private static final String DATABASE_TABLE = "reminders";
 private static final int DATABASE_VERSION = 6; //Needs to be incremented every time a column is added to trigger onUpgrade
 
 //Setting the column names as constants so they can be referenced elsewhere
 static final String KEY_TITLE = "title";
 static final String KEY_MAX = "max";
 static final String KEY_CURR = "curr";
 static final String KEY_ROWID = "_id";
 static final String KEY_THERM_NAME = "thermname";
 static final String KEY_BKG_NAME = "bkgname";
 static final String KEY_PIC_FILENAME = "pic_filename";
 static String[] ALL_COLUMN_KEYS = { KEY_TITLE,
 KEY_MAX, KEY_CURR, KEY_THERM_NAME};
 
 private DatabaseHelper mDbHelper;
 private SQLiteDatabase mDb;
 private static LayoutInflater inflater=null;
 private List<Long> mList;
 
 // Creates the database by defining all of the column names
 private static final String DATABASE_CREATE =
 "create table " + DATABASE_TABLE + " (" + KEY_ROWID + " integer primary key, "
 + KEY_TITLE + " text not null," + KEY_MAX + " text not null," + KEY_CURR + " text not null," 
 + KEY_THERM_NAME + " text not null," + KEY_BKG_NAME + " text not null," + KEY_PIC_FILENAME + " text not null);";
 
 private final Context mCtx;
 
 public ThermometersDbAdapter(Activity ctx, ArrayList<Long> mItems) {
 this.mCtx = ctx;
 mList = mItems; 
 }
 public ThermometersDbAdapter(Context ctx) {
 this.mCtx = ctx;
 }
 
 public ThermometersDbAdapter open() throws SQLException {
 mDbHelper = new DatabaseHelper(mCtx);
 mDb = mDbHelper.getWritableDatabase();
 return this;
 }
 
 public void close() {
 mDbHelper.close();
 }
 
 public long createReminder(String title, String max, String curr, String thermname , String bkgname, String picFilename){
 ContentValues initialValues = new ContentValues();
 // Creates the database row using the given initial values
 initialValues.put(KEY_TITLE, title);
 initialValues.put(KEY_MAX, max);
 initialValues.put(KEY_CURR, curr);
 initialValues.put(KEY_THERM_NAME, thermname);
 initialValues.put(KEY_BKG_NAME, bkgname);
 initialValues.put(KEY_PIC_FILENAME, picFilename);
 
// Log.d("DB adapter title", title, +" "+ max +" "+ curr);
 return mDb.insert(DATABASE_TABLE, null, initialValues);
 // Returns the created row in the form of a long (row number)
 }
 
 public boolean deleteReminder(long rowId){
 // deletes a row from the database based on the WHERE arguments
 return mDb.delete(DATABASE_TABLE, KEY_ROWID + "=" + rowId, null) >0;
 }
 
 public Cursor fetchAllReminders() {
 //fetches all reminders
 return mDb.query(DATABASE_TABLE, new String[] {KEY_ROWID, KEY_TITLE,
 KEY_MAX, KEY_CURR, KEY_THERM_NAME, KEY_BKG_NAME, KEY_PIC_FILENAME}, null, null, null, null, null);
 }
 
 public Cursor fetchReminder(long rowId) throws SQLException {
 //fetches a reminder based on the WHERE arguments
 Cursor mCursor = mDb.query(true, DATABASE_TABLE, new String[] {KEY_ROWID, KEY_TITLE,
 KEY_MAX, KEY_CURR, KEY_THERM_NAME, KEY_BKG_NAME, KEY_PIC_FILENAME}, KEY_ROWID +"=" + rowId, null, null, null, null, null);
 if (mCursor != null) {
 mCursor.moveToFirst();
 }
 return mCursor;
 }
 
 public boolean updateReminder(long rowId, String title, String max, String curr, String thermname, String bkgname, String picFilename){
 ContentValues args = new ContentValues();
 args.put(KEY_TITLE, title);
 args.put(KEY_MAX, max);
 args.put(KEY_CURR, curr);
 args.put(KEY_THERM_NAME, thermname);
 args.put(KEY_BKG_NAME, bkgname);
 args.put(KEY_PIC_FILENAME, picFilename);
 //updates the specified row in the database with the given values
 return
 mDb.update(DATABASE_TABLE, args, KEY_ROWID + "=" + rowId, null)>0;
 }
 
 public Long fetchReminderFromName(long rowId) throws SQLException{
 //Returns the database rowId based on a given listView rowId (these are often not the same)
 String[] allColumns = { KEY_ROWID
// , KEY_TITLE
 };
 Cursor cursor = mDb.query(DATABASE_TABLE,
 allColumns, null, null, null, null, null);
 Long statement = null;
 if (cursor != null) {
 Log.d("fetchReminder","cursor is not null");
 Log.d("fetchReminder",String.valueOf(cursor.getCount())+" cursor counted");
 if(cursor.moveToPosition((int) rowId)){
 cursor.moveToPosition((int) rowId);
 statement = (cursor.getLong(
 cursor.getColumnIndexOrThrow(KEY_ROWID)));
 }}
 return statement; 
 }
 
 private static class DatabaseHelper extends SQLiteOpenHelper {
 DatabaseHelper(Context context) {
 super(context, DATABASE_NAME, null, DATABASE_VERSION);
// Log.d("DB Helper version #", String.valueOf(DATABASE_VERSION));
 }
 @Override
 public void onCreate(SQLiteDatabase db) {
 //Creates the database helper
// Log.d("DB Helper", "onCreate Called");
 db.execSQL(DATABASE_CREATE);
 }
 
 @Override
 public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
 // not used, but could upgrade database with ALTER scripts
 // If you need to add a column
// Log.d("DB Helper", "onUpgrade Called");
 if (newVersion > oldVersion) {
 db.execSQL("ALTER TABLE reminders ADD COLUMN pic_filename STRING DEFAULT noname");
 }
 }
 }

 @Override
 public int getCount() {
 // Returns the number of entries in the database
// return data.size();
 Cursor c = mDb.query(DATABASE_TABLE, new String[] {KEY_ROWID, KEY_TITLE,
 }, null, null, null, null, null);
 int count = 0;
 count = c.getCount();
 return count;
 }

 @Override
 public Object getItem(int position) {
 // TODO Auto-generated method stub
// return mList.get(position);
 return position;
 }

 @Override
 public long getItemId(int position) {
 // TODO Auto-generated method stub
 return position;
 }

 @Override
 public View getView(int position, View convertView, ViewGroup parent) {
 // Important component of BaseAdapter. This class defines the view for each list row.
View vi=convertView;
 
 if(convertView==null)
 inflater = (LayoutInflater)mCtx.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
 vi = inflater.inflate(R.layout.reminder_row, null); //POTENTIAL NULL POINTER
 
 TextView title = (TextView)vi.findViewById(R.id.text1); // title
 TextView current = (TextView)vi.findViewById(R.id.text2); // current amount
 TextView max = (TextView)vi.findViewById(R.id.text4); // maximum amount
 ImageView logoview = (ImageView)vi.findViewById(R.id.imageView1);
 
 String[] allColumns = { KEY_ROWID,
 KEY_TITLE, KEY_CURR, KEY_MAX, KEY_THERM_NAME}; //
 Cursor cursor = mDb.query(DATABASE_TABLE,
 allColumns, null, null, null, null, null);
 String[] statement = new String[4];
 if (cursor != null) {
 Log.d("fetchReminder","cursor is not null");
 Log.d("fetchReminder",String.valueOf(cursor.getCount())+"cursor counted");
 if(cursor.moveToPosition(position)){
 cursor.moveToPosition(position);
 statement[0] = (cursor.getString(
 cursor.getColumnIndexOrThrow(KEY_TITLE)));
 statement[1] = (cursor.getString(
 cursor.getColumnIndexOrThrow(KEY_CURR)));
 statement[2] = (cursor.getString(
 cursor.getColumnIndexOrThrow(KEY_MAX)));
 statement[3] = (cursor.getString(
 cursor.getColumnIndexOrThrow(KEY_THERM_NAME)));

 Log.d("LocalStores DB fetchReminder will return", statement[0]+ ", " + statement[1] + ", " + statement[2] 
 + ", " + statement[3]);
 title.setText(statement[0]);
 current.setText(statement[1]);
 max.setText(statement[2]);
 
 // Sets the logo at the side of the list view based on the string in the THERM_NAME column
 if(statement[3].matches("blue") || statement[3].matches("blue")){
 int bkgresId = mCtx.getResources().getIdentifier("ic_blue", "drawable", "com.gbapps.databaseexample");
 logoview.setImageResource(bkgresId);
 }
 if(statement[3].matches("yellow")){
 int bkgresId = mCtx.getResources().getIdentifier("ic_yellow", "drawable", "com.gbapps.databaseexample");
 logoview.setImageResource(bkgresId);
 }
 if(statement[3].matches("red")){
 int bkgresId = mCtx.getResources().getIdentifier("ic_red", "drawable", "com.gbapps.databaseexample");
 logoview.setImageResource(bkgresId);
 }
 }}
 return vi;
 }
}

4. Main menu layout

<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"
 android:orientation="vertical"
 android:background="#999999"
 tools:context=".ReminderListActivity" >

 <LinearLayout
 android:layout_width="match_parent"
 android:layout_height="wrap_content"
 android:layout_marginTop="4dp"
 android:background="@drawable/grey_rect"
 android:orientation="horizontal"
 android:padding="4dp" >

 <Button
 android:id="@+id/topbutton"
 android:layout_width="0dp"
 android:layout_height="wrap_content"
 android:layout_weight="30"
 android:drawableTop="@android:drawable/ic_menu_add"
 android:text="@string/menu_insert"
 android:background="@drawable/grey_selector"
 android:textSize="14sp" />

 </LinearLayout>
 
 
 <ListView android:id="@+id/android:list"
 android:layout_width="match_parent"
 android:layout_height="match_parent"
 android:layout_marginTop="4dp" />

 <LinearLayout
 android:id="@+id/android:empty"
 android:layout_width="match_parent"
 android:layout_height="wrap_content"
 android:orientation="vertical" >
 
 <TextView
 android:layout_width="wrap_content"
 android:layout_height="wrap_content"
 android:text="@string/no_reminders" />
 
 </LinearLayout>
</LinearLayout>

5. Display view layout

<ScrollView 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:background="#999999"
 >

<LinearLayout
 android:layout_width="fill_parent"
 android:layout_height="wrap_content"
 android:orientation="vertical" >

 <LinearLayout
 android:layout_width="match_parent"
 android:layout_height="wrap_content"
 android:orientation="vertical"
 android:layout_marginRight="4dp"
 android:layout_marginLeft="2dp"
 android:layout_marginTop="4dp" >

 <TextView
 android:id="@+id/TextView01"
 android:layout_width="wrap_content"
 android:layout_height="wrap_content"
 android:padding="2dp"
 android:text="@string/title" />

 <EditText
 android:id="@+id/title"
 android:hint="@string/title"
 android:layout_width="match_parent"
 android:layout_height="wrap_content"
 android:layout_marginLeft="2dp"
 android:layout_marginRight="6dp"
 >

 <requestFocus />
 </EditText>

 </LinearLayout>

 <ImageView
 android:id="@+id/imageView2"
 android:layout_width="wrap_content"
 android:layout_height="wrap_content"
 android:layout_gravity="center_horizontal"
 android:layout_marginBottom="-4dp"
 android:src="@drawable/divider_gold" />

 <LinearLayout
 android:layout_width="match_parent"
 android:layout_height="wrap_content"
 android:orientation="vertical"
 android:layout_marginRight="4dp"
 android:layout_marginLeft="2dp"
 >

 <TextView
 android:id="@+id/textView1"
 android:layout_width="wrap_content"
 android:layout_height="wrap_content"
 android:padding="2dp"
 android:text="@string/max" />

 <EditText
 android:id="@+id/max"
 android:layout_width="match_parent"
 android:layout_height="wrap_content"
 android:layout_marginLeft="2dp"
 android:layout_marginRight="6dp"
 android:hint="@string/max"
 android:gravity="top"
 android:inputType="numberSigned|numberDecimal"
 android:padding="2dp" />

 <ImageView
 android:id="@+id/imageView3"
 android:layout_width="wrap_content"
 android:layout_height="wrap_content"
 android:layout_gravity="center_horizontal"
 android:layout_marginBottom="-4dp"
 android:src="@drawable/divider_gold" />

 </LinearLayout>

 <LinearLayout
 android:layout_width="match_parent"
 android:layout_height="wrap_content"
 android:orientation="vertical"
 android:layout_marginRight="4dp"
 android:layout_marginLeft="2dp"
 >

 <TextView
 android:id="@+id/textView2"
 android:layout_width="wrap_content"
 android:layout_height="wrap_content"
 android:padding="2dp"
 android:text="@string/curr" />

 <EditText
 android:id="@+id/curr"
 android:layout_width="match_parent"
 android:layout_height="wrap_content"
 android:layout_marginLeft="2dp"
 android:layout_marginRight="6dp"
 android:inputType="numberSigned|numberDecimal"
 android:padding="2dp" />

 <ImageView
 android:id="@+id/imageView4"
 android:layout_width="wrap_content"
 android:layout_height="wrap_content"
 android:layout_gravity="center_horizontal"
 android:layout_marginBottom="-4dp"
 android:src="@drawable/divider_gold" />
 </LinearLayout>

 <LinearLayout
 android:layout_width="match_parent"
 android:layout_height="wrap_content"
 android:orientation="vertical"
 android:layout_marginBottom="4dp" >

 <TextView
 android:id="@+id/textView3"
 android:layout_width="wrap_content"
 android:layout_height="wrap_content"
 android:layout_marginRight="4dp"
 android:layout_marginLeft="2dp"
 android:padding="3dp"
 android:text="@string/set_therm_name" />

 <LinearLayout
 android:layout_width="match_parent"
 android:layout_height="wrap_content"
 android:padding="2dp"
 android:layout_marginRight="4dp"
 android:layout_marginLeft="2dp" >

 <Spinner
 android:id="@+id/spinner1"
 android:layout_width="160dp"
 android:layout_height="wrap_content"
 android:layout_weight="1" />

 <Spinner
 android:id="@+id/spinner2"
 android:layout_width="160dp"
 android:layout_height="wrap_content"
 android:layout_weight="1" />
 </LinearLayout>

 <TextView
 android:id="@+id/textSetupSale"
 android:layout_width="wrap_content"
 android:layout_height="wrap_content"
 android:text=""
 android:textAppearance="?android:attr/textAppearanceSmall"
 android:visibility="gone" />
 </LinearLayout>

 <LinearLayout
 android:layout_width="match_parent"
 android:layout_height="wrap_content"
 android:orientation="vertical"
 android:layout_marginTop="4dp"
 android:layout_marginBottom="4dp"
 android:background="@drawable/grey_rect" >

 <Button
 android:id="@+id/confirm"
 android:layout_width="match_parent"
 android:layout_height="wrap_content"
 android:layout_marginLeft="4dp"
 android:layout_marginRight="4dp"
 android:drawableLeft="@android:drawable/ic_menu_save"
 android:drawableRight="@android:drawable/ic_menu_save"
 android:text="@string/confirm"
 android:background="@drawable/grey_selector" />
 </LinearLayout>

</LinearLayout> 
</ScrollView>

6. List row layout

<?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="wrap_content"
 android:gravity="center_vertical"
 android:orientation="horizontal" >
 
 <RelativeLayout
 android:layout_width="match_parent"
 android:layout_height="wrap_content"
 android:background="@drawable/white_rect"
 android:layout_toRightOf="@+id/imageView1"
 android:padding="3dp"
 android:layout_marginLeft="-25dp"
 android:layout_centerVertical="true"
 android:layout_marginTop="8dp"
 android:layout_marginRight="5dp"
 >

 <TextView
 android:id="@+id/text1"
 android:layout_width="wrap_content"
 android:layout_height="wrap_content"
 android:layout_alignParentLeft="true"
 android:layout_alignParentTop="true"
 android:layout_marginLeft="25dp"
 android:layout_marginTop="3dp"
 android:textColor="@color/text_colour_light"
 android:text="NAME" />

 <TextView
 android:id="@+id/text5"
 android:layout_width="wrap_content"
 android:layout_height="wrap_content"
 android:layout_alignParentRight="true"
 android:layout_below="@+id/text1"
 android:layout_marginRight="5dp"
 android:layout_marginBottom="2dp"
 android:textColor="@color/text_colour_light"
 android:text="@string/tabtext_raised" />

 <TextView
 android:id="@+id/text4"
 android:layout_width="wrap_content"
 android:layout_height="wrap_content"
 android:layout_alignBaseline="@+id/text5"
 android:layout_alignBottom="@+id/text5"
 android:layout_toLeftOf="@+id/text5"
 android:layout_marginRight="5dp"
 android:layout_marginBottom="2dp"
 android:textColor="@color/text_colour_light"
 android:text="######" />

 <TextView
 android:id="@+id/text3"
 android:layout_width="wrap_content"
 android:layout_height="wrap_content"
 android:layout_alignBaseline="@+id/text4"
 android:layout_alignBottom="@+id/text4"
 android:layout_toLeftOf="@+id/text4"
 android:layout_marginRight="5dp"
 android:layout_marginBottom="2dp"
 android:textColor="@color/text_colour_light"
 android:text="@string/tabetext_of" />

 <TextView
 android:id="@+id/text2"
 android:layout_width="wrap_content"
 android:layout_height="wrap_content"
 android:layout_alignBaseline="@+id/text3"
 android:layout_alignBottom="@+id/text3"
 android:layout_toLeftOf="@+id/text3"
 android:layout_marginRight="5dp"
 android:layout_marginBottom="2dp"
 android:textColor="@color/text_colour_light"
 android:text="###" />
</RelativeLayout>

<ImageView
 android:id="@+id/imageView1"
 android:layout_width="60dp"
 android:layout_height="60dp"
 android:layout_alignParentLeft="true"
 android:layout_centerVertical="true"
 android:background="@drawable/ic_launcher"
 android:minHeight="64dp"
 android:minWidth="64dp" />

</RelativeLayout>

Screenshots

The finished list screen with two entries

The finished list screen with two entries

The entry edit screen

The entry edit screen

Share This: Facebooktwittergoogle_plusredditpinterestlinkedintumblrmailby feather

Leave a Reply

Your email address will not be published. Required fields are marked *

Time limit is exhausted. Please reload the CAPTCHA.