signed

QiShunwang

“诚信为本、客户至上”

Android greenDAO数据库开发梳理 : Android ORM for your SQLite database

2021/4/26 17:32:05   来源:

首先名确一个关键字:Object/relation mapping (ORM):对象/关系映射(ORM)

greenDao是什么?为什么会产生这个框架,也就是说greenDao的诞生是为了解决什么需求的?

关于 Android 中常用的数据存储方式有sharePreference存储、网络存储、文件存储等,但是对于数据量比较大、结构复杂的数据我们想要存储只能通过数据库进行处理,Android 系统中集成了一个轻量级的数据库: SQLite 数据库,但是使用起来比较繁琐和复杂,所以 Android 又新推出了Jetpack 组件库:Room 持久性库,Room 持久性库在 SQLite 的基础上提供了一个抽象层,让用户能够在充分利用 SQLite 的强大功能的同时,获享更强健的数据库访问机制。如果不使用这个新的组件库或者说在jetpack组件库之前,我们怎么能更方便快捷的访问操作SQLiteDatabase数据库呢?开源ORM 框架———greenDAO框架。

下面我们来看官网对greenDAO的描述:GreenDAO的本质是为存储在关系数据库SQLite中的数据提供一个面向对象的接口。只需定义数据模型,Green DAO将创建Java数据对象(实体)和DAO(数据访问对象)。这将为您节省大量无聊的代码,只需来回移动数据。除此之外,Green DAO还提供一些高级ORM特性类似于会话缓存、急切加载和活动实体。

greenDAO’s Features at a glance

  • Maximum performance (probably the fastest ORM for Android); our benchmarks are open sourced too
  • Easy to use powerful APIs covering relations and joins
  • Minimal memory consumption
  • Small library size (<100KB) to keep your build times low and to avoid the 65k method limit
  • Database encryption: greenDAO supports SQLCipher to keep your user’s data safe
  • Strong community: More than 5.000 GitHub stars show there is a strong and active community

You want to learn more about greenDAO features like active entities, protocol buffers support, or eager loading?  Then have a look at our full feature list.

下面是翻译:

GreenDAO的特点一目了然

  • 最大性能(可能是Android最快的ORM);我们的基准测试也是开源的。
  • 易用覆盖关系和联接的强大API
  • 极小内存消耗
  • 小的库大小(<100 kb),以保持较低的构建时间,并避免65k方法限制
  • 数据库加密*GreenDAO支持SQLCiPHER,以确保用户数据的安全
  • 强群落:5.000多名GitHub明星展示了一个强大而活跃的社区

您想了解有关GreenDAO功能的更多信息,如活动实体、协议缓冲区支持或急切加载?那就来看看我们的特征列表.

官网地址如下:https://greenrobot.org/greendao/

GitHub地址:https://github.com/greenrobot/greenDAO

下面给出使用实例:

首先创建一个项目、添加依赖包:

Add the following Gradle configuration to your Android project. In your root build.gradle file:

buildscript {
    repositories {
        jcenter()
        mavenCentral() // add repository
    }
    dependencies {
        classpath 'com.android.tools.build:gradle:3.5.3'
        classpath 'org.greenrobot:greendao-gradle-plugin:3.3.0' // add plugin
    }
}

In your app modules app/build.gradle file:

apply plugin: 'com.android.application'
apply plugin: 'org.greenrobot.greendao' // apply plugin
 
dependencies {
    implementation 'org.greenrobot:greendao:3.3.0' // add library
}

Note that this hooks up the greenDAO Gradle plugin to your build process. When you build your project, it generates classes like DaoMaster, DaoSession and DAOs.

下面来看一个示例效果:在EditText中输入文字(比如做课堂笔记Note),点击添加按钮,就会将输入的文字笔记添加到数据库。下面是一个RecyclerView列表,它将数据库中的内容全部读出并展示,点击item条目会删除该条目同时删除数据库中的记录。

对应数据库字段以及数据:

下面按照实际的开发步骤贴出代码:

1.首先我们需要定义一个实体对象(Entity Object),它是我们映射到数据库中的对象,这里你只需要定义实体对象的字段就可以,其他的getter()\setter()方法等编译器会自动生成:

