ContactApp:深入掌握SQLite在Android中的CRUD操作

本文还有配套的精品资源,点击获取 menu-r.4af5f7ec.gif

简介:ContactApp是一个使用Java开发的Android应用程序,展示了在移动平台上如何有效地利用SQLite数据库执行基本的CRUD操作。该应用包含对SQLiteOpenHelper子类的实现,定义了创建和升级数据库的逻辑。它演示了如何使用SQL语句进行数据的读取、更新和删除操作。同时,ContactApp还展示了如何通过隐式意图与系统服务交互,如拨打电话和发送短信,以及如何存储和检索图片数据。此外,该应用还演示了Fragment的使用,以支持多屏幕设备和屏幕旋转时的状态保持。总体上,ContactApp是一个综合性的学习资源,帮助开发者掌握SQLite数据库操作、隐式意图应用和Fragment管理等方面的技能。 ContactApp:该项目使用SQLite。 SQLite CRUD操作的一个很好的例子

1. Java开发的Android应用简介

Android应用开发概述

Android应用开发是利用Java语言以及Android SDK(Software Development Kit)创建适用于移动设备的软件应用程序的过程。它允许开发者利用丰富的API集合,以实现各种功能,比如网络通信、多媒体处理、用户界面设计和数据存储等。

Java在Android开发中的地位

Java是Android应用开发的主要语言之一,其面向对象的特性和成熟的生态系统使得Java成为开发Android应用的首选语言之一。Java提供了丰富的类库和框架,帮助开发者快速搭建稳定的应用程序。

Android应用架构

一个典型的Android应用由多个组件构成,包括Activity、Service、Broadcast Receiver和Content Provider。Activity是用户界面的单一屏幕展示,Service负责后台任务处理,Broadcast Receiver监听系统事件,Content Provider管理数据的访问。Java开发者通过编写这些组件的代码来构建功能完备的应用。

// 示例:简单的Activity组件代码
public class MainActivity extends AppCompatActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }
}

在下一章节中,我们将深入探讨SQLite数据库的CRUD(创建、读取、更新、删除)操作,这是任何数据驱动型Android应用不可或缺的一部分。

2. SQLite数据库的CRUD操作详解

2.1 CRUD操作的理论基础

2.1.1 CRUD操作定义及其在数据库中的重要性

CRUD操作是指在数据库系统中进行的基本数据处理操作,代表创建(Create)、读取(Read)、更新(Update)和删除(Delete)。这四项操作构成了数据库交互的核心,几乎所有的应用程序都会依赖这些操作来管理数据。通过CRUD操作,开发者可以实现数据的增删改查,满足不同的业务需求。

2.1.2 数据库事务与原子性、一致性、隔离性、持久性(ACID)

在进行CRUD操作时,必须考虑到数据库事务的ACID属性。原子性(Atomicity)确保事务中的操作要么全部完成,要么完全不执行。一致性(Consistency)确保事务在完成时,数据库必须处于一致的状态。隔离性(Isolation)确保并发事务的执行互不干扰,而持久性(Durability)则确保一旦事务提交,其结果就永久地保存在数据库中。理解这些属性对于确保数据的完整性和可靠性至关重要。

2.2 创建(Create)数据的操作

2.2.1 INSERT语句的使用方法

在SQLite中,INSERT语句用于向数据库表中插入新的数据行。基本的语法如下:

INSERT INTO 表名称 (列1, 列2, 列3, ...)
VALUES (值1, 值2, 值3, ...);

例如,向一个名为 students 的表中插入一条新记录的SQL语句可能如下所示:

INSERT INTO students (name, age, grade)
VALUES ('Alice', 21, 'A');

2.2.2 批量插入数据的策略

为了提高数据插入的效率,可以使用批量插入的方式。这可以通过一次性的 INSERT 语句插入多行数据来实现。例如:

INSERT INTO students (name, age, grade)
VALUES ('Alice', 21, 'A'),
       ('Bob', 22, 'B'),
       ('Carol', 23, 'C');

