2012-04-27 5 views
1

Я пытаюсь вставить некоторые данные в созданную мной таблицу. У меня есть этот класс:Android SQLite INSERT вызывает сбой приложения

public class DataBase extends SQLiteOpenHelper { 
private static final String DB_NAME = "db_mydatabase"; 
private static final int DB_VERSION = 1; 

private static final String TBL_USERS = "users"; 
private static final String TBL_USERSE_CREATE = "CREATE TABLE IF NOT EXISTS " 
          + TBL_USERS + "(id integer PRIMARY KEY AUTOINCREMENT, " 
          + "usr varchar(128) NOT NULL UNIQUE, psw varchar(512));"; 

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

public List<String> GetUsersList() { 
    List<String> users = new ArrayList<String>(); 
    SQLiteDatabase db = this.getWritableDatabase(); 
    Cursor c = db.rawQuery("SELECT id, usr FROM " + TBL_USERS, null); 
    if (c != null) { 
     if (c.moveToFirst()) { 
      do { 
       String firstName = c.getString(c.getColumnIndex("USR")); 
       users.add(firstName); 
       } while (c.moveToNext()); 
     } 
    } 
    return users; 
} 

public void CreateNewUser(String username, String password) { 
    SQLiteDatabase db = this.getWritableDatabase(); 
    db.execSQL("INSERT INTO " + TBL_USERS + " (usr, psw) VALUES ('" + username + "', '" + password + "')"); 
      //If I comment this line, it doesn't crashes anymore, but I don't see why 
} 

@Override 
public void onCreate(SQLiteDatabase db) { 
    db.execSQL(TBL_USERSE_CREATE); 
} 

@Override 
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { 
    db.execSQL("DROP TABLE IF EXISTS " + TBL_USERS); 
    onCreate(db); 
} 

}

Так что, когда я нажимаю кнопку REGISTER, имя пользователя и пароль от EditText отправляются CreateNewUser. Мой класс активности выглядит следующим образом:

public class RegisterActivity extends Activity { 
List<String> values; 
DataBase dtb; 
@Override 
public void onCreate(Bundle savedInstanceState) { 
    super.onCreate(savedInstanceState); 
    setContentView(R.layout.register); 

    ListView listView = (ListView) findViewById(R.id.listView1); 

    dtb = new DataBase(MainActivity.MainContext); 
    values = dtb.GetUsersList(); 

    listView.setAdapter(new ArrayAdapter<String>(MainActivity.MainContext, R.layout.listitem, values)); 

    Button Create = (Button) findViewById(R.id.Create); 
    Create.setOnClickListener(new View.OnClickListener() { 
     public void onClick(View arg0) { 
      EditText username = (EditText)findViewById(R.id.Username); 
      EditText password = (EditText)findViewById(R.id.Password); 
      if (username.getText().length()>0 && password.getText().length()>0) { 
       if (values.indexOf(username.getText())<0) { 
        dtb.CreateNewUser(username.getText().toString(), password.getText().toString()); 
        values = dtb.GetUsersList(); 
       } 
      } 
     } 
    }); 
} 

}

Я новичок в SQLite программиста, и я получаю эту понятную критическую ошибку и зависания

 
> **04-24 12:30:51.340: E/CursorWindow(7986): Bad request for field slot 0,-1. numRows = 1, numColumns = 2** 04-24 12:30:51.350: 
> D/AndroidRuntime(7986): Shutting down VM 04-24 12:30:51.350: 
> W/dalvikvm(7986): threadid=3: thread exiting with uncaught exception 
> (group=0x4001b188) 04-24 12:30:51.350: E/AndroidRuntime(7986): 
> Uncaught handler: thread main exiting due to uncaught exception 
> **04-24 12:30:51.380: E/AndroidRuntime(7986): java.lang.IllegalStateException: get field slot from row 0 col -1 
> failed** 04-24 12:30:51.380: E/AndroidRuntime(7986): at 
> android.database.CursorWindow.getString_native(Native Method) 04-24 
> 12:30:51.380: E/AndroidRuntime(7986):  at 
> android.database.CursorWindow.getString(CursorWindow.java:329) 04-24 
> 12:30:51.380: E/AndroidRuntime(7986):  at 
> android.database.AbstractWindowedCursor.getString(AbstractWindowedCursor.java:49) 
> 04-24 12:30:51.380: E/AndroidRuntime(7986): at 
> com.bma.myagenda.DataBase.GetUsersList(DataBase.java:32) 04-24 
> 12:30:51.380: E/AndroidRuntime(7986):  at 
> com.bma.myagenda.RegisterActivity$1.onClick(RegisterActivity.java:46) 
> 04-24 12:30:51.380: E/AndroidRuntime(7986): at 
> android.view.View.performClick(View.java:2364) 04-24 12:30:51.380: 
> E/AndroidRuntime(7986): at 
> android.view.View.onTouchEvent(View.java:4179) 04-24 12:30:51.380: 
> E/AndroidRuntime(7986): at 
> android.widget.TextView.onTouchEvent(TextView.java:6541) 04-24 
> 12:30:51.380: E/AndroidRuntime(7986):  at 
> android.view.View.dispatchTouchEvent(View.java:3709) 04-24 
> 12:30:51.380: E/AndroidRuntime(7986):  at 
> android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:884) 04-24 
> 12:30:51.380: E/AndroidRuntime(7986):  at 
> android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:884) 04-24 
> 12:30:51.380: E/AndroidRuntime(7986):  at 
> android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:884) 04-24 
> 12:30:51.380: E/AndroidRuntime(7986):  at 
> android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:884) 04-24 
> 12:30:51.380: E/AndroidRuntime(7986):  at 
> android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:884) 04-24 
> 12:30:51.380: E/AndroidRuntime(7986):  at 
> com.android.internal.policy.impl.PhoneWindow$DecorView.superDispatchTouchEvent(PhoneWindow.java:1659) 
> 04-24 12:30:51.380: E/AndroidRuntime(7986): at 
> com.android.internal.policy.impl.PhoneWindow.superDispatchTouchEvent(PhoneWindow.java:1107) 
> 04-24 12:30:51.380: E/AndroidRuntime(7986): at 
> android.app.Activity.dispatchTouchEvent(Activity.java:2061) 04-24 
> 12:30:51.380: E/AndroidRuntime(7986):  at 
> com.android.internal.policy.impl.PhoneWindow$DecorView.dispatchTouchEvent(PhoneWindow.java:1643) 
> 04-24 12:30:51.380: E/AndroidRuntime(7986): at 
> android.view.ViewRoot.handleMessage(ViewRoot.java:1691) 04-24 
> 12:30:51.380: E/AndroidRuntime(7986):  at 
> android.os.Handler.dispatchMessage(Handler.java:99) 04-24 
> 12:30:51.380: E/AndroidRuntime(7986):  at 
> android.os.Looper.loop(Looper.java:123) 04-24 12:30:51.380: 
> E/AndroidRuntime(7986): at 
> android.app.ActivityThread.main(ActivityThread.java:4363) 04-24 
> 12:30:51.380: E/AndroidRuntime(7986):  at 
> java.lang.reflect.Method.invokeNative(Native Method) 04-24 
> 12:30:51.380: E/AndroidRuntime(7986):  at 
> java.lang.reflect.Method.invoke(Method.java:521) 04-24 12:30:51.380: 
> E/AndroidRuntime(7986): at 
> com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:860) 
> 04-24 12:30:51.380: E/AndroidRuntime(7986): at 
> com.android.internal.os.ZygoteInit.main(ZygoteInit.java:618) 04-24 
> 12:30:51.380: E/AndroidRuntime(7986):  at 
> dalvik.system.NativeStart.main(Native Method) 

