【Android】GreenDao 3.X 結合Volley以及Gson、ImageLoader實現資料儲存
關於GreenDao的優點已經不用再說了,關於第三方資料庫框架有很多,相對於Android系統本身的SQLite以及其它第三方而言,我感覺GreenDao使用更方便,體積小、速度更快。網上大多是關於GreenDao之前版本的介紹,關於3.0+新版的介紹不多。GreenDao新版改動還是挺大的,之前版本使用起來比較複雜,需要新建專案,然後再專案中配置各個實體的欄位等相關屬性,然後生成實體以及DAO操作相關的一些類。而GreenDao3.0及其以後是通過註解的方式定義實體類,並且是通過外掛來生成相應程式碼。
資料庫應用的場景也非常多,比如:電商類app中最常見的就是搜尋的歷史記錄等等,使用資料庫進行增刪改查就相對方便多了,並且GreenDao提供了資料庫加密設定,更加安全。
先來張效果圖
再看下我們通過@Entity設定的實體類中的欄位在資料庫中對應的欄位以及相應的儲存資料
這裡說明一下:此demo演示的場景是,有網時,聯網請求資料,請求成功後將資料儲存到GreenDao資料庫,沒網時,則從資料庫中取資料。訪問資料介面採用的是Volley框架,當然了你還可以使用OkHttp等,採用Gson解析方式,或者採用阿里的FastJson,兩種解析方式差不多,在設計實體類的時候要注意下,欄位什麼的要跟服務端給你的json串中欄位相同,從而操作更加簡單。其中請求介面返回三條資料,這裡解釋下為什麼第二條資料沒有圖片,這不是Bug。。。這是因為第二條資料壓根就沒給圖片,就是這麼任性,所以說有時間還是要學學後端的,這樣就可以自己寫服務端了,測試起來也方便。由於介面返回資料比較多,這裡主要是演示GreenDao3.0X資料庫儲存資料,這裡我只是解析了部分欄位,儲存的時候也只是儲存了兩文字欄位,圖片相對麻煩就沒有儲存,正式開發的話是儲存到快取中的。
首先我們需要在Gradle中新增如下配置
//首先在project的gradle檔案中引入greenDAO外掛
buildscript {
repositories {
mavenCentral()
}
dependencies {
classpath 'org.greenrobot:greendao-gradle-plugin:3.0.0'
}
}
//然後在module的gradle檔案中新增greenDAO的外掛,並引入相關類庫
apply plugin: 'org.greenrobot.greendao'
dependencies {
compile 'org.greenrobot:greendao:3.0.0'
}
最新版本是3.2.0,這裡說下為什麼我沒用3.2.0版本,因為使用此版本編譯一直報可奇怪的錯,這裡選用3.0.0也一樣,主要就是為了說明跟之前2.X版本的區別。其中,我們看到classpath ‘org.greenrobot:greendao-gradle-plugin:3.0.0’這是新增外掛的,用外掛生成我們的相應程式碼用的。
同時,我們還可以配置當外掛根據我們所定義的實體類自動生成的DaoMaster、DaoSession以及實體類相對應的XXXDAO類檔案的存放目錄。
greendao {
schemaVersion 1
daoPackage 'com.example.testproject.greendao.gen'
targetGenDir 'src/main/java'
}
說明:schemaVersion:表示指定資料庫schema版本號,如果需要資料庫升級,可以在這裡修改資料庫最新版本號。 daoPackage:表示生成的這些類檔案在哪個包下面(預設為你的entity所在的包名)。 targetGenDir:就是上面所說的制定這些類檔案所在的目錄,這裡我們設定跟我們程式碼目錄相同,都是在java目錄中,方便檢視。
我們接下來寫我們的實體類(ProductBean),這些實體類中的欄位是要寫進資料庫的,就相當於一張表(ProductBean表)。寫完之後我們選擇Build–>Make Project,剩下的就交給外掛了,就會自動幫我們生成(每次修改欄位啥的,不要忘記Build–>Make Project), 如下圖所示:
/**
* 實體類,儲存到資料庫
*/
@Entity
public class ProductBean {
private Long id;
@Property(nameInDb = "url")
private String picUrl;
@Property(nameInDb = "title")
private String proTitle;
@Property(nameInDb = "info")
private String proInfo;
@Property(nameInDb = "proId")
@Id
private Long proId;
}
這裡有幾點需要注意:GreenDao3.X 要求主鍵必須是Long或者long型別的。這裡由於介面請求的資料中含有一個id,所以我就用這個id作為主鍵,當然這個id是String型別的,需要轉換下。@Id:表示作為主鍵 @Property(nameInDb = “url”):表示該欄位在資料庫中的欄位名稱,還有很多屬性,大家可以到官網上去了解,最後別忘了在定義實體類上面要加上@Entity因為外掛要根據它生成相應的DAO。定義的有些欄位是沒用到的,大家測試的時候也可以自行刪除。
GreenDao3.X 配置完了,接下來就是擼程式碼了。官方推薦將DaoMaster 物件的方法放到 Application 層,這樣將避免多次建立生成 Session 物件。下面看下我們的application
/**
* 自定義MyApplication
*/
public class MyApplication extends Application {
private static MyApplication myApplication;
public RequestQueue requestQueue;
private static DaoMaster daoMaster;
private static DaoSession daoSession;
@Override
public void onCreate() {
super.onCreate();
myApplication = this;
//建立佇列
requestQueue = Volley.newRequestQueue(this);
}
public static DaoMaster getDaoMaster(Context context){
if(daoMaster == null){
DaoMaster.DevOpenHelper helper = new DaoMaster.DevOpenHelper(context,"mydata-db",null);
daoMaster = new DaoMaster(helper.getWritableDatabase());
}
return daoMaster;
}
public static DaoSession getDaoSession(Context context){
if(daoSession == null){
if(daoMaster == null){
daoMaster = getDaoMaster(context);
}
daoSession = daoMaster.newSession();
}
return daoSession;
}
public static MyApplication getApplication() {
return myApplication;
}
}
關於增、刪、改、查,這些就比較簡單了。這裡簡單說下,首先,我們先獲取DaoSession,從而來操作資料庫。檢視原始碼可以看到,GreenDao的一些例如:增、刪等操作內部已經封裝處理了事務回滾等操作,我們使用起來更加方便。
ProductBeanDao dao = MyApplication.getDaoSession(MainActivity.this).getProductBeanDao();
1. 插入(批量新增時屬於耗時操作,GreenDao提供的有非同步操作方法runInTx()方法)
ProductBean productBean = new ProductBean(null,null,productData.getName(),productData.getInfo(),Long.parseLong(productData.getId()));
dao.insert(productBean);
//dao.insertOrReplace(productBean);
//批量新增的情況(注意try的位置)
final List<ProductBean> lists = new ArrayList<ProductBean>();
for(int i=0;i<20;i++){
ProductBean productBean = new ProductBean();
productBean.setProTitle(xxxx);
productBean.setProInfo(xxxx);
lists.add(productBean);
}
try {
MyApplication.getDaoSession(MainActivity.this).runInTx(new Runnable() {
@Override
public void run() {
for(ProductBean bean : lists){
MyApplication.getDaoSession(MainActivity.this).insertOrReplace(bean);
}
}
});
}catch (Exception e){
e.printStackTrace();
}
2. 刪除(刪之前要先查一下,刪除的方法有很多,可以刪單條資料,也可以全部刪除等等)
ProductBean bean = dao.queryBuilder().where(ProductBeanDao.Properties.ProTitle.eq("中青年抗癌互助計劃")).build().unique();
if(bean != null){
dao.delete(bean);
}
3. 修改
ProductBean bean = dao.queryBuilder().where(ProductBeanDao.Properties.ProTitle.eq("中青年抗癌互助計劃")).build().unique();
if(bean != null){
bean.setProTitle("修改title");
dao.update(bean);
}
4. 查詢(可以寫多個查詢條件where,可以設定升序(orderAsc)、降序排列,limit:限制用於顯示查詢資料的數量,這裡只要求顯示3條資料,list():表示查詢結果為一個集合, 當然了,還可以查單條資料unique())
List<ProductBean> lists = dao.queryBuilder()
.where(ProductBeanDao.Properties.ProId.eq(3))
.where(.......)
.orderAsc(ProductBeanDao.Properties.ProId)
.limit(3)
.build().list();
最後看下MainActivity的全部程式碼(這裡我沒有采用id自增長的方式(不然資料會新增重複資料),而是用返回資料中的id作為主鍵,並且採用dao.insertOrReplace(productBean)的方式防止重複新增,不能使用dao.insert(),因為主鍵不可重複,這樣當再次點選按鈕新增重複的資料就會報錯。僅是測試,情景不同,具體情況具體對待)
public class MainActivity extends AppCompatActivity {
private ListView listView;
private ProductAdapter adapter;
private List<ListProBean> lists;
private Button btnRequest;
private static final String url = "http://test.xinlechou.com/index.php?r=api/insuranceList";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//初始化控制元件
iniViews();
getRequestDatas();
}
private void iniViews() {
listView = (ListView) findViewById(R.id.listView);
btnRequest = (Button) findViewById(R.id.btn_request);
}
public void getRequestDatas() {
btnRequest.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//資料庫,獲取DAO
final ProductBeanDao dao = MyApplication.getDaoSession(MainActivity.this).getProductBeanDao();
if(NetUtil.isNetConnected(MainActivity.this)){
//volley請求資料
StringRequest request = new StringRequest(url, new Response.Listener<String>() {
@Override
public void onResponse(String response) {
Gson gson = new Gson();
ListProBean bean = gson.fromJson(response,ListProBean.class);
if(bean.getError() == 0){
ArrayList<ProductData> datas = bean.getData();
adapter = new ProductAdapter(MainActivity.this,datas);
listView.setAdapter(adapter);
//將資料儲存到greendao資料庫
for(int i=0;i<datas.size();i++){
ProductData productData = datas.get(i);
ProductBean productBean = new ProductBean(null,null,productData.getName(),productData.getInfo(),Long.parseLong(productData.getId()));
//插入資料庫
// boolean flag = dao.insert(productBean) != -1 ? true : false;
boolean flag = dao.insertOrReplace(productBean) != -1 ? true : false;
if(flag){
Log.i("TAG","插入成功:"+i);
}else{
Log.i("TAG","插入失敗:"+i);
}
}
}
}
}, new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError error) {
//列印錯誤資訊
}
});
//將請求放到佇列中
MyApplication.getApplication().requestQueue.add(request);
}else{
Toast.makeText(MainActivity.this,"沒有聯網喲",Toast.LENGTH_SHORT).show();
//查資料庫
List<ProductBean> lists = dao.queryBuilder().build().list();
if(lists != null && lists.size() > 0){
Toast.makeText(MainActivity.this,"從資料庫中讀取資料",Toast.LENGTH_SHORT).show();
List<ProductData> productDatas = new ArrayList<ProductData>();
for(int i=0;i<lists.size();i++){
ProductBean productBean = lists.get(i);
String title = productBean.getProTitle();
String info = productBean.getProInfo();
ProductData productData = new ProductData();
productData.setName(title);
productData.setInfo(info);
productDatas.add(productData);
}
adapter = new ProductAdapter(MainActivity.this,productDatas);
listView.setAdapter(adapter);
}
}
}
});
}
}