前回のポストで HelloWorld を見てみましたが、次は Activity をもう一つ作って画面遷移してみます。
メニュー → 新規 → ファイル と選択するとこんなダイアログが出るので Activity クラス名を入力して決定します。
すると NextActivity.cs
ができます。
//NextActivity.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Android.App;
using Android.Content;
using Android.OS;
using Android.Runtime;
using Android.Views;
using Android.Widget;
namespace HelloXamarinAndroid
{
[Activity (Label = "NextActivity")]
public class NextActivity : Activity
{
protected override void OnCreate(Bundle bundle)
{
base.OnCreate(bundle);
// Create your application here
}
}
}
作ってくれるのはここまでです。レイアウト用の Next.axml やリソースファイルは別途作成する必要があります。今回は必要ないのでスルーで。
Android本家だと今はウィザードで Javaソース、レイアウトXML、リソースファイルまで作ってくれてしかも AndroidManifest.xml にも書いてくれちゃいます、便利な世の中になりましたね。
ちなみに Xamarin.Android では AndroidManifest.xml への登録は必要ありません。
画面遷移は本家と同じく Intent を使います。
//MainActivity.cs
button.Click += (sender, e) =>
{
// Goto NextActivity
var intent = new Intent(this, typeof(NextActivity));
this.StartActivity(intent);
};
本家だと NextActivity.class
としていたところは typeof(NextActivity)
になってますね。
さて、画面遷移時にデータを渡すという、よくある処理をやってみたいと思います。
データは Card
というクラスにします。
//Card.cs
namespace HelloXamarinAndroid
{
class Card
{
public string Name { get; set; }
public string Phone { get; set; }
}
}
C# なので、プロパティ作るのも楽でいいですね。getter/setter なんてアホらしくて…。 この Card クラスのインスタンスを、MainActivity から NextActivity に渡したいと思います。
Android では、Activity とか Service をまたぐオブジェクトは Percelable インターフェースを実装しなければならないのでした。
「じゃあ Xamarin では?」「IParcelable でしょ」というわけで IParcelable
インターフェースを実装するわけですが、こいつが IDisposable
や IJavaObject
を継承していてこれらも実装させられます。
なんか違う・・・とあきらめてググったところ、こんなんでました。
以降、これに習うことにします。
いきなりこれを忘れて、謎のビルドエラーと10分程格闘しました(汗)
ソリューションツリーの参照の右クリックメニューからアセンブリ参照ダイアログが出るので、Mono.Android.Export
を見つけて追加します。
Free 版はプログラムのサイズに制限があるのですが、アセンブリを追加することでその制限を超えてしまうものと思われます。
Card クラスを、IParcelable
を実装するのと共に Java.Lang.Object
から派生させます。
あーそういうことですか。
//Card.cs
namespace HelloXamarinAndroid
{
class Card : Java.Lang.Object, IParcelable
{
public string Name { get; set; }
public string Phone { get; set; }
public Card(string name, string phone)
{
this.Name = name;
this.Phone = phone;
}
#region IParcelable implementation
public int DescribeContents()
{
return 0;
}
public void WriteToParcel(Parcel dest, ParcelableWriteFlags flags)
{
dest.WriteString(this.Name);
dest.WriteString(this.Phone);
}
#endregion
}
}
まだ何か足りません。あ、CREATOR だ。
本家では public static final Parcelable.Creator<MyParcelable> CREATOR = …
な感じで用意していましたが、Xamarin.Android では次の2点が異なります。
IParcelableCreator
インターフェースを実装したクラスを用意する。IParcelableCreator
を返す static メソッドを用意し、[ExportField("CREATOR")]
属性を付ける。これらを実装すると、 Card クラスはこうなります。
//Card.cs
using Java.Interop;
namespace HelloXamarinAndroid
{
class Card : Java.Lang.Object, IParcelable
{
public string Name { get; set; }
public string Phone { get; set; }
public Card(string name, string phone)
{
this.Name = name;
this.Phone = phone;
}
#region IParcelable implementation
public int DescribeContents()
{
return 0;
}
public void WriteToParcel(Parcel dest, ParcelableWriteFlags flags)
{
dest.WriteString(this.Name);
dest.WriteString(this.Phone);
}
#endregion
[ExportField("CREATOR")]
public static IParcelableCreator GetCreator()
{
return new MyParcelableCreator();
}
// Parcelable.Creator の代わり
class MyParcelableCreator : Java.Lang.Object, IParcelableCreator
{
#region IParcelableCreator implementation
Java.Lang.Object IParcelableCreator.CreateFromParcel(Parcel source)
{
var name = source.ReadString();
var phone = source.ReadString();
return new Card(name, phone);
}
Java.Lang.Object[] IParcelableCreator.NewArray(int size)
{
return new Java.Lang.Object[size];
}
#endregion
}
}
}
これでやっと、「受け渡し可能な」クラスが作成できました。
まず渡す方。Intent に詰めます。
//MainActivity.cs
button.Click += (sender, e) =>
{
var card = new Card("amay", "987-654-3321");
// Goto NextActivity
var intent = new Intent(this, typeof(NextActivity));
intent.PutExtra("card", card); // intent に Card を詰める
this.StartActivity(intent);
};
次に取り出す方。Intent から取り出します。
//NextActivity.cs
namespace HelloXamarinAndroid
{
[Activity (Label = "NextActivity")]
public class NextActivity : Activity
{
protected override void OnCreate(Bundle bundle)
{
base.OnCreate(bundle);
// Create your application here
var card = this.Intent.GetParcelableExtra("card") as Card;
// Show toast
Toast.MakeText(this,
String.Format("name:{0}, phone:{1}", card.Name, card.Phone),
ToastLength.Long).Show();
}
}
}
〜 as Type
句は型が違っていたら null にしてくれる書き方です。
あと Toast。.Show()
は忘れずに。
これで実装完了。動かしてみます。
以上、受け渡し可能なクラスの実装方法でした。