Realm」カテゴリーアーカイブ

作ればわかる!Androidプログラミング Kotlin対応 10の実践サンプルで学ぶAndroidアプリ開発入門

作ればわかる!Androidプログラミング Kotlin対応 10の実践サンプルで学ぶAndroidアプリ開発入門
『作ればわかる!Androidプログラミング Kotlin対応 10の実践サンプルで学ぶAndroidアプリ開発入門』2019年06月19日新発売!
多少タイトルが長い感じがしますが、作ればわかる!Androidプログラミングの第五版にあたります。第五版と付いていないのは、今回プログラミング言語をJavaからKotlinに変えたからです。前書きにも書きましたが、KotlinだとJavaのように同じことをなんども書かなくてもすむのでコードの量が減り、プログラミングが軽快になります。

アクティビティやインテント、イベントリスナー、ConstraintLayout、UI部品の使い方といったAndroidアプリ開発で必要な基礎知識から、SurfaceViewによる描画、プリファレンスによる情報の記録、各種センサーやRealmデータベースといったかなり本格的な内容までが学べます。

目次
第1章 アプリを作るための準備
第2章 はじめてのアプリ作成
第3章 Kotlin入門
第4章 ハイ&ローゲーム
第5章 名刺切らしてまして
第6章 ご飯なんにする?
第7章 和室に入ったのだ~れ?
第8章 盗難防止アラーム
第9章 ブラックホールを避けろ!
第10章 若くても血圧は記録せよ
第11章 メモメモタイム
第12章 わたしはウクレレ
詳細は翔泳社さんのサイトでご確認ください。

自分で言うのもなんですが、今回はわかりやすい本になったと思います。
ぜひ、ご購読ください!

Xamarin、ザマリン、青空、晴れた空 -Xamarinで次世代mobile版データベースRealmを使う-

 こちらのサイトのメロディーとともにお楽しみください。

 Realmは、SQLite+ORMに変わるモバイルデータベースです。Realmは、NoSQLデータベース(非リレーショナルデータベース)ですので、オブジェクトを生成して手軽に永続化できます。
 現在、RealmはAndroidとiOSに対応しているので、Xamarinで使ってみます。Build Insiderに掲載されているXamarinでSQLiteを使うコンパクトなサンプルと同様なアプリをXamarin.Forms Portableで作成してみます。
 まず、Visual StudioでXamarin.Forms Portableなプロジェクトを作成します。
useRealm1
作成したら、NuGetパッケージマネージャで、realmを検索してインストールします。
 
 最初にModelクラスを作ります。グループ名だけを記録するGroup.csです。

using Realms;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace UseRealmApp
{
    public class Group : RealmObject
    {
        [ObjectId]
        public string ID { get; set; }
        public string Name { get; set; }
    }
}

 Realmにはいわゆるオートインクリメントな値を振る機能はありませんので、IDもStringにしてGUID値を記録することにします。
 次ぎにデータベースを操作するMemoDatabaseクラスを作成します。将来的にGroupクラスだけでなく、メモを記録するクラスなどを追加していくのでMemoDatabaseというクラス名にしました。
 GetGroups()メソッドはGroupクラスの全オブジェクトを取得します。GetGroups()メソッドの戻り値をListViewに表示します。GetGroupは指定したIDのオブジェクトを取得します。以降のメソッドについてはソースコードの下に解説を記します。