public class Note {

    private Long id;
    private String text;
    private String comment;
    private java.util.Date date;
    private NoteType type;

}

然后点击Android studio-->build-->Make Project按钮后,编译器就会自动创建完整的实体类:

完整的实体类:

package org.greenrobot.greendao.example;

import org.greenrobot.greendao.annotation.Convert;
import org.greenrobot.greendao.annotation.Entity;
import org.greenrobot.greendao.annotation.Generated;
import org.greenrobot.greendao.annotation.Id;
import org.greenrobot.greendao.annotation.Index;
import org.greenrobot.greendao.annotation.NotNull;

/**
 * Entity mapped to table "NOTE".
 */
@Entity(indexes = {
    @Index(value = "text, date DESC", unique = true)
})
public class Note {

    @Id
    private Long id;

    @NotNull
    private String text;
    private String comment;
    private java.util.Date date;

    @Convert(converter = NoteTypeConverter.class, columnType = String.class)
    private NoteType type;

    @Generated(hash = 1272611929)
    public Note() {
    }

    public Note(Long id) {
        this.id = id;
    }

    @Generated(hash = 1686394253)
    public Note(Long id, @NotNull String text, String comment, java.util.Date date, NoteType type) {
        this.id = id;
        this.text = text;
        this.comment = comment;
        this.date = date;
        this.type = type;
    }

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    @NotNull
    public String getText() {
        return text;
    }

    /** Not-null value; ensure this value is available before it is saved to the database. */
    public void setText(@NotNull String text) {
        this.text = text;
    }

    public String getComment() {
        return comment;
    }

    public void setComment(String comment) {
        this.comment = comment;
    }

    public java.util.Date getDate() {
        return date;
    }

    public void setDate(java.util.Date date) {
        this.date = date;
    }

    public NoteType getType() {
        return type;
    }

    public void setType(NoteType type) {
        this.type = type;
    }

}

GreenDao并且会自动生成3个核心类如下:

3个核心类介绍

DaoMaster:

使用 greenDAO 的入口点。DaoMaster 负责管理数据库对象(SQLiteDatabase)和 DAO 类(对象),我们可以通过它内部类 OpenHelper 和 DevOpenHelper SQLiteOpenHelper 创建不同模式的 SQLite 数据库。

DaoSession :

管理指定模式下的所有 DAO 对象,DaoSession提供了一些通用的持久性方法比如插入、负载、更新、更新和删除实体。

XxxDAO :

每个实体类 greenDAO都会生成一个与之对应DAO对象,如:User实体,则会生成一个一个UserDao类,通过这和UserDao对象调用queryBuilder()进而调用查询条件的方法、增删改查的方法等。

Entities

可持久化对象。通常, 实体对象代表一个数据库行使用标准 Java 属性(如一个POJO 或 JavaBean )。

三个核心类与数据实体对象之间的关系:

DaoMaster.class:

package org.greenrobot.greendao.example;

import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteDatabase.CursorFactory;
import android.util.Log;

import org.greenrobot.greendao.AbstractDaoMaster;
import org.greenrobot.greendao.database.StandardDatabase;
import org.greenrobot.greendao.database.Database;
import org.greenrobot.greendao.database.DatabaseOpenHelper;
import org.greenrobot.greendao.identityscope.IdentityScopeType;


// THIS CODE IS GENERATED BY greenDAO, DO NOT EDIT.
/**
 * Master of DAO (schema version 1000): knows all DAOs.
 */
public class DaoMaster extends AbstractDaoMaster {
    public static final int SCHEMA_VERSION = 1000;

    /** Creates underlying database table using DAOs. */
    public static void createAllTables(Database db, boolean ifNotExists) {
        NoteDao.createTable(db, ifNotExists);
    }

    /** Drops underlying database table using DAOs. */
    public static void dropAllTables(Database db, boolean ifExists) {
        NoteDao.dropTable(db, ifExists);
    }

