public class DatabaseHelper extends SQLiteOpenHelper { ... }
现在你想在不同的线程中对数据库进行写数据操作:
// Thread 1 Context context = getApplicationContext(); DatabaseHelper helper = new DatabaseHelper(context); SQLiteDatabase database = helper.getWritableDatabase(); database.insert(…); database.close(); // Thread 2 Context context = getApplicationContext(); DatabaseHelper helper = new DatabaseHelper(context); SQLiteDatabase database = helper.getWritableDatabase(); database.insert(…); database.close();
然后在你的Logcat中将输出类似下面的日志信息,而你的写数据操作将会无效。
android.database.sqlite.SQLiteDatabaseLockedException: database is locked (code 5)
上面问题的出现,源于你每创建一个 SQLiteOpenHelper 对象时,实际上也是在新建一个数据库连接。如果你尝试通过多个连接同时对数据库进行写数据操作,其一定会失败。
为确保我们能在多线程中安全地操作数据库,我们需要保证只有一个数据库连接被占用。
我们先编写一个负责管理单个 SQLiteOpenHelper 对象的单例 DatabaseManager 。
public class DatabaseManager { private static DatabaseManager instance; private static SQLiteOpenHelper mDatabaseHelper; public static synchronized void initialize(Context context, SQLiteOpenHelper helper) { if (instance == null) { instance = new DatabaseManager(); mDatabaseHelper = helper; } } public static synchronized DatabaseManager getInstance() { if (instance == null) { throw new IllegalStateException(DatabaseManager.class.getSimpleName() + " is not initialized, call initialize(..) method first."); } return instance; } public synchronized SQLiteDatabase getDatabase() { return new mDatabaseHelper.getWritableDatabase(); } }
为了能在多线程中进行写数据操作,我们得修改一下代码,具体如下:
// In your application class DatabaseManager.initializeInstance(getApplicationContext()); // Thread 1 DatabaseManager manager = DatabaseManager.getInstance(); SQLiteDatabase database = manager.getDatabase() database.insert(…); database.close(); // Thread 2 DatabaseManager manager = DatabaseManager.getInstance(); SQLiteDatabase database = manager.getDatabase() database.insert(…); database.close();
然后又导致另个崩毁
java.lang.IllegalStateException: attempt to re-open an already-closed object: SQLiteDatabase
既然我们只有一个数据库连接,Thread1 和 Thread2 对方法 getDatabase() 的调用就会取得一样的 SQLiteDatabase 对象实例。之后的事情就是,当 Thread1 尝试管理数据库连接时,Thread2 却仍然在使用该数据库连接。这也就是导致 IllegalStateException 崩毁的原因。
Leak foundCaused by: java.lang.IllegalStateException: SQLiteDatabase created and never closed
示例:
public class DatabaseManager { private AtomicInteger mOpenCounter = new AtomicInteger(); private static DatabaseManager instance; private static SQLiteOpenHelper mDatabaseHelper; private SQLiteDatabase mDatabase; public static synchronized void initializeInstance(SQLiteOpenHelper helper) { if (instance == null) { instance = new DatabaseManager(); mDatabaseHelper = helper; } } public static synchronized DatabaseManager getInstance() { if (instance == null) { throw new IllegalStateException(DatabaseManager.class.getSimpleName() + " is not initialized, call initializeInstance(..) method first."); } return instance; } public synchronized SQLiteDatabase openDatabase() { if(mOpenCounter.incrementAndGet() == 1) { // Opening new database mDatabase = mDatabaseHelper.getWritableDatabase(); } return mDatabase; } public synchronized void closeDatabase() { if(mOpenCounter.decrementAndGet() == 0) { // Closing database mDatabase.close(); } }}
然后你可以怎样子去调用它:
SQLiteDatabase database = DatabaseManager.getInstance().openDatabase(); database.insert(...); // database.close(); Don't close it directly! DatabaseManager.getInstance().closeDatabase(); // correct way
以后每当你需要使用数据库连接,你可以通过调用类 DatabaseManager 的方法openDatabase()。在方法里面,内置一个标志数据库被打开多少次的计数器。如果计数为1,代表我们需要打开一个新的数据库连接,否则,数据库连接已经存在。
在方法 closeDatabase() 中,情况也一样。每次我们调用 closeDatabase() 方法,计数器都会递减,直到计数为0,我们就需要关闭数据库连接了。
现在你可以线程安全地使用你的数据库连接了。
相关推荐
首先,我们来看多线程访问SQLite数据库。在Android中,主线程负责UI的更新和交互,而长时间运行的操作,如数据库查询,如果在主线程执行,可能会导致应用无响应(ANR)。因此,我们需要将这些操作放在工作线程或...
1. **线程安全**:SQLite本身是线程安全的,意味着在多线程环境中,不同的线程可以直接访问同一个数据库连接,不会引发数据不一致的问题。但要注意,同一时刻,只有一个线程可以执行写操作,这是为了避免并发写入...
然而,在多线程环境中,由于并发访问数据库,可能会遇到“database locked”(数据库被锁定)的问题。本文将深入探讨如何在Android中使用多线程操作SQLite并解决数据库被锁定的问题。 首先,理解“database locked...
标题"Android多线程操作"和描述"Android多线程开发实例,对使用多线程的用户有一定的参考价值!"暗示我们将深入探讨Android中的线程管理以及如何在实践中有效利用。 Android系统默认运行在主线程,也被称为UI线程,...
本实例将深入探讨Android多线程的实践应用及理论知识。 首先,我们要理解多线程的基本概念。在单线程环境中,程序按照顺序执行,而多线程则允许多个任务并行运行,提高了系统资源的利用率。Android主线程,也被称为...
Android多线程处理是移动应用开发中的关键概念,尤其是在性能优化和用户体验提升方面。Android系统采用的是单线程模型,即主线程(也称为UI线程)主要负责处理用户界面的交互和绘图,包括按键事件、触摸事件以及屏幕...
在Android中,当多个线程同时访问数据库时,如果没有正确处理并发,可能会导致数据不一致或数据丢失的问题。通常,我们会使用ContentProvider、SQLiteOpenHelper的子类或者使用线程同步机制(如synchronized关键字,...
在Android开发中,断点续传和多线程下载是提高用户下载体验的重要技术。本文将深入探讨如何在Android客户端实现这些功能,并结合服务器端的配合来完成整个流程。 首先,断点续传(Resumable Download)允许用户在...
SQLite是一个进程内的库,...SQLite 事务是完全兼容 ACID 的,允许从多个进程或线程安全访问。 SQLite 支持 SQL92(SQL2)标准的大多数查询语言的功能。 SQLite 使用 ANSI-C 编写的,并提供了简单和易于使用的 API。
该压缩包文件主要包含了关于Android应用开发中的一些关键技术,特别是Android快速框架和多线程下载框架的实现。这里我们将深入探讨这两个主题,并结合Afinal和Gson库来理解它们在实际开发中的应用。 首先,Android...
总结来说,实现Android的多任务多线程断点下载,需要结合HTTP请求、数据库操作、多线程编程以及文件系统操作等技术,确保在各种网络条件下提供稳定、高效的下载体验。上述代码片段展示了如何利用SQLite数据库记录和...
总的来说,这个"Android多线程断点下载Demo"涵盖了Android开发中的多个重要知识点,包括数据库操作、跨进程通信、后台服务以及多线程并发控制,是学习和理解Android高级特性的良好实践。通过深入研究和实践这个Demo...
在Android开发中,多线程断点续传...理解这些知识点并能实际应用,开发者就能构建出功能完善的Android多线程断点续传下载应用。通过阅读和学习`MulThreadDownload`中的源代码,可以深入理解这一过程的具体实现细节。
JDBC(Java Database Connectivity)是Java中用于访问数据库的标准API,也可以被Android平台使用。以下是如何在Android应用中通过JDBC直接访问MySQL数据库的详细步骤和注意事项: 1. **导入必要的库**: 在Android...
6. **权限管理**:在Android中,使用Socket和访问数据库都需要相应的权限。在AndroidManifest.xml中,需要添加INTERNET和READ/WRITE_EXTERNAL_STORAGE权限,以允许应用进行网络通信和读写数据库。 7. **异常处理**...
总之,通过Delphi XE7在Android平台上开发直接操作SQL Server 2008的应用,需要综合运用网络编程、数据库访问、Web服务设计以及移动应用开发等多个领域的知识。在实践中,不断学习和优化,才能打造出高效、稳定且...
这个"Android多线程断点下载源码"提供了实现这一功能的参考,适合开发者学习和实践。下面将详细介绍相关的知识点。 首先,我们要理解**多线程下载**的概念。在单线程下载中,文件数据从服务器到客户端是顺序传输的...
### Android多线程断点续传技术解析 #### 一、多线程断点续传的概念及重要性 在移动互联网应用中,特别是在资源下载方面,用户体验是非常关键的一环。对于大文件的下载,传统的单线程下载方式往往无法满足用户的...
异步操作数据库时,需要注意线程安全问题,防止多个线程同时访问数据库导致数据不一致。可以通过synchronized关键字、Lock对象或者使用数据库事务来保证数据一致性。 了解和掌握以上这些技术,你就能有效地在...
本文实例讲述了C#解决SQlite并发异常问题的方法。分享给大家供大家参考,...作者利用读写锁(ReaderWriterLock),达到了多线程安全访问的目标。 using System; using System.Collections.Generic; using System.Text;