Reputation: 339
Why does my application crash when I click my button
and how do I fix it?
I need to insert a row
into my SQLite
database
when a button is clicked. It contains two values, which should be easy enough. One is a date
, formatted using the simpledateformatter
. The other is simply a location from an ArrayList
. I have no red lines in my code, but my app crashes when I press the button to insert
the row. Below is code from the 3 Java
files interacting with each other. I have a hunch the problem lies in my Model.java, however it could be more than that. If more code is needed just ask.
MainActivity.java
public class MainActivity extends Activity {
final String TAG = "*** DEBUG ***";
public static final String SMOKIN_DATA_FILE = "smokin.dat";
public static final int EDIT_ACTIVITY = 1;
public static Model model = null;
public static MySmokinDatabase mySmokinDatabase;
public static Cursor cursor;
public static SimpleCursorAdapter adapter;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
restoreModel();
if (mySmokinDatabase == null)
mySmokinDatabase = new MySmokinDatabase(this);
refreshView();
}
@Override
protected void onResume() {
super.onResume();
if (model == null)
restoreModel();
refreshView();
}
protected void onPause() {
super.onPause();
saveModel();
}
private void refreshView() {
Spinner spinner = (Spinner) findViewById(R.id.location_spinner);
ArrayAdapter<String> adapter = new ArrayAdapter<String>(this,
android.R.layout.simple_spinner_item, model.getLocationsArray());
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
spinner.setAdapter(adapter);
SimpleDateFormat sdf = new SimpleDateFormat("E, MMM dd");
TextView dateText = (TextView) findViewById(R.id.date);
TextView countText = (TextView) findViewById(R.id.count);
TextView daysText = (TextView) findViewById(R.id.days);
TextView totalText = (TextView) findViewById(R.id.total);
TextView aveText = (TextView) findViewById(R.id.ave);
GregorianCalendar now = new GregorianCalendar();
dateText.setText(sdf.format(now.getTime()));
//get today's count from data in the SQLite table - count entries with today's date
countText.setText("" + "");
//mySmokinDatabase.getTodaysCount());
// Table data
daysText.setText("" + String.format("%10d", model.getDays()));
totalText.setText("" + "get total count from data in SQLite table - count total rows");
if (model.getDays() > 0)
aveText.setText("calc average from SQLite and model info");
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.activity_main, menu);
return true;
}
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (resultCode == RESULT_OK && requestCode == EDIT_ACTIVITY) {
saveModel();
}
}
public void smokedHandler(View view) {
Spinner spinner = (Spinner) findViewById(R.id.location_spinner);
String s = spinner.getSelectedItem().toString();
String d = model.getDates();
mySmokinDatabase.insertSmokinValues(new Model(s,d));
cursor = mySmokinDatabase.getAllSmokinCursor();
adapter.changeCursor(cursor);
refreshView();
}
public void restoreModel() {
// Restore from disk, or start with an empty model
try {
ObjectInputStream ois = new ObjectInputStream(
openFileInput(SMOKIN_DATA_FILE));
model = (Model) ois.readObject();
ois.close();
}
catch (Exception e){
Log.v("*** DEBUG ***", "Error writing to file: " + e);
model = new Model();
}
}
public void saveModel() {
Log.v("*** AJ ***", "In onPause");
try {
ObjectOutputStream oos = new ObjectOutputStream(
openFileOutput(SMOKIN_DATA_FILE, Context.MODE_PRIVATE));
oos.writeObject(model);
oos.close();
}
catch (Exception e){
Log.v("*** MatchIt ***", "Error writing to file: " + e);
}
}
DB File
public long insertSmokinValues(Model model) {
ContentValues newSmokinValues = new ContentValues();
newSmokinValues.put(KEY_DATE, model.getDates());
newSmokinValues.put(KEY_LOCATION, model.getLocations());
SQLiteDatabase db = smokinDBOpenHelper.getWritableDatabase();
return db.insert(SmokinDBOpenHelper.INCIDENTS_TABLE, null, newSmokinValues);
}
public Cursor getAllSmokinCursor() {
SQLiteDatabase db = smokinDBOpenHelper.getWritableDatabase();
return db.query(SmokinDBOpenHelper.INCIDENTS_TABLE, new String[]
{KEY_ID, KEY_LOCATION, KEY_DATE}, null, null, null, null, null);
}
Model File
private ArrayList<String> locations = new ArrayList<String>();
public String [] defaultLocations = {"Home", "Work", "Commuting", "School", "Bar",
"Restaurant", "Social Gathering", "Other"};
public Model(GregorianCalendar date){
startDate = date;
for (String s : this.defaultLocations)
locations.add(s);
}
public Model(String s, String d) {
place = s;
dates = d;
}
public String getDates() {
GregorianCalendar gc = new GregorianCalendar();
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm");
dates = sdf.format(gc.getTime());
return dates;
}
public String getLocations() {
for (String s : this.locations)
place = s;
return place;
}
As requested log cat:
03-18 15:52:42.397: W/dalvikvm(676): threadid=1: thread exiting with uncaught
exception
(group=0x40a13300)
03-18 15:52:42.457: E/AndroidRuntime(676): FATAL EXCEPTION: main
03-18 15:52:42.457: E/AndroidRuntime(676): java.lang.IllegalStateException: Could not
execute method of the activity
03-18 15:52:42.457: E/AndroidRuntime(676): at
android.view.View$1.onClick(View.java:3591)
03-18 15:52:42.457: E/AndroidRuntime(676): at
android.view.View.performClick(View.java:4084)
03-18 15:52:42.457: E/AndroidRuntime(676): at
android.view.View$PerformClick.run(View.java:16966)
03-18 15:52:42.457: E/AndroidRuntime(676): at
android.os.Handler.handleCallback(Handler.java:615)
03-18 15:52:42.457: E/AndroidRuntime(676): at
android.os.Handler.dispatchMessage(Handler.java:92)
03-18 15:52:42.457: E/AndroidRuntime(676): at android.os.Looper.loop(Looper.java:137)
03-18 15:52:42.457: E/AndroidRuntime(676): at
android.app.ActivityThread.main(ActivityThread.java:4745)
03-18 15:52:42.457: E/AndroidRuntime(676): at
java.lang.reflect.Method.invokeNative(Native Method)
03-18 15:52:42.457: E/AndroidRuntime(676): at
java.lang.reflect.Method.invoke(Method.java:511)
03-18 15:52:42.457: E/AndroidRuntime(676): at
com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:786)
03-18 15:52:42.457: E/AndroidRuntime(676): at
com.android.internal.os.ZygoteInit.main(ZygoteInit.java:553)
03-18 15:52:42.457: E/AndroidRuntime(676): at dalvik.system.NativeStart.main(Native
Method)
03-18 15:52:42.457: E/AndroidRuntime(676): Caused by:
java.lang.reflect.InvocationTargetException
03-18 15:52:42.457: E/AndroidRuntime(676): at
java.lang.reflect.Method.invokeNative(Native Method)
03-18 15:52:42.457: E/AndroidRuntime(676): at
java.lang.reflect.Method.invoke(Method.java:511)
03-18 15:52:42.457: E/AndroidRuntime(676): at
android.view.View$1.onClick(View.java:3586)
03-18 15:52:42.457: E/AndroidRuntime(676): ... 11 more
03-18 15:52:42.457: E/AndroidRuntime(676): Caused by: java.lang.NullPointerException
03-18 15:52:42.457: E/AndroidRuntime(676): at
com.example.smokin4ThomasSullivan.MainActivity.smokedHandler(MainActivity.java:119)
03-18 15:52:42.457: E/AndroidRuntime(676): ... 14 more
line 119: adapter.changeCursor(cursor); The method involved is posted in my DB file
As always any help is appreciated!
Upvotes: 3
Views: 1401
Reputation: 6867
Log says everything: you're trying to use adapter
which is null
in this line:
adapter.changeCursor(cursor);
Edit:
As I thought, you declare your adapter
field here:
public static SimpleCursorAdapter adapter;
But you don't initialize it, and as you should know in Java if you declare a field without initialization, it's set to null
. That's why you get your error.
I haven't personally used SimpleCursorAdapter
class, but you might want to take a look at constructor for it which is described in android documentation:
http://developer.android.com/reference/android/widget/SimpleCursorAdapter.html
So basically inside onCreate()
method, you should do something like this:
adapter = new SimpleCursorAdapter( this,
R.layout.some_layout,
cursor,
columns,
to,
0 );
Used constructor's parameters are described in documentation to which I posted link earlier.
You might also want to check this code which uses SimpleCursorAdapter
:
http://www.mysamplecode.com/2012/07/android-listview-cursoradapter-sqlite.html
Upvotes: 3
Reputation: 11310
Edit:
Like others guys say. It is correct that the adapter
is responsible for the NPE
However it is also important to adopt the right way by dealing with Sqlite cursor
.
It is important to do following
replace
public Cursor getAllSmokinCursor() {
SQLiteDatabase db = smokinDBOpenHelper.getWritableDatabase();
return db.query(SmokinDBOpenHelper.INCIDENTS_TABLE, new String[]
{KEY_ID, KEY_LOCATION, KEY_DATE}, null, null, null, null, null);
}
with
public List<Model> getAllSmokinCursor() {
List<Model> models= new ArrayList<Model>();
SQLiteDatabase db = smokinDBOpenHelper.getWritableDatabase();
Cursor cursor= db.query(SmokinDBOpenHelper.INCIDENTS_TABLE, new String[]
{KEY_ID, KEY_LOCATION, KEY_DATE}, null, null, null, null, null);
cursor.moveToFirst();
while (!cursor.isAfterLast()) {
Model device = fromCursorToObject(cursor);
models.add(device);
cursor.moveToNext();
}
// Make sure to close the cursor
cursor.close();
return models;
}
I use here a list because you don't have any restriction in your requestpublic static Device
fromCursorToObject(Cursor cursor) {
Model model = new Model();
int i = 0;
model.setId(cursor.getLong(i++));
model.setLocation(cursor.getString(i++));
model.setDate(cursor.getString(i++));
return model;
}
i assume that you must add getter/setter to your Model class and also ID field (private Long id)
Upvotes: 1
Reputation: 14089
First of all you should close the database in these functions :
public long insertSmokinValues(Model model) {
ContentValues newSmokinValues = new ContentValues();
newSmokinValues.put(KEY_DATE, model.getDates());
newSmokinValues.put(KEY_LOCATION, model.getLocations());
SQLiteDatabase db = smokinDBOpenHelper.getWritableDatabase();
return db.insert(SmokinDBOpenHelper.INCIDENTS_TABLE, null, newSmokinValues);
}
public Cursor getAllSmokinCursor() {
SQLiteDatabase db = smokinDBOpenHelper.getWritableDatabase();
return db.query(SmokinDBOpenHelper.INCIDENTS_TABLE, new String[]
{KEY_ID, KEY_LOCATION, KEY_DATE}, null, null, null, null, null);
}
Second if you don't want to change the cursor in the adapter when there is no results in gestSmokinCursor
simply check with moveToFirst
if the cursor contains a result, if not throw a custom exception say EmptyCursorException
which you can handle when you get the cursor.
Also you need to think about how you are closing your cursors, as I'm not sure if your adapter is closing the cursors when you change them and when the activity is destroyed, but this is also your responsibility.
If your NullPointerException
is on this line:
adapter.changeCursor(cursor);
Then your adapter is simply null
and needs to be initiated and this has nothing to do with the database, however there are still a lot of problems with your code that you should address, otherwise you will encounter errors and leaks when people start using the app.
Upvotes: 1