    /**
     * WARNING: Drops all table on Upgrade! Use only during development.
     * Convenience method using a {@link DevOpenHelper}.
     */
    public static DaoSession newDevSession(Context context, String name) {
        Database db = new DevOpenHelper(context, name).getWritableDb();
        DaoMaster daoMaster = new DaoMaster(db);
        return daoMaster.newSession();
    }

    public DaoMaster(SQLiteDatabase db) {
        this(new StandardDatabase(db));
    }

    public DaoMaster(Database db) {
        super(db, SCHEMA_VERSION);
        registerDaoClass(NoteDao.class);
    }

    public DaoSession newSession() {
        return new DaoSession(db, IdentityScopeType.Session, daoConfigMap);
    }

    public DaoSession newSession(IdentityScopeType type) {
        return new DaoSession(db, type, daoConfigMap);
    }

    /**
     * Calls {@link #createAllTables(Database, boolean)} in {@link #onCreate(Database)} -
     */
    public static abstract class OpenHelper extends DatabaseOpenHelper {
        public OpenHelper(Context context, String name) {
            super(context, name, SCHEMA_VERSION);
        }

        public OpenHelper(Context context, String name, CursorFactory factory) {
            super(context, name, factory, SCHEMA_VERSION);
        }

        @Override
        public void onCreate(Database db) {
            Log.i("greenDAO", "Creating tables for schema version " + SCHEMA_VERSION);
            createAllTables(db, false);
        }
    }

    /** WARNING: Drops all table on Upgrade! Use only during development. */
    public static class DevOpenHelper extends OpenHelper {
        public DevOpenHelper(Context context, String name) {
            super(context, name);
        }

        public DevOpenHelper(Context context, String name, CursorFactory factory) {
            super(context, name, factory);
        }

        @Override
        public void onUpgrade(Database db, int oldVersion, int newVersion) {
            Log.i("greenDAO", "Upgrading schema from version " + oldVersion + " to " + newVersion + " by dropping all tables");
            dropAllTables(db, true);
            onCreate(db);
        }
    }

}

DaoSession.class: 

package org.greenrobot.greendao.example;

import java.util.Map;

import org.greenrobot.greendao.AbstractDao;
import org.greenrobot.greendao.AbstractDaoSession;
import org.greenrobot.greendao.database.Database;
import org.greenrobot.greendao.identityscope.IdentityScopeType;
import org.greenrobot.greendao.internal.DaoConfig;

import org.greenrobot.greendao.example.Note;

import org.greenrobot.greendao.example.NoteDao;

// THIS CODE IS GENERATED BY greenDAO, DO NOT EDIT.

/**
 * {@inheritDoc}
 * 
 * @see org.greenrobot.greendao.AbstractDaoSession
 */
public class DaoSession extends AbstractDaoSession {

    private final DaoConfig noteDaoConfig;

    private final NoteDao noteDao;

    public DaoSession(Database db, IdentityScopeType type, Map<Class<? extends AbstractDao<?, ?>>, DaoConfig>
            daoConfigMap) {
        super(db);

        noteDaoConfig = daoConfigMap.get(NoteDao.class).clone();
        noteDaoConfig.initIdentityScope(type);

        noteDao = new NoteDao(noteDaoConfig, this);

        registerDao(Note.class, noteDao);
    }
    
    public void clear() {
        noteDaoConfig.clearIdentityScope();
    }

    public NoteDao getNoteDao() {
        return noteDao;
    }

}

你不用太多的关心上面两个类。我们来看一下数据库的初始化,以及数据库的库名和数据库中与我们这个实体类Note.class对象对应的数据表在哪里命名?

数据库的初始化:自定义MyApplication.class继承Application类,并在Manifest中声明这个MyApplication.class如下:

package org.greenrobot.greendao.example;

import android.app.Application;
import android.content.Context;

import org.greenrobot.greendao.database.Database;

public class MyApplication extends Application {

    private DaoSession daoSession;