使用批量插入可以减少对数据库的访问次数,提升整体性能。

2.3 读取(Read)数据的操作

2.3.1 SELECT语句及其在数据查询中的应用

SELECT 语句用于从数据库中查询数据,是数据检索中最常用的SQL命令。基本语法如下:

SELECT 列名称 FROM 表名称 WHERE 条件;

例如,如果想查询 students 表中年龄大于20岁的学生,可以使用如下SQL语句:

SELECT * FROM students WHERE age > 20;

2.3.2 复杂查询的优化技巧

在进行复杂查询时,可能涉及多个表的联合查询、分组、排序以及使用聚合函数等。优化这些查询的技巧包括: - 确保在查询中涉及到的字段有适当的索引。 - 使用 EXPLAIN QUERY PLAN 来查看查询的执行计划,找出可能的瓶颈。 - 尽量减少数据传输量,比如只选择需要的列而不是使用 SELECT * 。 - 使用子查询或临时表来处理复杂逻辑。

2.4 更新(Update)数据的操作

2.4.1 UPDATE语句的用法及注意事项

UPDATE 语句用于修改数据库中已存在的数据。基本语法如下:

UPDATE 表名称
SET 列1 = 值1, 列2 = 值2, ...
WHERE 条件;

例如,更新 students 表中Alice的成绩为'A+'的SQL语句是:

UPDATE students
SET grade = 'A+'
WHERE name = 'Alice';

在使用 UPDATE 语句时,务必谨慎,因为错误的 WHERE 子句可能导致数据被错误地更新。

2.4.2 安全性考虑和事务控制

更新操作的安全性考虑包括: - 使用事务来保证数据操作的原子性。 - 在进行重要的数据修改之前备份数据。 - 使用参数化查询防止SQL注入攻击。

事务的控制可以通过以下SQL命令: - BEGIN TRANSACTION :开始一个事务。 - COMMIT :提交事务,所有的更改将被永久保存到数据库中。 - ROLLBACK :回滚事务,撤销自上一个 BEGIN TRANSACTION 以来的所有更改。

2.5 删除(Delete)数据的操作

2.5.1 DELETE语句的正确使用场景

DELETE 语句用于删除表中的行。基本语法如下:

DELETE FROM 表名称 WHERE 条件;

例如,删除 students 表中名为Bob的学生记录的SQL语句是:

DELETE FROM students WHERE name = 'Bob';

使用 DELETE 语句时,需要谨慎,确保 WHERE 条件正确指定了要删除的数据,以避免意外删除其他数据。

2.5.2 防止数据意外丢失的方法

为了防止数据意外丢失,可以采取以下措施: - 在执行 DELETE 操作前备份相关数据。 - 使用事务来管理可能需要回滚的操作。 - 对于不可逆的删除操作,可以先使用 UPDATE 将数据标记为删除状态而不是直接删除记录,以此保留数据的历史状态。 - 设置用户权限,限制对关键数据的删除操作权限,尤其是对非管理员用户的删除权限。

在本章中,我们详细探讨了SQLite数据库的CRUD操作,涵盖了理论基础和实践技巧。下一章将继续深入SQLite数据库的操作,探讨 SQLiteOpenHelper 类的使用及其在数据库版本管理中的重要角色。

3. SQLiteOpenHelper与数据库版本管理

3.1 SQLiteOpenHelper类的作用

3.1.1 SQLiteOpenHelper的定义和生命周期

SQLiteOpenHelper是一个抽象类,为管理数据库的创建和版本管理提供帮助。通过继承SQLiteOpenHelper类,开发者可以轻松地处理数据库的创建和版本更新。SQLiteOpenHelper类的核心职责是处理 onCreate onUpgrade 方法,分别用于创建新数据库和在数据库更新时升级数据库。

public class MyDatabaseHelper extends SQLiteOpenHelper {
    // 定义数据库名称和版本
    private static final String DATABASE_NAME = "example.db";
    private static final int DATABASE_VERSION = 1;

