androidormsugarorm

Android - Sugar ORM Save Crash


I am trying to integrate Sugar ORM (v 1.3) into my Android app and I keep getting a crash (NullPointerException) when trying to save a newly created entity.

Here is my crash...

01-21 06:02:36.012    2856-2856/com.spuddmobile.kel E/AndroidRuntime﹕ FATAL EXCEPTION: main
    Process: com.spuddmobile.kel, PID: 2856
    java.lang.NullPointerException
            at com.orm.SugarRecord.save(SugarRecord.java:109)
            at com.orm.SugarRecord.save(SugarRecord.java:45)
            at com.spuddmobile.kel.Fragments.NewAppFragment._SaveForm(NewAppFragment.java:231)
            at com.spuddmobile.kel.Fragments.NewAppFragment.onMenuItemSelection(NewAppFragment.java:175)
            at com.spuddmobile.kel.Activities.MainActivity.onOptionsItemSelected(MainActivity.java:89)
            at android.app.Activity.onMenuItemSelected(Activity.java:2600)
            at com.android.internal.policy.impl.PhoneWindow.onMenuItemSelected(PhoneWindow.java:1012)
            at com.android.internal.view.menu.MenuBuilder.dispatchMenuItemSelected(MenuBuilder.java:735)
            at com.android.internal.view.menu.MenuItemImpl.invoke(MenuItemImpl.java:152)
            at com.android.internal.view.menu.MenuBuilder.performItemAction(MenuBuilder.java:874)
            at com.android.internal.view.menu.ActionMenuView.invokeItem(ActionMenuView.java:546)
            at com.android.internal.view.menu.ActionMenuItemView.onClick(ActionMenuItemView.java:115)
            at android.view.View.performClick(View.java:4438)
            at android.view.View$PerformClick.run(View.java:18422)
            at android.os.Handler.handleCallback(Handler.java:733)
            at android.os.Handler.dispatchMessage(Handler.java:95)
            at android.os.Looper.loop(Looper.java:136)
            at android.app.ActivityThread.main(ActivityThread.java:5017)
            at java.lang.reflect.Method.invokeNative(Native Method)
            at java.lang.reflect.Method.invoke(Method.java:515)
            at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:779)
            at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:595)
            at dalvik.system.NativeStart.main(Native Method)

Here is my AppManifest.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.spuddmobile.kel" >

    <application
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:name="com.orm.SugarApp"
        android:theme="@style/AppTheme" >

        <meta-data android:name="DATABASE" android:value="kel.db" />
        <meta-data android:name="VERSION" android:value="1" />
        <meta-data android:name="QUERY_LOG" android:value="true" />
        <meta-data android:name="DOMAIN_PACKAGE_NAME" android:value="com.spuddmobile.kel.Model" />

        <activity
            android:name=".Activities.MainActivity"
            android:label="@string/app_name"
            android:windowSoftInputMode="stateHidden|adjustResize">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
            <meta-data android:name="android.support.UI_OPTIONS" android:value="splitActionBarWhenNarrow" />
        </activity>
    </application>

</manifest>

As you can see I am definitely setting the android:name to com.orm.SugarApp per the documentation.

Here is my entity/domain class...

public class Appraisal extends SugarRecord<Appraisal>
{
    Double rent;
    Integer area;
    Integer currentPeriod;
    Integer reviewFrequency;
    Integer rentFreePeriod;
    Integer interimRentPeriod;
    Double interimRentPrice;
    Integer secondInterimRentPeriod;
    Double secondInterimRentPrice;
    Double incentives;
    Integer breakPeriod;
    Double breakPenalty;
    Double breakIncentiveRent;
    Integer breakIncentiveRentPeriod;
    Double breakRisk;
    String name;
    Date createdDate;
    Date updatedDate;

    public Appraisal ()
    {

    }

    public Appraisal (Double rent,
                      Integer area,
                      Integer currentPeriod,
                      Integer reviewFrequency,
                      Integer rentFreePeriod,
                      Integer interimRentPeriod,
                      Double interimRentPrice,
                      Integer secondInterimRentPeriod,
                      Double secondInterimRentPrice,
                      Double incentives,
                      Integer breakPeriod,
                      Double breakPenalty,
                      Double breakIncentiveRent,
                      Integer breakIncentiveRentPeriod,
                      Double breakRisk,
                      String name,
                      Date createdDate,
                      Date updatedDate)
    {
        this.rent = rent;
        this.area = area;
        this.currentPeriod = currentPeriod;
        this.reviewFrequency = reviewFrequency;
        this.rentFreePeriod = rentFreePeriod;
        this.interimRentPeriod = interimRentPeriod;
        this.interimRentPrice = interimRentPrice;
        this.secondInterimRentPeriod = secondInterimRentPeriod;
        this.secondInterimRentPrice = secondInterimRentPrice;
        this.incentives = incentives;
        this.breakPeriod = breakPeriod;
        this.breakPenalty = breakPenalty;
        this.breakIncentiveRent = breakIncentiveRent;
        this.breakIncentiveRentPeriod = breakIncentiveRentPeriod;
        this.breakRisk = breakRisk;
        this.name = name;
        this.createdDate = createdDate;
        this.updatedDate = updatedDate;
    }
}

Notice that my entity does in fact extend SugarRecord and I do provide the required empty constructor as well as a parameterized constructor. I am NOT overriding the super init method with a context because according to the documentation that is no longer required in v1.3 of Sugar ORM.

Finally, the code that crashes...

// create new app
Appraisal nApp = new Appraisal();
nApp.save();

The save is where it crashes. Now, I have checked to ensure the database is being created correctly, via the Android Device Monitor, and it does in fact exist with an APPRAISAL table. However, when I query the table it's empty which makes sense as Sugar never completes the save() function.

Does anyone have any idea with I'm doing wrong here? Just to ensure I have given all pertinent information, my Gradle build script is below.

buildscript {
    repositories {
        mavenCentral()
    }
    dependencies {
        classpath 'com.android.tools.build:gradle:1.0.0'
    }
}

apply plugin: 'android'

android {
    compileSdkVersion 13
    buildToolsVersion '19.1.0'
    defaultConfig {
        applicationId 'com.spuddmobile.kel'
        minSdkVersion 13
        targetSdkVersion 17
    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt'
        }
    }
    productFlavors {}
}

repositories {
    mavenCentral()
}

dependencies {
    compile 'com.noveogroup.android:android-logger:1.3.4'
    compile 'com.github.satyan:sugar:1.3'
}

Solution

  • Your entity has a default no-parameter constructor where you DO NOT intialize any field... So every value of your fields is null.

    As you have a NullPointerException, if I were you, I will try to init every field with a default value. For example :

    public Appraisal ()
    {
        this.rent = 0.0;
        this.area = 0;
        ...
    }