    @Override
    public void onCreate() {
        super.onCreate();

        /**
         * 1、通过DaoMaster内部类OpenHelper获取需要连接的一个标准的数据库对象:SQLiteDatabase
         */
        ExampleOpenHelper helper = new ExampleOpenHelper(this, "notes-db");
        Database db = helper.getWritableDb();

        /**
         * 2、创建数据库管理对象
         * DaoMaster是使用greenDAO的入口点。DaoMaster负责管理数据库对象(SQLiteDatabase)和DAO类(对象),
         * 我们可以通过它内部类OpenHelper和DevOpenHelper SQLiteOpenHelper创建不同模式的SQLite数据库
         */
        DaoMaster daoMaster = new DaoMaster(db);
        /**
         * 3、创建数据库链接会话
         * 管理指定模式下的所有DAO对象,DaoSession提供了一些通用的持久性方法比如插入、负载、更新、更新和删除实体。
         */
        daoSession = daoMaster.newSession();
    }

    public DaoSession getDaoSession() {
        return daoSession;
    }

    public static class ExampleOpenHelper extends DaoMaster.OpenHelper {

        public ExampleOpenHelper(Context context, String name) {
            super(context, name);
        }

        @Override
        public void onCreate(Database db) {
            super.onCreate(db);

            // Insert some example data.
            // INSERT INTO NOTE (_id, DATE, TEXT) VALUES(1, 0, 'Example Note')
            db.execSQL("INSERT INTO " + NoteDao.TABLENAME + " (" +
                    NoteDao.Properties.Id.columnName + ", " +
                    NoteDao.Properties.Date.columnName + ", " +
                    NoteDao.Properties.Text.columnName +
                    ") VALUES(1, 0, 'Example Note')");
        }
    }
}

看上面的代码,第1步中获取数据库对象时new ExampleOpenHelper(this, "notes-db");第二个参数用于指定数据库的库名。

你也可以不用像上面那样继承DaoMaster.OpenHelper那样自定义自己的ExampleOpenHelper。可以直接使用DaoMaster.OpenHelper类进行获取数据库对象:

public class MyApplication extends Application {

    public static DaoSession mSession;

    @Override
    public void onCreate() {
        super.onCreate();

        initDb();
    }

    /**
     * 连接数据库并创建会话
     */
    public void initDb() {
        // 1、获取需要连接的数据库对象
        DaoMaster.DevOpenHelper devOpenHelper = new DaoMaster.DevOpenHelper(this, "test.db");
        SQLiteDatabase db = devOpenHelper.getWritableDatabase();
        // 2、创建数据库管理对象
        DaoMaster daoMaster = new DaoMaster(db);
        // 3、创建数据库会话
        mSession = daoMaster.newSession();
    }

    // 供外接使用
    public DaoSession getDaoSession() {
        return mSession;
    }
}

我们还有一个自动生成的类没说,NoteDao.class:

package org.greenrobot.greendao.example;

import android.database.Cursor;
import android.database.sqlite.SQLiteStatement;

import org.greenrobot.greendao.AbstractDao;
import org.greenrobot.greendao.Property;
import org.greenrobot.greendao.internal.DaoConfig;
import org.greenrobot.greendao.database.Database;
import org.greenrobot.greendao.database.DatabaseStatement;

// THIS CODE IS GENERATED BY greenDAO, DO NOT EDIT.
/** 
 * DAO for table "NOTE".
*/
public class NoteDao extends AbstractDao<Note, Long> {

    public static final String TABLENAME = "NOTE";

    /**
     * Properties of entity Note.<br/>
     * Can be used for QueryBuilder and for referencing column names.
     */
    public static class Properties {
        public final static Property Id = new Property(0, Long.class, "id", true, "_id");
        public final static Property Text = new Property(1, String.class, "text", false, "TEXT");
        public final static Property Comment = new Property(2, String.class, "comment", false, "COMMENT");
        public final static Property Date = new Property(3, java.util.Date.class, "date", false, "DATE");
        public final static Property Type = new Property(4, String.class, "type", false, "TYPE");
    }

    private final NoteTypeConverter typeConverter = new NoteTypeConverter();

    public NoteDao(DaoConfig config) {
        super(config);
    }
    
    public NoteDao(DaoConfig config, DaoSession daoSession) {
        super(config, daoSession);
    }

