在Android开发中,需要添加附带的db数据库,用于实现某些需求。例如,选择城市的功能,需要添加city.db。
使用SQLite Database Browser,这款可视化工具来操作db文件。
SQLite DataBase Browser打开city.db,如下图所示:
本篇介绍查找城市
1. 添加city.db文件:
通过是将db文件放置到raw文件夹下,因此,在/res/raw文件夹下放置city.db文件。
2. 将外部db文件信息拷贝到运用程序的数据库中:
数据库本质上是指定路径下一个db文件。
数据库的路径:
存放在/data/data/<package name>/databases/目录下。
拷贝一个文件信息到另外一个文件中,可以用文件流来实现。创建一个文件流的操作类:
public class WriterDBUtils {
//这里的信息字段和外部db文件中信息保持一致。
public static final String CITYDB_NAME = "city.db";
//表名
public static final String TABLE_PROVICE = "m_province";
public static final String TABLE_CITY = "m_city";
//字段名
public static final String COLUMN_PID = "pid";
public static final String COLUMN_CNAME = "cname";
public static final String COLUMN_PNAME = "pname";
/**
*利用文件流进行拷贝
*/
public static void copyDBFromRaw(Context context) {
InputStream inputStream = null;
OutputStream outputStream = null;
try {
StringBuffer stringBuffer = new StringBuffer();
stringBuffer.append("/data/data/");
stringBuffer.append(context.getPackageName());
stringBuffer.append("/databases");
File dir=new File(stringBuffer.toString());
if(!dir.exists()){//防止databases文件夹不存在,不然,会报ENOENT (No such file or directory)的异常
dir.mkdirs();
}
stringBuffer.append("/");
stringBuffer.append(CITYDB_NAME);
File file = new File(stringBuffer.toString());
if (file == null || !file.exists()) {//数据库不存在,则进行拷贝数据库的操作。
inputStream = context.getResources().openRawResource(R.raw.city);
outputStream = new FileOutputStream(file.getAbsolutePath());
byte[] b = new byte[1024];
int length;
while ((length = inputStream.read(b)) > 0) {
outputStream.write(b, 0, length);
}
//写完后刷新
outputStream.flush();
}
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (inputStream != null) {//关闭流,释放资源
inputStream.close();
}
if(outputStream!=null){
outputStream.close();
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
文件流是耗时任务,不能在UI线程中执行,可以考虑后台服务中IntentService来执行。IntentService自带异步线程,执行完后自动关闭服务。
public class WriteCityDBIntentService extends IntentService {
public static final String TAG=WriteCityDBIntentService.class.getSimpleName();
public WriteCityDBIntentService() {
super(TAG);
}
/**
* 异步执行,不在主线程执行,执行完后自动停止Service。
* @param intent
*/
@Override
protected void onHandleIntent(Intent intent) {
WriterDBUtils.copyDBFromRaw(BaseApplication.getAppContext());
}
}
别忘记,Service是四大组件之一,需要注册。
<service android:name=".service.WriteCityDBIntentService"></service>
备注下异常:
ENOENT (No such file or directory)的异常
解决方式:
1. 没有给读写权限
2. 路径不对,少了"/",路径下少了那个文件夹(没有创建)。
3. 根据数据库中数据,实现选择城市功能:
采用DAO设计模式,操作数据库。RxJava执行数据库操作,RxAndroid上更新UI。
这里,列举查询省份的操作:
查询省份的SQL:
public class ProvinceDao implements DAO<Province> {
@Override
public List<Province> queryAll() {
SQLiteDatabase database = null;
Cursor cursor = null;
List<Province> list = null;
try {
database = context.openOrCreateDatabase(WriterDBUtils.CITYDB_NAME, Context.MODE_PRIVATE, null);
if (database != null) {
cursor = database.query(WriterDBUtils.TABLE_PROVICE, new String[]{WriterDBUtils.COLUMN_PID,WriterDBUtils. COLUMN_PNAME}, null, null, null, null, null);
if (cursor != null && cursor.moveToFirst()) {
list = new ArrayList<>();
do {
list.add(ValuesTransform.transformProvince(cursor));
} while (cursor.moveToNext());
}
}
} catch (Exception e) {
e.printStackTrace();
} finally {//释放资源
if (cursor != null) {
cursor.close();
}
if (database != null) {
database.close();
}
}
return list;
}
}
RxJava异步执行,RxAndroid更新UI:
/**
* 查询省份信息
*/
public void queryProvince(){
Subscription subscription= Observable.create(new Observable.OnSubscribe<List<Province>>() {
@Override
public void call(Subscriber<? super List<Province>> subscriber) {
//执行查询操作
List<Province> list= provinceDAO.queryAll();
subscriber.onNext(list);
}
}).subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())//订阅者执行的线程,UI线程
.subscribe(new Action1<List<Province>>() {
@Override
public void call(List<Province> provinces) {
//更新UI
provinceAdapter.addData(provinces);
}
});
this.compositeSubscription.add(subscription);
}
4. 项目效果展示:
项目代码Github上:https://github.com/13767004362/SQLitePractice
资源参考:
- DataBase Browser for SQLite: https://github.com/sqlitebrowser/sqlitebrowser
- RXJava: https://github.com/ReactiveX/RxJava
- RxAndroid: https://github.com/ReactiveX/RxAndroid