ответ

1

Изменение:

String firstName = c.getString(c.getColumnIndex("USR")); 

To:

String firstName = c.getString(c.getColumnIndex("usr")); //USR != usr 
1

Попробуйте заменить код вставки с это:

public void CreateNewUser(String username, String password) { 
    SQLiteDatabase db = this.getWritableDatabase(); 

ContentValues initialValues = new ContentValues(); 
initialValues.put(usr, username); 
initialValues.put(psw, password); 

db.insert(TBL_USERS, null, initialValues); 
} 
+0

Спасибо. Это лучший способ избежать строк, я полагаю, – ali

+0

@ali yes, что также избежит строк. И он возвращает вам идентификатор только что вставленного столбца, который execSQL не может. – zapl

1

изменение

String firstName = c.getString(c.getColumnIndex("USR")); 

к

String firstName = c.getString(1); 

ошибка

CursorWindow(7986): Bad request for field slot 0,-1. numRows = 1, numColumns = 2 
...java.lang.IllegalStateException: get field slot from row 0 col -1 failed 

означает, что вы запрос столбец с индексом -1 в в первой строке в Cursor. Единственная часть вашего кода, запрашивающая данные от Cursor, - c.getString(columnIndex). Это означает, что в столбцеIndex вы должны быть -1. Теперь, если вы читаете documentation из Cursor.getColumnIndex вы видите найдете:

Возвращает индекс с нуля для данного имени столбца, или -1, если столбец не существует.

Значение колонки "USR" отсутствует. Если вы посмотрите на определение таблицы, вы увидите, что вы назвали его "usr". Таким образом, чтобы исправить ошибку, вы можете сделать

String firstName = c.getString(c.getColumnIndex("usr")); 

Но (что не является обязательным и может привести к ошибкам): Так как вы просили Cursor как SELECT id, usr FROM .. вы гарантированно что id на колонке 0 и usr на колонке 1 в вашем Cursor и вы можете просто использовать 1 напрямую.

Существует также другие вещи, которые могли бы улучшить:

if (c != null) { 
    while(c.moveToNext()) { 
     String firstName = c.getString(1); 
     users.add(firstName); 
    } 
    c.close(); 
} 

а) можно упростить if() do {} while() к простому while() {}
б) следует закрыть Cursor когда вам не нужно Это. Вы предупреждаете об этом как минимум.

Вы также должны сделать свой INSERT спасителем от ошибок/инъекций путем использования версии bindArgs execSQL.Попробуйте ввести ' в имя пользователя, и вы увидите, что он рухнет, как вы это сделаете. Использование bindArgs предотвратит это, поскольку оно автоматически ускользает от '.

db.execSQL("INSERT INTO " + TBL_USERS + " (usr, psw) VALUES (?, ?)", new String[]{ username, password }); 

Если я закомментировать эту строку, она не вылетает больше, но я не понимаю, почему

Это происходит потому, что Cursor пусто, то и вы не достигнете код, вызвавший ошибку.

Одна последняя вещь: varchar(128) не имеет никакого эффекта в SQLite с:

Обратите внимание, что числовые аргументы в скобках, что после имени типа (например: «VARCHAR (255)») игнорируются по SQLite - SQLite делает не налагать ограничений длины на длину строк, BLOB или числовых значений. source

Смежные вопросы