    /** Creates the underlying database table. */
    public static void createTable(Database db, boolean ifNotExists) {
        String constraint = ifNotExists? "IF NOT EXISTS ": "";
        db.execSQL("CREATE TABLE " + constraint + "\"NOTE\" (" + //
                "\"_id\" INTEGER PRIMARY KEY ," + // 0: id
                "\"TEXT\" TEXT NOT NULL ," + // 1: text
                "\"COMMENT\" TEXT," + // 2: comment
                "\"DATE\" INTEGER," + // 3: date
                "\"TYPE\" TEXT);"); // 4: type
        // Add Indexes
        db.execSQL("CREATE UNIQUE INDEX " + constraint + "IDX_NOTE_TEXT_DATE_DESC ON \"NOTE\"" +
                " (\"TEXT\" ASC,\"DATE\" DESC);");
    }

    /** Drops the underlying database table. */
    public static void dropTable(Database db, boolean ifExists) {
        String sql = "DROP TABLE " + (ifExists ? "IF EXISTS " : "") + "\"NOTE\"";
        db.execSQL(sql);
    }

    @Override
    protected final void bindValues(DatabaseStatement stmt, Note entity) {
        stmt.clearBindings();
 
        Long id = entity.getId();
        if (id != null) {
            stmt.bindLong(1, id);
        }
        stmt.bindString(2, entity.getText());
 
        String comment = entity.getComment();
        if (comment != null) {
            stmt.bindString(3, comment);
        }
 
        java.util.Date date = entity.getDate();
        if (date != null) {
            stmt.bindLong(4, date.getTime());
        }
 
        NoteType type = entity.getType();
        if (type != null) {
            stmt.bindString(5, typeConverter.convertToDatabaseValue(type));
        }
    }

    @Override
    protected final void bindValues(SQLiteStatement stmt, Note entity) {
        stmt.clearBindings();
 
        Long id = entity.getId();
        if (id != null) {
            stmt.bindLong(1, id);
        }
        stmt.bindString(2, entity.getText());
 
        String comment = entity.getComment();
        if (comment != null) {
            stmt.bindString(3, comment);
        }
 
        java.util.Date date = entity.getDate();
        if (date != null) {
            stmt.bindLong(4, date.getTime());
        }
 
        NoteType type = entity.getType();
        if (type != null) {
            stmt.bindString(5, typeConverter.convertToDatabaseValue(type));
        }
    }

    @Override
    public Long readKey(Cursor cursor, int offset) {
        return cursor.isNull(offset + 0) ? null : cursor.getLong(offset + 0);
    }    

    @Override
    public Note readEntity(Cursor cursor, int offset) {
        Note entity = new Note( //
            cursor.isNull(offset + 0) ? null : cursor.getLong(offset + 0), // id
            cursor.getString(offset + 1), // text
            cursor.isNull(offset + 2) ? null : cursor.getString(offset + 2), // comment
            cursor.isNull(offset + 3) ? null : new java.util.Date(cursor.getLong(offset + 3)), // date
            cursor.isNull(offset + 4) ? null : typeConverter.convertToEntityProperty(cursor.getString(offset + 4)) // type
        );
        return entity;
    }
     
    @Override
    public void readEntity(Cursor cursor, Note entity, int offset) {
        entity.setId(cursor.isNull(offset + 0) ? null : cursor.getLong(offset + 0));
        entity.setText(cursor.getString(offset + 1));
        entity.setComment(cursor.isNull(offset + 2) ? null : cursor.getString(offset + 2));
        entity.setDate(cursor.isNull(offset + 3) ? null : new java.util.Date(cursor.getLong(offset + 3)));
        entity.setType(cursor.isNull(offset + 4) ? null : typeConverter.convertToEntityProperty(cursor.getString(offset + 4)));
     }
    
    @Override
    protected final Long updateKeyAfterInsert(Note entity, long rowId) {
        entity.setId(rowId);
        return rowId;
    }
    
    @Override
    public Long getKey(Note entity) {
        if(entity != null) {
            return entity.getId();
        } else {
            return null;
        }
    }

    @Override
    public boolean hasKey(Note entity) {
        return entity.getId() != null;
    }

    @Override
    protected final boolean isEntityUpdateable() {
        return true;
    }
    
}

