基础准备:理解安卓数据库架构
安卓默认使用轻量级SQLite数据库,数据存储在/data/data/<包名>/databases/
目录,读取前需完成:
-
创建数据库
继承SQLiteOpenHelper
类定义数据库结构:public class DBHelper extends SQLiteOpenHelper { private static final String DATABASE_NAME = "UserDB"; private static final int DATABASE_VERSION = 1; private static final String TABLE_USERS = "users"; private static final String COLUMN_ID = "id"; private static final String COLUMN_NAME = "name"; public DBHelper(Context context) { super(context, DATABASE_NAME, null, DATABASE_VERSION); } @Override public void onCreate(SQLiteDatabase db) { String createTable = "CREATE TABLE " + TABLE_USERS + " (" + COLUMN_ID + " INTEGER PRIMARY KEY AUTOINCREMENT, " + COLUMN_NAME + " TEXT)"; db.execSQL(createTable); } @Override public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { db.execSQL("DROP TABLE IF EXISTS " + TABLE_USERS); onCreate(db); } }
方法1:原生SQLite读取(适合小型项目)
步骤详解
-
获取可读数据库对象
DBHelper dbHelper = new DBHelper(context); SQLiteDatabase db = dbHelper.getReadableDatabase(); // 只读模式
-
执行查询语句
使用rawQuery()
或query()
方法:// 原始SQL查询 Cursor cursor = db.rawQuery("SELECT * FROM users WHERE name=?", new String[]{"小明"}); // 结构化查询(推荐) Cursor cursor = db.query( "users", // 表名 new String[]{"id", "name"}, // 返回列 "age > ?", // WHERE条件 new String[]{"18"}, // 条件参数 null, null, null // GROUP BY, HAVING, ORDER BY );
-
解析Cursor数据
if (cursor != null && cursor.moveToFirst()) { do { int id = cursor.getInt(cursor.getColumnIndexOrThrow("id")); String name = cursor.getString(cursor.getColumnIndexOrThrow("name")); Log.d("UserData", "ID: " + id + ", Name: " + name); } while (cursor.moveToNext()); }
-
关闭资源(防止内存泄漏)
if (cursor != null) cursor.close(); db.close();
✅ 优点:无额外依赖,控制灵活
⚠️ 风险:
- 直接SQL操作易出错(如SQL注入)
- 手动管理Cursor易导致内存泄漏
方法2:Room Persistence Library(官方推荐方案)
Google推出的ORM库,自动生成模板代码,提供编译时校验。
实现步骤
-
添加依赖(
build.gradle
)dependencies { def room_version = "2.5.0" implementation "androidx.room:room-runtime:$room_version" annotationProcessor "androidx.room:room-compiler:$room_version" }
-
定义数据实体
@Entity(tableName = "users") public class User { @PrimaryKey(autoGenerate = true) public int id; @ColumnInfo(name = "user_name") public String name; }
-
创建DAO接口
@Dao public interface UserDao { @Query("SELECT * FROM users WHERE name = :userName") List<User> getUsersByName(String userName); }
-
构建数据库对象
@Database(entities = {User.class}, version = 1) public abstract class AppDatabase extends RoomDatabase { public abstract UserDao userDao(); } // 初始化实例(单例模式) AppDatabase db = Room.databaseBuilder( context.getApplicationContext(), AppDatabase.class, "user_database" ).build();
-
异步读取数据(避免主线程阻塞)
Executor executor = Executors.newSingleThreadExecutor(); executor.execute(() -> { List<User> users = db.userDao().getUsersByName("小明"); // 更新UI需切回主线程:runOnUiThread()或LiveData });
✅ 核心优势:
- 编译时SQL语法检查
- 自动线程管理
- 支持LiveData实时更新UI
方法3:ContentProvider跨进程读取
适用于应用间共享数据(如通讯录读取)。
关键步骤
-
声明权限(
AndroidManifest.xml
)<uses-permission android:name="com.example.provider.READ_PERMISSION"/>
-
通过URI查询数据
Uri uri = Uri.parse("content://com.example.provider/users"); Cursor cursor = getContentResolver().query( uri, // 目标URI null, // 返回列(null表示全部) "gender=?", // 筛选条件 new String[]{"male"}, // 参数 null // 排序 );
-
解析Cursor流程同原生方案
⚠️ 注意:
- 需目标应用暴露ContentProvider
- 敏感数据需显式声明权限
安全与性能优化
-
线程管理
- 禁止主线程操作数据库(
Room
默认强制异步) - 原生SQLite使用
AsyncTask
或ThreadPoolExecutor
- 禁止主线程操作数据库(
-
防SQL注入
永远使用参数化查询(占位符),避免拼接SQL
-
连接复用
单例模式管理数据库实例(避免多次打开)
-
数据加密
敏感数据集成SQLCipher:implementation 'net.zetetic:android-database-sqlcipher:4.5.3'
总结建议
场景 | 推荐方案 | 复杂度 |
---|---|---|
简单查询/小型应用 | 原生SQLite | |
稳定应用/团队协作 | Room Persistence | |
跨应用数据共享 | ContentProvider |
关键提示:
- 始终在后台线程执行数据库操作
- 使用完
Cursor
和SQLiteDatabase
后立即关闭- 生产环境推荐Room + LiveData架构
引用说明:
本文代码示例基于Android官方文档SQLite指南和Room使用指南,安全建议参照OWASP移动安全标准,数据库加密方案采用SQLCipher开源库。
原创文章,发布者:酷盾叔,转转请注明出处:https://www.kd.cn/ask/8797.html