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'
}
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;
...
}