这个类中第一行一个静态变量就定义了与我们数据实体对象对应的数据表的表名。

在NoteActivity中查询数据并显示:(请不要复制这个例子到项目中运行,因为这里还有一些类我没有贴出。)

/*
 * Copyright (C) 2011 Markus Junginger, greenrobot (http://greenrobot.de)
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.greenrobot.greendao.example;

import android.os.Bundle;
import android.text.Editable;
import android.text.TextWatcher;
import android.util.Log;
import android.view.View;
import android.view.inputmethod.EditorInfo;
import android.widget.EditText;

import org.greenrobot.greendao.query.Query;

import java.text.DateFormat;
import java.util.Date;
import java.util.List;

import androidx.appcompat.app.AppCompatActivity;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;

public class NoteActivity extends AppCompatActivity {

    private EditText editText;
    private View addNoteButton;

    private NoteDao noteDao;
    private Query<Note> notesQuery;
    private NotesAdapter notesAdapter;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        setUpViews();

        // get the note DAO
        DaoSession daoSession = ((MyApplication) getApplication()).getDaoSession();
        noteDao = daoSession.getNoteDao();

        /**
         * 查询数据库对应表中所有的笔记数据
         * query all notes, sorted a-z by their text
         */
        notesQuery = noteDao.queryBuilder().orderAsc(NoteDao.Properties.Text).build();
        updateNotes();
    }

    private void updateNotes() {
        List<Note> notes = notesQuery.list();
        notesAdapter.setNotes(notes);
    }

    protected void setUpViews() {
        RecyclerView recyclerView = findViewById(R.id.recyclerViewNotes);
        recyclerView.setHasFixedSize(true);
        recyclerView.setLayoutManager(new LinearLayoutManager(this));

        notesAdapter = new NotesAdapter(noteClickListener);
        recyclerView.setAdapter(notesAdapter);

        addNoteButton = findViewById(R.id.buttonAdd);
        addNoteButton.setEnabled(false);

        editText = findViewById(R.id.editTextNote);
        editText.setOnEditorActionListener((v, actionId, event) -> {
            if (actionId == EditorInfo.IME_ACTION_DONE) {
                addNote();
                return true;
            }
            return false;
        });
        editText.addTextChangedListener(new TextWatcher() {

            @Override
            public void onTextChanged(CharSequence s, int start, int before, int count) {
                boolean enable = s.length() != 0;
                addNoteButton.setEnabled(enable);
            }

            @Override
            public void beforeTextChanged(CharSequence s, int start, int count, int after) {
            }

            @Override
            public void afterTextChanged(Editable s) {
            }
        });
    }

    public void onAddButtonClick(View view) {
        addNote();
    }

    private void addNote() {
        String noteText = editText.getText().toString();
        editText.setText("");

        final DateFormat df = DateFormat.getDateTimeInstance(DateFormat.MEDIUM, DateFormat.MEDIUM);
        String comment = "Added on " + df.format(new Date());

        Note note = new Note();
        note.setText(noteText);
        note.setComment(comment);
        note.setDate(new Date());
        note.setType(NoteType.TEXT);
        noteDao.insert(note);
        Log.d("DaoExample", "Inserted new note, ID: " + note.getId());

        updateNotes();
    }

    NotesAdapter.NoteClickListener noteClickListener = new NotesAdapter.NoteClickListener() {
        @Override
        public void onNoteClick(int position) {
            Note note = notesAdapter.getNote(position);
            Long noteId = note.getId();

            noteDao.deleteByKey(noteId);
            Log.d("DaoExample", "Deleted note, ID: " + noteId);

            updateNotes();
        }
    };
}

