技術顧問の増田です。前回は、路線APIを使って、生のWeb APIを使ってデータを取得しましたが、いちいちJSON形式やXML形式のデータを分解していくのは手間が掛かります。
有名どころの Web API は、提供側がライブラリを用意してくれたり、有志の方が便利なライブラリを作ってくれたりするので探してみるとよいです。今回は、CoreTweet という Twitter API を扱うライブラリを使って Android アプリを作ります。お気に入り(現在は「いいね」)のリストを取得するためのツールです。
サンプルコードは、http://github.com/moonmile/sg-xamarin-sample の sgFavo フォルダにあります。
バックナンバー
- 第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 アプリを作ろう:カメラ機能を使おう
CoreTweet とは何か?
CoreTweet https://github.com/CoreTweet/CoreTweet は C#などの.NET言語からTwitter APIをアクセスするためのオープンソースなライブラリです。LINQ を使って検索できたりするのですが、ここでは「いいね」を取ってくるためだけに使います。
nuget.org からもダウンロードができるので、Visual Studio を使ってプロジェクトに手軽に追加することができます。MonoAndroid(いわゆる Xamarin.Android が使うフレームワーク)にも対応しているので、コンソールで動くコードを、そのまま Android 上に持って来ることができます。勿論、Xamarin.iOS でも動きますね。
Twitter APIを利用する
Twitter を使うためにはログインが必要なように、Twitter APIを使うにもログインが必要になります。そこで、OAuth 認証を使うのですが、アプリケーションの API キーの取得などの詳細は、以下を参照してください。
Twitter APIの使い方まとめ
https://syncer.jp/twitter-api-matome
あれこれ頑張ってアプリケーションで使う API KEY と API SECRET を取得して、ログインユーザーから ACCESS TOKEN と ACCESS TOKEN SECRET を作ります。
1 2 3 4 |
const string ApiKey = "API_KEY"; const string ApiSecret = "API_SECRET"; const string AccessToken = "ACCESS_TOKEN"; const string AccessTokenSecret = "ACCESS_TOKEN_SECRET"; |
上のコードでは空欄になっていますが、ここに取得したそれぞれのキー情報が入ります。これを使ってコンソールアプリを作っていきましょう。
コンソールアプリで試してみる
コンソールアプリを作って、ファボの一覧を取得してみましょう。CoreTweet は NuGet で取得してプロジェクトに追加しておきます。
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 |
class Program { static void Main(string[] args) { var prog = new Program(); var t = prog.Go(); t.Wait(); } // ここは消しておくこと!!! const string ApiKey = "API_KEY"; // ① const string ApiSecret = "API_SECRET"; const string AccessToken = "ACCESS_TOKEN"; const string AccessTokenSecret = "ACCESS_TOKEN_SECRET"; public async Task Go() { var tokens = CoreTweet.Tokens.Create(ApiKey, ApiSecret, AccessToken, AccessTokenSecret); // ② var favs = await tokens.Favorites.ListAsync(); // ③ foreach ( var it in favs ) // ④ { Console.WriteLine("---"); Console.WriteLine($"Id: {it.Id}"); Console.WriteLine($"Name: {it.User.ScreenName} {it.User.Name}"); Console.WriteLine(it.Text); } return; } } |
- アプリケーションキー等を描き込みます。
- アクセストークなどを指定して、CoreTweet.Tokens.Create メソッドを呼び出します。
- Favorites#ListAsync メソッドでお気に入りのリストを取得します。最大で20件取得できます。続けて取得するときは、next key を使うのですが、今回は20件だけ使います。
- ファボのリストをコンソールに表示します。
結果
実行すると、きちんとデータが取れることが分かります。
Androidで取得してみる
コンソールで動作させたものを、Android でも動かしてみましょう。
デザイナ
デザイナには、ボタンと ListView を貼り付けます。
コード
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 |
[Activity(Label = "sgFavo", MainLauncher = true, Icon = "@drawable/icon")] public class MainActivity : Activity { // ここは消しておくこと!!! const string ApiKey = "API_KEY"; // ① const string ApiSecret = "API_SECRET"; const string AccessToken = "ACCESS_TOKEN"; const string AccessTokenSecret = "ACCESS_TOKEN_SECRET"; TextView text1; ListView lv1; Button button1; 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 text1 = FindViewById(Resource.Id.text1); // ② lv1 = FindViewById(Resource.Id.lv1); button1 = FindViewById<button>(Resource.Id.button1); button1.Click += Button1_Click; // ③ } /// /// 更新ボタン /// </button> |
ほぼ、コンソールアプリのときと同じですが、ListView に表示するときのちょっとだけ工夫しています。
- 自作ツールなので、アプリキーなどは直書きで。
- 各種コントロールの名前を取得
- ボタンをタップしたときに、Twitter APIにアクセスする
- CoreTweet の呼び出しは、コンソールアプリと同じです。
- ListView に表示するために List コレクションに直します。ツイートの中身は Status クラスに入っているので、そのまま使います。
- 通常の ArrayAdapter を使うと、ToString メソッドをオーバーライドしないといけないのと、1行の文字列しか使えないので、独自に StatusAdapter クラスを作ります。
- 独自の StatusAdapter クラスのオブジェクトを Adapter プロパティに設定します。
- ファボの数をテキストに表示させます。
ListView の表示は、BaseAdapter クラスを継承した、カスタムのアダプターを作ると、項目となるクラス(ここでは、CoreTweet.Statusクラス)と、表示の結び付けができます。MVVM パターンのバインドみたいなものですね。
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 |
public class StatusAdapter : BaseAdapter // ① { Activity _activity; // ② List _items; // ③ public StatusAdapter( Activity act, List items ) // ④ { _activity = act; _items = items; } public override Status this[int position] // ⑤ { get { return _items[position]; } } public override int Count // ⑥ { get { return _items.Count; } } public override long GetItemId(int position) // ⑦ { return _items[position].Id; } public override View GetView(int position, View convertView, ViewGroup parent) // ⑧ { var view = convertView; if ( view == null ) // ⑨ { view = _activity.LayoutInflater.Inflate(Android.Resource.Layout.SimpleListItem2, null); } var it = _items[position]; // ⑩ view.FindViewById(Android.Resource.Id.Text1).Text = it.User.Name; // ⑪ view.FindViewById(Android.Resource.Id.Text2).Text = it.Text; return view; } } |
カスタムのアダプタは、BaseAdapterを継承した定番の処理になります。
- BaseAdapterクラスを継承します。
- Activity を保持します。通常は、MainActivity が渡されるはずです。
- 項目を List コレクションで保持しておきます。
- コンストラクタです。
- インデックスで、項目を返す定番
- 項目数を返す定番
- IDを返す定番です。ここでは Twitte の ID を返しています。これだと正確にはユニークにならないのですが…まあ、一応。ユニークでさえあればよいので、position を返しても構いません。
- 表示されるときに呼び出されます。ここが、表示の肝です。
- 初回は、convertView が null なので、レイアウトを設定します。ここでは、既存の Android.Resource.Layout.SimpleListItem2 を設定しています。2行使える項目のレイアウトです。
- position で指定項目を取り出して、
- テキストに表示します。リソースは、Android.Resource.Id.Text1 のようにあらかじめ指定された ID があります。
ListView の項目は、Windows 10 のスタート画面の作り方と似ています。
実行
実行すると、うまくスクリーン名(User.Name)と、ツイートの内容(Text)が表示されていることがわかります。
ListViewをカスタムする
ListView の項目をもう少しツイッターっぽく変えてみましょう。既存のレイアウトだけでは無理な場合は、カスタムの axml を作って、ListView の項目レイアウトにすることができます。
CustomRow.axml を追加する
ソリューションエクスプローラーで、sgFavo プロジェクトに axml ファイルを追加します。
CustomRow.axml のデザイン
デザインは、こんな感じに作っています…が、デザイナで全てあれこれやるのは大変なので、直接 axml ファイルを編集します。
CustomRow.axml
1 |
コード
MainActivity クラスは、既存テンプレートを作ったときと同じものを使えます。ここでは、StatusAdapter クラスの GetView メソッドの内容を書き替えます。
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 |
public class StatusAdapter : BaseAdapter { Activity _activity; List _items; public StatusAdapter(Activity act, List items) { _activity = act; _items = items; } public override Status this[int position] { get { return _items[position]; } } public override int Count { get { return _items.Count; } } public override long GetItemId(int position) { return _items[position].Id; } public override View GetView(int position, View convertView, ViewGroup parent) { var view = convertView; if (view == null) { view = _activity.LayoutInflater.Inflate(Resource.Layout.CustomRow, null); } var it = _items[position]; view.FindViewById(Resource.Id.Text1).Text = it.User.Name; // ① view.FindViewById(Resource.Id.Text2).Text = it.Text; // 画像は非同期で表示する var t = getImage(it.User.ProfileImageUrl); // ② t.ContinueWith((e) => { // ③ view.FindViewById(Resource.Id.Image).SetImageBitmap(e.Result); }); return view; } private async Task getImage(string url) // ④ { var hc = new HttpClient(); using (var st = await hc.GetStreamAsync(url)) // ⑤ { var bmp = await Android.Graphics.BitmapFactory.DecodeStreamAsync(st); return bmp; } } } |
- CustomRow.axml で記述した TextView に User.Name と Text を割り当てます。
- ツイートした人のアイコンを表示させます。User.ProfileImageUrl に画像のURLがあります。直接 async/await は使えないので、
- ContinueWith メソッドで、画像データの取得の終了時に表示されるようにします。
- 非同期で、ツイッターのアイコンを取得する関数です。
- 画像データをダウンロードして、ImageView に表示すするための Bitmap データを作ります。これは Windows の Bitmap と違う(ハズ)なので、適宜 Stream 経由で扱うとよいでしょう。
プロフィールのアイコンを、非同期で読み込むところがミソですよね。
結果
プロフィールアイコンの読み込みがちょっと遅い(リストを動かさないと更新されない?)のが難点ですが、ひとまず、画像までも含めて Twitter のファボを取ってくることができます。
まとめ
CoreTweet のようなライブラリを使うと Web API が簡単にアクセスできるようになります。開発規模にもよるのですが、機能が豊富な Web API の場合は利用するライブラリを作る、単機能でアクセスできる場合は Web API を直接使う、という使い分けをするとよいでしょう。
さて、ここまで Web API はデータの取り出しだけやってきましたが、次回はデータの登録をするための Web API を呼び出してみたいと思います。アンケートに答える Android アプリを使って、サーバーにアップロードする仕組みを解説します。
次回も、お楽しみに。