SHOEISHA iD

※旧SEメンバーシップ会員の方は、同じ登録情報(メールアドレス&パスワード)でログインいただけます

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

Windowsで進化するマルチプラットフォームGUI開発

マルチプラットフォームなGUI「Avalonia UI」で予測気温表示アプリを作ろう

Windowsで進化するマルチプラットフォームGUI開発 第6回

  • X ポスト
  • このエントリーをはてなブックマークに追加

予測気温表示アプリ──JSON処理とAPIの呼び出し

予測気温をWebAPIから取得する

 Open-Meteoで公開されているWebAPIを利用すると、さまざまな気象情報が入手可能です。しかもこのAPIは特別な認証などは必要ないため、とても手軽に活用できます。

 今回は、次のURLで参照できる予測気温を利用することにします。任意の緯度経度の予測気温をJSON文字列で返すAPIです。

https://api.open-meteo.com/v1/forecast?latitude={緯度}&longitude={経度}&hourly=temperature_2m

 JSON文字列は、次のようなフォーマットになっています。

{
    latitude: 34.6,
    longitude: 135.5,
    ...
    hourly: {
        time: [
            "2022-12-30T00:00",
            ...
            "2023-01-05T23:00"
        ],
        temperature_2m: [
            5.8,
            ...
            -1.1
        ]
    }
}

 今回は、時系列のデータのみを参照するので、hourly以下のデータを利用します。

.NET標準のJSON処理

 .NETでJSON文字列を処理するにはいくつかの方法がありますが、今回は標準のJsonSerializerクラスを利用することにします。JsonSerializer.Deserializeメソッドを使えば、JSON文字列を解析してC#のオブジェクトに変換できます。

 気温の時系列データは、次のようなクラス定義としました。

[リスト6]Temp.cs
// 日時と気温のリスト
public class Hourly
{
    public List<DateTime>? time { get; set; }           // 日時
    public List<float>? temperature_2m { get; set; }    // 気温
}
// 時刻毎の気温データ
public class Temp
{
    public Hourly? hourly { get; set; }
}

 Tempクラスは、JSON文字列の時系列データをそのままモデルにしたものです。時系列以外のデータは使用しないので、Tempクラス以外の定義は不要です。このTempクラスを使って、Deserializeメソッドで解析するには、次のように指定します。

var jsonData = JsonSerializer.Deserialize<Temp>(予測気温のjson文字列);

 JSON文字列とTempクラスのプロパティが合致するものだけ、オブジェクトとして変換されます。つまり変数jsonDataには、JSON文字列を変換したTempオブジェクトがセットされることになります。

.NET標準のHTTPクライアントを利用する

 次に、JSON文字列を取得するWebAPIの呼び出し処理を追加しましょう。これは、.NETのHttpClientクラスを使えば簡単です。HttpClientクラスはstaticとしてインスタンスを生成し、各処理で共有するようにします。

 WebAPIの取得処理は、次のようにOpenMeteoクラスのGetTempAsyncメソッドとして定義しました。

[リスト7]Temp.cs
public class OpenMeteo
{
    static readonly HttpClient client = new();

    // 予測気温を取得する
    public static async Task<string> GetTempAsync(CapitalPoint cp)
    {
        var tmp = new StringBuilder();

        try
        {
            // Open Meteo APIから、指定の緯度経度地点の予測気温を取得する
            var result =
                await client.GetAsync($"https://api.open-meteo.com/v1/forecast?latitude={cp.Lat}&longitude={cp.Lon}&hourly=temperature_2m");

            var json = await result.Content.ReadAsStringAsync();

            // 結果のJSON文字列を解析する
            var jsonData = JsonSerializer.Deserialize<Temp>(json);

            ~中略~
        }
        return tmp.ToString();
    }
}

 HttpClientクラスのGetAsyncメソッドで、HTTP通信でGET処理を行います。ここでは、指定の緯度経度を、メソッドのパラメータ、CapitalPointを参照しています。HTTPのレスポンスは、非同期のReadAsStringAsyncメソッドで受けとります。

LINQを用いて現在時刻以降を取得する

 APIの予測データはデフォルトでは7日先までのデータとなり、少し長すぎるので、今回は現在時刻を含む1日(25時間)分を切り出す形にしてみました(APIのパラメータで調整も可能)。

