Search code examples
javalistviewandroid-sqliteandroid-cursoradapter

SQLite Column '_id' does not exists


The app: I have an app that creates multiple machines with:

  • id, name and location

each of these machines I have to let the user input the income

  • id, note, date, money, machines_id

The Problem: java.lang.IllegalArgumentException: column '_id' does not exist, WHEN CLEARLY it does in the DBHelper.

What I have tried: Uninstalling the app, deleting the DB with the ADM, upgrading DB version.

My question: what am i missing ?

If you need any other class or have any feedback dont hesitate to indulge me pls!

DBHelper

public class DBHelpter extends SQLiteOpenHelper {

private static final String DB_NAME = "machines.db";
private static final int DB_VERSION = 2;

public static final String TABLE_MACHINES = "machines";
public static final String MACHINES_COLUMN_NAME = "name";
public static final String MACHINES_COLUMN_LOCATION = "location";
public static final String MACHINES_ID = "_id";

public static final String TABLE_INCOME = "income";
public static final String INCOME_COLUMN_MONEY = "money";
public static final String INCOME_COLUMN_DATE = "date";
public static final String INCOME_COLUMN_NOTE = "note";
public static final String INCOME_ID = "_id";
public static final String INCOME_COLUMN_MACHINES_ID = "machines_id";

private Context mContext;

public DBHelpter(Context context) {
    super(context, DB_NAME, null, DB_VERSION);
}

@Override
public void onCreate(SQLiteDatabase db) {
    String query1 = String.format("CREATE TABLE " + TABLE_MACHINES + "("
        + MACHINES_ID + " INTEGER PRIMARY KEY AUTOINCREMENT, "
        + MACHINES_COLUMN_NAME + " TEXT NOT NULL, "
        + MACHINES_COLUMN_LOCATION + " TEXT NOT NULL)",
            TABLE_MACHINES, MACHINES_COLUMN_NAME, MACHINES_COLUMN_LOCATION, MACHINES_ID);

    String query2 = String.format("CREATE TABLE " + TABLE_INCOME + "("
        + INCOME_ID + " INTEGER PRIMARY KEY AUTOINCREMENT, "
        + INCOME_COLUMN_MONEY + " REAL NOT NULL, "
        + INCOME_COLUMN_DATE + " DATE NOT NULL, "
        + INCOME_COLUMN_NOTE + " TEXT NOT NULL, "
        + INCOME_COLUMN_MACHINES_ID + " INTEGER NOT NULL)",
            TABLE_INCOME, INCOME_ID, INCOME_COLUMN_MONEY, INCOME_COLUMN_DATE, INCOME_COLUMN_NOTE, INCOME_COLUMN_MACHINES_ID);
    db.execSQL(query1);
    db.execSQL(query2);

}

@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
    String query1 = String.format("DROP TABLE IF EXISTS " + TABLE_MACHINES);
    String query2 = String.format("DROP TABLE IF EXISTS " + TABLE_INCOME);
    db.execSQL(query1);
    db.execSQL(query2);
    onCreate(db);

}

public void insertNewMachine(String name, String location){
    SQLiteDatabase db = this.getWritableDatabase();
    ContentValues values = new ContentValues();
    values.put(MACHINES_COLUMN_NAME, name);
    values.put(MACHINES_COLUMN_LOCATION, location);
    db.insertWithOnConflict(TABLE_MACHINES, null, values, SQLiteDatabase.CONFLICT_REPLACE);
    db.close();
}

public void updateMachine(long id, String name, String location){
    SQLiteDatabase db = this.getWritableDatabase();
    ContentValues values = new ContentValues();
    values.put(MACHINES_COLUMN_NAME, name);
    values.put(MACHINES_COLUMN_LOCATION, location);
    db.update(TABLE_MACHINES, values, MACHINES_ID + " = ?", new String[]{Long.toString(id)});
    db.close();
}

