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実行結果

Xamarin、ザマリン、青空、晴れた空 -住所から緯度・経度を取得する-

 こちらのサイトのメロディーとともにお楽しみください。
正式なタイトルはVisual StudioのXamarinでAndroidアプリを作る(#6) Geocorderを使うです。
6回目となる今回は、Geocorderを使って住所から緯度・経度を取得してみます。今回もdeveloper.xamarin.comのレシピ、ほとんどそのままですが、日本の住所の与え方や若干補足説明があった方が良いかと思い書きます。

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent">
    <Button
        android:id="@+id/geocodeButton"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:text="@string/geocodeButtonText" />
    <TextView
        android:id="@+id/addressText"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent" />
</LinearLayout>

画面には、緯度・経度引きを起動するボタンと取得した情報を表示するテキストビューを配置します。

次にMainActivityのコードです。

using System;
using Android.App;
using Android.Content;
using Android.Runtime;
using Android.Views;
using Android.Widget;
using Android.OS;
using System.Threading;
using Android.Locations;
using System.Linq;

namespace Geocorder
{
    [Activity(Label = "Geocorder", MainLauncher = true, Icon = "@drawable/icon")]
    public class MainActivity : Activity
    {
        protected override void OnCreate(Bundle bundle)
        {
            base.OnCreate(bundle);

            // Set our view from the "main" layout resource
            SetContentView(Resource.Layout.Main);

            // Get our button from the layout resource,
            // and attach an event to it
            var button = FindViewById<Button>(Resource.Id.geocodeButton);
            button.Click += (sender, e) => {
                new Thread(new ThreadStart(() => {
                    var geo = new Geocoder(this);

                    //var addresses = geo.GetFromLocationName("50 Church St, Cambridge, MA", 1);
                    var addresses = geo.GetFromLocationName("東京都港区六本木5-11-16", 1);

                    RunOnUiThread(() => {
                        var addressText = FindViewById<TextView>
                               (Resource.Id.addressText);

                        addresses.ToList().ForEach((addr) => {
                            addressText.Append(addr.ToString() +
                                   "\r\n\r\n");
                        });
                    });
                })).Start();

            };
        }
    }
}

Geocoder#GetFromLocationNameには、日本語の住所をそのまんま与えます。
RunOnUiThreadは内部で、Handler#postを呼んでいます。
geocoder実行結果
緯度・経度のほかに郵便番号や詳細な住所も取得していますね。

Xamarin、ザマリン、青空、晴れた空 -加速度センサーを使う-

 こちらのサイトのメロディーとともにお楽しみください。
正式なタイトルはVisual StudioのXamarinでAndroidアプリを作る(#5) 加速度センサーを使うです。
 5回目となる今回は、加速度センサーを使ってみます。developer.xamarin.comのレシピを参考にします。
今回はMainActivityの全コードを掲載します。
MainActivity

using System;
using Android.App;
using Android.Content;
using Android.Runtime;
using Android.Views;
using Android.Widget;
using Android.OS;
using Android.Hardware;

namespace AcceleGet
{
    [Activity(Label = "AcceleGet", MainLauncher = true, Icon = "@drawable/icon")]
    public class MainActivity : Activity, ISensorEventListener
    {
        static readonly object _syncLock = new object();
        SensorManager _sensorManager;
        TextView _sensorTextView;

        protected override void OnCreate(Bundle bundle)
        {
            base.OnCreate(bundle);
            // Set our view from the "main" layout resource
            SetContentView(Resource.Layout.Main);
            _sensorManager = (SensorManager)GetSystemService(Context.SensorService);
            _sensorTextView = FindViewById<TextView>(Resource.Id.accelerometer_text);
        }
        public void OnAccuracyChanged(Sensor sensor, [GeneratedEnum] SensorStatus accuracy)
        {
            //throw new NotImplementedException();
        }
        public void OnSensorChanged(SensorEvent e)
        {
            lock (_syncLock)
            {
                _sensorTextView.Text = string.Format("x={0:f}, y={1:f}, z={2:f}", e.Values[0], e.Values[1], e.Values[2]);
            }
        }
        protected override void OnResume()
        {
            base.OnResume();
            _sensorManager.RegisterListener(this,
                                            _sensorManager.GetDefaultSensor(SensorType.Accelerometer),
                                            SensorDelay.Ui);
        }
        protected override void OnPause()
        {
            base.OnPause();
            _sensorManager.UnregisterListener(this);
        }
    }
}

 センサーを使うにはISensorEventListenerインターフェースをインプリメントします。
ISensorEventListenerインターフェースをインプリメントする場合は、OnAccuracyChangedメソッドとOnSensorChangedを実装する必要があります。
 加速度センサーを使うには、OnResumeメソッドで、SensorType.Accelerometerを指定して、SensorManagerのRegisterListenerでリスナーを登録します。SensorDelay.Uiはセンサーの値を取得する間隔の指定です。
 OnPauseメソッドではUnregisterListenerでリスナーの登録を解除します。
 OnSensorChangedメソッドで加速度センサーの値を取得して画面に表示します。lockで他のスレッドから更新されないように排他制御しています。

実行画面

実行画面

Xamarin、ザマリン、青空、晴れた空

 今回からタイトルを変えました。こちらのサイトのメロディーとともにお楽しみください。
正式なタイトルはVisual StudioのXamarinでAndroidアプリを作る(#4) TwoTouchMailを作るです。
 4回目となる今回は、「作ればわかる!Androidプログラミング」の第二章のサンプルアプリTwoTouchMailをXamarinで作ってみます。とは言っても、インテントでデータを渡す方法やアクティビティを指定しない暗黙的なインテントについてはこれまでの3回ですでに説明しました。
 今回説明するのは、dimens.xml、RadioGroupの使い方、そしてStrings.xmlに登録した文字列をC#のコードで取得する方法です。
dimens.xmlにはpaddingで使うマージンのサイズを登録します。dimens.xmlは新規作成するXMLファイルです。
dimen.xml

<?xml version="1.0" encoding="utf-8" ?>
<resources>
  <!-- Default screen margins, per the Android Design guidelines. -->
  <dimen name="activity_horizontal_margin">16dp</dimen>
  <dimen name="activity_vertical_margin">16dp</dimen>
</resources>

 そして、レイアウトファイルにマージンを指定します。下記のサンプルはお迎えを頼むPickUp.axmlです。
RelativeLayoutの内側に余白を作るためにdimens.xmlの縦横marginをpaddingXXXXXXに指定しています。
PickUp.axml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    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">
    <TextView
        android:text="@string/subject"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textSize="18sp"
        android:id="@+id/textView" />
    <EditText
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:id="@+id/editText"
        android:layout_below="@+id/textView"
        android:layout_alignParentLeft="true"
        android:layout_alignParentStart="true"
        android:text="@string/button_pickup" />
    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textAppearance="?android:attr/textAppearanceMedium"
        android:text="@string/place"
        android:id="@+id/textView3"
        android:layout_below="@+id/editText"
        android:layout_alignParentLeft="true"
        android:layout_alignParentStart="true"
        android:layout_marginTop="16dp" />
    <RadioGroup
        android:id="@+id/rg_place"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:layout_below="@+id/textView3"
        android:layout_alignParentLeft="true"
        android:layout_alignParentStart="true">
        <RadioButton
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@string/station"
            android:checked="true"
            android:id="@+id/radioButton1" />
        <RadioButton
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@string/school"
            android:id="@+id/radioButton2" />
        <RadioButton
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@string/always"
            android:id="@+id/radioButton3" />
    </RadioGroup>
    <Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@string/button_send"
        android:id="@+id/button"
        android:layout_below="@+id/rg_place"
        android:layout_centerHorizontal="true" />
</RelativeLayout>

PickUp2
これで、TextViewやRadioGroupの周囲に空白ができます。

 次にRadioGroupの使い方に進みます。PickUp.axmlにあるようにRadioGroupは複数のRadioButtonをグループ化して、択一にするために使います。この例の場合、一番上のラジオボタンのandroid:checkedが”true”になっています。
 RadioGroupを使うPickUpActivityクラスのコードをみていきましょう。
PickUpActivityクラス

   public class PickUpActivity : Activity
    {
        protected override void OnCreate(Bundle savedInstanceState)
        {
            base.OnCreate(savedInstanceState);

            // Create your application here
            SetContentView(Resource.Layout.PickUp);

            var btnSend = FindViewById<Button>(Resource.Id.button);

            btnSend.Click += delegate {
                RadioGroup rgPlace = (RadioGroup)FindViewById(Resource.Id.rg_place);
                int checkedId = rgPlace.CheckedRadioButtonId;
                String strPlace = ((RadioButton)FindViewById(checkedId)).Text;
                EditText edit01 = (EditText)FindViewById(Resource.Id.editText);
                String title = edit01.Text;

                Context context = this;
                Android.Content.Res.Resources res = context.Resources;

                var uri = Android.Net.Uri.Parse("mailto:" + res.GetString(Resource.String.mail_to));

                Intent intent = new Intent(Intent.ActionSendto, uri);
                intent.PutExtra(Intent.ExtraSubject, title);
                intent.PutExtra(Intent.ExtraText, strPlace + "に迎えにきて");
                StartActivity(intent);

            };

        }
    }

 
 btnSendがクリックされたら、選択されているRadioButtonのTextをメール本文に含めるようにしたいのですが、まず選択されているラジオボタンのIDを次のコードで取得します。
int checkedId = rgPlace.CheckedRadioButtonId;
Android SDKをJavaで使っている場合、選択されているボタンのIDはメソッドで取得します。Xamarinの場合はプロパティとして取得できますので、若干お得感があります。
 次にStrings.xmlに登録した文字列を取得する方法ですが、Android.Content.ResのResourcesクラスのGetStringメソッドで取得できます。Resource.String.mail_toはStrings.xmlに登録した送信先のメールアドレスです。
 そして、ActionSendtoを指定してIntentを生成し、PutExtraメソッドでタイトルや本文を付与し、StartActivityメソッドで暗黙的インテント(明示的に遷移先を指定しないインテント)を発行します。
 すると、メールアプリが起動します。
mailapp2
 これで簡単にメールを送るアプリができました。

Visual StudioのXamarinでAndroidアプリを作る(#3) 暗黙的なインテント

暗黙的なインテントとは遷移先のアクティビティを指定しないインテントのこと
以下の例はIntentにurlとそれを見たいのだということを引数で指定して、
StartActivityメソッドを実行する。
button.Click += delegate {
  var uri = Android.Net.Uri.Parse(“http://www.bing.co.jp”);
  Intent intent = new Intent(Intent.ActionView, uri);
  StartActivity(intent);
};
implicit2
実行すると、ブラウザが起動してwww.bing.co.jpが表示される。

Visual StudioのXamarinでAndroidアプリを作る(#2) Activity間のデータ渡し

Activity間でデータを渡す
遷移元ActivityではIntentを生成し、PutExtraメソッドで渡したいデータを積む。
button.Click += delegate {
  var secondActivity = new Intent(this, typeof(SecondActivity));
  secondActivity.PutExtra(“MyData”, “FirstActivityの方から来ました”);
  StartActivity(secondActivity);
};
遷移先Activityではデータ型に応じたGetXXXXXExtraメソッドでデータを取得する。
var txtView1 = FindViewById(Resource.Id.textView1);
txtView1.Text = Intent.GetStringExtra(“MyData”) ?? “Data not available”;

first
遷移元
second
遷移先