    public MyDatabaseHelper(Context context) {
        super(context, DATABASE_NAME, null, DATABASE_VERSION);
    }

    @Override
    public void onCreate(SQLiteDatabase db) {
        // 创建表的SQL语句
        String CREATE_USERS_TABLE = "CREATE TABLE users (_id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT, age INTEGER)";
        db.execSQL(CREATE_USERS_TABLE);
    }

    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
        // 升级数据库的处理逻辑
        db.execSQL("DROP TABLE IF EXISTS users");
        onCreate(db);
    }
}

SQLiteOpenHelper的生命周期从构造函数开始,当数据库第一次被访问时,会调用 onCreate 方法创建数据库。如果数据库版本发生了变化(通过比较 DATABASE_VERSION 与数据库内版本号),则会调用 onUpgrade 方法来更新数据库结构。

3.1.2 数据库的创建和打开

SQLiteOpenHelper实例化时并不会立即创建数据库,只有在首次访问数据库时,比如首次尝试读写数据时,数据库才会被创建。这个机制确保了数据库只在必要时创建,提高了应用程序的效率。

MyDatabaseHelper dbHelper = new MyDatabaseHelper(context);
SQLiteDatabase db = dbHelper.getWritableDatabase();

调用 getWritableDatabase getReadableDatabase 方法时,SQLiteOpenHelper会检查数据库是否存在且版本是否匹配。如果不匹配,它会调用 onUpgrade 方法。这两个方法最终都会返回一个 SQLiteDatabase 对象,通过这个对象,应用程序可以执行CRUD操作。

3.2 管理数据库版本

3.2.1 版本控制的策略与实现

数据库版本管理是移动应用开发中维护数据结构的常见做法。随着应用的更新,数据库结构可能需要变更,例如添加新表、修改表结构或索引、删除旧数据等。SQLiteOpenHelper通过 onUpgrade 方法提供了一种实现数据库版本控制的策略。

@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
    if (oldVersion < 2) {
        db.execSQL("ALTER TABLE users ADD COLUMN email TEXT");
    }
    if (oldVersion < 3) {
        db.execSQL("CREATE TABLE messages ( _id INTEGER PRIMARY KEY AUTOINCREMENT, content TEXT, timestamp INTEGER)");
    }
    if (oldVersion < 4) {
        db.execSQL("DROP TABLE messages");
        db.execSQL("CREATE TABLE messages ( _id INTEGER PRIMARY KEY AUTOINCREMENT, content TEXT)");
    }
}

onUpgrade 方法中,可以执行任意数量的数据库版本比较和数据库更新操作。通常,在每个版本的发布中,开发者都会增加 DATABASE_VERSION 的值,并在 onUpgrade 中处理所有旧版本到新版本的变更。

3.2.2 数据迁移机制

数据迁移是指在更新数据库结构时,将旧数据从一个版本迁移到新版本的过程。在Android中,这一过程通过 onUpgrade 方法实现。在 onUpgrade 中,开发者可以编写必要的逻辑,例如数据复制或转换,以确保数据的完整性和一致性。

if (oldVersion < 2) {
    Cursor cursor = db.rawQuery("SELECT * FROM old_table", null);
    if (cursor.moveToFirst()) {
        do {
            String data = cursor.getString(cursor.getColumnIndex("data"));
            ContentValues values = new ContentValues();
            values.put("data", data);
            db.insert("new_table", null, values);
        } while (cursor.moveToNext());
    }
    cursor.close();
    db.execSQL("DROP TABLE old_table");
}

在上面的示例中,旧表 old_table 的数据被读取出来,并插入到新表 new_table 中。完成数据迁移后,旧表被删除。此过程确保了数据从旧版本成功迁移到了新版本的数据库结构中。

3.3 实践中的SQLiteOpenHelper应用

3.3.1 CRUD操作与SQLiteOpenHelper的结合

