LoginSignup
12
9

More than 5 years have passed since last update.

OrmaとDagger2でRepositoryレイヤーを作成する - Android

Posted at

システムをレイヤー化し、各レイヤーに独自の責任を持たせよう

データをローカルに格納するためにSQLiteに保存する場合がありますが、データベースの作成とかアクセスとかCursorとか少し面倒です。😧

自分はそんなめんどくささから、OrmaDagger2を使用しています。
OrmaはAndroid用のORMで、実装としてはSQLiteDatabaseのラッパーとなっております。

Dagger2はGooglの依存性注入ライブラリーです。

Repositoryレイヤーはこんな感じにしています。

Repository behind the scenes (1).png

MVPなどで実装する場合、ご覧のようにPresenterはRepositoryと依存関係を持つ感じで、Repositoryオブジェクトだけでデータベース関連の操作を実行します。そうすることでアプリ全体のデータベースエントリーポイントとなります。

では深掘りして動作を理解していきましょう。

サンプルアプリを作成しましたのでご覧ください。
シンプルなTodoアプリです。

まずデータベーステーブルのアクセスに関するOrmaとmodel周りから
Ormaでは、テーブルに対応するスキーマはPOJOにアノテーションを付加したものです。Ormaのannotation processorがアノテーションをみてヘルパークラスを生成します。(引用:モデルクラスの定義

@Table
public class Todo {

    @PrimaryKey(autoincrement = true)
    public long id;

    @Column(indexed = true)
    public String title;

    @Column
    @Nullable // allows NULL (default: NOT NULL)
    public String content;

    @Column(indexed = true)
    public boolean done;

    @Override
    public String toString() {
        return "Todo{" +
                "id=" + id +
                ", title='" + title + '\'' +
                ", content='" + content + '\'' +
                ", done=" + done +
                '}';
    }
}

次にデータベースを実行する上での基本的なクエリをインターフェースに定義します。

public interface DataSource<T> {
    void add(T item);
    void add(List<T> items);
    void update(T item);
    void update(List<T> items);
    void remove(T item);
    boolean isEmpty();
}

SELECT系のクエリはモデルによってフィルターをかけたり、Rxで処理したかったりと別れる場合があるのでDataSourceを継承したインターフェースを定義しています。

public interface TodoDataSource extends DataSource<Todo> {
    Observable<Todo> fetchAsObservable(long id);
    Single<List<Todo>> fetchAllAsSingle();
}

データベースハンドルであるOrmaDatabaseを使用してCRUD操作をする必要があるため、Daggerを使用して依存関係を作ります。

public class LocalTodoDataSource implements TodoDataSource {

    private OrmaDatabase ormaDatabase;

    @Inject
    public LocalTodoDataSource(OrmaDatabase ormaDatabase) {
        this.ormaDatabase = ormaDatabase;
    }

}

これでデータベースのクエリを実行できる用意ができたので、Presenterがデータソースとやり取りできるようにするエントリーポイントであるRepositoryのインターフェースを作成します。

public interface Repository {
    LocalTodoDataSource localTodoData();
}

そしてアクセスするためのRepositoryImplを作成します。

public class RepositoryImpl implements Repository{

    public LocalTodoDataSource localTodoDataSource;

    @Inject
    public RepositoryImpl(LocalTodoDataSource localTodoDataSource) {
        this.localTodoDataSource = localTodoDataSource;
    }

    @Override
    public LocalTodoDataSource localTodoData() {
        return localTodoDataSource;
    }
}

最後に、Presenterにすべてのデータソースに依存するリポジトリレイヤを準備しますが、これらの依存関係はDaggerによってつくられます。 Daggerはこれらのデータソースの単一のインスタンスを保持し、必要なときにいつでも提供(Provide)します。

これで、リポジトリの依存関係を提供し、Todoのローカルデータを取り出すことができるようになります。

public class TodoListPresenter implements TodoListContract.Presenter {

    Repository repository;

    @Inject
    public TodoListPresenter(Repository repository) {
        this.repository = repository;
    }
}

以上です。いかがでしょうか。リポジトリレイヤーを作成し、インターフェースでやりとりすることで保存する仕組みをOrma以外にRealmやPref、リモートのデータソースと切り離すこともできるようになると思います。

ご覧いただきありがとうございました! 😃

Happy Coding!

12
9
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
12
9