I've developed an app for Android which stores car filling information in an SQLite database. Everything seems to work fine on my 4.0.3 phone and my 4.0.3 AVD, but I would like it to also work in Jelly Bean and newer versions. The app really doesn't do anything very complicated. When I fire the app up in the emulated Jelly Bean device I get a FATAL EXCEPTION error:
09-05 01:45:40.311: W/dalvikvm(1062): threadid=1: thread exiting with uncaught exception >(group=0x414c4700)
09-05 01:45:40.331: E/AndroidRuntime(1062): FATAL EXCEPTION: main
09-05 01:45:40.331: E/AndroidRuntime(1062): java.lang.RuntimeException: Unable to start >activity ComponentInfo{ard.util.fueltracker/ard.util.fueltracker.TitleScreenActivity}: >java.lang.IllegalStateException: attempt to re-open an already-closed object: >SQLiteDatabase: /data/data/ard.util.fueltracker/databases/vehicleDatabase
09-05 01:45:40.331: E/AndroidRuntime(1062): at >android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2211)
In my initial searches in Google I thought I had Instance issues somehow, so I followed Approach #1 here (http://www.androiddesignpatterns.com/2012/05/correctly-managing-your-sqlite-database.html), but this doesn't seem to make a difference. Still works in ICS with the changes too.
Here's the code from my TitleScreenActivity:
package ard.util.fueltracker;
import java.util.List;
import ard.util.fueltracker.util.SystemUiHider;
import android.annotation.SuppressLint;
import android.annotation.TargetApi;
import android.app.Activity;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.view.MotionEvent;
import android.view.View;
import android.view.Window;
import android.view.WindowManager;
import android.content.Intent;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemSelectedListener;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.Spinner;
import android.widget.Toast;
/**
* An example full-screen activity that shows and hides the system UI (i.e.
* status bar and navigation/system bar) with user interaction.
*
* #see SystemUiHider
*/
#SuppressLint("NewApi")
public class TitleScreenActivity extends Activity implements OnItemSelectedListener {
/**
* Whether or not the system UI should be auto-hidden after
* {#link #AUTO_HIDE_DELAY_MILLIS} milliseconds.
*/
private static final boolean AUTO_HIDE = false;
/**
* If {#link #AUTO_HIDE} is set, the number of milliseconds to wait after
* user interaction before hiding the system UI.
*/
private static final int AUTO_HIDE_DELAY_MILLIS = 3000;
/**
* If set, will toggle the system UI visibility upon interaction. Otherwise,
* will show the system UI visibility upon interaction.
*/
private static final boolean TOGGLE_ON_CLICK = false;
/**
* The flags to pass to {#link SystemUiHider#getInstance}.
*/
//private static final int HIDER_FLAGS = SystemUiHider.FLAG_HIDE_NAVIGATION;
private static final int HIDER_FLAGS = 0;
/**
* The instance of the {#link SystemUiHider} for this activity.
*/
private SystemUiHider mSystemUiHider;
// Spinner element
Spinner spinner;
// Buttons
Button btnAdd;
Button btnLogo;
#SuppressLint("NewApi")
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
getWindow().requestFeature(Window.FEATURE_ACTION_BAR); //new
getActionBar().hide(); //new
getWindow().setFlags(
WindowManager.LayoutParams.FLAG_FULLSCREEN,WindowManager.LayoutParams.FLAG_FULLSCREEN);
setContentView(R.layout.activity_title_screen);
// Spinner element
spinner = (Spinner) findViewById(R.id.titleSelectionSpinner);
// buttons
btnAdd = (Button) findViewById(R.id.button_go);
btnLogo = (Button) findViewById(R.id.button_ard_logo);
// Spinner click listener
spinner.setOnItemSelectedListener(this);
// Check for Add New Vehicle entry to create menu option in drop down list
checkAddNewVehicle();
// Loading spinner data from database
loadSpinnerData();
//"Go" button actions
btnAdd.setOnClickListener(new View.OnClickListener() {
public void onClick(View arg0) {
//Starting a new Intent
Intent screenAddVehicle = new Intent(getApplicationContext(), AddVehicleActivity.class);
Intent screenRecordViewing = new Intent(getApplicationContext(), RecordViewing.class);
String SpinnerChoice = spinner.getSelectedItem().toString();
//Sending data to another Activity
//store value of vehicle label for Record Viewing screen
screenRecordViewing.putExtra("vehicleLabel", SpinnerChoice);
//interpret Spinner choice as Menu items
//"Add New Vehicle" always at Position 0
if (SpinnerChoice == spinner.getItemAtPosition(0).toString()) {
startActivity(screenAddVehicle);
} else {
//display value of selection if not "Add New Vehicle"
//Toast.makeText(spinner.getContext(), "Selection:" + SpinnerChoice, Toast.LENGTH_LONG).show();
//go to Record Viewing screen
startActivity(screenRecordViewing);
}
}
});
//"Logo" button - display program copyright
btnLogo.setOnClickListener(new View.OnClickListener() {
public void onClick(View arg0) {
Toast.makeText(getApplicationContext(), "FuelTracker is Copyright 2013 by Authentic Ruby Designs", Toast.LENGTH_LONG).show();
}
});
final View controlsView = findViewById(R.id.fullscreen_content_controls);
final View contentView = findViewById(R.id.fullscreen_content);
// Set up an instance of SystemUiHider to control the system UI for
// this activity.
mSystemUiHider = SystemUiHider.getInstance(this, contentView,
HIDER_FLAGS);
mSystemUiHider.setup();
mSystemUiHider
.setOnVisibilityChangeListener(new SystemUiHider.OnVisibilityChangeListener() {
// Cached values.
int mControlsHeight;
int mShortAnimTime;
#Override
#TargetApi(Build.VERSION_CODES.HONEYCOMB_MR2)
public void onVisibilityChange(boolean visible) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB_MR2) {
// If the ViewPropertyAnimator API is available
// (Honeycomb MR2 and later), use it to animate the
// in-layout UI controls at the bottom of the
// screen.
if (mControlsHeight == 0) {
mControlsHeight = controlsView.getHeight();
}
if (mShortAnimTime == 0) {
mShortAnimTime = getResources().getInteger(
android.R.integer.config_shortAnimTime);
}
controlsView
.animate()
.translationY(visible ? 0 : mControlsHeight)
.setDuration(mShortAnimTime);
} else {
// If the ViewPropertyAnimator APIs aren't
// available, simply show or hide the in-layout UI
// controls.
controlsView.setVisibility(visible ? View.VISIBLE
: View.GONE);
}
if (visible && AUTO_HIDE) {
// Schedule a hide().
delayedHide(AUTO_HIDE_DELAY_MILLIS);
}
}
});
// Set up the user interaction to manually show or hide the system UI.
contentView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
if (TOGGLE_ON_CLICK) {
mSystemUiHider.toggle();
} else {
mSystemUiHider.show();
}
}
});
// Upon interacting with UI controls, delay any scheduled hide()
// operations to prevent the jarring behavior of controls going away
// while interacting with the UI.
findViewById(R.id.button_go).setOnTouchListener(
mDelayHideTouchListener);
}
#Override
protected void onPostCreate(Bundle savedInstanceState) {
super.onPostCreate(savedInstanceState);
// Trigger the initial hide() shortly after the activity has been
// created, to briefly hint to the user that UI controls
// are available.
//delayedHide(100);
}
/**
* Touch listener to use for in-layout UI controls to delay hiding the
* system UI. This is to prevent the jarring behavior of controls going away
* while interacting with activity UI.
*/
View.OnTouchListener mDelayHideTouchListener = new View.OnTouchListener() {
#Override
public boolean onTouch(View view, MotionEvent motionEvent) {
if (AUTO_HIDE) {
delayedHide(AUTO_HIDE_DELAY_MILLIS);
}
return false;
}
};
Handler mHideHandler = new Handler();
Runnable mHideRunnable = new Runnable() {
#Override
public void run() {
mSystemUiHider.hide();
}
};
/**
* Schedules a call to hide() in [delay] milliseconds, canceling any
* previously scheduled calls.
*/
private void delayedHide(int delayMillis) {
mHideHandler.removeCallbacks(mHideRunnable);
mHideHandler.postDelayed(mHideRunnable, delayMillis);
}
#Override
public void onItemSelected(AdapterView<?> arg0, View arg1, int arg2,
long arg3) {
// TODO Auto-generated method stub
}
#Override
public void onNothingSelected(AdapterView<?> arg0) {
// TODO Auto-generated method stub
}
/**
* Function to check that Add New Vehicle is the first label in the DB table
*/
private void checkAddNewVehicle() {
// database handler
//DatabaseHandler db = new DatabaseHandler(getApplicationContext());
DatabaseHandler db = DatabaseHandler.getInstance(getApplicationContext());
// table data
List<String> labels = db.getAllLabels();
//Check for "Add New Vehicle" entry at first row of table
if (labels.isEmpty() ) {
db.insertLabel("Add New Vehicle");
}
}
/**
* Function to load the spinner data from SQLite database
* */
private void loadSpinnerData() {
// database handler
//DatabaseHandler db = new DatabaseHandler(getApplicationContext());
DatabaseHandler db = DatabaseHandler.getInstance(getApplicationContext());
// Spinner Drop down elements
List<String> labels = db.getAllLabels();
// Creating adapter for spinner
ArrayAdapter<String> dataAdapter = new ArrayAdapter<String>(this,
android.R.layout.simple_spinner_item, labels);
// Drop down layout style - list view with radio button
dataAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
// attaching data adapter to spinner
spinner.setAdapter(dataAdapter);
}
}
And here's my DatabaseHandler class:
package ard.util.fueltracker;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.List;
import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.widget.TableLayout;
public class DatabaseHandler extends SQLiteOpenHelper {
//create static instance
private static DatabaseHandler mInstance = null;
// Database Version
private static final int DATABASE_VERSION = 1;
// Database Name
private static final String DATABASE_NAME = "vehicleDatabase";
// Labels table name
private static final String TABLE_LABELS = "labels";
// Fuel Data table name
private static final String TABLE_FUELDATA = "fuel_data";
// Labels Table Columns names
private static final String KEY_ID = "id";
private static final String KEY_NAME = "name";
// Fuel Data Tables Columns names
private static final String KEY_ENTRY = "entry_id";
private static final String FIELD_VEHICLEID = "vehicle_id";
private static final String FIELD_DATE = "date";
private static final String FIELD_FTYPE = "fuel_type";
private static final String FIELD_BRAND = "brand";
private static final String FIELD_PRICE = "price";
private static final String FIELD_KMS = "kms";
private static final String FIELD_LITRES = "litres";
private static final String FIELD_LPER = "l_per";
private static final String FIELD_MPG = "mpg";
// Fuel Data Columns for display - query shorthand
private static final String[] fuelDataDisplayCols = { FIELD_DATE, FIELD_FTYPE, FIELD_BRAND, FIELD_PRICE,
FIELD_KMS, FIELD_LITRES, FIELD_LPER, FIELD_MPG };
public static DatabaseHandler getInstance(Context ctx) {
//Use the application context to avoid leaking Activity's context
if (mInstance == null) {
mInstance = new DatabaseHandler(ctx.getApplicationContext());
}
return mInstance;
}
private DatabaseHandler(Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
}
// Creating Tables
#Override
public void onCreate(SQLiteDatabase db) {
// Category table create query
String CREATE_CATEGORIES_TABLE = "CREATE TABLE " + TABLE_LABELS + "("
+ KEY_ID + " INTEGER PRIMARY KEY," + KEY_NAME + " TEXT)";
db.execSQL(CREATE_CATEGORIES_TABLE);
// Fuel Data table create query
String CREATE_FUELDATA_TABLE = "CREATE TABLE " + TABLE_FUELDATA + "("
+ KEY_ENTRY + " INTEGER PRIMARY KEY," + FIELD_VEHICLEID + " INTEGER,"
+ FIELD_DATE + " TEXT," + FIELD_FTYPE + " TEXT," + FIELD_BRAND +
" TEXT," + FIELD_PRICE + " REAL," + FIELD_KMS + " REAL,"
+ FIELD_LITRES + " REAL," + FIELD_LPER + " REAL," + FIELD_MPG +
" REAL)";
db.execSQL(CREATE_FUELDATA_TABLE);
db.close();
}
// Upgrading database
#Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
// Drop older table if existed
db.execSQL("DROP TABLE IF EXISTS " + TABLE_LABELS);
db.execSQL("DROP TABLE IF EXISTS " + TABLE_FUELDATA);
// Create tables again
onCreate(db);
}
/**
* Inserting new label into Labels table
* */
public void insertLabel(String label){
SQLiteDatabase db = this.getWritableDatabase();
ContentValues values = new ContentValues();
values.put(KEY_NAME, label);
// Inserting Row
db.insert(TABLE_LABELS, null, values);
db.close(); // Closing database connection
}
/**
* Inserting entry data into Fuel Data table
*/
//public void insertFuelData(int vehicleID, String date, String ftype, String brand,
// float price, float kms, float litres) {
public void insertFuelData(ArrayList<String> fuelEntryData) {
SQLiteDatabase dbWrite = this.getWritableDatabase();
ArrayList<String> fuelEntry = fuelEntryData;
ContentValues values = new ContentValues();
//turn array values into individual field values with correct datatype
int vehicleID = getVehicleID(fuelEntry.get(0));
String date = fuelEntry.get(1);
String ftype = fuelEntry.get(2);
String brand = fuelEntry.get(3);
double price = Double.parseDouble((fuelEntry.get(4)));
double kms = Double.parseDouble((fuelEntry.get(5)));
double litres = Double.parseDouble((fuelEntry.get(6)));
//values for calculations
double lper;
double mpg;
//Format calculations to round to one significant digit
DecimalFormat df = new DecimalFormat("###.#");
//calculate Liters/100Kilometres
lper = (100 / (kms / litres));
//calculate U.S. Miles Per Gallon
mpg = (kms / litres) * 2.35;
//Prepare data and Insert row into table
values.put(FIELD_VEHICLEID, vehicleID);
values.put(FIELD_DATE, date);
values.put(FIELD_FTYPE, ftype);
values.put(FIELD_BRAND, brand);
values.put(FIELD_PRICE, price);
values.put(FIELD_KMS, kms);
values.put(FIELD_LITRES, litres);
values.put(FIELD_LPER, df.format(lper));
values.put(FIELD_MPG, df.format(mpg));
dbWrite.insert(TABLE_FUELDATA, null, values);
dbWrite.close();
}
/**
* Getting all labels
* returns list of labels
* */
public List<String> getAllLabels(){
List<String> labels = new ArrayList<String>();
// Select All Query
String selectQuery = "SELECT * FROM " + TABLE_LABELS;
SQLiteDatabase db = this.getReadableDatabase();
Cursor cursor = db.rawQuery(selectQuery, null);
// looping through all rows and adding to list
if (cursor.moveToFirst()) {
do {
labels.add(cursor.getString(1));
} while (cursor.moveToNext());
}
// closing connection
cursor.close();
db.close();
// returning lables
return labels;
}
/**
* Get entries based on vehicle id
*/
public List<List<String>> getFuelData(int vehicleID) {
//List of Lists - each row/entry of data is a separate List
List<List<String>> fuelDataTable = new ArrayList<List<String>>();
List<String> fuelDataRow = new ArrayList<String>();
//Select Query
String selectQuery = "SELECT * FROM " + TABLE_FUELDATA +
" WHERE vehicle_id = ? ";
SQLiteDatabase db = this.getReadableDatabase();
Cursor cursor = db.rawQuery(selectQuery, new String[] { String.valueOf(vehicleID) });
// looping through all rows and 9 columns (not incl key) and adding to list
if (cursor.moveToFirst()) {
do {
for(int i = 1; i < 10; i++) {
//doesn't work with non-string values
//fuelDataRow.add(cursor.getString(i));
}
//add each row in its entirety to the List; multi-dimenionsal list
fuelDataTable.add(fuelDataRow);
//empty fuelDataRow
fuelDataRow.clear();
} while (cursor.moveToNext());
}
// closing connection
cursor.close();
db.close();
//return data
return fuelDataTable;
}
public List<String> getFuelDataRows(int vehicleID) {
List<String> fuelDataTable = new ArrayList<String>();
SQLiteDatabase db = this.getReadableDatabase();
//Get data from database table
Cursor c = db.query(TABLE_FUELDATA, fuelDataDisplayCols, " vehicle_id=? ", new String[] { String.valueOf(vehicleID) }, null, null, FIELD_DATE);
//Insert Header row into Array
fuelDataTable.add("Date");
fuelDataTable.add("Type");
fuelDataTable.add("Brand");
fuelDataTable.add("Price");
fuelDataTable.add("KMs");
fuelDataTable.add("Litres");
fuelDataTable.add("L/100");
fuelDataTable.add("MPG");
//Go to beginning of Cursor data and loop through
c.moveToFirst();
while (!c.isAfterLast()) {
//add each cell in the row to List array
fuelDataTable.add(c.getString(c.getColumnIndex(FIELD_DATE)));
fuelDataTable.add(c.getString(c.getColumnIndex(FIELD_FTYPE)));
fuelDataTable.add(c.getString(c.getColumnIndex(FIELD_BRAND)));
fuelDataTable.add(String.valueOf(c.getDouble(c.getColumnIndex(FIELD_PRICE))));
fuelDataTable.add(String.valueOf(c.getDouble(c.getColumnIndex(FIELD_KMS))));
fuelDataTable.add(String.valueOf(c.getDouble(c.getColumnIndex(FIELD_LITRES))));
fuelDataTable.add(String.valueOf(c.getDouble(c.getColumnIndex(FIELD_LPER))));
fuelDataTable.add(String.valueOf(c.getDouble(c.getColumnIndex(FIELD_MPG))));
c.moveToNext();
}
// Make sure to close the cursor
c.close();
db.close();
return fuelDataTable;
}
public int getVehicleID(String label) {
// set variables
SQLiteDatabase dbReader = this.getReadableDatabase();
String vLabel = label;
//Query String
String selectQuery = "SELECT " + KEY_ID + " FROM " + TABLE_LABELS +
" WHERE name = ? ";
Cursor c = dbReader.rawQuery(selectQuery, new String[] { vLabel });
//avoid out of bounds exception
c.moveToFirst();
//extract value as integer
int vID = c.getInt(c.getColumnIndex(KEY_ID));
c.close();
return vID;
}
}
Some of it probably looks ugly - this is my first app project and Eclipse auto-populated some of the methods upon creation - but it is working OK in Ice Cream Sandwich.
Thanks for any clues.
db.close() is not needed in public void onCreate(). This will probably fix your problem.
Related
I have created a simple android application which asks for the users details such as name, number, blood type and saves it in a database. This happens in edit texts on the editscreen the application is then suppose to display all the data in the Main Activity screen in a TextView. I have made the code so that it displays the text in the textview however when I switch the application off and back on again the text simply disappears and is no longer there, I am also trying to make the text stay in the edit text like
Name: Jim
But when I change screens, so for example If I go from MainActivity to EditScreen the text is no longer visible in the Edit Screen.
Edit Screen which has the edit texts
package com.example.androidsimpledbapp1;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.EditText;
import android.widget.TextView;
public class EditScreen extends Activity {
/*
* Code Issues:
* Data is not being persisted on screen
* Also the edit text data is not being persisted
* Database is not overwriting row in the DB e.g. GaryJamesJimmy instead of Overwriting
* Database needs to retrieve all other rows and display them in the TextView
* Will need to implement overwriting functionality on the DB for each row
* Is Data even persisting?
*/
EditText firstNameInput;
EditText bloodTypeInput;
EditText contacNameInput;
EditText phoneNumberInput;
EditText relationshipInput;
MyDBHandler dbHandler;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_edit_screen);
//Setting EditTexts
firstNameInput = (EditText) findViewById(R.id.inputname);
bloodTypeInput = (EditText) findViewById(R.id.inputblood);
contacNameInput = (EditText) findViewById(R.id.inputcontact);
phoneNumberInput = (EditText) findViewById(R.id.inputnum);
relationshipInput = (EditText) findViewById(R.id.inputraltion);
//Setting DbHandler object
dbHandler = new MyDBHandler(this, null, null, 1);
}
public void saveMe(View v){
/*
* Making a new object
* Object takes 5 parameters
*/
Details detail = new Details(firstNameInput.getText().toString(),
bloodTypeInput.getText().toString(),
contacNameInput.getText().toString(),
phoneNumberInput.getText().toString(),
relationshipInput.getText().toString());
dbHandler.addProduct(detail);
//Sending Text To Main Activity
String dbString = dbHandler.databaseToString();
Intent myIntent = new Intent(v.getContext(),MainActivity.class);
myIntent.putExtra("mytext",dbString);
startActivity(myIntent);
//End of Sending to Main Activity
//Settint the text in Edit Text
firstNameInput.setText(dbString);
}
public void clearBtnPressed(View v){
dbHandler.deleteProducts();
}
}
Main Activity - This is the screen with the textview where the text is suppose to be displayed
package com.example.androidsimpledbapp1;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.TextView;
public class MainActivity extends Activity {
TextView mTextView;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//Grabs the TextView
mTextView = (TextView)findViewById(R.id.dbname);
mTextView.setText(getIntent().getStringExtra("mytext"));
}
//Changing Activity
public void editBtnPressed(View v){
Intent intent = new Intent(MainActivity.this, EditScreen.class);
startActivity(intent);
}
}
Database Class
package com.example.androidsimpledbapp1;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.database.Cursor;
import android.content.Context;
import android.content.ContentValues;
public class MyDBHandler extends SQLiteOpenHelper {
/*
* Class for Working with DB
*/
//Update each time DB structure changes e.g. adding new property
private static final int DATABASE_VERSION =1;
//DB Name
private static final String DATABASE_NAME = "details.db";
//Table name
public static final String TABLE_PRODUCTS = "products";
//DB Columns
public static final String COLUMN_ID = "_Id";
public static final String COLUMN_PERSONNAME = "firstName";
public static final String COLUMN_PERSONBLOOD = "bloodType";
public static final String COLUMN_PERSONCONTACT = "contactName";
public static final String COLUMN_PERSONNUMBER = "phoneNumber";
public static final String COLUMN_PERSONRELATION = "relationship";
//Constructor
/*
* Passing information to super class in SQL
* Context is background information
* name of db
* Database version
*/
public MyDBHandler(Context context, String name, SQLiteDatabase.CursorFactory factory, int version){
super(context, DATABASE_NAME, factory, DATABASE_VERSION);
}
/*
* What to do first time when you create DB
* Creates the table the very first time
* (non-Javadoc)
* #see android.database.sqlite.SQLiteOpenHelper#onCreate(android.database.sqlite.SQLiteDatabase)
* Remember to use Commas as shown below
*/
#Override
public void onCreate(SQLiteDatabase db){
String query = "CREATE TABLE "+ TABLE_PRODUCTS + "(" +
COLUMN_ID + " INTEGER PRIMARY KEY AUTOINCREMENT, "+
COLUMN_PERSONNAME + " TEXT, "+
COLUMN_PERSONBLOOD + " TEXT, "+
COLUMN_PERSONCONTACT + " TEXT, "+
COLUMN_PERSONNUMBER + " TEXT, " +
COLUMN_PERSONRELATION + " TEXT " +
");";
//Execute the query
db.execSQL(query);
}
/*
* If ever upgrading DB call this method
* (non-Javadoc)
* #see android.database.sqlite.SQLiteOpenHelper#onUpgrade(android.database.sqlite.SQLiteDatabase, int, int)
*/
#Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion){
//Delete the current table
db.execSQL("DROP TABLE IF EXISTS" + TABLE_PRODUCTS);
//create new table
onCreate(db);
}
//Add new row to the database
public void addProduct(Details details){
//Built in class - set values for different columns
//Makes inserting rows quick and easy
ContentValues values = new ContentValues();
values.put(COLUMN_PERSONNAME, details.get_firstName());
values.put(COLUMN_PERSONBLOOD, details.get_bloodType());
values.put(COLUMN_PERSONCONTACT, details.get_contactName());
values.put(COLUMN_PERSONNUMBER, details.get_phoneNumber());
values.put(COLUMN_PERSONRELATION, details.get_relationship());
SQLiteDatabase db = getWritableDatabase();
db.insert(TABLE_PRODUCTS, null, values);
db.close();
}
/*Updating Rows in the Database
public void updateProducts(Details details){
ContentValues cv = new ContentValues();
SQLiteDatabase db = getWritableDatabase();
db.update(TABLE_PRODUCTS, cv, COLUMN_ID + "=" + 1, null);
}
*/
/*Table was deleted*/
public void deleteProducts(){
SQLiteDatabase db = getWritableDatabase();
db.delete(TABLE_PRODUCTS, null, null);
}
//Take DB and Convert to String
public String databaseToString(){
String dbString = "";
SQLiteDatabase db = getWritableDatabase();
//Every Column and row
String query = "SELECT * FROM " + TABLE_PRODUCTS + " WHERE 1";
//Cursor points to a location in your results
//First row point here, second row point here
Cursor c = db.rawQuery(query, null);
c.moveToFirst();
while(!c.isAfterLast()){
//Extracts first name and adds to string
if(c.getString(c.getColumnIndex("firstName"))!=null){
dbString += c.getString(c.getColumnIndex("firstName"));
c.moveToNext();
/*
* Displaying all other columns
*/
}
}
db.close();
return dbString;
}
}
Details Class
package com.example.androidsimpledbapp1;
public class Details {
//primary key
private int _id;
//Properties
private String _firstName;
private String _bloodType;
private String _contactName;
private String _phoneNumber;
private String _relationship;
//Dont Have to Enter Everything each time
public Details(){
}
public Details(String firstName){
this.set_firstName(firstName);
}
//Passing in details
//Setting values from the user
public Details(String firstName, String bloodType,
String contactName, String phoneNumber,
String relationship){
this.set_firstName(firstName);
this.set_bloodType(bloodType);
this.set_contactName(contactName);
this.set_phoneNumber(phoneNumber);
this.set_relationship(relationship);
}
//Retrieve the data
public int get_id() {
return _id;
}
//Setter allows to give property
public void set_id(int _id) {
this._id = _id;
}
public String get_firstName() {
return _firstName;
}
public void set_firstName(String _firstName) {
this._firstName = _firstName;
}
public String get_bloodType() {
return _bloodType;
}
public void set_bloodType(String _bloodType) {
this._bloodType = _bloodType;
}
public String get_contactName() {
return _contactName;
}
public void set_contactName(String _contactName) {
this._contactName = _contactName;
}
public String get_phoneNumber() {
return _phoneNumber;
}
public void set_phoneNumber(String _phoneNumber) {
this._phoneNumber = _phoneNumber;
}
public String get_relationship() {
return _relationship;
}
public void set_relationship(String _relationship) {
this._relationship = _relationship;
}
}
When you switch your app, it's on pause state which may be the cause of your problem.
I suggest you search for "saving activity when onPause state"
I am trying to update current credits column of the only row in the database using a drop down spinner which gets values from an arraylist. Very unsure about how to go about doing this operation. Thank you for any help in advance.
My database code:
package com.example.parkangel;
import android.content.Context;
import android.database.Cursor;
import android.database.SQLException;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
public class UDbHelper extends SQLiteOpenHelper
{
public static final String KEY_ROWID = "_id";
public static final String KEY_PFNAME = "payeeFname";
public static final String KEY_PSNAME = "payeeSname";
public static final String KEY_CARD = "card";
public static final String KEY_CREDITS = "credits";
private static final String DATABASE_NAME = "UserData.db";
private static final String DATABASE_TABLE = "UserTable";
private static final int DATABASE_VERSION = 1;
//private UDbHelper dbHelper;
//private final Context ourContext;
private static UDbHelper instance;
private SQLiteDatabase ourDatabase;
public UDbHelper(Context context)
{
super(context, DATABASE_NAME, null, DATABASE_VERSION);
}
public static UDbHelper getInstance(Context context)
{
if (instance == null)
{
instance = new UDbHelper(context);
}
return instance;
}
#Override
public void onCreate(SQLiteDatabase db)
{
// TODO Auto-generated method stub
db.execSQL("CREATE TABLE " + DATABASE_TABLE + " (" +
KEY_ROWID + " INTEGER PRIMARY KEY AUTOINCREMENT, " +
KEY_PFNAME + " TEXT NOT NULL, " + KEY_PSNAME + "
TEXT NOT NULL, " +
KEY_CARD + " TEXT NOT NULL, " + KEY_CREDITS + " TEXT
NOT NULL);");
}
#Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion)
{
// TODO Auto-generated method stub
db.execSQL("DROP TABLE IF EXISTS " + DATABASE_TABLE);
onCreate(db);
}
public synchronized UDbHelper open() throws SQLException
{
System.out.println ("running open");
if(ourDatabase == null || !ourDatabase.isOpen())
ourDatabase = getWritableDatabase();
return this;
}
public String getData()
{
// TODO Auto-generated method stub
String[] columns = new String[] {KEY_ROWID, KEY_PFNAME, KEY_PSNAME,
KEY_CARD, KEY_CREDITS};
Cursor c = ourDatabase.query(DATABASE_TABLE, columns, null, null,
null, null, null);
String result = " ";
int iRow = c.getColumnIndexOrThrow(KEY_ROWID);
int iPFname = c.getColumnIndexOrThrow(KEY_PFNAME);
int iPSname = c.getColumnIndexOrThrow(KEY_PSNAME);
int iCard = c.getColumnIndexOrThrow(KEY_CARD);
int iCredits = c.getColumnIndexOrThrow(KEY_CREDITS);
for(c.moveToFirst(); !c.isAfterLast(); c.moveToNext()){
result = result + c.getString(iRow) + " " +
c.getString(iPFname) + " " +
c.getString(iPSname)
+ " " + c.getString(iCard) + " " +
c.getString(iCredits) + "\n";
}
return result;
}
}
My main activity code I will be doing the operation through:
package com.example.parkangel;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.Spinner;
import android.widget.TextView;
public class Balance extends Activity{
Button add;
TextView display;
Spinner spinner3;
String[] money = {"Select amount", "£1", "£2", "£5", "£10"};
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.balance_layout);
TextView tv = (TextView) findViewById(R.id.firstn);
UDbHelper db = new UDbHelper(this);
db.open();
String data = db.getData();
db.close();
tv.setText(data);
ArrayAdapter<String> adapter3 = new ArrayAdapter<String>(Balance.this,
android.R.layout.simple_spinner_item, money);
spinner3 = (Spinner) findViewById (R.id.moneytoadd);
spinner3.setAdapter(adapter3);
add = (Button) findViewById(R.id.topup);
}
public void onClick(View arg0)
{
}
public void updateActivity(View view){
Intent book = new Intent(Balance.this, BookTicket.class);
startActivity(book);
}
public void addBalance(View view){
Intent addB = new Intent(Balance.this, Balance.class);
startActivity(addB);
}
public void doUpdate(View view){
Intent upd = new Intent(Balance.this, UpdateTicket.class);
startActivity(upd);
}
}
Your question is fairly compound, getting selected field from spinner, updating database... I'm not going to provide a complete answer, but this should get you started:
This is how you would get the selected field from the spinner, which you can then use to update your database. One word of warning, I believe setOnItemSelectedListener is called when it is initially set, so you may need to ignore the first call.
Spinner spinner;
spinner.setOnItemSelectedListener( new AdapterView.OnItemSelectedListener() {
#Override
public void onItemSelected(AdapterView<?> arg0, View view, int arg2,
long arg3) {
if(! (view instanceof TextView)){
// view is probably a textview, but record type if not.
System.out.println("incorrect view type " + view.getClass().getSimpleName());
return;
}
EditText et = (EditText) view;
String fieldName = et.getText().toString().trim();
//Now we got selected name, send name
//to a function that updates our database.
}
#Override
public void onNothingSelected(AdapterView<?> arg0) {
// TODO Auto-generated method stub
}
});
I didn't find the problem but I can tell you that your code is VERY INEFFICIENT. You are using String to build your result in the getData method. Each time you try to append the new data (Row) to the old one you are creating a new string to hold the new data. If you are retrieving 1000 row from the database, this means that you are creating 1000 string to build the final one. I recommend using StringBuilder instead as following:
StringBuilder strBuilder= new StringBuilder();
for(c.moveToFirst(); !c.isAfterLast(); c.moveToNext()){
strBuilder.append( c.getString(iRow) + " " +
c.getString(iPFname) + " " +
c.getString(iPSname)
+ " " + c.getString(iCard) + " " +
c.getString(iCredits) + "\n");
}
return str= strBuilder.toString();
Here is an example of how to insert into your DB:
SQLiteDatabase db = this.getWritableDatabase();
ContentValues values = new ContentValues();
values.put(KEY_PFNAME , editText1.getText().toString());
values.put(KEY_PSNAME , stringArrayList.get(position));
values.put(KEY_CARD , "12345677");
values.put(KEY_CREDITS , "55");
// Inserting Row
db.insert(DATABASE_TABLE, null, values);
db.close(); // Closing database connection
Project Description: I'm creating an android application where I want to add notes to the schedule of my study.
I based my notepad on this tutorial: http://developer.android.com/training/notepad/index.html - Notepadv3Solution
I've added to the database column "p_id" - this is the id of the subject that was clicked. I want to use this id later.
Problem: The notes aren't being added. Or maybe they are being added but don't display. I have no errors in the console.
Code:
NotatkiActivity.java - class with list of notes
package pack.organizer;
import android.app.ListActivity;
import android.content.Intent;
import android.database.Cursor;
import android.os.Bundle;
import android.view.ContextMenu;
import android.view.ContextMenu.ContextMenuInfo;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.AdapterView.AdapterContextMenuInfo;
import android.widget.ListView;
import android.widget.SimpleCursorAdapter;
import android.widget.TextView;
import android.widget.Toast;
public class NotatkiActivity extends ListActivity {
private static final int ACTIVITY_CREATE=0;
private static final int ACTIVITY_EDIT=1;
private static final int INSERT_ID = Menu.FIRST;
private static final int DELETE_ID = Menu.FIRST + 1;
Intent myIntent;
long idp;
private NotesDbAdapter mDbHelper;
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.notatki);
myIntent= getIntent();
idp = Long.valueOf(myIntent.getStringExtra("id_p"));
mDbHelper = new NotesDbAdapter(this);
mDbHelper.open();
fillData();
registerForContextMenu(getListView());
}
private void fillData() {
//myIntent= getIntent();
//String idp = myIntent.getStringExtra("id_p");
Cursor notesCursor = mDbHelper.fetchAllNotes();
startManagingCursor(notesCursor);
// Create an array to specify the fields we want to display in the list (only TITLE)
String[] from = new String[]{NotesDbAdapter.KEY_TITLE, NotesDbAdapter.KEY_BODY};
// and an array of the fields we want to bind those fields to (in this case just text1)
int[] to = new int[]{R.id.text1, R.id.text2};
// Now create a simple cursor adapter and set it to display
SimpleCursorAdapter notes =
new SimpleCursorAdapter(this, R.layout.notes_row, notesCursor, from, to);
setListAdapter(notes);
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
super.onCreateOptionsMenu(menu);
menu.add(0, INSERT_ID, 0, "Dodaj notatkę");
return true;
}
#Override
public boolean onMenuItemSelected(int featureId, MenuItem item) {
switch(item.getItemId()) {
case INSERT_ID:
createNote();
return true;
}
return super.onMenuItemSelected(featureId, item);
}
#Override
public void onCreateContextMenu(ContextMenu menu, View v,
ContextMenuInfo menuInfo) {
super.onCreateContextMenu(menu, v, menuInfo);
menu.add(0, DELETE_ID, 0, "Usuń notatkę");
}
#Override
public boolean onContextItemSelected(MenuItem item) {
switch(item.getItemId()) {
case DELETE_ID:
AdapterContextMenuInfo info = (AdapterContextMenuInfo) item.getMenuInfo();
mDbHelper.deleteNote(info.id);
fillData();
return true;
}
return super.onContextItemSelected(item);
}
private void createNote() {
Intent i = new Intent(this, NoteEdit.class);
i.putExtra("idprzedmiotu", idp);
startActivityForResult(i, ACTIVITY_CREATE);
}
protected void onListItemClick(ListView l, View v, int position, long id) {
super.onListItemClick(l, v, position, id);
myIntent = getIntent();
idp = Long.valueOf(myIntent.getStringExtra("id_p"));
Intent i = new Intent(this, NoteEdit.class);
i.putExtra(NotesDbAdapter.KEY_ROWID, id);
//i.putExtra(NotesDbAdapter.KEY_PRZEDMIOTID, id_p);
startActivityForResult(i, ACTIVITY_EDIT);
}
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent intent) {
super.onActivityResult(requestCode, resultCode, intent);
fillData();
}
}
NoteEdit.java
package pack.organizer;
import android.app.Activity;
import android.content.Intent;
import android.database.Cursor;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
public class NoteEdit extends Activity {
private EditText mTitleText;
private EditText mBodyText;
private Long mRowId;
private Long mpId;
private NotesDbAdapter mDbHelper;
private Bundle bundle;
Intent myIntent;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mDbHelper = new NotesDbAdapter(this);
mDbHelper.open();
setContentView(R.layout.note_edit);
setTitle("Edytuj notatkę");
mTitleText = (EditText) findViewById(R.id.title);
mBodyText = (EditText) findViewById(R.id.body);
Button confirmButton = (Button) findViewById(R.id.confirm);
mRowId = (savedInstanceState == null) ? null : (Long) savedInstanceState.getSerializable(NotesDbAdapter.KEY_ROWID);
if (mRowId == null) {
Bundle extras = getIntent().getExtras();
mRowId = extras != null ? extras.getLong(NotesDbAdapter.KEY_ROWID) : null;
}
bundle = getIntent().getExtras();
mpId = bundle.getLong("idprzedmiotu");
populateFields();
confirmButton.setOnClickListener(new View.OnClickListener() {
public void onClick(View view) {
setResult(RESULT_OK);
finish();
}
});
}
private void populateFields() {
if (mRowId != null) {
Cursor note = mDbHelper.fetchNote(mRowId);
if( note != null && note.moveToFirst()){
startManagingCursor(note);
mTitleText.setText(note.getString(
note.getColumnIndexOrThrow(NotesDbAdapter.KEY_TITLE)));
mBodyText.setText(note.getString(
note.getColumnIndexOrThrow(NotesDbAdapter.KEY_BODY)));
}
}
}
#Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
saveState();
outState.putSerializable(NotesDbAdapter.KEY_ROWID, mRowId);
}
#Override
protected void onPause() {
super.onPause();
saveState();
}
#Override
protected void onResume() {
super.onResume();
populateFields();
}
private void saveState() {
String title = mTitleText.getText().toString();
String body = mBodyText.getText().toString();
if (mRowId == null) {
long id = mDbHelper.createNote(title, body, mpId);
if (id > 0) {
mRowId = id;
}
} else {
mDbHelper.updateNote(mRowId, mpId, title, body);
}
}
}
NotesDbAdapter.java
package pack.organizer;
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;
public class NotesDbAdapter {
public static final String KEY_TITLE = "title";
public static final String KEY_BODY = "body";
public static final String KEY_ROWID = "_id";
public static final String KEY_PRZEDMIOTID = "p_id";
private static final String TAG = "NotesDbAdapter";
private DatabaseHelper mDbHelper;
private SQLiteDatabase mDb;
/**
* Database creation sql statement
*/
private static final String DATABASE_CREATE =
"create table notes (_id integer primary key autoincrement, "
+ "p_id integer not null, title text not null, body text not null);";
private static final String DATABASE_NAME = "data";
private static final String DATABASE_TABLE = "notes";
private static final int DATABASE_VERSION = 2;
private final Context mCtx;
private static class DatabaseHelper extends SQLiteOpenHelper {
DatabaseHelper(Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
}
#Override
public void onCreate(SQLiteDatabase db) {
db.execSQL(DATABASE_CREATE);
}
#Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
Log.w(TAG, "Upgrading database from version " + oldVersion + " to "
+ newVersion + ", which will destroy all old data");
db.execSQL("DROP TABLE IF EXISTS notes");
onCreate(db);
}
}
/**
* Constructor - takes the context to allow the database to be
* opened/created
*
* #param ctx the Context within which to work
*/
public NotesDbAdapter(Context ctx) {
this.mCtx = ctx;
}
/**
* Open the notes database. If it cannot be opened, try to create a new
* instance of the database. If it cannot be created, throw an exception to
* signal the failure
*
* #return this (self reference, allowing this to be chained in an
* initialization call)
* #throws SQLException if the database could be neither opened or created
*/
public NotesDbAdapter open() throws SQLException {
mDbHelper = new DatabaseHelper(mCtx);
mDb = mDbHelper.getWritableDatabase();
return this;
}
public void close() {
mDbHelper.close();
}
/**
* Create a new note using the title and body provided. If the note is
* successfully created return the new rowId for that note, otherwise return
* a -1 to indicate failure.
*
* #param title the title of the note
* #param body the body of the note
* #return rowId or -1 if failed
*/
public long createNote(String title, String body, long p_id) {
ContentValues initialValues = new ContentValues();
initialValues.put(KEY_TITLE, title);
initialValues.put(KEY_BODY, body);
initialValues.put(KEY_PRZEDMIOTID, p_id);
return mDb.insert(DATABASE_TABLE, null, initialValues);
}
/**
* Delete the note with the given rowId
*
* #param rowId id of note to delete
* #return true if deleted, false otherwise
*/
public boolean deleteNote(long rowId) {
return mDb.delete(DATABASE_TABLE, KEY_ROWID + "=" + rowId, null) > 0;
}
/**
* Return a Cursor over the list of all notes in the database
*
* #return Cursor over all notes
*/
public Cursor fetchAllNotes() {
return mDb.query(DATABASE_TABLE, new String[] {KEY_ROWID, KEY_PRZEDMIOTID, KEY_TITLE,
KEY_BODY}, null, null, null, null, null);
}
/**
* Return a Cursor positioned at the note that matches the given rowId
*
* #param rowId id of note to retrieve
* #return Cursor positioned to matching note, if found
* #throws SQLException if note could not be found/retrieved
*/
public Cursor fetchNote(long rowId) throws SQLException {
Cursor mCursor =
mDb.query(true, DATABASE_TABLE, new String[] {KEY_ROWID, KEY_PRZEDMIOTID,
KEY_TITLE, KEY_BODY}, KEY_ROWID + "=" + rowId, null,
null, null, null, null);
if (mCursor != null) {
mCursor.moveToFirst();
}
return mCursor;
}
/**
* Update the note using the details provided. The note to be updated is
* specified using the rowId, and it is altered to use the title and body
* values passed in
*
* #param rowId id of note to update
* #param title value to set note title to
* #param body value to set note body to
* #return true if the note was successfully updated, false otherwise
*/
public boolean updateNote(long rowId, long p_id, String title, String body) {
ContentValues args = new ContentValues();
args.put(KEY_TITLE, title);
args.put(KEY_BODY, body);
args.put(KEY_PRZEDMIOTID, p_id);
return mDb.update(DATABASE_TABLE, args, KEY_ROWID + "=" + rowId, null) > 0;
}
}
You should create your own notepad instead of using full source code from internet ...it will give you step by step solution and it is better for your programming dude :) please don't take it as wrong way my friend :)
I'm trying to code a simple randomizer app. I had the randomizer button working, but then I changed some code (which I thought was irrelevant to the randomizer button) and it started crashing and getting the "CursorIndexOutOfBoundsException Index 0 requested, with a size of 0" error. I couldn't find any fixes to this that apply to my code. Can anyone help me fix this?
Here is my main class with the button:
package com.example.randomgamechooser;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.view.Menu;
import android.view.View;
import android.widget.TextView;
public class MainScreen extends Activity {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main_screen);
}
public void chooseGame (View view) {
GameList dbUtil = new GameList(this);
dbUtil.open();
String string = dbUtil.getRandomEntry();
//TextView textView = new TextView(this);
TextView textView = (TextView) findViewById(R.id.chosenbox);
textView.setTextSize(40);
textView.setText(string);
//setContentView (textView);
dbUtil.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.main_screen, menu);
return true;
}
//starts the Game Selection activity
public void openGames (View view) {
Intent intent = new Intent(this, GameSelction.class);
startActivity(intent);
}
}
Here is the GameList class:
package com.example.randomgamechooser;
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 java.util.Random;
public class GameList {
private static final String TAG = "GameList";
//database name
private static final String DATABASE_NAME = "game_list";
//database version
private static final int DATABASE_VERSION = 1;
//table name
private static final String DATABASE_TABLE = "game_list";
//table columns
public static final String KEY_NAME = "name";
public static final String KEY_GENRE = "genre";
public static final String KEY_ROWID = "_id";
//database creation sql statement
private static final String CREATE_GAME_TABLE =
"create table " + DATABASE_TABLE + " (" + KEY_ROWID + " integer primary key autoincrement, "
+ KEY_NAME +" text not null, " + KEY_GENRE + " text not null);";
//Context
private final Context mCtx;
private DatabaseHelper mDbHelper;
private static SQLiteDatabase mDb;
//Inner private class. Database Helper class for creating and updating database.
private static class DatabaseHelper extends SQLiteOpenHelper {
DatabaseHelper(Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
}
// onCreate method is called for the 1st time when database doesn't exists.
#Override
public void onCreate(SQLiteDatabase db) {
Log.i(TAG, "Creating DataBase: " + CREATE_GAME_TABLE);
db.execSQL(CREATE_GAME_TABLE);
}
//onUpgrade method is called when database version changes.
#Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
Log.w(TAG, "Upgrading database from version " + oldVersion + " to "
+ newVersion);
}
}
//Constructor - takes the context to allow the database to be opened/created
//#param ctx the Context within which to work
public GameList(Context ctx) {
this.mCtx = ctx;
}
//This method is used for creating/opening connection
//#return instance of GameList
//#throws SQLException
public GameList open() throws SQLException {
mDbHelper = new DatabaseHelper(mCtx);
mDb = mDbHelper.getWritableDatabase();
return this;
}
//This method is used for closing the connection.
public void close() {
mDbHelper.close();
}
//This method is used to create/insert new game.
//#param name
// #param genre
// #return long
public long createGame(String name, String genre) {
ContentValues initialValues = new ContentValues();
initialValues.put(KEY_NAME, name);
initialValues.put(KEY_GENRE, genre);
return mDb.insert(DATABASE_TABLE, null, initialValues);
}
// This method will delete game.
// #param rowId
// #return boolean
public static boolean deleteGame(long rowId) {
return mDb.delete(DATABASE_TABLE, KEY_ROWID + "=" + rowId, null) > 0;
}
// This method will return Cursor holding all the games.
// #return Cursor
public Cursor fetchAllGames() {
return mDb.query(DATABASE_TABLE, new String[] {KEY_ROWID, KEY_NAME,
KEY_GENRE}, null, null, null, null, null);
}
// This method will return Cursor holding the specific game.
// #param id
// #return Cursor
// #throws SQLException
public Cursor fetchGame(long id) throws SQLException {
Cursor mCursor =
mDb.query(true, DATABASE_TABLE, new String[] {KEY_ROWID,
KEY_NAME, KEY_GENRE}, KEY_ROWID + "=" + id, null,
null, null, null, null);
if (mCursor != null) {
mCursor.moveToFirst();
}
return mCursor;
}
public int getAllEntries()
{
Cursor cursor = mDb.rawQuery(
"SELECT COUNT(name) FROM game_list", null);
if(cursor.moveToFirst()) {
return cursor.getInt(0);
}
return cursor.getInt(0);
}
public String getRandomEntry()
{
//id = getAllEntries();
Random random = new Random();
int rand = random.nextInt(getAllEntries());
if(rand == 0)
++rand;
Cursor cursor = mDb.rawQuery(
"SELECT name FROM game_list WHERE _id = " + rand, null);
if(cursor.moveToFirst()) {
return cursor.getString(0);
}
return cursor.getString(0);
}
// This method will update game.
// #param id
// #param name
// #param standard
// #return boolean
public boolean updateGame(int id, String name, String standard) {
ContentValues args = new ContentValues();
args.put(KEY_NAME, name);
args.put(KEY_GENRE, standard);
return mDb.update(DATABASE_TABLE, args, KEY_ROWID + "=" + id, null) > 0;
}
}
And here is the cause part of the error log:
08-01 13:03:38.325: E/AndroidRuntime(278): Caused by: android.database.CursorIndexOutOfBoundsException: Index 0 requested, with a size of 0
08-01 13:03:38.325: E/AndroidRuntime(278): at android.database.AbstractCursor.checkPosition(AbstractCursor.java:580)
08-01 13:03:38.325: E/AndroidRuntime(278): at android.database.AbstractWindowedCursor.checkPosition(AbstractWindowedCursor.java:214)
08-01 13:03:38.325: E/AndroidRuntime(278): at android.database.AbstractWindowedCursor.getString(AbstractWindowedCursor.java:41)
08-01 13:03:38.325: E/AndroidRuntime(278): at com.example.randomgamechooser.GameList.getRandomEntry(GameList.java:153)
EDIT: Here is the ListView class:
public class GameSelction extends Activity
{
GameList dbUtil = new GameList(this);
private SimpleCursorAdapter dataAdapter;
//#SuppressWarnings("deprecation")
#SuppressLint("NewApi")
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_game_selction);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB){
getActionBar() .setDisplayHomeAsUpEnabled(true);
}
displayListView();
}
private void displayListView() {
dbUtil.open();
Cursor cursor = dbUtil.fetchAllGames();
// The desired columns to be bound
String[] columns = new String[] {
GameList.KEY_NAME,
GameList.KEY_GENRE,
};
// the XML defined views which the data will be bound to
int[] to = new int[] {
R.id.name,
R.id.genre,
};
// create the adapter using the cursor pointing to the desired data
//as well as the layout information
dataAdapter = new SimpleCursorAdapter(
this, R.layout.game_info,
cursor,
columns,
to,
0);
ListView listView = (ListView) findViewById(R.id.listView1);
// Assign adapter to ListView
listView.setAdapter(dataAdapter);
listView.setOnItemClickListener(new OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> listView, View view,
int position, long rowId) {
// Get the cursor, positioned to the corresponding row in the result set
//Cursor cursor = (Cursor) listView.getItemAtPosition(position);
GameList.deleteGame(rowId);
}
});
}
/**
* Set up the {#link android.app.ActionBar}, if the API is available.
*/
#TargetApi(Build.VERSION_CODES.HONEYCOMB)
private void setupActionBar() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
getActionBar().setDisplayHomeAsUpEnabled(true);
}
}
//opens the AddGame activity
public void openAddgame (View view) {
Intent intent = new Intent(this, AddGame.class);
startActivity(intent);
}
public void buttonBackMain (View view) {
Intent intent = new Intent(this, MainScreen.class);
startActivity(intent);
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.game_selction, menu);
return true;
}
}
The problem is in this section of code:
public String getRandomEntry()
{
//...
Cursor cursor = mDb.rawQuery(
"SELECT name FROM game_list WHERE _id = " + rand, null);
if(cursor.moveToFirst()) {
return cursor.getString(0);
}
return cursor.getString(0);
}
What you ended up doing was saying return cursor.getString(0); whether or not there were results in the cursor. So remove the second occurrence, and it should work.
EDIT:
After scanning your code, it seems that the only place you use this method is to fill a TextView. In that case you can use this as a chance to communicate a visual error message to yourself or your users, or do anything else with it that you want. So I would suggest using something to the effect of
public String getRandomEntry()
{
//EDIT: This will make your random generator less biased toward 1.
Random random = new Random();
int rand = random.nextInt(getAllEntries()) + 1;
/* Assuming your _id starts at 1 and auto-increments, this will
* start the random digits at 1 and go as high as your highest _id */
Cursor cursor = mDb.rawQuery(
"SELECT name FROM game_list WHERE _id = " + rand, null);
if(cursor.moveToFirst()) {
return cursor.getString(0);
}
return "There were no games in the database to choose from.";
}
EDIT:
Try using this. Notice that this code uses mDb.query(), which you used elsewhere. I'm not sure why rawQuery() would refuse to work, but maybe this will do it.
public String getRandomEntry()
{
Random random = new Random();
int rand = random.nextInt(getAllEntries()) + 1;
Cursor cursor = mDb.query(true, DATABASE_TABLE, new String[] {KEY_NAME},
KEY_ROWID + "=" + rand, null, null, null, null, null);
if(cursor.moveToFirst()) {
return cursor.getString(0);
}
return "There were no games in the database to choose from.";
}
Based on the initial look, the SQLiteDatabase object represented by mDB appears to be empty, as that's what is throwing the error.
What the error is saying is that your code is requesting the item at index 0 (basically, the first item), but the size of your index is 0 (basically, there are no items in the index).
Somewhere along the line, your database object is either emptied or not populated. To test this, run your fetchAllGames method and verify the contents of the index.
Didn't read the whole code, but I guess the problem is that, you are trying to get first element, from empty database.
Just check if the size of cursor greater than 0, before getting element.
if (cursor.getColumnCount() > 0)
return cursor.getString(0);
else return "no items";
I have tried to adapt the Google notepad tutorial ( http://developer.android.com/resources/tutorials/notepad/index.html ) for using SQLite databases to store GPS co-ords when the user tags current location. I've had no trouble getting the location added to the database but currently having trouble populating an array from the database in order to draw the locations on the map
private void fillData() {
/**
* Get all of the geotags from the database and populate the strarrlatitude and strarrlongitude arrays
* Also calls 'drawpins' to draw the geotags on the map
*/
Cursor c = mDbHelper.fetchAllNotes();
startManagingCursor(c);
strarrlatitude = new String[] { LocationsDbAdapter.COL_LATITUDE};
System.out.println(strarrlatitude);
strarrlongitude = new String[] { LocationsDbAdapter.COL_LONGITUDE };
drawpins();
}
I'm using a separate class called LocationsDbAdapter for handling database management as demonstrated in the notepad tutorial. The COL_LATITUDE and COL_LONGITUDE variables point to the column titles.
I've used a for loop to determine that nothing seems to be going into the strarrlatitude array but using the SQLite CLI I've checked that the database is being determined
Any help would be most gratefully received - if any more information is required I'll upload it as quick as possible
Many thanks
EDIT: Added the main two classes below for extra reference. I was trying not to overload with too much information but that was an error in judgement.
package com.nick.locationapp;
import java.util.List;
import android.content.Context;
import android.content.Intent;
import android.database.Cursor;
import android.graphics.drawable.Drawable;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.os.Bundle;
import android.text.AlteredCharSequence;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.widget.LinearLayout;
import android.widget.TextView;
import android.widget.Toast;
import com.google.android.maps.GeoPoint;
import com.google.android.maps.MapActivity;
import com.google.android.maps.MapView;
import com.google.android.maps.MyLocationOverlay;
import com.google.android.maps.Overlay;
import com.google.android.maps.OverlayItem;
import com.nick.androidsoar.R;
public class AndroidSoarActivity extends MapActivity {
/** Called when the activity is first created. */
LinearLayout linearLayout;
MapView mapView;
TextView LocationText;
double dbllatitude;
double dbllongitude;
double dblaltitude;
String debugstring;
String strlatitude = "0";
String strlongitude = "0";
String[] strarrlatitude;
String[] strarrlongitude;
String[] strarrlatitude1 = {"50.0","40.0","43.0","100.0"};
String[] strarrlongitude1 = {"12.4","123.4","60.2","72.0"};
Double[] debuglat = {50.0,40.0,43.0,100.0};
Double[] debuglong = {12.4,123.4,60.2,72.0};
Double dbllat;
Double dbllong;
int intlatitude;
int intlongitude;
private LocationsDbAdapter mDbHelper;
public static final int INSERT_ID = Menu.FIRST;
List<Overlay> mapOverlays;
Drawable drawable;
HelloItemizedOverlay itemizedOverlay;
#Override
protected boolean isRouteDisplayed() {
return false;
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
//Identifies the textview as variable 'LocationText'
LocationText = (TextView)findViewById(R.id.locationtext);
//mDbHelper points to the LocationsDbAdapter class used for handling the database
mDbHelper = new LocationsDbAdapter (this);
mDbHelper.open();
//defines the mapview as variable 'mapView' and enables zoom controls
mapView = (MapView) findViewById(R.id.mapview);
mapView.setBuiltInZoomControls(true);
mapOverlays = mapView.getOverlays();
//points variable 'drawable' to the icon resource of a pushpin, used for marking tags on the map
drawable = this.getResources().getDrawable(R.drawable.pushpin);
//Adds a current location overlay to the map 'mapView' and turns on the map's compass
MyLocationOverlay myLocationOverlay = new MyLocationOverlay(this, mapView);
mapView.getOverlays().add(myLocationOverlay);
myLocationOverlay.enableMyLocation();
myLocationOverlay.enableCompass();
mapView.postInvalidate();
/**
* Code required to receive gps location. Activates GPS provider, and is set to update only after
* at least 10 seconds and a position change of at least 10 metres
*/
LocationListener locationListener = new MyLocationListener();
//setting up the location manager
LocationManager locman = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
locman.requestLocationUpdates(LocationManager.GPS_PROVIDER, 10000, 10, locationListener);
//fillData();
}
/**
* Generates the menu from the resource 'mainmenu.xml'
*/
#Override
public boolean onCreateOptionsMenu(Menu menu) {
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.mainmenu, menu);
return true;
}
/**
* Code to run depending on the menu button pressed
*/
#Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.new_tag:
createTag();
fillData();
//Toast.makeText(getApplicationContext(), "geotag added to db", Toast.LENGTH_SHORT).show();
return true;
case R.id.draw_pins:
//fillData();
drawpins();
return true;
case R.id.create_tag:
Intent intent = new Intent(AndroidSoarActivity.this, TagCreate.class);
startActivity(intent);
}
return super.onOptionsItemSelected(item);
}
/**
* Create a new geotag pin from the current location
*/
private void createTag() {
//String titleName = "title " + titleNumber++;
mDbHelper.createNote(strlatitude, strlongitude);
Toast.makeText(getApplicationContext(), "geotag of lat: "+dbllatitude+" long: "+dbllongitude+" added to db ", Toast.LENGTH_SHORT).show();
fillData();
}
private void fillData() {
/**
* Get all of the geotags from the database and populate the strarrlatitude and strarrlongitude arrays
* Also calls 'drawpins' to draw the geotags on the map
*/
System.out.println("Fetching data");
Cursor c = mDbHelper.fetchAllNotes();
System.out.println(c.toString());
startManagingCursor(c);
strarrlatitude = new String[] { LocationsDbAdapter.COL_LATITUDE };
//System.out.println(strarrlatitude);
strarrlongitude = new String[] { LocationsDbAdapter.COL_LONGITUDE };
}
/**
* Creates an array of geopoints, pulling the locations from strarrlatitude and strarrlongitude
* and creates a mapview overlay using the geopoints
*/
private void drawpins() {
itemizedOverlay = new HelloItemizedOverlay(drawable);
GeoPoint[] mapPoints = new GeoPoint[strarrlatitude.length];
OverlayItem[] mapItems = new OverlayItem[strarrlatitude.length];
for(int i=1; i<strarrlatitude.length;i++){
dbllat = Double.parseDouble(strarrlatitude[i]);
dbllong = Double.parseDouble(strarrlongitude[i]);
System.out.println(i);
mapPoints[i] = new GeoPoint((int) (dbllat * 1E6), (int) (dbllong * 1E6));
mapItems[i] = new OverlayItem(mapPoints[i], "", "");
itemizedOverlay.addOverlay(mapItems[i]);
mapOverlays.add(itemizedOverlay);
}
}
private final class MyLocationListener implements LocationListener {
/**
* Code to run when the listener receives a new location
*/
#Override
public void onLocationChanged(Location locFromGps) {
Toast.makeText(getApplicationContext(), "Location changed, Lat: "+locFromGps.getLatitude()+" Long: "+ locFromGps.getLongitude(), Toast.LENGTH_SHORT).show();
//LocationText.setText("Your Location: Latitude " +locFromGps.getLatitude() + " Longitude: " +locFromGps.getLongitude());
dbllatitude = locFromGps.getLatitude();
dbllongitude = locFromGps.getLongitude();
dblaltitude = locFromGps.getAltitude();
strlatitude = Double.toString(dbllatitude);
strlongitude = Double.toString(dbllongitude);
dblaltitude = (dblaltitude / 0.3048);
LocationText.setText("Your Location: Latitude " + dbllatitude + " Longitude: " +dbllongitude + " Altitude " + dblaltitude);
}
#Override
public void onProviderDisabled(String provider) {
// called when the GPS provider is turned off (user turning off the GPS on the phone)
}
#Override
public void onProviderEnabled(String provider) {
// called when the GPS provider is turned on (user turning on the GPS on the phone)
}
#Override
public void onStatusChanged(String provider, int status, Bundle extras) {
// called when the status of the GPS provider changes
}
}
}
/**
* Following class has been adapted from Google's Android Notepad tutorial: http://developer.android.com/resources/tutorials/notepad/index.html
*
*/
package com.nick.locationapp;
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;
public class LocationsDbAdapter {
public static final String COL_LATITUDE = "latitude";
public static final String COL_LONGITUDE = "longitude";
//public static final String KEY_NOTE = "note";
public static final String COL_TITLE = "title";
public static final String COL_ROWID = "_id";
//public static final String TABLE_LOC = "locations";
private static final String TAG = "LocationsDbAdapter";
private DatabaseHelper mDbHelper;
private SQLiteDatabase mDb;
/**
* Database creation sql statement
*/
private static final String DATABASE_CREATE =
"CREATE TABLE locations (_id integer primary key autoincrement, "
+ "latitude text not null, longitude text not null);";
private static final String DATABASE_NAME = "data";
private static final String DATABASE_TABLE = "locations";
private static final int DATABASE_VERSION = 1;
private final Context mCtx;
private static class DatabaseHelper extends SQLiteOpenHelper {
DatabaseHelper(Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
}
/**
* SQL for creating the table. Table and column names are declared as variables
*/
#Override
public void onCreate(SQLiteDatabase db) {
db.execSQL("CREATE TABLE "+DATABASE_TABLE+" ("+COL_ROWID+ " INTEGER PRIMARY KEY AUTOINCREMENT, "+COL_LATITUDE+ " TEXT, "+COL_LONGITUDE+" TEXT "+COL_TITLE+" TEXT)");
}
#Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
Log.w(TAG, "Upgrading database from version " + oldVersion + " to "
+ newVersion + ", which will destroy all old data");
db.execSQL("DROP TABLE IF EXISTS location");
onCreate(db);
}
}
public LocationsDbAdapter(Context ctx) {
this.mCtx = ctx;
}
public LocationsDbAdapter open() throws SQLException {
mDbHelper = new DatabaseHelper(mCtx);
mDb = mDbHelper.getWritableDatabase();
return this;
}
public void close() {
mDbHelper.close();
}
/**
* Code for adding latitude and longitude into the database
* #param latitude
* #param longitude
* #return
*/
public long createNote(String latitude, String longitude) {
ContentValues geotagValues = new ContentValues();
geotagValues.put(COL_LATITUDE, latitude);
geotagValues.put(COL_LONGITUDE, longitude);
//geotagValues.put(COL_TITLE, title);
return mDb.insert(DATABASE_TABLE, null, geotagValues);
}
/**
* Query to return all data
* #return
*/
public Cursor fetchAllNotes() {
return mDb.query(DATABASE_TABLE, new String[] {COL_ROWID, COL_LATITUDE, COL_LONGITUDE}, null, null, null, null, null);
}
}
*
public void getData()
{
List<String> labels = new ArrayList<String>();
placeData = new PlaceDataSQL(MainActivity.this);
String selectQuery = "SELECT * FROM xmlTable;";
SQLiteDatabase db = placeData.getWritableDatabase();
Cursor cursor = db.rawQuery(selectQuery, null);
{
// looping through all rows and adding to list
if (cursor.moveToFirst()) {
do {
labels.add(cursor.getString(1));
Log.i("imagespath",arr[i]);
i++;
} while (cursor.moveToNext());
}
cursor.close();enter code here
db.close();
}
}
*