在实现CRUD操作时,SQLiteOpenHelper类提供了一个数据库的抽象层,使得开发者可以更容易地进行数据库操作。以下是结合SQLiteOpenHelper进行CRUD操作的一个示例。

SQLiteDatabase db = dbHelper.getWritableDatabase();
ContentValues values = new ContentValues();
values.put("name", "John Doe");
values.put("age", 30);
// 插入数据
long newRowId = db.insert("users", null, values);

// 查询数据
Cursor cursor = db.query("users", new String[]{"_id", "name", "age"}, null, null, null, null, null);
while (cursor.moveToNext()) {
    int id = cursor.getInt(cursor.getColumnIndex("_id"));
    String name = cursor.getString(cursor.getColumnIndex("name"));
    int age = cursor.getInt(cursor.getColumnIndex("age"));
    // 处理查询到的数据
}

// 更新数据
values.clear();
values.put("age", 31);
db.update("users", values, "_id = ?", new String[]{String.valueOf(newRowId)});

// 删除数据
db.delete("users", "_id = ?", new String[]{String.valueOf(newRowId)});

在实际应用中,使用SQLiteOpenHelper可以简化数据库操作代码,提高代码的可读性和可维护性。它将数据库的创建、打开、版本管理封装起来,让开发者专注于数据操作的业务逻辑。

3.3.2 性能优化与维护

在使用SQLiteOpenHelper管理数据库时,还需要注意性能优化和数据库的维护。以下是一些性能优化和维护的建议:

  • 索引使用: 在数据库表的频繁查询字段上创建索引,可以显著提升查询效率。但索引也会增加写操作的成本,因此需要在查询性能和写入性能之间找到平衡。
  • 异步操作: 将数据库操作放在后台线程中执行,避免阻塞UI线程,提高应用响应速度。
  • 事务使用: 在进行多条数据操作时使用事务,可以保证操作的原子性,防止部分更新导致的数据不一致问题。
  • 数据库清理: 定期清理不再需要的数据,优化数据库文件大小,提高读写效率。
db.beginTransaction();
try {
    // 执行一系列CRUD操作...
    db.setTransactionSuccessful();
} catch (Exception e) {
    // 处理异常...
} finally {
    db.endTransaction();
}

事务允许我们将多个数据库操作捆绑在一起,作为一个单元一次性完成。这在更新大量数据或插入依赖关系数据时特别有用。正确的使用事务可以显著提高数据的一致性和完整性。

通过合理的使用SQLiteOpenHelper,以及上述的性能优化和维护策略,可以有效提高Android应用中数据库操作的效率和稳定性。

4. SQL读取、更新、删除操作实践

在本章节中,我们将深入探讨在Android应用中如何通过SQL语句进行高效的数据读取、更新和删除操作。这些操作对于管理和维护数据库中的数据至关重要。我们将分析这些操作的实践技巧,包括如何优化查询速度,确保数据更新和删除的安全性,以及防止SQL注入等安全问题。

4.1 高效读取(Read)数据的实践技巧

4.1.1 使用索引提高查询速度

在数据库操作中,读取数据通常是最频繁的操作之一。为了提高查询速度,索引的使用是必不可少的。索引可以显著减少查询所需扫描的数据量,从而加快数据检索的速度。

索引的创建和使用是一个精细的过程。一个简单的索引创建示例如下:

CREATE INDEX idx_column_name ON table_name (column_name);

逻辑分析与参数说明: - CREATE INDEX 指令用于创建一个新的索引。 - idx_column_name 是索引的名称,应遵循命名规则。 - table_name 是我们要为其创建索引的表名。 - (column_name) 是我们希望根据其创建索引的列名。

创建索引时的注意事项: - 索引会占用额外的存储空间,因此只有在该列查询频繁时才考虑创建索引。 - 索引会增加插入、更新和删除操作的成本,因为它需要同时更新索引。 - 通常不建议在经常更改的列上创建索引,如频繁更新的日期或状态字段。

4.1.2 查询优化器的作用及调整