NoteActivity的布局文件:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
                xmlns:tools="http://schemas.android.com/tools"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:paddingBottom="@dimen/activity_vertical_margin"
                android:paddingLeft="@dimen/activity_horizontal_margin"
                android:paddingRight="@dimen/activity_horizontal_margin"
                android:paddingTop="@dimen/activity_vertical_margin"
                tools:context="org.greenrobot.greendao.example.NoteActivity"
                tools:ignore="RtlHardcoded">

    <Button
        android:id="@+id/buttonAdd"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentRight="true"
        android:onClick="onAddButtonClick"
        android:text="@string/add"/>

    <EditText
        android:id="@+id/editTextNote"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_toLeftOf="@id/buttonAdd"
        android:hint="@string/enter_new_note"
        android:imeOptions="actionDone"
        android:inputType="text"/>

    <TextView
        android:id="@+id/textViewNoteInstructions"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_below="@id/editTextNote"
        android:gravity="center_horizontal"
        android:paddingBottom="8dp"
        android:paddingLeft="8dp"
        android:paddingRight="8dp"
        android:text="@string/click_to_remove"
        android:textSize="12sp"/>

    <androidx.recyclerview.widget.RecyclerView
        android:id="@+id/recyclerViewNotes"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_below="@id/textViewNoteInstructions"
        android:scrollbars="vertical"/>

</RelativeLayout>

RecyclerView适配器代码如下:

package org.greenrobot.greendao.example;

import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;

import java.util.ArrayList;
import java.util.List;

import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;

public class NotesAdapter extends RecyclerView.Adapter<NotesAdapter.NoteViewHolder> {

    private NoteClickListener clickListener;
    private List<Note> dataset;

    public interface NoteClickListener {
        void onNoteClick(int position);
    }

    static class NoteViewHolder extends RecyclerView.ViewHolder {

        public TextView text;
        public TextView comment;

        public NoteViewHolder(View itemView, final NoteClickListener clickListener) {
            super(itemView);
            text = itemView.findViewById(R.id.textViewNoteText);
            comment = itemView.findViewById(R.id.textViewNoteComment);
            itemView.setOnClickListener(view -> {
                if (clickListener != null) {
                    clickListener.onNoteClick(getAdapterPosition());
                }
            });
        }
    }

    public NotesAdapter(NoteClickListener clickListener) {
        this.clickListener = clickListener;
        this.dataset = new ArrayList<>();
    }

    public void setNotes(@NonNull List<Note> notes) {
        dataset = notes;
        notifyDataSetChanged();
    }

    public Note getNote(int position) {
        return dataset.get(position);
    }

    @NonNull
    @Override
    public NotesAdapter.NoteViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        View view = LayoutInflater.from(parent.getContext())
                .inflate(R.layout.item_note, parent, false);
        return new NoteViewHolder(view, clickListener);
    }

    @Override
    public void onBindViewHolder(NotesAdapter.NoteViewHolder holder, int position) {
        Note note = dataset.get(position);
        holder.text.setText(note.getText());
        holder.comment.setText(note.getComment());
    }

    @Override
    public int getItemCount() {
        return dataset.size();
    }
}

上面只是梳理了GreenDao的使用流程,以及我们需要知道的知识点。当然这并不是所有的知识点,我们需要学习的还很多。这个例子请不要复制到项目中运行,因为这里还有一些类我没有贴出。如果想看完整的代码、并运行上面的实例,请至GreenDao的GitHub地址:https://github.com/greenrobot/greenDAO下载demo示例。上面的例子就是来自官网给的实例。

 

在说会上面的NoteActivity.class,一般对数据的增删改查,正式的项目开发中我们并不会直接在Activity中直接那么写。而是把它封装到一个诸如NoteDBManager.class的类中,这里贴出一个示例:


public class MessageManager {
    private static MessageManager messageManager;
    /**
     * DaoSession
     */
    private DaoSession mDaoSession;
    private MessageDao messageDao;

    private MessageManager() {
    }

    @Deprecated
    public static MessageManager getMMInstance(Context context) {
        return getInstance();
    }

    public static MessageManager getInstance() {
        if (null == messageManager) {
            synchronized (MessageManager.class) {
                if (messageManager == null) {
                    messageManager = new MessageManager();
                    messageManager.mDaoSession = MyApplication.getDaoSession();
                    messageManager.messageDao = messageManager.mDaoSession.getMessageDao();
                }
            }
        }
        return messageManager;
    }

