Основная проблема
Вероятно, ваша проблема связана с тем, что имя столбца не найдено.
Это происходит потому, что вы не заключаете строку callquiz в кавычки и если значение не являетсячисло, то оно принимает значение как имя столбца.
Эта проблема может быть исправлена с помощью: -
String YOUR_QUERY = "SELECT * FROM user WHERE title= '"+ callquiz + "'";
Улучшение с помощью удобного метода запроса.
Однако лучший способ защиты от такой ошибки - использовать вспомогательный метод класса query класса SQLiteDatabase.Это также защищает от внедрения SQL.
Использовать этот код можно вместо: -
String YOUR_QUERY = "SELECT * FROM user WHERE title =" + callquiz;// callquiz - это строковая переменная, которую я использую для хранения спецификатора данных для моей таблицы SQLiteDatabase dbfectch;dbfectch = db.getWritableDatabase ();Курсор c = dbfectch.rawQuery (YOUR_QUERY, null);
be: -
//String YOUR_QUERY = "SELECT * FROM user WHERE title= "+ callquiz; //<<<<<<<<<< NOT NEEDED
//callquiz is a string variable i use to hold the data specifier for my table
SQLiteDatabase dbfectch;
dbfectch = db.getWritableDatabase();
Cursor c = dbfectch.query(DBHandler.TABLE, //<<<<<<<<<< The table to query
null, //<<<<<<<<<< The columns null for all eqv to *
DBHandler.COL_TASK_TITLE + "=?", //<<<<<<<<<< The WHERE clause ? is replaced on a 1 for 1 basis from the WHERE args (next paramter)
new String[]{callquiz}, //<<<<<<<<<< The WHERE args that replace ?
null, //<<<<<<<<<< GROUP BY clause, null = no clause
null, //<<<<<<<<<< HAVING clause, null = no clause
null //<<<<<<<<<< ORDER BY clause, null = no clause
);
- Обратите внимание, что соответствующие ключевые слова предоставляются и не должны включаться
- Вышеуказанное приведет к тому, что запрос будет соответствовать исправлению, включая строку в одинарных кавычках.
Проверка курсора на ноль
В отношении проверки правильности курсора, возвращенного изметод SQLiteDabase для null бесполезен и может привести к проблемам.Такой Курсор никогда не будет нулевым, скорее, если теперь строки извлечены, Курсор будет иметь 0 строк.Переезд в ??????вместо этого методы будут возвращать false, если перемещение не может быть выполнено (кроме того, метод Cursor getCount вернет 0).
Упрощенный цикл с использованием while (cursor.moveToNext) {....}
Прощеиспользуйте while (cursor.MoveToNext) { do your stuff.... }
для перебора курсора.Таким образом, более правильный код может быть: -
SQLiteDatabase dbfectch;
dbfectch = db.getWritableDatabase();
Cursor c = dbfectch.query(DBHandler.TABLE, //<<<<<<<<<< The table to query
null, //<<<<<<<<<< The columns null for all eqv to *
DBHandler.COL_TASK_TITLE + "=?", //<<<<<<<<<< The WHERE clause ? is replaced on a 1 for 1 basis from the WHERE args (next parameter)
new String[]{callquiz}, //<<<<<<<<<< The WHERE args that replace ?
null, //<<<<<<<<<< GROUP BY clause, null = no clause
null, //<<<<<<<<<< HAVING clause, null = no clause
null //<<<<<<<<<< ORDER BY clause, null = no clause
);
while (c.moveToNext()) {
results.add(c.getString(c.getColumnIndex(DBHandelr.COL_ANS)));
}
Использовать один адаптер
В какой-то момент список может измениться (например, у вас может быть код, удаляющий строку), вы не можетена самом деле не нужно создавать экземпляр нового адаптера каждый раз, вместо этого вы должны обновить список с помощью вызова метода NotifyDatasetChanged адаптера.Таким образом, это не очень хороший код, чтобы потом следовать просто: -
ArrayAdapter adapter = new ArrayAdapter<String>(this,
android.R.layout.simple_list_item_1, results);
listView.setAdapter(adapter);
Скорее вы могли бы использовать: -
if (adapter == null) {
adapter = new ArrayAdapter<String>(this,
android.R.layout.simple_list_item_1, results);
listview.setAdapter(adapter);
} else {
adapter.notifyDatasetChanged();
}
- Обратите внимание, что это не способствует восстановлениюРезультаты ArrayList также предполагает, что адаптер был объявлен как переменная класса (поскольку результаты могут помочь улучшить его перестройку перед вызовом метода notifyDatasetChanged).
Ограничения ArrayList
Часто вы хотите, чтобы пользователь взаимодействовал со списком (например, если долго нажимать на элемент, чтобы удалить его (просто нецелесообразно щелкать мышью без промежуточного диалога для подтверждения удаления, хотя бы длинный щелчок обеспечивает некоторую защиту от случайных нажатий)).
Проблема с использованием ArrayList заключается в том, что только отображаемая строка доступна напрямую, и этого может быть недостаточно для идентификации базовой строки.Скорее ArrayList был бы лучше, поскольку у вас обычно был бы такой объект (в вашем случае, возможно, your_more_comprehensive_object мог бы быть user объект, который включает значение соответствующего ID столбец).Однако без использования CustomAdapter или переопределения метода toString в классе объекта вы будете ограничены.
Для ListView более простое решение - вместо этого использовать адаптер курсора.Для использования CursorAdapter (например, SimpleCursorAdapter) требуется наличие столбца с именем _id .
Рабочий пример с использованием SimpleCursorAdapter со слушателями
Поэтому вы можете рассмотреть следующеерабочий пример, основанный на вашем коде (надеюсь, комментарии и объяснение выше объяснят все): -
DBHanlder.java
public class DBHandler extends SQLiteOpenHelper {
public static final String DB_NAME = "AnswerTables.db";
public static final int DB_VERSION = 2;
public static final String TABLE = "user";
public static final String COL_TASK_TITLE = "title";
//public static final String ID = "id"; //<<<<<<<<<< replaced by line below
public static final String ID = BaseColumns._ID; //<<<<<<<<<< make column the standard _id
public static final String COL_ANS="answer";
public DBHandler(Context context) {
super(context, DB_NAME, null, DB_VERSION);
SQLiteDatabase db=getWritableDatabase();
}
@Override
public void onCreate(SQLiteDatabase db) {
String createtable="CREATE TABLE " + TABLE + " ( "+ ID +" INTEGER PRIMARY KEY, "+ COL_TASK_TITLE+ " TEXT NOT NULL,"+ COL_ANS+" TEXT NOT NULL);";
db.execSQL(createtable);
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
db.execSQL("DROP TABLE IF EXISTS " + TABLE);
onCreate(db);
}
public boolean insertData(String name,String quiz){
SQLiteDatabase db=this.getWritableDatabase();
ContentValues contex=new ContentValues();
contex.put(COL_TASK_TITLE,name);
contex.put(COL_ANS,quiz);
long result=db.insert(TABLE,null,contex);
if(result==-1)
{
return false;
}else{
return true;
}
}
//<<<<<<<<<< new method
public Cursor getAllUsersWithTitle(String title) {
String whereclause = COL_TASK_TITLE + "=?";
String[] whereargs = new String[]{title};
SQLiteDatabase db = this.getWritableDatabase();
return db.query(TABLE,null,whereclause,whereargs,null,null,null);
}
//<<<<<<<<<< new method
public boolean deleteUserById(long id) {
String whereclause = ID + "=?";
String[] whereargs = new String[]{String.valueOf(id)};
SQLiteDatabase db = this.getWritableDatabase();
return (db.delete(TABLE,whereclause,whereargs) > 0);
}
}
- Обратите внимание, что для включения вышеуказанного вам необходимо выполнить одно из следующих действий: -
- удалить / очистить данные приложения
- удалить приложение
- увеличить значение, назначенное для DB_version при изменении структуры / схемы БД
- Обратите внимание, что вам, скорее всего, не нужно / не нужно AUTOINCREMENT, и его издержки см. Автоинкремент SQLite
MainActivity.java
public class MainActivity extends AppCompatActivity {
Context context; //<<<<<<<<<< ADDED for Toast from handler
ListView listView;
DBHandler db;
Cursor cursor;
SimpleCursorAdapter sca;
String callquiz;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
context = this;
listView = this.findViewById(R.id.list);
db = new DBHandler(this);
addSomeUsers(); //<<<<<<<<<< Add some testing data
callquiz = "Fred";
refreshOrInitialiseListView(); //<<<<<<<<<< handle the listview
//<<<<<<<<<< EXTRA >>>>>>>>>>
//<<<<<<<<<< Add A click Listener to toast the clicked item
listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> adapterView, View view, int i, long l) {
Toast.makeText(context,
"You clicked on the Item with a title of " +
cursor.getString(cursor.getColumnIndex(DBHandler.COL_TASK_TITLE)) +
" and ans is " + cursor.getString(cursor.getColumnIndex(DBHandler.COL_ANS)) +
" whose ID is " + String.valueOf(l) //<<<<<<<<<< note 4th parameter passed is the id
,
Toast.LENGTH_SHORT).show();
}
});
listView.setOnItemLongClickListener(new AdapterView.OnItemLongClickListener() {
@Override
public boolean onItemLongClick(AdapterView<?> adapterView, View view, int i, long l) {
db.deleteUserById(l);
refreshOrInitialiseListView();
return true; //<<<<<<<<<<<< indicate that the long click has been handled
}
});
}
//<<<<<<<<<< ADDED to clean up (not needed for the main activity but does not hurt)
@Override
protected void onDestroy() {
cursor.close();
db.close();
super.onDestroy();
}
//<<<<<<<<<< ADDED to refresh the ListView is the activity is resumed e.g. return from invoked activity.
@Override
protected void onResume() {
super.onResume();
refreshOrInitialiseListView();
}
private void refreshOrInitialiseListView() {
cursor = db.getAllUsersWithTitle(callquiz);
if (sca == null) {
sca = new SimpleCursorAdapter(
this,
android.R.layout.simple_list_item_2,
cursor,
new String[]{DBHandler.COL_TASK_TITLE,DBHandler.COL_ANS},
new int[]{android.R.id.text1,android.R.id.text2},
0
);
listView.setAdapter(sca);
} else {
sca.swapCursor(cursor);
}
}
private void addSomeUsers() {
if (DatabaseUtils.queryNumEntries(db.getWritableDatabase(),DBHandler.TABLE) < 1) {
db.insertData("Fred","Freds Quiz");
db.insertData("Fred","Fred's 2nd Quiz");
db.insertData("Fred","Fred's 3rd quiz");
db.insertData("Mary","Mary's first quiz");
db.insertData("Mary","mary's 2nd quiz");
db.insertData("Mary","Mary's 3rd quiz");
}
}
}
Запуск приложения с нуля приведет к тому, что 3 из 6 строк (элементов) будут перечислены в ListView(с отображением заголовка и ответа).
- Нажатие на элемент приведет к тому, что детали элемента будут обожжены.
- Длительное нажатие на элемент удалит этот элемент из таблицы и дополнительно изсписок.
Примечание Рабочий пример предназначен для демонстрации и имеет ограничения (например, если вы удалите все элементы / строки, то, если вы не удалите базу данных, ничего не будетотображается)