Android Studio读取现有SQLite数据库调用getData方法启动Activity报错如何修复
问题修复方案
问题根因
你代码里的核心问题有以下几个:
- 数据库路径硬编码不符合安卓系统规范,高版本安卓或多用户设备会出现路径找不到的问题
- 数据库创建流程存在锁库风险,调用
getReadableDatabase()后未及时关闭导致复制数据库失败 - MainActivity重复初始化数据库工具类,属于无意义的重复操作
- 获取查询游标后未做异常处理和资源释放,容易触发崩溃和内存泄漏
修复代码
1. 修复DataBaseHelper类
package com.example.cyberartillery; import android.content.Context; import android.database.Cursor; import android.database.SQLException; import android.database.sqlite.SQLiteDatabase; import android.database.sqlite.SQLiteException; import android.database.sqlite.SQLiteOpenHelper; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.io.File; public class DataBaseHelper extends SQLiteOpenHelper { private static String DB_NAME = "northwind"; private SQLiteDatabase myDataBase; private final Context mContext; // 动态获取数据库路径,避免硬编码错误 private String DB_PATH; public DataBaseHelper(Context context) { super(context, DB_NAME, null, 1); this.mContext = context; DB_PATH = context.getDatabasePath(DB_NAME).getParent() + "/"; } public void createDataBase() throws IOException { boolean dbExist = checkDataBase(); if(dbExist){ //数据库已存在,无需操作 }else{ this.getReadableDatabase(); // 新增关闭逻辑,避免锁库导致复制失败 this.close(); try { copyDataBase(); } catch (IOException e) { throw new Error("Error copying database"); } } } private boolean checkDataBase(){ SQLiteDatabase checkDB = null; try{ File dbFile = new File(DB_PATH + DB_NAME); // 先判断文件是否存在,再尝试打开,减少异常触发 if(dbFile.exists()){ checkDB = SQLiteDatabase.openDatabase(dbFile.getAbsolutePath(), null, SQLiteDatabase.OPEN_READONLY); } }catch(SQLiteException e){ //数据库不存在 } if(checkDB != null){ checkDB.close(); } return checkDB != null; } private void copyDataBase() throws IOException{ InputStream myInput = mContext.getAssets().open(DB_NAME); String outFileName = DB_PATH + DB_NAME; OutputStream myOutput = new FileOutputStream(outFileName); byte[] buffer = new byte[1024]; int length; while ((length = myInput.read(buffer))>0){ myOutput.write(buffer, 0, length); } myOutput.flush(); myOutput.close(); myInput.close(); } public void openDataBase() throws SQLException { String myPath = DB_PATH + DB_NAME; myDataBase = SQLiteDatabase.openDatabase(myPath, null, SQLiteDatabase.OPEN_READONLY); } @Override public synchronized void close() { if(myDataBase != null) myDataBase.close(); super.close(); } @Override public void onCreate(SQLiteDatabase db) { } @Override public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { } public Cursor getData() { if(myDataBase == null || !myDataBase.isOpen()){ throw new IllegalStateException("Database not open, call openDataBase() first"); } return myDataBase.rawQuery("SELECT * FROM Categories WHERE CategoryID = 2", null); } }
2. 修复MainActivity类
package com.example.cyberartillery; import android.database.Cursor; import android.database.SQLException; import android.os.Bundle; import android.app.Activity; import android.view.View; import android.widget.Toast; import java.io.IOException; public class MainActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); // 去掉重复初始化逻辑 DataBaseHelper myDbHelper = new DataBaseHelper(this); try { myDbHelper.createDataBase(); } catch (IOException ioe) { throw new Error("Unable to create database"); } try { myDbHelper.openDataBase(); }catch(SQLException sqle){ throw sqle; } // 正确处理查询游标 Cursor cursor = null; try { cursor = myDbHelper.getData(); if(cursor.moveToFirst()){ // 示例:读取分类名称,字段名要和你实际数据库里的一致 String categoryName = cursor.getString(cursor.getColumnIndexOrThrow("CategoryName")); Toast.makeText(this, "查询到的分类:" + categoryName, Toast.LENGTH_SHORT).show(); // 这里可以把数据赋值给TextView等控件展示 }else{ Toast.makeText(this, "未查询到对应数据", Toast.LENGTH_SHORT).show(); } }catch (Exception e){ e.printStackTrace(); Toast.makeText(this, "查询失败:" + e.getMessage(), Toast.LENGTH_SHORT).show(); }finally { // 一定要关闭游标,避免内存泄漏 if(cursor != null && !cursor.isClosed()){ cursor.close(); } // 如果其他页面还要用数据库,可以把关闭逻辑放到onDestroy方法里 myDbHelper.close(); } findViewById(R.id.MainImage1).setClickable(true); findViewById(R.id.MainImage1).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { if (v.getId() == R.id.MainImage1) { // 自定义点击逻辑 } } }); } }
额外注意事项
- 请确认你
assets目录下确实存在northwind数据库文件,文件后缀不要写错 - 请确认数据库里确实存在
Categories表,以及CategoryID、CategoryName等你用到的字段名正确,大小写也要匹配 - 测试前请先卸载旧应用,把之前错误生成的数据库文件清空,避免旧文件干扰
内容的提问来源于stack exchange,提问作者Movses Movsisyan
相关产品推荐
相关产品推荐