[リスト8]Temp.cs
~中略~
public static async Task<string> GetTempAsync(CapitalPoint cp)
{
~中略~
    // 結果のJSON文字列を解析する
    var jsonData = JsonSerializer.Deserialize<Temp>(json);

    // 現在のUTC日時を求める(1)
    DateTime now = DateTime.UtcNow;
    now = new DateTime(now.Year, now.Month, now.Day, now.Hour, 0, 0);

    // 現在時以降の25時間分の気温を抽出し、文字列にする(2)
    var temps = jsonData?.hourly?.time?.Select((value, index) => new { value, index }).Where((tmp => now.CompareTo(tmp.value) <= 0)).Take(25);
    if (temps != null)
    {
        foreach (var item in temps)
        {
            var local = TimeZoneInfo.ConvertTimeFromUtc(item.value, TimeZoneInfo.FindSystemTimeZoneById("Tokyo Standard Time")); // JSTに変換(3)
            tmp.Append(local.ToString("yyyy年MM月dd日(ddd) HH時"));
            tmp.Append("  ");
            tmp.Append(string.Format("{0:f1}", jsonData?.hourly?.temperature_2m?[item.index])); // 日時のインデックスを用いて気温を参照する(4)
            tmp.Append(" ℃\n");
        }
    }
~中略~
}

 取得したデータ内容で、注意点は2つあります。1つ目は、時刻のタイムゾーンがGMT(UTC)になっていることです。2つ目は、日時と気温のデータがペアではなく、それぞれのリストになっていることです。

 25時間分を抽出する方法はいくつかありますが、今回はLINQを用いて現在時刻から25時間分のデータを取得しました(2)。

 時刻に関しては、現在のUTC時刻を元にデータを特定し(1)、表示時にJST(日本標準時)に変換するようにしました(3)。また、日時のリストのインデックス(何番目か)から気温のデータを参照するようにしています(4)。

クリック後の画面表示を追加する

 作成したGetTempAsyncメソッドは、結果を文字列として返しています。この文字列をビューモデルのResultプロパティに設定するようにします。なお、GetTempAsyncメソッドは非同期メソッドのため、呼び出し時にawaitをつけ、OnClickメソッドにもasyncをつけています。

[リスト9]MainWindowViewModel.cs
private async void OnClick()
{
    if (Capitalpoint.Name != "") {
        Result = "お待ちください";
        Result = await OpenMeteo.GetTempAsync(Capitalpoint);
    }
    else
    {
        Result = "県庁所在地を選択してください ";
    }
}
気温表示
気温表示

最後に

 最後に、Avalonia UIを紹介しました。.NET環境でのマルチプラットフォーム向けフレームワークでは、連載では紹介できなかった、Uno Platformもあります。また、.NET環境以外でも、Flutterなど魅力的なフレームワークがあります。

 このようなマルチプラットフォーム向けフレームワークは、もちろんネイティブアプリのようにかゆい所に手が届くというわけではありません。ただし、マルチプラットフォーム向け開発のハードルはずいぶんと低くなったのは間違いありません。

参考文献

この記事は参考になりましたか?

  • X ポスト
  • このエントリーをはてなブックマークに追加
Windowsで進化するマルチプラットフォームGUI開発連載記事一覧

もっと読む

この記事の著者

WINGSプロジェクト 高江 賢(タカエ ケン)

WINGSプロジェクトについて>有限会社 WINGSプロジェクトが運営する、テクニカル執筆コミュニティ(代表 山田祥寛)。主にWeb開発分野の書籍/記事執筆、翻訳、講演等を幅広く手がける。2018年11月時点での登録メンバは55名で、現在も執筆メンバを募集中。興味のある方は、どしどし応募頂きたい。著書記事多数。 RSS X: @WingsPro_info(公式)、@WingsPro_info/wings(メンバーリスト) Facebook

※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です

山田 祥寛(ヤマダ ヨシヒロ)

静岡県榛原町生まれ。一橋大学経済学部卒業後、NECにてシステム企画業務に携わるが、2003年4月に念願かなってフリーライターに転身。Microsoft MVP for Visual Studio and Development Technologies。執筆コミュニティ「WINGSプロジェクト」代表。主な著書に「独習シリーズ(Java・C#・Python・PHP・Ruby・JSP&サーブレットなど)」「速習シリーズ(ASP.NET Core・Vue.js・React・TypeScript・ECMAScript、Laravelなど)」「改訂3版JavaScript本格入門」「これからはじめるReact実践入門」「はじめてのAndroidアプリ開発 Kotlin編 」他、著書多数

※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です

この記事は参考になりましたか?

この記事をシェア

  • X ポスト
  • このエントリーをはてなブックマークに追加
CodeZine(コードジン)
https://codezine.jp/article/detail/17316 2023/03/01 11:00

おすすめ

アクセスランキング

アクセスランキング

イベント

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

新規会員登録無料のご案内

  • ・全ての過去記事が閲覧できます
  • ・会員限定メルマガを受信できます

メールバックナンバー

アクセスランキング

アクセスランキング