public void deleteMachine(long id){
    SQLiteDatabase db = this.getWritableDatabase();
    db.delete(TABLE_MACHINES, MACHINES_ID + " = ?", new String[]{id + ""});
    db.close();
}

public ArrayList<MachinesClass> getAllMachines(){
    ArrayList<MachinesClass> machinesList = new ArrayList<>();
    SQLiteDatabase db = this.getReadableDatabase();
    Cursor cursor = db.rawQuery("SELECT * FROM "+ TABLE_MACHINES, null);
    while (cursor.moveToNext()){
        final long id = cursor.getLong(cursor.getColumnIndex(MACHINES_ID));
        final String name = cursor.getString(cursor.getColumnIndex(MACHINES_COLUMN_NAME));
        final String location = cursor.getString(cursor.getColumnIndex(MACHINES_COLUMN_LOCATION));
        machinesList.add(new MachinesClass(id, name, location));
    }
    cursor.close();
    db.close();
    return machinesList;
}

public void insertNewIncome(Double money, String date, String note, long machines_id){
    SQLiteDatabase db = this.getWritableDatabase();
    ContentValues values = new ContentValues();
    values.put(INCOME_COLUMN_MONEY, money);
    values.put(INCOME_COLUMN_DATE, date);
    values.put(INCOME_COLUMN_NOTE, note);
    values.put(INCOME_COLUMN_MACHINES_ID, machines_id);
    db.insertWithOnConflict(TABLE_INCOME, null, values, SQLiteDatabase.CONFLICT_REPLACE);
    db.close();
}

public void updateIncome(Double money, String date, String note, long machines_id){
    SQLiteDatabase db = this.getWritableDatabase();
    ContentValues values = new ContentValues();
    values.put(INCOME_COLUMN_MONEY, money);
    values.put(INCOME_COLUMN_DATE, date);
    values.put(INCOME_COLUMN_NOTE, note);
    db.update(TABLE_INCOME, values, "_id = ?", new String[]{Long.toString(machines_id)});
    db.close();
}

public void deleteIncome(long id){
    SQLiteDatabase db = this.getWritableDatabase();
    db.delete(TABLE_INCOME, "_id = ?", new String[]{Long.toString(id)});
}

public double getIncomeOfMachine(long machinesId){
    SQLiteDatabase db = getReadableDatabase();
    Cursor cursor = db.rawQuery("SELECT machines_id, SUM(money) AS total FROM income WHERE machines_id = "+machinesId+"", null);
    cursor.moveToFirst();
    double total_amount = cursor.getDouble(cursor.getColumnIndex("total"));
    return total_amount;
}

public ArrayList<String> getInfoFromMachine(long machinesId){
    ArrayList<String> all_notes = new ArrayList<>();
    SQLiteDatabase db = getReadableDatabase();
    Cursor cursor = db.rawQuery("SELECT note, date FROM income WHERE machines_id = "+machinesId+"",null);
    cursor.moveToFirst();
    while (cursor.moveToNext()){
        String note = cursor.getString(cursor.getColumnIndex("note"));
        String date = cursor.getString(cursor.getColumnIndex("date"));
        all_notes.add(date);
        all_notes.add(note);
    }
    db.close();
    cursor.close();
    return all_notes;
}

MachineInfo

