IrishWhiskey
IrishWhiskey

Reputation: 339

Insert on Button Click

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

Answers (3)

Piotr Chojnacki
Piotr Chojnacki

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

Festus Tamakloe
Festus Tamakloe

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

Emil Davtyan
Emil Davtyan

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

Related Questions