查询优化器是数据库管理系统的一个组件,它的作用是确定执行SQL查询的最佳方式。优化器使用统计信息和内部算法来决定使用哪些索引、如何连接表,以及执行查询的顺序等。

优化查询的一般步骤包括:

  1. 重写查询语句,使其尽可能高效。
  2. 确保在适当的列上使用索引。
  3. 分析查询执行计划,寻找可能的优化空间。

在Android中,虽然我们没有直接的方式来控制SQLite查询优化器的行为,但通过合理的索引设计和查询语句的编写,我们可以间接影响优化器的选择。

4.2 安全更新(Update)与删除(Delete)数据

4.2.1 使用事务确保数据一致性

事务是保证数据完整性和一致性的重要机制。在Android中,可以使用 BEGIN TRANSACTION COMMIT ROLLBACK 语句来处理事务。

BEGIN TRANSACTION;
UPDATE table_name SET column1 = value1 WHERE id = some_id;
UPDATE table_name SET column2 = value2 WHERE id = some_id;
COMMIT;

逻辑分析与参数说明: - BEGIN TRANSACTION 开始一个新的事务。 - UPDATE 语句用于更新表中的数据。 - COMMIT 表示提交事务,即保存所有在事务中做的修改。 - 如果在事务中执行了错误操作,可以使用 ROLLBACK 来撤销事务中的所有更改。

事务应该遵循ACID原则,确保在发生错误时,数据不会处于不一致状态。

4.2.2 WHERE子句的准确使用

在执行数据更新和删除操作时,务必使用准确的 WHERE 子句来定位数据。错误的 WHERE 子句可能会导致数据被错误地更新或删除。

DELETE FROM table_name WHERE id = some_id;

逻辑分析与参数说明: - DELETE FROM 指令用于删除表中的数据。 - WHERE 子句指定了哪些行将被删除。 - some_id 是要匹配的特定ID值。

在使用 WHERE 子句时,需要特别注意数据类型匹配和条件的精确性,以避免意外删除不相关数据。

4.3 防止SQL注入的安全实践

4.3.1 参数化查询的原理与应用

SQL注入是一种常见的安全威胁,它发生在应用程序将不可信的输入直接用于SQL语句时。参数化查询是一种防止SQL注入的常用方法。

在SQLite中,参数化查询可以通过使用占位符来实现:

String sql = "SELECT * FROM users WHERE username = ? AND password = ?";
Cursor c = db.rawQuery(sql, new String[] { username, password });

逻辑分析与参数说明: - ? 是一个占位符,用于在执行查询时被实际参数值所替代。 - rawQuery 方法是执行SQL查询的方法,它接受SQL语句和一个参数数组。 - username password 是用于替换占位符的实际参数值。

通过这种方式,即使输入包含恶意SQL代码,也不会被执行,因为它不会被解释为SQL语句的一部分。

4.3.2 输入验证与错误处理

除了使用参数化查询外,对用户输入进行验证和清洗也是防止SQL注入的有效手段。此外,合理地处理SQL执行中的错误同样重要。

例如,可以使用正则表达式来验证用户名和密码的格式,或者限制输入的长度和内容。错误处理通常涉及捕获可能发生的异常,并给出合适的用户提示或记录错误日志。

try {
    // 执行数据库操作
} catch (SQLException e) {
    // 记录错误日志,并向用户显示通用错误信息
    Log.e("DB Error", e.getMessage());
    Toast.makeText(context, "数据库操作出错,请稍后再试", Toast.LENGTH_SHORT).show();
}

在上述代码块中: - 使用try-catch结构来捕获可能抛出的 SQLException 异常。 - 当异常发生时,记录异常信息到日志,并向用户展示一个错误提示消息。 - context Toast 是Android中的上下文和用户界面提示类,分别用于显示日志和消息。

总之,有效的输入验证、合理的错误处理以及参数化查询的使用,共同构成了防御SQL注入的安全实践基础。在实际开发中,这些方法应被综合考虑并妥善运用。

5. 隐式意图与系统服务交互

