技術顧問の増田です。今回はもう少し本格的な Android アプリの制作ということで、RSS を扱います。ニュースや新着情報を取得するために一世風靡した RSS ですが、最近は下火ですよね…というか、誰が使っているのかわかりませんが、まあ、RSS の取得です。
バックナンバー
- 第1回 C#で自作Android アプリを作ろう:出帆準備編
- 第2回 C#で自作Android アプリを作ろう:試験運用編
- 第3回 C#で自作Android アプリを作ろう:時計アプリを作る
- 第4回 C#で自作Android アプリを作ろう:RSSを取得してリスト表示
- 第5回 C#で自作Android アプリを作ろう:Web APIで路線情報を表示
- 第6回 C#で自作Android アプリを作ろう:Twitter APIでファボリストを取得
- 第7回 C#で自作Android アプリを作ろう:簡易アンケートを作ろう
- 第8回 C#で自作Android アプリを作ろう:カメラ機能を使おう
RSSで何を取得するのか?
今回の目的は、RSS を取得すること自体ではなくて、
– インターネットに接続してデータを取ってくる
– 取ってきたデータをリストで表示する
ところになります。この手の応用は広くて、Web APIでデータを取得したり、Twiter のような既存の Web API を使ったりできるようになります。ちなみに、Web API のやり方は次回に解説します。
サンプルコードは、http://github.com/moonmile/sg-xamarin-sample にある sgCheckRss です。適宜ダウンロードして確認してみてください。
いきなり Android でやらない
さて、RSS の取得ですが、プログラム的には HttpClient と XDocument を使います。HttpClient は、HTTP プロトコルでデータを取ってこれるクラスで、ブラウザで URL を指定するように、このクラスを使うと指定した URL からデータを取ってくることができます。ブラウザだとあれこれと画像データとかを持って来るのですが、RSS のように XML 形式のデータだけ取ってくると転送量が減って、非常に高速にデータを取得できます。いちいち、ブラウザで最新情報をチェックするよりも、RSS で最新情報だけを記述した XML をダウンロードするほうが、Web サーバーの負担が減ります。インターネットでの転送量も減るし、社内からアクセスしたときのデータ量も減ります。まあ、そういう目的で RSS がある/あった訳ですが、人的にはどれだけ使われているかわかりません。ただし、マシン間の転送とか、自動収集をするときにはよいでしょう。
で、RSS で取得したデータは XML 形式なので、これを分解します。XML 形式のデータを分解するには、.NET Framework の System.Xml.Linq.XDocument を使うのが便利です。
というわけで、HttpClient と XDocument の2つの実験を始めるわけですが、これをいきなり Android アプリでやろうとしてはダメです。いや、手慣れていて一発で動くようなパターンであればそれでもいいんですが、いったんコンソールアプリで実験コードを組んだほうが良いでしょう。テスト的に、仮のコードを組むというのは重要で、
– コーディング → 実験 のサイクルが素早くなる
– 自然とライブラリ化できる
の2点で有利です。Hyper-V 上で Android が動くとは言え、Visual Studio でビルドして実行、というサイクルはコンソールアプリよりもかなり遅くなります。ならば、コアな部分だけコンソールアプリを使って実験してみましょう。
コンソールアプリで実験
いきなりですが、ざっと書いたのが以下なコードです。これ自体は、一気に書いたのではなくて、一度 XmlSerializer を使ってデシリアライズを試したのですが、うまくいかないので手作業で XDocument を使っています。まあ、これぐらいの XML 形式のデータであれば手作業でやってもあまり変わりません。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
class Program { static void Main(string[] args) { var url = "https://blogs.windows.com/feed/"; // ① var rsscl = new RSSClient(); var task = rsscl.Open(url); // ② task.Wait(); // ③ var msg = task.Result; // ④ Console.WriteLine(msg); // ⑤ var rss = RSS.Load(msg); // ⑥ } } public class RSSClient { public async Task Open(string url) { var cl = new HttpClient(); // ⑦ var res = await cl.GetStringAsync(url); return res; } } |
- Microsoft の RSS を実験用に使わせて貰います。ええ、何処かの図書館にアクセスすると訴えられてしまうので、実験用の RSS は慎重に選びましょう。
- コンソールなアプリでは static な Main メソッドでは async が使えないので、タスクだけ取得します。
- タスク待ちをする定番処理ですね。
- 結果を XML 形式で受け取ります。失敗を考えるのは面倒なので、成功したものとして突き進みます。所詮、実験用のツールですから。
- 取得した XML 形式のデータをコンソールに表示して確認します。
- XML 形式のデータを内部で XDocument を使って分解します。これは、後で再利用しやすいように、Rss.cs ファイルに分離させています。
- HTTP プロトコルで指定した URL を呼び出すのは、HttpClient#GetStringAsync メソッドを使えばokです。
次は、独自に作った RSS クラスです。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 |
public class RSS { public static RSS Load( string xml ) { var st = new StringReader(xml); // ① var doc = XDocument.Load(st); #if false // ② // デシリアライズがうまくいかないので、自前でRSSクラスにつめる var items = new XElement("items"); var channel = doc.Root.Element("channel"); foreach ( var it in channel.Elements()) { if ( it.Name == "item") { items.Add(it); } } channel.Add(items); var sb = new StringBuilder(); var xw = XmlWriter.Create(sb); doc.Save(xw); var sbs = new StringReader(sb.ToString()); var xs = new System.Xml.Serialization.XmlSerializer(typeof(RSS)); var rss = xs.Deserialize(sbs) as RSS; return rss; #endif // リフレクションを使ったほうがシンプルだけど、 // 手間じゃないのでベタに書く var rss = new RSS(); var channel = doc.Root.Element("channel"); // ③ rss.channel = new RSSChannel(); rss.channel.title = channel.Element("title").Value; rss.channel.title = channel.Element("title").Value; rss.channel.language = channel.Element("language").Value; rss.channel.Items = new List(); foreach (var it in channel.Elements()) { if (it.Name == "item") { var item = new RSSItem(); item.title = it.Element("title").Value; item.link = it.Element("link").Value; item.guid = it.Element("guid").Value; item.pubDate = DateTime.Parse( it.Element("pubDate").Value); item.description = it.Element("description").Value; rss.channel.Items.Add(item); } } return rss; } public RSSChannel channel { get; set; } // ④ } public class RSSChannel // ⑤ { public string title { get; set; } public string language { get; set; } public List Items { get; set; } } public class RSSItem // ⑥ { public string title { get; set; } public string link { get; set; } public string guid { get; set; } public DateTime pubDate { get; set; } public string description { get; set; } public override string ToString() // ⑦ { return this.title; } } |
- StringReaderで文字列ストリームにして、XDocument.Load で XML を分解します。Stream を使って XDocument オブジェクトにするのは、定番の処理なので覚えてしまってください。
- 本来は、XmlSerializer を使って一気に XML 形式から C# のクラスにデシリアライズできればよいのですが、残念ながら RSS の仕様上できません。でも、作ろうとした名残の練習用に #if false で残しておきます。この手の情報は後で意外と役に立ちます。
- 分解したルート要素から、最初の channel を取り出します。その後は、子要素が続く item 要素を追加していきます。このあたりの構造がもとの RSS の XML 構造と C# のクラス構造と食い違っていますが、まあ、これでいいです。使いやすいように変換してしまいます。
- 取り出すときのルートになる channel プロパティを定義しておきます。小文字になっているのは、リフレクションを使って自動で取り出したいと思った名残ですね。XML 形式の RSS と名前を統一するにもよいので、ここは小文字のままいきます。
- 作成したクラスは、RSSChannel と RSSItem になります。RSS に完全に準拠する必要はありません。所詮、社内ツールなのですから。プロパティ名や子要素も読み取りやすい形式にしてしまいましょう。
- こっちは RSSItem の定義。
- RSSItem#ToString をオーバーライドしておくと、リスト表示するときに便利です。ここでは、タイトル(title)を表示させています。
これを実行すると、以下のようになります。
特にエラーが出てなけば実験は成功です。会社などからアクセスしてプロキシサーバを通す場合は、適宜 HttpClient クラスのオプションを設定します。通常は、Internet Explorer の設定が引き継がれるので、ブラウザで接続できていれば大丈夫なはずです。
Android 画面を作る
画面構成は簡単で、更新用のボタン(Button)とリスト表示(ListView)があるだけです。ListViewコントロールは、データを表示するための定番のコントロールです。
デザイナでの表示
axmlの記述
1 2 3 |
<button> </button> |
Android からの呼び出し
既に RSS を使ってデータを取り出すクラスはできているので、これをそのまま Android のプロジェクトにコピーします。
おおまかなところは、時計アプリと同じですね。ボタンをタップして ListView に登録するところが Android なのでちょっと見慣れないと思います。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
[Activity(Label = "sgCheckRss", MainLauncher = true, Icon = "@drawable/icon")] public class MainActivity : Activity { TextView textUrl; // ① ListView lv; Button btnGet; 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 this.textUrl = FindViewById(Resource.Id.textView1); // ② this.lv = FindViewById(Resource.Id.listView1); this.btnGet = FindViewById<button>(Resource.Id.button1); btnGet.Click += BtnGet_Click; // ③ } RSS _rss; // ④ /// /// RSSを取得 /// </button> |
/// /// private async void BtnGet_Click(object sender, EventArgs e) { var url = “https://blogs.windows.com/feed/”; // ⑤ var rsscl = new RSSClient(); var xml = await rsscl.Open(url); var rss = RSS.Load(xml); _rss = rss; var arr = new ArrayAdapter(this, // ⑥ Android.Resource.Layout.SimpleListItem1, rss.channel.Items); lv.Adapter = arr; // ⑦ lv.ItemClick += Lv_ItemClick; // ⑧ } private void Lv_ItemClick(object sender, AdapterView.ItemClickEventArgs e) { textUrl.Text = _rss.channel.Items[e.Position].link; // ⑨ } public class RSSClient { public async Task Open(string url) { var cl = new HttpClient(); var res = await cl.GetStringAsync(url); return res; } } }
解説をしましょう。
- Button や ListView コントロールをフィールドとして保持しておきます。
- FindViewById メソッドで読み出し。
- ボタンクリックのイベントを登録します。
- 取得した RSS を保持する変数です。
- RSS を取得する部分は、コンソールアプリで実験したときと同じものです。
- ListView のへ用事ですが、ArrayAdapter クラスを使って登録します。リストになっている rss.channel.Items を登録します。表示するときのデザインは、Android.Resource.Layout.SimpleListItem1 で指定します。
- 作成した ArrayAdapter オブジェクトを ListView コントロールの Adapter プロパティに設定します。ここは定番の処理です。
- リストをタップしたときのイベントを登録します。
- リストをタップしたときに、RSS のリンクの情報を表示させています。
ListView にアイテムを表示する手順は、6,7 になります。ここでは、既存のデザイン(1行だけ表示するもの)を使っていますが、カスタムデザインを作ることも可能です。これは、次回以降で解説をしましょう。
以下に、詳しい情報があります。
Part 3 – Customizing a ListView’s Appearance – Xamarin
https://developer.xamarin.com/guides/android/user_interface/working_with_listviews_and_adapters/part_3_-_customizing_a_listview’s_appearance/
エミュレータで実行する
Hyper-V のエミュレータで実行した結果が次のようになります。
タイトルだけのリストですが、RSS の情報が取れていることがわかります。項目をタップしたときに URL でブラウザを呼び出すると、少し実用的になるでしょう。
まとめ
今更、RSS という訳でもないですが、これでインターネットを通して WEB サーバーから情報が取れるようになりました。RSS の中身は単なる XML 形式のデータなので適当に分解してやれば、ListView などに表示することは簡単です。
次回は、Web API を利用してデータを取ってきます。オープンデータとして公開されている Web API を使ってデータを取得、Android に表示をするところまで作っていきましょう。
駅データ 無料ダウンロード 『駅データ.jp』
http://www.ekidata.jp/
を使っていきます。では、お楽しみに。