Android開發中拷貝db檔案寫入SQLite
在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
相關文章
- IOCP 檔案拷貝
- iOS開發-深拷貝&淺拷貝iOS
- IO流-檔案拷貝
- 檔案內容拷貝
- Golang命令列拷貝檔案Golang命令列
- asm拷貝檔案到檔案系統ASM
- 11g中節點間拷貝檔案
- [java IO流]之檔案拷貝Java
- c語言拷貝檔案程式C語言
- Python基礎 - 檔案拷貝Python
- 二進位制檔案拷貝
- 自己寫的unix檔案拷貝指令cp實現函式函式
- TC中開啟檔案和寫入檔案
- JavaScript中的淺拷貝與深拷貝JavaScript
- VUE 中 的深拷貝和淺拷貝Vue
- 檔案操作(二進位制拷貝)
- 使用expect指令碼SCP拷貝檔案指令碼
- linux 帶路徑拷貝檔案Linux
- linux採用scp命令拷貝檔案到本地,拷貝本地檔案到遠端伺服器Linux伺服器
- 資料檔案拷貝檔案頭驗證錯誤
- 理解JS中的淺拷貝與深拷貝JS
- PHP中的淺拷貝和深拷貝薦PHP
- C++---寫時拷貝解決深淺拷貝問題C++
- Java IO 流之拷貝(複製)檔案Java
- linux parallel rsync 拷貝N多檔案LinuxParallel
- 零拷貝讀取檔案成 Go 物件Go物件
- 使用UltraEdit 拷貝二進位制檔案
- 在Linux下ssh 環境的登入 和 檔案拷貝Linux
- android下根據路徑不同拷貝檔案至指定路徑Android
- 淺談Java中的淺拷貝和深拷貝Java
- linux下拷貝命令中的檔案過濾操作記錄Linux
- 瞭解一下js物件深拷貝與淺拷貝(前端開發面試)JS物件前端面試
- Java實現檔案拷貝的4種方法.Java
- 【ASM學習】從ASM拷貝檔案的方法ASM
- 在js中如何區分深拷貝與淺拷貝?JS
- Android 開發中如何動態載入 so 庫檔案Android
- vue深拷貝淺拷貝Vue
- python 指標拷貝,淺拷貝和深拷貝Python指標