Java 当使用游标从SQLITE数据库读取数据时,应用程序崩溃
我正在尝试制作一个简单的应用程序,在这个应用程序中,我可以使用SQLite数据库保存注释并使用listview查看它们。 问题是我看不到listview的内容。应用程序立即崩溃。我发现cursor database.query有问题,但我没有找到解决方法 Mainactivity.java:Java 当使用游标从SQLITE数据库读取数据时,应用程序崩溃,java,android,sqlite,cursor,Java,Android,Sqlite,Cursor,我正在尝试制作一个简单的应用程序,在这个应用程序中,我可以使用SQLite数据库保存注释并使用listview查看它们。 问题是我看不到listview的内容。应用程序立即崩溃。我发现cursor database.query有问题,但我没有找到解决方法 Mainactivity.java: package com.example.notemaker; import android.database.Cursor; import android.database.sqlite.SQLiteDat
package com.example.notemaker;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.os.Bundle;
import android.support.design.widget.FloatingActionButton;
import android.support.design.widget.Snackbar;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.view.View;
import android.view.Menu;
import android.view.MenuItem;
import android.content.Intent;
import android.view.Window;
import android.database.sqlite.SQLiteDatabase.CursorFactory;
import android.widget.ArrayAdapter;
import android.widget.ListAdapter;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.Toast;
import java.util.ArrayList;
public class MainActivity extends AppCompatActivity {
private ListView listView;
private ArrayList<String> listItem;
private ArrayAdapter adapter;
private DBOpenHelper helper;
private SQLiteDatabase database;
private TextView noNotesView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Toolbar toolbar = findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
FloatingActionButton fab = findViewById(R.id.fab);
fab.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Intent intent = new Intent(MainActivity.this, Edit_notes.class);
startActivity(intent);
}
});
noNotesView = findViewById(R.id.empty_notes);
listView = (ListView) findViewById(R.id.listView);
listItem = new ArrayList<>();
ViewData();
}
private void ViewData(){
helper = new DBOpenHelper(this, "notes.db", null, 1); // db
database = helper.getWritableDatabase();
String table_name = "note_table";
String[] columns = {"ID", "NOTE_TEXT"};
String where = null;
String where_args[] = null;
String group_by = null;
String having = null;
String order_by = null;
Cursor result = database.query(table_name, columns, where, where_args, group_by, having, order_by);
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.menu_main, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
int id = item.getItemId();
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}
@Override
public void onResume()
{
super.onResume();
ViewData();
}
}
Editnotes.java:
package com.example.notemaker;
import android.content.ContentValues;
import android.content.DialogInterface;
import android.database.sqlite.SQLiteDatabase;
import android.os.Bundle;
import android.support.v7.app.AlertDialog;
import android.support.v7.app.AppCompatActivity;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.EditText;
import android.widget.Toast;
import java.util.Date;
public class Edit_notes extends AppCompatActivity {
private DBOpenHelper dbop;
private SQLiteDatabase sdb;
// private TestDBOpenHelper tdb;
// private SQLiteDatabase sdb;
@Override
protected void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.note_edit);
getSupportActionBar().setTitle("");
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.cancel_button_menu, menu);
getMenuInflater().inflate(R.menu.save_button_menu, menu);
return super.onCreateOptionsMenu(menu);
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
int id = item.getItemId();
// Create confirmation dialog when click on CANCEL button
if (id == R.id.cancel_note) {
final AlertDialog.Builder alert = new AlertDialog.Builder(this);
alert.setTitle("NoteMaker");
alert.setMessage("Cancel this note ?");
alert.setPositiveButton("Yes", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
Toast.makeText(alert.getContext(), "Note cancelled", Toast.LENGTH_SHORT).show();
finish();
}
});
alert.setNegativeButton("No", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
dialog.dismiss();
}
});
alert.create().show();
return true;
}
// Save note title and note text to the database
if (id == R.id.save_note)
{
// tdb = new TestDBOpenHelper(this, "test.db", null, 1);
// sdb = tdb.getWritableDatabase();
String note_title_string = findViewById(R.id.input_note_title).toString();
String note_text_string = findViewById(R.id.input_note).toString();
//if (!note_title_string.isEmpty()){
// long date = new Date().getTime(); // Get date
AddData(note_title_string); // Add title to the database
Toast.makeText(this, "Note saved", Toast.LENGTH_SHORT).show();
finish();
// }
//else{
// Toast.makeText(this, "Title cannot be empty", Toast.LENGTH_SHORT).show();
// }
return true;
}
return super.onOptionsItemSelected(item);
}
public void AddData (String newEntry){
dbop = new DBOpenHelper(this, "notes.db", null, 1);
sdb = dbop.getWritableDatabase();
ContentValues cv = new ContentValues();
cv.put("note", newEntry);
sdb.insert("note_table", null, cv);
//long insertData = dbop.insertNote(newEntry);
}
}
导致崩溃的问题是,您可能在DBOpenHelper的onCreate方法创建表之前运行应用程序 DBOpenHelper的onCreate方法在数据库的整个生命周期内只自动运行一次,因此没有应用为创建表所做的更改。卸载应用程序会导致应用程序的数据以及数据库被删除,从而允许运行onCreate方法 但是,我仍然无法查看我的listview的内容- 要使ListView显示数据,您需要实例化一个合适的适配器,然后使用ListView的setAdapter方法设置ListView要使用的适配器 工作示例 以下是一个简化版本(无晶圆厂),以方便使用SimpleCorsorAdapter并基于您的代码 请注意,对于游标适配器,游标必须有一个名为\u id的列,因此列名在整个过程中都发生了更改 大多数更改已被注释(除已删除的晶圆厂代码外),因此请阅读注释 应用上述内容时,您需要卸载应用程序,以便应用更改的列名。 DBOpenHelper.java
public类DBOpenHelper扩展了SQLiteOpenHelper{
//类的构造函数在这里我们只是映射到
//超级级
public DBOpenHelper(上下文、字符串名称、SQLiteDatabase.CursorFactory
工厂,int版本){
超级(上下文、名称、工厂、版本);
}
//在创建数据库时调用的重写方法
public void onCreate(SQLiteDatabase db){
//创建数据库
db.execSQL(创建_表);
}
//要升级数据库时调用的重写方法
//请注意,在本例中,我们只是重建数据库,而不考虑
//数据丢失理想情况下,您应该有一种在
//我们正在重建数据库
public void onUpgrade(SQLiteDatabase db,int version\u old,int version\u new)
{
//删除这些表并重新创建它们
db.execSQL(drop_table);
db.execSQL(创建_表);
}
//创建和删除所需的一组常量字符串
//数据库
私有静态最终字符串create\u table=“create table note\u table(”+
BaseColumns.\u ID+“integer主键自动增量”,+//尝试卸载应用程序并重新运行。我刚卸载了,应用程序不再崩溃。但是我仍然无法查看我的ListView的内容。不要添加错误的屏幕截图:将其粘贴到问题中。我感谢您的帮助。我正在阅读您的代码。但是应用程序崩溃了(我卸载并重新编译了它),但没有成功尝试在空对象引用上调用虚拟方法“void android.widget.ListView.setAdapter(android.widget.ListAdapter)”,这将指示行ListView=(ListView)findViewById(R.id.ListView);
已被忽略,或者id为ListView的ListView不在活动_主布局中。很抱歉,无法使其工作:(创建一个新项目,复制上述代码,使其工作,然后应用缺少的代码,例如FAB。并在高兴时应用于原始项目。
package com.example.notemaker;
import android.content.ContentValues;
import android.content.DialogInterface;
import android.database.sqlite.SQLiteDatabase;
import android.os.Bundle;
import android.support.v7.app.AlertDialog;
import android.support.v7.app.AppCompatActivity;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.EditText;
import android.widget.Toast;
import java.util.Date;
public class Edit_notes extends AppCompatActivity {
private DBOpenHelper dbop;
private SQLiteDatabase sdb;
// private TestDBOpenHelper tdb;
// private SQLiteDatabase sdb;
@Override
protected void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.note_edit);
getSupportActionBar().setTitle("");
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.cancel_button_menu, menu);
getMenuInflater().inflate(R.menu.save_button_menu, menu);
return super.onCreateOptionsMenu(menu);
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
int id = item.getItemId();
// Create confirmation dialog when click on CANCEL button
if (id == R.id.cancel_note) {
final AlertDialog.Builder alert = new AlertDialog.Builder(this);
alert.setTitle("NoteMaker");
alert.setMessage("Cancel this note ?");
alert.setPositiveButton("Yes", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
Toast.makeText(alert.getContext(), "Note cancelled", Toast.LENGTH_SHORT).show();
finish();
}
});
alert.setNegativeButton("No", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
dialog.dismiss();
}
});
alert.create().show();
return true;
}
// Save note title and note text to the database
if (id == R.id.save_note)
{
// tdb = new TestDBOpenHelper(this, "test.db", null, 1);
// sdb = tdb.getWritableDatabase();
String note_title_string = findViewById(R.id.input_note_title).toString();
String note_text_string = findViewById(R.id.input_note).toString();
//if (!note_title_string.isEmpty()){
// long date = new Date().getTime(); // Get date
AddData(note_title_string); // Add title to the database
Toast.makeText(this, "Note saved", Toast.LENGTH_SHORT).show();
finish();
// }
//else{
// Toast.makeText(this, "Title cannot be empty", Toast.LENGTH_SHORT).show();
// }
return true;
}
return super.onOptionsItemSelected(item);
}
public void AddData (String newEntry){
dbop = new DBOpenHelper(this, "notes.db", null, 1);
sdb = dbop.getWritableDatabase();
ContentValues cv = new ContentValues();
cv.put("note", newEntry);
sdb.insert("note_table", null, cv);
//long insertData = dbop.insertNote(newEntry);
}
}
public class DBOpenHelper extends SQLiteOpenHelper {
// constructor for the class here we just map onto the constructor of the
// super class
public DBOpenHelper(Context context, String name, SQLiteDatabase.CursorFactory
factory, int version) {
super(context, name, factory, version);
}
// overridden method that is called when the database is to be created
public void onCreate(SQLiteDatabase db) {
// create the database
db.execSQL(create_table);
}
// overridden method that is called when the database is to be upgraded
// note in this example we simply reconstruct the database not caring for
// data loss ideally you should have a method for storing the data while
// are reconstructing the database
public void onUpgrade(SQLiteDatabase db, int version_old, int version_new)
{
// drop the tables and recreate them
db.execSQL(drop_table);
db.execSQL(create_table);
}
// a bunch of constant strings that will be needed to create and drop
// databases
private static final String create_table = "create table note_table(" +
BaseColumns._ID + " integer primary key autoincrement, " + //<<<<<<<<<< changed column name to _id for CursorAdapter
"NOTE_TEXT string" +
")";
private static final String drop_table = "drop table note_table";
/**
* ADDED to demonstrate typical inclusion of DB access within the helper
* @param note
* @return the id of the added note or -1 if not added.
*/
public long addNote(String note) {
SQLiteDatabase db = this.getWritableDatabase();
ContentValues cv = new ContentValues();
cv.put("NOTE_TEXT",note);
return db.insert("note_table",null,cv);
}
}
public class MainActivity extends AppCompatActivity {
private ListView listView;
private ArrayList<String> listItem;
private ArrayAdapter adapter; //<<<<<<<<<< Not used
private SimpleCursorAdapter sca; //<<<<<<<<<< ADDED
private Cursor csr; //<<<<<<<<<< ADDED
private DBOpenHelper helper;
private SQLiteDatabase database;
private TextView noNotesView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
helper = new DBOpenHelper(this,"notes.db", null, 1); //<<<<<< moved to here
database = helper.getWritableDatabase(); //<<<<<<<<<< moved to here so has scope throughout the class
//noNotesView = findViewById(R.id.empty_notes); //<<<<<<<<<< commented out for simplicity
listView = (ListView) findViewById(R.id.listView);
listItem = new ArrayList<>();
addSomeTestData(); //Adds a row every time the App is run (for testing)
ViewData();
}
private void ViewData(){
String table_name = "note_table";
String[] columns = {"_id", "NOTE_TEXT"}; //<<<<<<<<<< ID column is now _id
String where = null;
String where_args[] = null;
String group_by = null;
String having = null;
String order_by = null;
csr = database.query(table_name, columns, where, where_args, group_by, having, order_by);
//<<<<<<<<<< ADDED following code to method to instantiate the adapter and set the adapter
// and to alternatively swap the cursor to refresh the listview
if (sca == null) {
sca = new SimpleCursorAdapter(
this,
android.R.layout.simple_list_item_1,
csr,
new String[]{"NOTE_TEXT"},
new int[]{android.R.id.text1},
0);
listView.setAdapter(sca);
} else {
sca.swapCursor(csr);
}
}
private void addSomeTestData() {
helper.addNote("My Note"); //<<<<<<<<<< Uses the addNote method in the DB helper
}
/**
* ADDED for correct cursor handling i.e. close
* although not really required in mainactivity
*/
@Override
protected void onDestroy() {
super.onDestroy();
csr.close();
}
@Override
public void onResume()
{
super.onResume();
ViewData();
}
}