public class MachineInfo extends AppCompatActivity {

private TextView mLocation, mMoney, mNotes;
private DBHelpter mDBHelpter;
private ListView mNotesList;
private FloatingActionButton mFAB;
private SQLiteDatabase db;
private Cursor mCursor;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_machine_info);

    getSupportActionBar().setDisplayHomeAsUpEnabled(true);

    mDBHelpter = new DBHelpter(getApplicationContext());
    db = mDBHelpter.getWritableDatabase();

    mLocation = (TextView) findViewById(R.id.tvLocation);
    mMoney = (TextView) findViewById(R.id.tvMoney);
    mNotes = (TextView) findViewById(R.id.tvNotes);
    mFAB = (FloatingActionButton) findViewById(R.id.fabAddIncome);
    mNotesList = (ListView) findViewById(R.id.lvNotes);

    SharedPreferences mSharedPreferences = getSharedPreferences(PREFS_NAME, Context.MODE_PRIVATE);
    Long machines_id = mSharedPreferences.getLong("machines_id", 0);

    double total_amount = mDBHelpter.getIncomeOfMachine(machines_id);
    mMoney.setText(String.format("%.3f",total_amount));

    String location = mSharedPreferences.getString("location", null);
    mLocation.setText(location);

    mCursor = db.rawQuery("SELECT note, date FROM income WHERE machines_id = "+machines_id+"",null);
    ListAdapter adapter = new ListAdapter(this, mCursor);
    mNotesList.setAdapter(adapter);
    db.close();

    mFAB.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            Intent i = new Intent(getApplicationContext(), IncomeCreation.class);
            startActivity(i);
        }
    });

}

ListAdapter

public class ListAdapter extends CursorAdapter {


public ListAdapter(Context context, Cursor c) {
    super(context, c);
}

public View newView(Context context, Cursor cursor, ViewGroup parent) {
    return LayoutInflater.from(context).inflate(R.layout.notes_list, parent, false);
}

@Override
public void bindView(View view, Context context, Cursor cursor) {

    DBHelpter mDBHelper = new DBHelpter(context);
    SQLiteDatabase db = mDBHelper.getWritableDatabase();

    TextView mNote = (TextView) view.findViewById(R.id.tvNote);
    TextView mNotesDate = (TextView) view.findViewById(R.id.tvNoteDate);

    String note = cursor.getString(cursor.getColumnIndex("note"));
    String date = cursor.getString(cursor.getColumnIndex("date"));

    mNote.setText(note);
    mNotesDate.setText(date);

}

Error

 java.lang.RuntimeException: Unable to start activity ComponentInfo{tech.destinum.machines/tech.destinum.machines.MachineInfo}: java.lang.IllegalArgumentException: column '_id' does not exist
      at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2416)
      at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2476)
      at android.app.ActivityThread.-wrap11(ActivityThread.java)
      at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1344)
      at android.os.Handler.dispatchMessage(Handler.java:102)
      at android.os.Looper.loop(Looper.java:148)
      at android.app.ActivityThread.main(ActivityThread.java:5417)
      at java.lang.reflect.Method.invoke(Native Method)
      at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:726)
      at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:616)
   Caused by: java.lang.IllegalArgumentException: column '_id' does not exist
      at android.database.AbstractCursor.getColumnIndexOrThrow(AbstractCursor.java:333)
      at android.widget.CursorAdapter.init(CursorAdapter.java:180)
      at android.widget.CursorAdapter.<init>(CursorAdapter.java:128)
      at tech.destinum.machines.ListAdapter.<init>(ListAdapter.java:0)
      at tech.destinum.machines.MachineInfo.onCreate(MachineInfo.java:62)
      at android.app.Activity.performCreate(Activity.java:6237)
      at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1107)
      at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2369)
      at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2476) 
      at android.app.ActivityThread.-wrap11(ActivityThread.java) 
      at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1344) 
      at android.os.Handler.dispatchMessage(Handler.java:102) 
      at android.os.Looper.loop(Looper.java:148) 
      at android.app.ActivityThread.main(ActivityThread.java:5417) 
      at java.lang.reflect.Method.invoke(Native Method) 
      at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:726) 
      at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:616) 

Solution

  • As stated by the Javadoc for CursorAdapter:

    The Cursor must include a column named "_id" or this class will not work.

    Therefore, you must add _id to the projection so that the resulting cursor will have that column. E.g.:

        Cursor cursor = db.rawQuery("SELECT _id, note, date FROM income WHERE machines_id = "+machinesId+"", null);