using Realms;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace UseRealmApp
{
    public class MemoDatabase
    {
        Realm realm;
        public MemoDatabase()
        {
            realm = Realm.GetInstance();
        }
        public IEnumerable<Group> GetGroups()
        {
            return realm.All<Group>().ToList();
        }
        public Group GetGroup(string id)
        {
            return realm.All<Group>()
                        .ToList()
                        .FirstOrDefault(x => x.ID == id);
        }
        public string SaveGroup(Group group)
        {
            var newGroup = realm.All<Group>()
                             .ToList()
                             .FirstOrDefault(x => x.ID == group.ID);

            using (var trans = realm.BeginWrite())
            {
                if (newGroup == null)
                {
                    newGroup = realm.CreateObject<Group>();
                    newGroup.ID = Guid.NewGuid().ToString();
                }

                newGroup.Name = group.Name;
 
                trans.Commit();
            }

            return newGroup?.ID;    // ? Nullable型
        }
        public string DeleteGroup(string id)
        {
            var item = realm.All<Group>()
                             .ToList()
                             .FirstOrDefault(x => x.ID == id);

            if (item == null)
                return null;

            using (var trans = realm.BeginWrite())
            {
                realm.Remove(item);
                trans.Commit();
            }

            return id;
        }
    }
}

 SaveGroupメソッドはオブジェクトを保存します。usingでトランザクション処理を囲みます。DeleteGroupメソッドは指定したIDのオブジェクトを削除します。

 app.csでページを表示します。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Xamarin.Forms;

namespace UseRealmApp
{
    public class App : Application
    {
        public App()
        {
            MainPage = new MyPage();
        }
    }
    class MyPage : ContentPage
    {

        readonly MemoDatabase _db = new MemoDatabase();

        public MyPage()
        {

            var listView = new ListView
            {
                ItemsSource = _db.GetGroups(), 
                ItemTemplate = new DataTemplate(typeof(TextCell)) 
            };
            listView.ItemTemplate.SetBinding(TextCell.TextProperty, "Name");
            listView.ItemTapped += async (s, a) => {
                var group = (Group)a.Item;
                if (await DisplayAlert("削除してよろしいですか", group.Name, "OK", "キャンセル"))
                {
                    _db.DeleteGroup(group.ID); // groupの削除
                    listView.ItemsSource = _db.GetGroups(); // リストの更新
                }
            };
            var entry = new Entry
            { 
                HorizontalOptions = LayoutOptions.FillAndExpand
            };
            var buttonAdd = new Button
            {
                WidthRequest = 60,
                Text = "追加"
            };
            buttonAdd.Clicked += (s, a) => { 
                if (!String.IsNullOrEmpty(entry.Text))
                { // Entryに文字列が入力されている場合に保存
                    var group = new Group { Name = entry.Text };
                    _db.SaveGroup(group);
                    listView.ItemsSource = _db.GetGroups(); //リストの更新
                    entry.Text = "";
                }
            };

            Content = new StackLayout
            { 
                Padding = new Thickness(0, Device.OnPlatform(20, 0, 0), 0, 0),
                Children = {
                    new StackLayout {
                        Padding = 5,
                        Orientation = StackOrientation.Horizontal,
                        Children = {entry, buttonAdd} 
                    },
                    listView 
                }
            };
        }
    }
}

 ListViewにはグループ名を一覧表示し、タップしたら削除確認のダイアログを表示します。
useRealm2
 Entryにグループ名を入力して追加ボタンをタップしたら、データベースに記録してListViewを更新します。
useRealm3
 XamarinでもRealmを簡単に使うことができました。

Realmはレアルムではなく、レルム

外国語のカタカナ読みを議論するのは不毛だと思うけど、なんて読んでいいのかわからないのも困るので、Realmはレルムと読むそうです。(not レアルム)
Realmは、SQLiteやCoreDataに置き換わるモバイルデータベース。
SQLiteのORマッパーではないという注意書きを付けたくなるほど使いやすいらしい。
詳しい説明はこちらからどうぞ。

使ってみた感想は「もうSQLiteには戻れない」です。

