1. 程式人生 > >【Android】GreenDao 3.X 結合Volley以及Gson、ImageLoader實現資料儲存

【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);
                    }
                }
            }
        });
    }
}

當然了,這裡主要介紹了GreenDao3.X 的一些基本使用,還有一些更加深入的知識點,比如:表與表之間的一對一、一對多等對映關係,以及我們要進行資料庫升級等操作,我們要自定義OpenHelper繼承DaoMaster.DevOpenHelper重寫onUpgrade()方法,不然資料庫在更新的時候就會新建表,原資料就會丟失。對於這些知識點目前沒有深究,以後用到了,我再加以補充,希望能對大家有所幫助,如果發現講述的有問題,歡迎指出