Android开发中拷贝db文件写入SQLite

来源:互联网 发布:java暑期培训班 编辑:程序博客网 时间:2024/06/07 04:00

在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
1 0