redev

technical miscellaneous memorandum

Yahoo気象情報APIでJSONデータを取得する

ネットワーク通信 - mixi-inc/AndroidTraining
の実習と課題3でYoutubeAPIが使えないので他のAPIを使用することにした。

APIはこちら
気象情報API - Yahoo!デベロッパーネットワーク

  • 取得したJSONデータ
{
    "ResultInfo":{
        "Count":1,
        "Total":1,
        "Start":1,
        "Status":200,
        "Latency":0.003336,
        "Description":"",
        "Copyright":"(C) Yahoo Japan Corporation."
    },
    "Feature":[
        {
            "Id":"201701130415_xxx.21671_yy.692798",
            "Name":"地点(xxx.21671,yy.692798)の2017年01月13日 04時15分から60分間の天気情報",
            "Geometry":{
                "Type":"point",
                "Coordinates":"xxx.21671,yy.692798"
            },
            "Property":{
                "WeatherAreaCode":5510,
                "WeatherList":{
                    "Weather":[
                        {
                            "Type":"observation",
                            "Date":"201701130415",
                            "Rainfall":0.00
                        },{
                            "Type":"forecast",
                            "Date":"201701130425",
                            "Rainfall":4.13
                        },{
                            "Type":"forecast",
                            "Date":"201701130435",
                            "Rainfall":0.00
                        },{
                            "Type":"forecast",
                            "Date":"201701130445",
                            "Rainfall":3.38
                        },{
                            "Type":"forecast",
                            "Date":"201701130455",
                            "Rainfall":0.00
                        },{
                            "Type":"forecast",
                            "Date":"201701130505",
                            "Rainfall":0.85
                        },{
                            "Type":"forecast",
                            "Date":"201701130515",
                            "Rainfall":0.00
                        }
                    ]
                }
            }
        }
    ]
}
  • AsyncTaskLoaderをextendしたローダ

アプリケーションIDの箇所はXXXでマスクしてある

package jp.mixi.assignment.network.networkAssignment;

import android.content.Context;
import android.support.v4.content.AsyncTaskLoader;

import org.json.JSONException;
import org.json.JSONObject;

import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;

public class MyAsyncTaskLoader extends AsyncTaskLoader<JSONObject> {
    private JSONObject cache;

    public MyAsyncTaskLoader (Context context) {
        super(context);
    }

    //非同期処理の中身
    @Override
    public JSONObject loadInBackground() {
        JSONObject json = null;
        try{
            URL url = new URL("http://weather.olp.yahooapis.jp/v1/place?coordinates=xxx.2167111,yy.69279806&output=json&appid=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX");
            HttpURLConnection con = null;
            try {
                con = (HttpURLConnection)url.openConnection();
                con.connect();
                InputStream is = con.getInputStream();

                StringBuilder src = new StringBuilder();
                while(true) {
                    byte[] line = new byte[1024];
                    int size = is.read(line);
                    if (size <= 0)
                        break;
                    src.append(new String(line, "utf-8"));
                }
                json = new JSONObject(src.toString());
            } catch (IOException | JSONException e) {
                e.printStackTrace();
            } finally {
                con.disconnect();
            }
        } catch (MalformedURLException e) {
            e.printStackTrace();
        }
        return json;
    }

    @Override
    public void deliverResult(JSONObject data) {
        if(isReset()) {
            if(cache != null) {
                cache = null; //キャッシュデータがある場合は削除してメモリから破棄可能にする
            }
            return;
        }

        //得られたデータをキャッシュする
        cache = data;

        //ローダが開始されている場合、親にデータが得られたことを通知する
        if(isStarted()) {
            super.deliverResult(data);
        }
    }

    @Override
    protected void onStartLoading() {
        //キャッシュがある場合はそちらを返す
        if(cache != null) {
            deliverResult(cache);
            return;
        }

        //データソースに変更があったり、キャッシュデータが無い場合はloadInBackground()に行くようにする
        if(takeContentChanged() || cache == null) {
            forceLoad();
        }
    }

    //ローダの非同期処理がストップするときのコールバック
    @Override
    protected void onStopLoading() {
        cancelLoad();
        super.onStopLoading();
    }

    //ローダがリセットされるときのコールバック
    @Override
    protected void onReset() {
        onStopLoading();
        super.onReset();
    }
}
  • Activity

ローダを呼び出し、結果(JSONObject)をパースする。
ListViewに貼り付けても良いのだが、取り敢えずTextViewにそのままべたっと貼った。

package jp.mixi.assignment.network.networkAssignment;

import android.os.Build;
import android.os.Bundle;
import android.os.StrictMode;
import android.support.v4.app.FragmentActivity;
import android.support.v4.app.LoaderManager;
import android.support.v4.content.Loader;
import android.view.Menu;
import android.widget.TextView;
import android.widget.Toast;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

public class MainActivity extends FragmentActivity implements LoaderManager.LoaderCallbacks<JSONObject> {

    @Override
    protected void onCreate(Bundle savedInstanceState) {

        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB) {
            StrictMode.setThreadPolicy(
                    new StrictMode.ThreadPolicy.Builder()
                    .detectNetwork()
                    .penaltyDeath()
                    .build());
        }
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        LoaderManager manager = getSupportLoaderManager();
        Bundle argsForLoader = new Bundle();
        manager.initLoader(0, argsForLoader, MainActivity.this);
    }

    @Override
    public Loader<JSONObject> onCreateLoader(int id, Bundle args) {
        switch (id) {
            case 0:
                return new MyAsyncTaskLoader(this);
            default:
                return null;
        }
    }

    @Override
    public void onLoadFinished(Loader<JSONObject> loader, JSONObject result) {
        String name = "";
        String weather = "";
        String[] type = new String[7];
        String[] date = new String[7];
        String[] rain = new String[7];
        try {
            JSONArray feature = result.getJSONArray("Feature");
            name = feature.getJSONObject(0).getString("Name");
            JSONArray jWeather = feature.getJSONObject(0).getJSONObject("Property").getJSONObject("WeatherList").getJSONArray("Weather");
            for (int i=0; i<7; i++) {
                type[i] = jWeather.getJSONObject(i).getString("Type");
                date[i] = jWeather.getJSONObject(i).getString("Date");
                rain[i] = jWeather.getJSONObject(i).getString("Rainfall");
            }
        } catch (JSONException e) {
            e.printStackTrace();
        }
        for (int i=0; i<7; i++) {
            date[i] = date[i].substring(0, 4) + "年" + date[i].substring(4, 6) + "月" + date[i].substring(6, 8) + "日" +
                    date[i].substring(8, 10) + "時" + date[i].substring(10, 12) + "分";
            rain[i] += "mm/h";
            weather += ((0 == i) ? "観測" : "予報") + "\n"
                    + date[i] + rain[i] + "\n";
        }
        Toast.makeText(this, name, Toast.LENGTH_LONG).show();
        TextView tv = (TextView)findViewById(R.id.title);
        tv.setText(weather);
    }

    @Override
    public void onLoaderReset(Loader<JSONObject> loader) {}

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.main, menu);
        return true;
    }

}