    /**
     * 每天执行一次删除无效过期消息
     */
    public static void oneDayDelInvalidMsg() {
        Context context = MyApplication.getInstance().getApplicationContext();
        final SharedPreferences msgSp = context.getSharedPreferences(MsgCenterActivity.MSG_SP_NAME,
                Context.MODE_PRIVATE);
        SimpleDateFormat format = new SimpleDateFormat("yyyyMMdd", Locale.getDefault());
        final String curDay = format.format(new Date());
        String deleteDay = msgSp.getString("delete_day", "");
        if (!curDay.equals(deleteDay)) {
            MessageManager.getInstance().deleteInvalidMessage();
            SharedPreferences.Editor editor = msgSp.edit();
            editor.putString("delete_day", curDay);
            editor.commit();
        }
    }


    /**
     * 根据id删除推送消息
     *
     * @param mid
     */
    public void deleteMessageByMid(String mid) {
        try {
            QueryBuilder<Message> qb = messageDao.queryBuilder();
            DeleteQuery<Message> bd = qb.where(Properties.Mid.eq(mid)).buildDelete();
            bd.executeDeleteWithoutDetachingEntities();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 根据id删除推送消息(假删除)
     *
     * @param mid
     */
    public void deleteMessageNewByMid(String mid) {
        try {
            QueryBuilder<Message> qb = messageDao.queryBuilder();
            List<Message> msgList ;
            msgList = qb.where(Properties.Mid.eq(mid)).list();
            if (null != msgList && !msgList.isEmpty()) {
                Message msg = msgList.get(0);
                if (null != msg) {
                    msg.setIsdelete(1);
                    messageDao.insertOrReplace(msg);
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public void deleteMessageByMid(String mid, String mobile) {
        try {
            QueryBuilder<Message> qb = messageDao.queryBuilder();
            DeleteQuery<Message> bd = qb.where(qb.and(Properties.Mid.eq(mid), Properties.Mobile.eq(mobile)))
                    .buildDelete();
            bd.executeDeleteWithoutDetachingEntities();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 根据类型id删除所有消息
     *
     * @param typeId
     */
    public void deleteMessageByType(String typeId) {
        try {
            QueryBuilder<Message> qb = messageDao.queryBuilder();
            DeleteQuery<Message> bd = qb.where(Properties.MsgType.eq(typeId)).buildDelete();
            bd.executeDeleteWithoutDetachingEntities();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 根据类型id删除该用户手机号
     *
     * @param typeId
     * @param mobile
     */
    public void deleteTypeMessageByTypeMob(String typeId, String mobile) {
        try {
            QueryBuilder<Message> qb = messageDao.queryBuilder();
            DeleteQuery<Message> bd = qb.where(qb.and(Properties.MsgType.eq(typeId), Properties.Mobile.eq(mobile)))
                    .buildDelete();
            bd.executeDeleteWithoutDetachingEntities();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public void deleteInvalidMessage() {
        try {
            QueryBuilder<Message> qb = messageDao.queryBuilder();
            DeleteQuery<Message> bd = qb.where(qb.and(Properties.EffectiveTime.lt(System.currentTimeMillis()),
                    Properties.EffectiveTime.isNotNull())).buildDelete();
            bd.executeDeleteWithoutDetachingEntities();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public void updateMessageStatus(String mobile) {
        try {
            String curTime = getCurTime();
            QueryBuilder<Message> qb = messageDao.queryBuilder();
            List<Message> msgList ;
            msgList = qb.where(qb.and(Properties.Status.eq(0),
                    Properties.Mobile.eq(mobile), Properties.Isdelete.notEq(1))).list();
            if (null != msgList && !msgList.isEmpty()) {
                int size = msgList.size();
                for (int i = 0; i < size; i++) {
                    Message msg = msgList.get(i);
                    if (null != msg) {
                        msg.setStatus(1);
                        msg.setReadTime(curTime);
                        messageDao.update(msg);
                    }
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

然后通过管理类的单例在Activity中调用封装后的增删改查方法!。

忠言逆耳:对于初学者请一定先运行GitHub官网给的dome示例。而不是盲目的找示例demo,那样只会放慢你学习的脚步。

岁月鎏金,用知识铭刻生命的每分每秒!