かずきのBlog@hatena

日本マイクロソフトに勤めています。XAML + C#の組み合わせをメインに、たまにASP.NETやJavaなどの.NET系以外のことも書いています。掲載内容は個人の見解であり、所属する企業を代表するものではありません。

Xamarin.AndroidでHello worldというかひな形プログラムを見てみる

長らくReactivePropertyの検証用にしか使ってなかったXamarinですが、Genymotionを入れて現実的な速さでAndroidのエミュレータが動くようになったので、ちょいと試してみようと思います。

Xamarinを入れるとVisual StudioでAndroidのプロジェクトが作れます。

f:id:okazuki:20140723201002p:plain

新規作成すると、以下のような構造のプロジェクトが作られます。

f:id:okazuki:20140723201224p:plain

とりあえず、今回使いファイルだけ手早く説明すると以下のようになっています。 - Main.axml - メイン画面の見た目の定義 - Strings.xml - 文字列リソースを定義するXML - MainActivity.cs - Main.axmlを表示するためのアクティビティ

Strings.xml

文字列をstringタグで定義していきます。ここで定義した文字列はaxml内で、@string/nameで使うことができます。例えば、以下のファイルでApp6の文字列を使う場合は@string/ApplicationNameになります。

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <string name="Hello">Hello World, Click Me!</string>
    <string name="ApplicationName">App6</string>
</resources>

コードから文字列を取得する場合は、Activityを継承したクラスなどで以下のように記述すると文字列をとってこれます。

this.GetString(Resource.String.ApplicationName)

Resourceクラスは、文字列リソースや画面定義などから必要な定数が自動生成されるクラスになります。Strings.xmlの内容はResource.Stringの下に定義されます。

Main.axml/MainActivity.cs

このプログラムではMain.axmlは、MainActivityで表示されるようになっています。これは自動で紐づけられるわけではなくて、MainActivityクラスのOnCreateメソッドで明示的にコードで書かれています。

OnCreateは、Androidの画面を表すActivityが作られたときに呼ばれるクラスで、ここでActivityの初期化処理なんかをやるみたいです。OnCreateで、以下のようにResourceクラスを使って、自分自身の表示コンテンツにMain.axmlを指定しています。

protected override void OnCreate(Bundle bundle)
{
    base.OnCreate(bundle);

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

    // ...省略...
}

axmlファイルは、Resource.Layoutの下にaxmlファイル名で定数が定義されます。SetContentViewのメソッドに、この定数を渡すことで、画面に表示させることが出来ます。

Main.axmlは、ちょっとまだよくわかりませんが、ボタンが置いてある風なことは理解できます。

<?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/MyButton"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:text="@string/Hello" />
</LinearLayout>

Buttonに定義されているandroid:id属性の@+id/MyButtonを使ってプログラムからボタンをひっぱってくることが出来るようになっています。@+id/MyButtonのように書くと、Resource.Idの下にMyButtonという定数が生成されるようになります。この定数を使ってActivityのFindViewByIdメソッドを使ってコントロールのインスタンスを取得できます。OnCreateの中では、以下のようにしてボタンのインスタンスを取得しています。

// Get our button from the layout resource,
// and attach an event to it
Button button = FindViewById<Button>(Resource.Id.MyButton);

個人的にはここはvar使いたいですね。なので以下のようになおしました。

// Get our button from the layout resource,
// and attach an event to it
var button = FindViewById<Button>(Resource.Id.MyButton);

ボタンを取得したら、あとはクリックの処理なんかを付け足したり好きなようにできます。初期状態では、クリックしたらボタンのテキストを書き換える処理が入っています。

button.Click += delegate { button.Text = string.Format("{0} clicks!", count++); };

個人的にdelegate使ってるのが気に入らないので以下のようにラムダ式に置き換えました。

button.Click += (_, __) => button.Text = string.Format("{0} clicks!", count++);

あと文字列リソースがあるにも関わらず、文字列をハードコーディングしているのが気に入らないのでStrings.xmlに以下の定義を追加します。

<?xml version="1.0" encoding="utf-8"?>
<resources>
  <string name="Hello">Hello World, Click Me!</string>
  <string name="ApplicationName">App6</string>
  <string name="ClickMessage">{0} clicks!</string>
</resources>

そして、Clickイベントハンドラの中身を以下のようにします。

button.Click += (_, __) => button.Text = string.Format(this.GetString(Resource.String.ClickMessage), count++);

これでちょっと満足。GetStringメソッドには、書式付文字列に値を埋め込むオーバーライドがあるので、もっとすっきりかけるように感じますが、とりあえず深追いはやめておくことにします。(java.lang.Objectとかちょっと怖いので後回し)

実行して動作確認

実行すると、以下のようにボタンがあるだけの画面が出てきます。

f:id:okazuki:20140723203435p:plain

ボタンをクリックするとボタンのテキストが更新されます。

f:id:okazuki:20140723203543p:plain

まとめ

Androidというより、C#の書き方が気に入らなかったですね。