Java(Android)でRealmを使う簡単な手順を説明します。
Android Studioでプロジェクトを作成したら、build.gradleを編集します。
build.gradle(Project)にはclasspathを追加します。

    dependencies {
        classpath 'com.android.tools.build:gradle:2.1.0'
        classpath "io.realm:realm-gradle-plugin:1.0.0"	// 追記(ついに1.0.0!)

build.gradle(Module)にはpluginを追加します。

apply plugin: 'com.android.application'
apply plugin: 'realm-android'		// 追記

たとえば、何かの会のメンバーを登録して、ある条件で抽出して画面に表示する処理を作成してみます。
まず、Memberクラスを作成します。

package com.example.kanehiro.tryrealm;

import io.realm.RealmObject;

public class Member extends RealmObject {
    private long id;
    private String name;
    private boolean admin;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public long getId() {
        return id;
    }

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

    public boolean getAdmin() {
        return admin;
    }

    public void setAdmin(boolean admin) {
        this.admin = admin;
    }

}

Memberクラスには、idと名前、そしてadmin(管理者)かどうのかブール値(真偽値)を持たせます。
そして、それぞれのプロパティにgetterとsetterを用意します。
次にアクティビティのコードです。

package com.example.kanehiro.tryrealm;

import android.os.AsyncTask;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.widget.TextView;

import io.realm.Realm;
import io.realm.RealmConfiguration;
import io.realm.RealmResults;

public class MainActivity extends AppCompatActivity {

    private Realm realm;
    private RealmConfiguration realmConfig;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        // Create the Realm configuration
        realmConfig = new RealmConfiguration.Builder(this).build();

        new AsyncTask<Void, Void, String>() {
            @Override
            protected String doInBackground(Void... voids) {
                String info;
                memberWrite();
                info = memberQuery(false);
                memberDelete();
                return info;
            }

            @Override
            protected void onPostExecute(String result) {
                TextView txt01 = (TextView)findViewById(R.id.txt01);
                txt01.setText(result);
            }
        }.execute();

    }
    private void memberWrite() {

        Realm realm = Realm.getInstance(realmConfig);

        realm.executeTransaction(new Realm.Transaction() {
            @Override
            public void execute(Realm realm) {
                for (int i = 0; i < 30; i++) {
                    Member member = realm.createObject(Member.class);
                    member.setId(i);
                    member.setName("Member" + i);
                    if ((i % 3) == 0){
                        member.setAdmin(true);
                    }
                }
            }
        });
        realm.close();
    }
    private String memberQuery(boolean admin) {

        StringBuilder strBuild = new StringBuilder();
        Realm realm = Realm.getInstance(realmConfig);
        RealmResults<Member> results = realm.where(Member.class)
                .equalTo("admin", admin).findAll();
        for (Member m : results) {
            strBuild.append(m.getId());
            strBuild.append(",");
            strBuild.append(m.getName());
            strBuild.append("\n");

        }

        realm.close();
        return strBuild.toString();
    }

    private void memberDelete() {
        Realm realm = Realm.getInstance(realmConfig);
        realm.executeTransaction(new Realm.Transaction() {
            @Override
            public void execute(Realm realm) {
                realm.delete(Member.class);
            }
        });
        realm.close();
    }
}

onCreateメソッドから見ていきましょう。RealmConfiguration.BuilderでRealm configurationオブジェクトを生成します。
追加するレコードの件数は少ないけど、AsyncTaskクラスを使って非同期に書き込み、読み込み、削除を実行します。
抽出結果はテキストビューに表示します。
memberWriteメソッドでMemberを書込みます。まず、Realm.getInstanceでRealmを取得します。
書き込み(追加、変更、削除)処理は、トランザクションの中で行わなければなりません。
ここでは、トランザクションブロックを使っています。realm.executeTransactionの部分です。
トランザクションはexecuteTransactionメソッドを抜けたタイミングでコミットされます。
memberQuery()で、クエリーを発行しています。whereにクラスを指定して、.equalToなどで検索条件を指定します。
ここではadminかどうかが検索条件です。findAll()で取得します。
次に取得した結果セットをループしてgetterで値を取得し、文字列として返します。
memberDelete()では、realm.delete(Member.class)で全オブジェクトを削除しています。
adminじゃないMemberを抽出した結果が次の画像です。
tryrealm実行結果