5.1 隐式意图的概念和作用

5.1.1 隐式意图与显式意图的区别

在Android开发中,意图(Intent)是用来在组件间传递消息的一种机制。它们可以是显式的,也可以是隐式的。显式意图直接指向特定的组件,比如明确指出要启动的Activity。而隐式意图则不指定具体的组件,而是表达一个通用的操作请求,系统会根据Intent中的信息来决定哪个组件可以响应这个请求。

隐式意图通常用于实现跨应用的操作,比如打开网页、拨打电话、发送短信等。它们是基于组件注册在AndroidManifest.xml中声明的能力进行匹配的。应用通过声明特定的action、category、data等属性来告知系统它可以处理哪些类型的隐式意图。

5.1.2 Android系统服务的分类与使用

Android系统提供了大量的系统服务,用以支持应用在后台执行各种任务,例如位置服务、闹钟服务、通知服务等。这些服务可以分为两类:框架层服务和系统级服务。

  • 框架层服务:这些服务通常是应用通过标准的Android API可以调用的。例如,使用LocationManager获取位置信息,使用SensorManager获取传感器数据等。
  • 系统级服务:这些服务通常是由系统应用或具有特殊权限的应用调用的。例如,通知管理器、电话管理器、窗口管理器等。

使用系统服务时,应用通常需要在AndroidManifest.xml中声明相应的权限,然后在代码中通过上下文(Context)对象调用系统服务。

5.2 系统服务的调用与交互

5.2.1 使用Intent进行服务调用

在Android中,可以使用Intent来启动系统服务。例如,要打开浏览器访问一个网址,可以创建一个带有action为 Intent.ACTION_VIEW 的Intent,并设置URL数据:

Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setData(Uri.parse("***"));
startActivity(intent);

系统会解析这个Intent,并找到能够处理这个action和data的Activity进行启动。

5.2.2 系统服务返回数据的处理方式

并非所有系统服务都会返回数据,但对于那些需要返回结果的服务,通常会使用 startActivityForResult() 方法启动服务。服务处理完毕后,会通过调用 setResult() 设置结果,然后结束服务,这样调用服务的Activity就可以通过重写的 onActivityResult() 方法来接收结果。

public void startActivityForResult(Intent intent, int requestCode) {
    // ...
}

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    if (requestCode == 0 && resultCode == RESULT_OK) {
        // 处理返回的数据
    }
}

5.3 实现特定功能的服务交互示例

5.3.1 短信发送功能的实现

要发送短信,应用需要请求SEND_SMS权限,然后创建一个Intent来启动短信发送界面:

<uses-permission android:name="android.permission.SEND_SMS"/>
Intent intent = new Intent(Intent.ACTION_SENDTO);
intent.setData(Uri.parse("smsto:" + phoneNumber));
intent.putExtra("sms_body", messageBody);
startActivity(intent);

应用通过这种方式间接地调用短信发送服务,用户确认后短信才会被发送出去。

5.3.2 网络请求与数据返回处理

网络请求通常会用到 AsyncTask Volley 或者 Retrofit 等网络库。如果使用 HttpURLConnection 进行网络请求,代码示例如下:

URL url = new URL("***");
HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();
try {
    InputStream in = new BufferedInputStream(urlConnection.getInputStream());
    readStream(in); // 假设这是用来读取数据的函数
} finally {
    urlConnection.disconnect();
}

如果需要在Android 6.0及以上版本使用网络请求,需要在运行时请求网络权限:

<uses-permission android:name="android.permission.INTERNET"/>

系统服务和隐式意图的使用是Android应用开发中十分重要的部分,它们允许应用能够执行更加丰富和灵活的操作。通过合适的权限管理和逻辑处理,开发者可以在遵守系统规范的同时,充分利用系统服务,提高应用的功能性和用户体验。

6. 图片的存储和检索以及SQLite中的图片存储(BLOB)

6.1 图片数据的存储策略

随着移动应用的发展,图片数据的存储和检索变得越来越重要。合理地存储图片不仅能够节省存储空间,还能提高应用的检索效率。

