Here's an example that uses a spinner and selecting it shows the distance to the next item change and the current odometer reading. It's very basic and rather than using the date/time of service uses the odometer reading and (kilometers).
Should I use SQLite with int and time for this?
- You would probably want two intervals the distance and the time as servicing is often on a whichever comes first (the distance travelled or the time since the lasts service) the examples only assumes distance.
It is based upon 3 tables one for the cars, one for the service_items (oil filter change etc) and then a mapping/reference table (intervals). This has one row for each car/service item each row includes the referenced car and the referenced service_item, the odometer reading when the item was last serviced and the service interval.
It has a spinner that allows you to select the service item and selecting a service item displays how long to the next service for that item.
The database helper, DBHelper.java (subclass of SQLiteOpenHelper class) is :-
public class DBHelper extends SQLiteOpenHelper {
public static final String DBNAME = "service";
public static final int DBVERSION = 1;
public static final String TBITEM = "service_item";
public static final String TBCAR = "car";
public static final String TBINTERVAL = "interval";
public static final String COL_TBITEMS_ID = BaseColumns._ID;
public static final String COL_TBITEMS_NAME = "item_name";
static final String crt_items_sql = "CREATE TABLE IF NOT EXISTS " +
TBITEM + "(" +
COL_TBITEMS_ID + " INTEGER PRIMARY KEY, " +
COL_TBITEMS_NAME + " TEXT " +
")";
public static final String COL_TBCAR_ID = BaseColumns._ID;
public static final String COL_TBCAR_OWNERNAME = "owner_name";
public static final String COL_TBCAR_ODOMETER = "odometer";
static final String crt_car_sql = "CREATE TABLE IF NOT EXISTS " +
TBCAR + "(" +
COL_TBCAR_ID + " INTEGER PRIMARY KEY, " +
COL_TBCAR_OWNERNAME + " TEXT, " +
COL_TBCAR_ODOMETER + " INTEGER " +
")";
public static final String COL_TBINTERVAL_ITEMREF = "item_id_reference";
public static final String COL_TBINTERVAL_CARREF = "car_id_reference";
public static final String COL_TBINTERVAL_INTERVAL = "item_interval";
public static final String COL_TBINTERVAL_LASTDONE = "item_last_done";
static final String crt_intervals_sql = "CREATE TABLE IF NOT EXISTS " +
TBINTERVAL + "(" +
COL_TBINTERVAL_ITEMREF + " INTEGER REFERENCES " + TBITEM + "(" + COL_TBITEMS_ID + ")," +
COL_TBINTERVAL_CARREF + " INTEGER REFERENCES " + TBCAR + "(" + COL_TBCAR_ID + ")," +
COL_TBINTERVAL_INTERVAL + " INTEGER, " +
COL_TBINTERVAL_LASTDONE + " INTEGER DEFAULT 0 " +
")";
SQLiteDatabase mDB;
public DBHelper(Context context) {
super(context, DBNAME, null, DBVERSION);
mDB = this.getWritableDatabase();
}
@Override
public void onCreate(SQLiteDatabase db) {
db.execSQL(crt_items_sql);
db.execSQL(crt_car_sql);
db.execSQL(crt_intervals_sql);
}
@Override
public void onUpgrade(SQLiteDatabase db, int i, int i1) {
}
public long addCar(String name, long odometer) {
ContentValues cv = new ContentValues();
cv.put(COL_TBCAR_OWNERNAME,name);
cv.put(COL_TBCAR_ODOMETER,odometer);
return mDB.insert(TBCAR,null,cv);
}
public long addItem(String name) {
ContentValues cv = new ContentValues();
cv.put(COL_TBITEMS_NAME,name);
return mDB.insert(TBITEM,null,cv);
}
public long addInterval(long item_id, long car_id, long interval, long last_done) {
ContentValues cv = new ContentValues();
cv.put(COL_TBINTERVAL_ITEMREF, item_id);
cv.put(COL_TBINTERVAL_CARREF, car_id);
cv.put(COL_TBINTERVAL_INTERVAL,interval);
cv.put(COL_TBINTERVAL_LASTDONE,last_done);
return mDB.insert(TBINTERVAL,null,cv);
}
public long getCarOdometer(long car_id) {
long rv = -1;
Cursor csr = mDB.query(TBCAR,null,null,null,null,null,null);
if (csr.moveToFirst()) {
rv = csr.getLong(csr.getColumnIndex(COL_TBCAR_ODOMETER));
}
csr.close();
return rv;
}
public long getNextDueForItem(long car_id, long item_id) {
long rv = -1;
long odometer = getCarOdometer(car_id);
long last_done = 0;
long interval = 0;
String whereclause = COL_TBINTERVAL_ITEMREF + "=? AND " + COL_TBINTERVAL_CARREF + "=?";
String[] whereargs = new String[]{String.valueOf(item_id),String.valueOf(car_id)};
Cursor csr = mDB.query(TBINTERVAL,null,whereclause,whereargs,null,null,null);
if (csr.moveToFirst()) {
last_done = csr.getLong(csr.getColumnIndex(COL_TBINTERVAL_LASTDONE));
interval = csr.getLong(csr.getColumnIndex(COL_TBINTERVAL_INTERVAL));
long dueat = last_done + interval;
rv = dueat - odometer;
}
csr.close();
return rv;
}
}
The Activity MainActivity.java is :-
public class MainActivity extends AppCompatActivity {
Spinner mSpinner;
TextView mSpinner_selection;
ArrayAdapter<String> mSA;
ArrayList<String> items = new ArrayList<>(
Arrays.asList("Change Oil","Change Oil Filter","Change Air Filter","Change Spark Plugs")
);
DBHelper mDBHlpr;
long mCurrentCar = 1;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mSpinner = this.findViewById(R.id.spinner);
mSpinner_selection = this.findViewById(R.id.selected_spinner);
mSpinner_selection.setText("Nothing selected as yet"); //<<<< will likely not be seen
// Instaiate the Database Helper (will create the Database and tables when first run)
mDBHlpr = new DBHelper(this);
addSomeData();
handleSpinner();
}
// Setup the Spinner and the Item Select Listener
private void handleSpinner() {
if (mSA == null) {
mSA = new ArrayAdapter<String>(this,android.R.layout.simple_list_item_1,items);
mSpinner.setAdapter(mSA);
mSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
@Override
public void onItemSelected(AdapterView<?> adapterView, View view, int i, long l) {
//<<<<<<<<<< NOTE not the best way as assumes a direct map
// from the list to the service_item.
long duein = mDBHlpr.getNextDueForItem(mCurrentCar,(long)i + 1);
long odometer = mDBHlpr.getCarOdometer(mCurrentCar);
String text_to_show =
"You are due to " + mSA.getItem(i) + " in " + String.valueOf(duein) +
"Your Odometer reads " + String.valueOf(odometer);
mSpinner_selection.setText(text_to_show);
}
@Override
public void onNothingSelected(AdapterView<?> adapterView) {
}
});
}
}
// Add some data, a car and the service items based upon the ArrayList of items
// noting that for display purposes the interval increase per service_item
private void addSomeData() {
long thiscar = mDBHlpr.addCar("My Car",1123);
long interval = 10000;
for (String s: items) {
long thisitem = mDBHlpr.addItem(s);
mDBHlpr.addInterval(thisitem,thiscar,interval,0);
interval = interval + 500;
}
}
}
The layout for the MainActivity is activity_main.xml is :-
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hello World!" />
<Spinner
android:id="@+id/spinner"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
</Spinner>
<TextView
android:id="@+id/selected_spinner"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</LinearLayout>
- Note this is just a demo, to show how a spinner can be used.
- When first run it will show :-

- Selecting Change Oil Filter will show :-

- 10500 because 500 is progressively added to the service interval in the addSomeData method in MainActivity (just to show different data).