6.1.1 Android中的图片格式与存储方式

在Android平台上,图片数据存储主要分为文件存储和数据库存储两种方式。文件存储简单直接,但管理起来较为麻烦,而且当需要关联其他数据(如用户信息)时,就显得不够灵活。数据库存储则能将图片作为二进制大对象(BLOB)存储在数据库表中,与图片相关的其他数据也一起存储,便于管理。

6.1.2 BLOB字段的介绍及其在图片存储中的应用

BLOB(Binary Large Object)是用于存储大量二进制数据的数据类型。在SQLite中,BLOB字段可以用来存储图片数据,它能够保证图片数据的完整性不会因为存储而受损。使用BLOB字段存储图片,可以在查询、更新或删除操作时,像处理其他普通数据那样处理图片数据。

6.2 图片数据的存入与读取

将图片数据存入SQLite数据库中,或是从数据库中检索图片数据,是常见的操作需求。

6.2.1 将图片转换为BLOB数据存入数据库

首先,我们需要将图片文件转换为字节数组。这通常通过输入/输出流(InputStream)来实现,然后将得到的字节数组存储为BLOB类型的数据插入到SQLite数据库中。

InputStream in = new FileInputStream("path_to_image");
ByteArrayOutputStream out = new ByteArrayOutputStream();
byte[] buffer = new byte[4096];
int n;
while ((n = in.read(buffer)) > 0) {
    out.write(buffer, 0, n);
}
byte[] imageInByte = out.toByteArray();
// 接下来就可以将imageInByte数组存储到数据库的BLOB字段中

6.2.2 从数据库中读取BLOB数据并转换为图片

当需要从数据库检索图片时,可以将BLOB字段的数据读取出来,并转换回图片文件。

// 假设从数据库获取到了BLOB数据
byte[] imageInByte = //...获取BLOB数据的字节数组
Bitmap bmp = BitmapFactory.decodeByteArray(imageInByte, 0, imageInByte.length);
// 现在有了Bitmap对象,就可以将其保存为图片文件或者直接显示在界面上

6.3 图片存储的实践案例分析

以一个虚构的应用ContactApp为例,探讨图片存储的实现方式及其性能考量。

6.3.1 ContactApp中图片存储的具体实现

ContactApp是一个联系人应用,每个联系人可以存储一张图片。开发者决定使用SQLite数据库来存储联系人信息,并将图片作为BLOB存储在同一个表中。

6.3.2 图片数据管理的最佳实践与性能考量

在实现图片存储时,应当注意以下几点: - 使用适当大小的BLOB字段以避免不必要的存储空间浪费。 - 在内存紧张时,考虑使用缓存机制,避免直接从数据库加载大体积的图片数据。 - 对于需要频繁访问的图片,可以将它们存储在外部存储器,并在数据库中保存路径引用,以减少数据库I/O操作。 - 考虑使用异步任务处理图片的加载和存储,避免阻塞主线程。

通过这种方式,ContactApp能够有效地管理用户添加的联系人图片,同时保证应用性能。

本文还有配套的精品资源,点击获取 menu-r.4af5f7ec.gif

简介:ContactApp是一个使用Java开发的Android应用程序,展示了在移动平台上如何有效地利用SQLite数据库执行基本的CRUD操作。该应用包含对SQLiteOpenHelper子类的实现,定义了创建和升级数据库的逻辑。它演示了如何使用SQL语句进行数据的读取、更新和删除操作。同时,ContactApp还展示了如何通过隐式意图与系统服务交互,如拨打电话和发送短信,以及如何存储和检索图片数据。此外,该应用还演示了Fragment的使用,以支持多屏幕设备和屏幕旋转时的状态保持。总体上,ContactApp是一个综合性的学习资源,帮助开发者掌握SQLite数据库操作、隐式意图应用和Fragment管理等方面的技能。

本文还有配套的精品资源,点击获取 menu-r.4af5f7ec.gif

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值