65665


初投稿です。Androidアプリ開発を勉強して2週間のひよこです。お手柔らかにお願いします。

### この質問は記述が長すぎるため、version2があります。そちらで本件は解決しております！以下を参照ください。↓

<https://ja.stackoverflow.com/a/65678/34348>

# 目的

1.Codezineの記事を参考に、APIとJsonフォーマットを用いたアプリを開発する手順を知る。  
2.非同期処理を行うための手順を知る。  
3.Jsonフォーマットで取得できた情報を画面に反映する。

※タイトルは、都市名。詳細は、天気の情報。  
※参考記事: [Androidアプリでの非同期処理とWeb API連携 -
CodeZine](https://codezine.jp/article/detail/9746)

# 開発環境

MacOS Catalina10.15.2  
Android Studio 3.4.1  
Build #AI-183.6156.11.34.5522156.built on May 2, 2019  
JRE: 1.8.0_152-release-1343-b01 x86_64  
JVM: OpenJDK 64-bit Server VM by JetBrains s.r.o  
選択言語:Java  
Activity数:2つ(MainActivity.java,WeatherInfoActivity.java)

# 問題点

livedoor社のAPIを用いて、取得したいデータを取得することができない。  
API詳細(<http://weather.livedoor.com/weather_hacks/webservice>)

* * *

# ソースコード

### AndroidManifest.xml

[code]

    <?xml version="1.0" encoding="utf-8"?>
    <manifest xmlns:android="http://schemas.android.com/apk/res/android"
        package="com.example.api_example">
    
        <uses-permission android:name="android.permission.INTERNET"/>
        <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
    
        <application
            android:allowBackup="true"
            android:icon="@mipmap/ic_launcher"
            android:label="@string/app_name"
            android:roundIcon="@mipmap/ic_launcher_round"
            android:supportsRtl="true"
            android:theme="@style/AppTheme">
            <activity android:name=".WeatherInfoActivity"></activity>
            <activity android:name=".MainActivity">
                <intent-filter>
                    <action android:name="android.intent.action.MAIN" />
    
                    <category android:name="android.intent.category.LAUNCHER" />
                </intent-filter>
            </activity>
        </application>
    
    </manifest>
    
[/code]

### MainActivity.java

[code]

    package com.example.api_example;
    
    import androidx.appcompat.app.AppCompatActivity;
    
    import android.content.Intent;
    import android.os.Bundle;
    import android.view.View;
    import android.widget.AdapterView;
    import android.widget.ListView;
    import android.widget.SimpleAdapter;
    
    import java.util.ArrayList;
    import java.util.HashMap;
    import java.util.List;
    import java.util.Map;
    
    public class MainActivity extends AppCompatActivity {
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
    
            List<Map<String, String>> list = new ArrayList<Map<String,String>>();
    
            Map<String, String> map = new HashMap<String, String>();
            map.put("name", "大阪");
            map.put("id", "270000");
            list.add(map);
            map = new HashMap<String, String>();
            map.put("name", "神戸");
            map.put("id", "280010");
            list.add(map);
            map = new HashMap<String, String>();
            map.put("name", "豊岡");
            map.put("id", "280020");
            list.add(map);
            map = new HashMap<String, String>();
            map.put("name", "京都");
            map.put("id", "260010");
            list.add(map);
            map = new HashMap<String, String>();
            map.put("name", "舞鶴");
            map.put("id", "260020");
            list.add(map);
            map = new HashMap<String, String>();
            map.put("name", "奈良");
            map.put("id", "290010");
            list.add(map);
            map = new HashMap<String, String>();
            map.put("name", "風屋");
            map.put("id", "290020");
            list.add(map);
            map = new HashMap<String, String>();
            map.put("name", "和歌山");
            map.put("id", "300010");
            list.add(map);
            map = new HashMap<String, String>();
            map.put("name", "潮岬");
            map.put("id", "300020");
            list.add(map);
    
            ListView lvCityList = (ListView) findViewById(R.id.lvCityList);
    
            String[] from = {"name"};
            int[] to = {android.R.id.text1};
            SimpleAdapter adapter = new SimpleAdapter(MainActivity.this, list, android.R.layout.simple_expandable_list_item_1, from, to);
    
            lvCityList.setAdapter(adapter);
            lvCityList.setOnItemClickListener(new ListItemClickListener());
    
        }
      
        private class ListItemClickListener implements AdapterView.OnItemClickListener {
    
            @Override
            public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
                Map<String, String> item = (Map<String, String>) parent.getItemAtPosition(position);
                String cityName = item.get("name");
                String cityId = item.get("id");
    
                Intent intent = new Intent(MainActivity.this, WeatherInfoActivity.class);
                intent.putExtra("cityName", cityName);
                intent.putExtra("cityId", cityId);
                startActivity(intent);
            }
        }
    }
    
[/code]

### activity_main.xml

[code]

    <?xml version="1.0" encoding="utf-8"?>
    <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        xmlns:tools="http://schemas.android.com/tools"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:context=".MainActivity">
    
        <ListView xmlns:android="http://schemas.android.com/apk/res/android"
            android:id="@+id/lvCityList"
            android:layout_width="match_parent"
            android:layout_height="match_parent" >
        </ListView>
    
    </androidx.constraintlayout.widget.ConstraintLayout>
    
[/code]

[![activity_main.xmlイメージ](https://i.stack.imgur.com/cd19E.png)]

### WeatherInfoActivity.java

[code]

    package com.example.api_example;
    
    import androidx.appcompat.app.AppCompatActivity;
    
    import android.content.Intent;
    import android.nfc.Tag;
    import android.os.AsyncTask;
    import android.os.Bundle;
    import android.util.Log;
    import android.widget.TextView;
    
    import org.json.JSONArray;
    import org.json.JSONException;
    import org.json.JSONObject;
    
    import java.io.BufferedReader;
    import java.io.IOException;
    import java.io.InputStream;
    import java.io.InputStreamReader;
    import java.io.UnsupportedEncodingException;
    import java.net.HttpURLConnection;
    import java.net.MalformedURLException;
    import java.net.URL;
    
    public class WeatherInfoActivity extends AppCompatActivity {
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_weather_info);
    
    //        intentにgetIntentメソッドを用いて、intentで飛ばされてきたMainActivityからの「cityName」と「cityID」を取得する。
    //        そしてこれをString型にキャストする。
            Intent intent = getIntent();
            String CityName = intent.getStringExtra("cityName");
            String CityId = intent.getStringExtra("cityId");
    
    
    //        TextViewをactivity_weather_infoが三つ持っているので、それらに該当するViewのID番号を取得する。
            TextView tvCityName = (TextView) findViewById(R.id.tvCityName);
            TextView tvWeatherTelop = (TextView) findViewById(R.id.tvWeatherTelop);
            TextView tvWeatherDesc = (TextView) findViewById(R.id.tvWeatherDesc);
    
    //        ここで、新しくreceiverとしてWeatherInfoReceiverのオブジェクトを生成する。引数は、上記にて定義したcityName,tvCityName,tvWeatherTelop,tvWeatherDescの4つ。
            WeatherInfoReceiver receiver = new WeatherInfoReceiver(CityName, tvCityName, tvWeatherTelop, tvWeatherDesc);
    //       WeatherInfoReceverのオブジェクトであるreceiverに、executeメソッドを用いて、引数をCityIdに設定する。これで,WeatherInfoReceiverクラスのオブジェクトであるreceiverで、URLレスポンスをさせるためのcityid番号が渡った。
            receiver.execute(CityId);
    
        }
    
    //        非同期処理を行うためのクラス。AsyncTaskの<>の理解のためにいかに記述する。
    //        第一引数は引数、第二引数は経過について、第三引数は戻り値についての型を指定している。従って、それぞれの引数にintとかStringとかvoidがあることもある。
        private class WeatherInfoReceiver extends AsyncTask<String, String, String> {
            private String _cityName;
            private TextView _tvCityName;
            private TextView _tvWeatherTelop;
            private TextView _tvWeatherDesc;
    
    
            public WeatherInfoReceiver(String cityName, TextView tvCityName, TextView tvWeatherTelop, TextView tvWeatherDesc) {
                _cityName = cityName;
                _tvCityName = tvCityName;
                _tvWeatherTelop = tvWeatherTelop;
                _tvWeatherDesc = tvWeatherDesc;
            }
    
    //        別スレッドで非同期処理が実行され、その時に行う処理内容
            @Override
            public String doInBackground(String... params) {
    //            MainAvtivityからgetIntentで取得した都道府県のidがparamsに格納されている。ここで、paramsは可変長変数であり、リストのような振る舞いをすることがわかっている。
                String id = params[0];
    //            ここで、APIを取得するためのURLをString型の変数に代入しておく。なお、ここでidが末尾につくことで、各都市に該当するURLにアクセス可能。
                String urlStr = "http://weather.livedoor.com/forecast/webservice/json/v1?city=" + id;
    
    //            ここで、HttpURLConnectionクラスのオブジェクトconを定義し、nullを代入する。
    //            同様に、InputStreamクラスのオブジェクトisを宣言し、nullを代入する。
    //            結果を代入するresultには、空文字を代入しておく。これに以下の処理ないで何かしらの文字列を代入することになる。
                HttpURLConnection con = null;
                InputStream is = null;
                String result = "";
    
                try {
    //                URLクラス＝World Wide Web上のリソースへのポインタを表すクラス。リソースはファイルやディレクトリのような単純なものよりも、データベースや検索エンジンに対するクエリーなど、複雑なオブジェクトへの参照であることもある。
    //                URLの種類や形式によっては、公式リファレンスの以下を参照(https://docs.oracle.com/javase/jp/6/api/java/net/URL.html)。ここでは、そのURLクラスのオブジェクトurlを宣言した。
                    URL url = new URL(urlStr);
    //                ここで、HTTPConnectionのオブジェクトconに、openConnectionメソッドを使用して取得した何かを代入する。
                    HttpURLConnection con = url.openConnection();
    //                ここで、HTTP通信のGETメソッドを指定している。
                    con.setRequestMethod("GET");
    //                追記。                
                    con.setDoInput(true);
    //                ここで、接続を開始する。
                    con.connect();
    //                ここで、nullにしておいたisに、conに対してgetInputStreamメソッドを使用したものを代入する。ここが問題だと思われる。InputStreamが機能していない。
                    is = con.getInputStream();
    //                resultに、is2Stringメソッドに引数として、isを与えたものを代入する。この後に、以下の処理でそれぞれの接続等々を切断し、結果としてresultを返す。
                    result = is2String(is);
    
                }
                catch(MalformedURLException ex) {
                }
                catch(IOException ex) {
                }
                finally {
                    if(con != null) {
                        con.disconnect();
                    }
    
                    if(is != null) {
                        try {
                            is.close();
                        }
                        catch(IOException ex) {
                        }
                    }
                }
                return result;
            }
    
    //        メインスレッドで実行させる処理(非同期処理で得たAPIの結果などをViweに紐付け、反映させる等)
            @Override
            public void onPostExecute(String result) {
                String desc = "";
                String dateLabel = "";
                String telop = "";
                try {
                    JSONObject rootJSON = new JSONObject(result);
                    JSONObject descriptionJSON = rootJSON.getJSONObject("description");
                    desc = descriptionJSON.getString("text");
                    JSONArray forecasts = rootJSON.getJSONArray("forecasts");
                    JSONObject forecastNow = forecasts.getJSONObject(0);
                    dateLabel = forecastNow.getString("dateLabel");
                    telop = forecastNow.getString("telop");
                }
                catch(JSONException ex) {
                }
    
                _tvCityName.setText(String.format("%sの%sの天気:", _cityName, dateLabel));
                _tvWeatherTelop.setText(telop);
                _tvWeatherDesc.setText(desc);
            }
    
    
    //          ここでは、取得したデータをsbという名前で宣言したStringBifferに代入したものを戻り値として返すメソッド。
            private String is2String(InputStream is) throws IOException, UnsupportedEncodingException {
    //            BufferReaderのオブジェクトとして、readerを宣言し、これにBufferReaderにInputStreamを引数として渡してオブジェクトを生成する。
    //            そもそも、BufferReaderとは何か？文字ストリームを数文字「まとめて」取得するための文字入力ストリームクラス。
    //            通常、read()メソッドを呼び出す毎に1文字単位で取得するが、ネットワーク環境等によっては数文字をまとめて取得した方が処理が早まる可能性がある。
    //            そこで、一回のread()メソッドで数文字をあらかじめ取得し、「バッファ」に保存することで、その後の取得をバッファから返し、処理速度の向上を図るのがこのクラスの役目。
    //            文字ストリームとは、「文字の並び」を意味する。Stringクラス、char型の配列、テキストファイル 等が文字ストリームとなる。バッファとは緩衝材という意味の文言。なぜバッファがこの文脈にあるかというと、、、？
    //            =>元々は、「とりあえずのデータを格納する変数」という意味として、変数名にbufをつけて使用していた。
    //            これらの変数に、文字列を格納することが多くなり、それが転じて、現在では「文字列を格納する変数」という意味で使用されることが多くなった。
    //            StringBufferクラスの「Buffer」も同じ意味。
                BufferedReader reader = new BufferedReader(new InputStreamReader(is, "UTF-8"));
    //            文字列を連結する処理が多い場合に使用する。StringBufferの方がStringBuilderよりも文字列の連結に欠損が見られないなどの優位性があるみたい。
                StringBuffer sb = new StringBuffer();
                String st = "";
    //            char型のリストを用意し、、、よくわからんです。。
    //            ここで、int型のlineを宣言。whileのなかで、reader.read(b)の代入先として用いている。
    //            ここで、StringBufferクラスにガンガンappendして、charにキャストした数字も含む文字列をどんどん連結させていく。
    //            whileのなかで、lineが0未満、つまりもうreadLineメソッドで読み込むことができなくなた場合に、ループを抜ける。
                while((st = reader.readLine()) != null) {
                    sb.append(st);
                }
    //            ここで、StringBufferのオブジェクトをString型にキャストして、戻り値として返す。これが99行目に該当する。
                return sb.toString();
            }
        }
    }
    
[/code]

### activity_weather_info.xml

[code]

    <?xml version="1.0" encoding="utf-8"?>
    <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        xmlns:tools="http://schemas.android.com/tools"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:context=".WeatherInfoActivity">
    
        <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:orientation="vertical">
    
            <TextView
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_marginBottom="10dp"
                android:gravity="center"
                android:text="@string/tv_winfo_title"
                android:textSize="25sp" />
    
            <LinearLayout
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_marginBottom="10dp"
                android:orientation="horizontal">
    
                <TextView
                    android:id="@+id/tvCityName"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:textSize="20sp" />
    
                <TextView
                    android:id="@+id/tvWeatherTelop"
                    android:layout_width="0dp"
                    android:layout_height="wrap_content"
                    android:layout_weight="1"
                    android:textSize="20sp" />
    
            </LinearLayout>
    
                <TextView
                android:id="@+id/tvWeatherDesc"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_marginBottom="30dp"
                android:textSize="15sp" />
        </LinearLayout>>
    
    </androidx.constraintlayout.widget.ConstraintLayout>
    
[/code]

「大阪」をタップしたときの遷移先の画面。Jsonフォーマットで取得できるはずの情報が取得できていない。  
[![activity_weather_info.xml](https://i.stack.imgur.com/k8lW3.png)](https://i.stack.imgur.com/k8lW3.png)

* * *

# 調査内容

### A.宣言している全ての変数に意図した値が入っているのか確認した。

### B.URLは間違えていないのか、curlコマンドで確認した。

### C.InputStreamが動作しない件についてググった。

### D.Cの結果にて、setDoInputメソッドをconに対して適応し、その結果を確認した。

###
E.とりあえず、Dの結果はおいておいて、ググったものから他の参考になりそうなものを漁った。ぐぐる文字を日本語に変更してみた。「getInputStream()
機能しない」に変更した。

### F.getInputStreamが機能していないなら、例外処理に回っているのか！と気づき、IOExceptionに追記した。

# 調査結果

### Aの結果

ブレークポイントを用いて変数を確かめた。  
WeatherInfoActivityで、conまでの値を調べたところ、conには選択した都市に対応するJsonフォーマットデータを取得するためのリンク先(<http://weather.livedoor.com/forecast/webservice/json/v1?city=280020>)
が代入されていた。以下が、このURLで検索した先のデータ。

[code]

    {"pinpointLocations":[{"link":"http://weather.livedoor.com/area/forecast/2820900","name":"\u8c4a\u5ca1\u5e02"},{"link":"http://weather.livedoor.com/area/forecast/2822200","name":"\u990a\u7236\u5e02"},{"link":"http://weather.livedoor.com/area/forecast/2822500","name":"\u671d\u6765\u5e02"},{"link":"http://weather.livedoor.com/area/forecast/2858500","name":"\u9999\u7f8e\u753a"},{"link":"http://weather.livedoor.com/area/forecast/2858600","name":"\u65b0\u6e29\u6cc9\u753a"}],"link":"http://weather.livedoor.com/area/forecast/280020","forecasts":[{"dateLabel":"\u4eca\u65e5","telop":"\u6674\u306e\u3061\u66c7","date":"2020-04-15","temperature":{"min":null,"max":null},"image":{"width":50,"url":"http://weather.livedoor.com/img/icon/5.gif","title":"\u6674\u306e\u3061\u66c7","height":31}},{"dateLabel":"\u660e\u65e5","telop":"\u66c7\u6642\u3005\u6674","date":"2020-04-16","temperature":{"min":{"celsius":"6","fahrenheit":"42.8"},"max":{"celsius":"17","fahrenheit":"62.6"}},"image":{"width":50,"url":"http://weather.livedoor.com/img/icon/9.gif","title":"\u66c7\u6642\u3005\u6674","height":31}},{"dateLabel":"\u660e\u5f8c\u65e5","telop":"\u66c7\u306e\u3061\u96e8","date":"2020-04-17","temperature":{"min":null,"max":null},"image":{"width":50,"url":"http://weather.livedoor.com/img/icon/13.gif","title":"\u66c7\u306e\u3061\u96e8","height":31}}],"location":{"city":"\u8c4a\u5ca1","area":"\u8fd1\u757f","prefecture":"\u5175\u5eab\u770c"},"publicTime":"2020-04-15T17:00:00\u002b0900","copyright":{"provider":[{"link":"http://tenki.jp/","name":"\u65e5\u672c\u6c17\u8c61\u5354\u4f1a"}],"link":"http://weather.livedoor.com/","title":"(C) LINE Corporation","image":{"width":118,"link":"http://weather.livedoor.com/","url":"http://weather.livedoor.com/img/cmn/livedoor.gif","title":"livedoor \u5929\u6c17\u60c5\u5831","height":26}},"title":"\u5175\u5eab\u770c \u8c4a\u5ca1 \u306e\u5929\u6c17","description":{"text":" \u5175\u5eab\u770c\u306f\u3001\u4e0a\u7a7a\u306e\u6c17\u5727\u306e\u8c37\u306e\u5f71\u97ff\u3067\u8584\u96f2\u304c\u5e83\u304c\u3063\u3066\u3044\u307e\u3059\u304c\u3001\u9ad8\u6c17\u5727\u306b\u8986\u308f\u308c\u3066\u304a\u304a\u3080\u306d\u6674\u308c\u3066\u3044\u307e\u3059\u3002\n\n 15\u65e5\u306e\u5175\u5eab\u770c\u306f\u3001\u9ad8\u6c17\u5727\u306b\u8986\u308f\u308c\u3066\u6674\u308c\u307e\u3059\u304c\u3001\u4e0a\u7a7a\u306e\u6c17\u5727\u306e\u8c37\u306e\u5f71\u97ff\u3067\u591c\u306f\u66c7\u308b\u3067\u3057\u3087\u3046\u3002\n\n 16\u65e5\u306e\u5175\u5eab\u770c\u306f\u3001\u5317\u90e8\u3067\u306f\u6c17\u5727\u306e\u8c37\u3084\u6e7f\u3063\u305f\u7a7a\u6c17\u306e\u5f71\u97ff\u3067\u304a\u304a\u3080\u306d\u66c7\u308b\u898b\u8fbc\u307f\u3067\u3059\u3002\u5357\u90e8\u3067\u306f\u9ad8\u6c17\u5727\u306b\u8986\u308f\u308c\u3066\u304a\u304a\u3080\u306d\u6674\u308c\u308b\u3067\u3057\u3087\u3046\u3002","publicTime":"2020-04-15T16:34:00\u002b0900"}}
    
[/code]

上記の、conに対して、以下のInputStreamメソッドを用いると、

[code]

    is = con.getInputStream();
    
[/code]

isがnullで、conに対してInputStreamメソッドが機能していない？ことがわかった。

### Bの結果

MainActivityの一番上にある「大阪」に該当するURLで実行した結果。取得したい情報がJsonフォーマットで確認できる。従って、アクセスしているURLに問題はない。

[code]

    % curl -s http://weather.livedoor.com/forecast/webservice/json/v1\?city\=270000 | jq -r
    {
      "pinpointLocations": [
        {
          "link": "http://weather.livedoor.com/area/forecast/2710000",
          "name": "大阪市"
        },
        {
          "link": "http://weather.livedoor.com/area/forecast/2714000",
          "name": "堺市"
        },
        {
          "link": "http://weather.livedoor.com/area/forecast/2720200",
          "name": "岸和田市"
        },
        {
          "link": "http://weather.livedoor.com/area/forecast/2720300",
          "name": "豊中市"
        },
        {
          "link": "http://weather.livedoor.com/area/forecast/2720400",
          "name": "池田市"
        },
        {
          "link": "http://weather.livedoor.com/area/forecast/2720500",
          "name": "吹田市"
        },
        {
          "link": "http://weather.livedoor.com/area/forecast/2720600",
          "name": "泉大津市"
        },
        {
          "link": "http://weather.livedoor.com/area/forecast/2720700",
          "name": "高槻市"
        },
        {
          "link": "http://weather.livedoor.com/area/forecast/2720800",
          "name": "貝塚市"
        },
        {
          "link": "http://weather.livedoor.com/area/forecast/2720900",
          "name": "守口市"
        },
        {
          "link": "http://weather.livedoor.com/area/forecast/2721000",
          "name": "枚方市"
        },
        {
          "link": "http://weather.livedoor.com/area/forecast/2721100",
          "name": "茨木市"
        },
        {
          "link": "http://weather.livedoor.com/area/forecast/2721200",
          "name": "八尾市"
        },
        {
          "link": "http://weather.livedoor.com/area/forecast/2721300",
          "name": "泉佐野市"
        },
        {
          "link": "http://weather.livedoor.com/area/forecast/2721400",
          "name": "富田林市"
        },
        {
          "link": "http://weather.livedoor.com/area/forecast/2721500",
          "name": "寝屋川市"
        },
        {
          "link": "http://weather.livedoor.com/area/forecast/2721600",
          "name": "河内長野市"
        },
        {
          "link": "http://weather.livedoor.com/area/forecast/2721700",
          "name": "松原市"
        },
        {
          "link": "http://weather.livedoor.com/area/forecast/2721800",
          "name": "大東市"
        },
        {
          "link": "http://weather.livedoor.com/area/forecast/2721900",
          "name": "和泉市"
        },
        {
          "link": "http://weather.livedoor.com/area/forecast/2722000",
          "name": "箕面市"
        },
        {
          "link": "http://weather.livedoor.com/area/forecast/2722100",
          "name": "柏原市"
        },
        {
          "link": "http://weather.livedoor.com/area/forecast/2722200",
          "name": "羽曳野市"
        },
        {
          "link": "http://weather.livedoor.com/area/forecast/2722300",
          "name": "門真市"
        },
        {
          "link": "http://weather.livedoor.com/area/forecast/2722400",
          "name": "摂津市"
        },
        {
          "link": "http://weather.livedoor.com/area/forecast/2722500",
          "name": "高石市"
        },
        {
          "link": "http://weather.livedoor.com/area/forecast/2722600",
          "name": "藤井寺市"
        },
        {
          "link": "http://weather.livedoor.com/area/forecast/2722700",
          "name": "東大阪市"
        },
        {
          "link": "http://weather.livedoor.com/area/forecast/2722800",
          "name": "泉南市"
        },
        {
          "link": "http://weather.livedoor.com/area/forecast/2722900",
          "name": "四條畷市"
        },
        {
          "link": "http://weather.livedoor.com/area/forecast/2723000",
          "name": "交野市"
        },
        {
          "link": "http://weather.livedoor.com/area/forecast/2723100",
          "name": "大阪狭山市"
        },
        {
          "link": "http://weather.livedoor.com/area/forecast/2723200",
          "name": "阪南市"
        },
        {
          "link": "http://weather.livedoor.com/area/forecast/2730100",
          "name": "島本町"
        },
        {
          "link": "http://weather.livedoor.com/area/forecast/2732100",
          "name": "豊能町"
        },
        {
          "link": "http://weather.livedoor.com/area/forecast/2732200",
          "name": "能勢町"
        },
        {
          "link": "http://weather.livedoor.com/area/forecast/2734100",
          "name": "忠岡町"
        },
        {
          "link": "http://weather.livedoor.com/area/forecast/2736100",
          "name": "熊取町"
        },
        {
          "link": "http://weather.livedoor.com/area/forecast/2736200",
          "name": "田尻町"
        },
        {
          "link": "http://weather.livedoor.com/area/forecast/2736600",
          "name": "岬町"
        },
        {
          "link": "http://weather.livedoor.com/area/forecast/2738100",
          "name": "太子町"
        },
        {
          "link": "http://weather.livedoor.com/area/forecast/2738200",
          "name": "河南町"
        },
        {
          "link": "http://weather.livedoor.com/area/forecast/2738300",
          "name": "千早赤阪村"
        }
      ],
      "link": "http://weather.livedoor.com/area/forecast/270000",
      "forecasts": [
        {
          "dateLabel": "今日",
          "telop": "晴のち曇",
          "date": "2020-04-15",
          "temperature": {
            "min": null,
            "max": {
              "celsius": "20",
              "fahrenheit": "68.0"
            }
          },
          "image": {
            "width": 50,
            "url": "http://weather.livedoor.com/img/icon/5.gif",
            "title": "晴のち曇",
            "height": 31
          }
        },
        {
          "dateLabel": "明日",
          "telop": "晴時々曇",
          "date": "2020-04-16",
          "temperature": {
            "min": {
              "celsius": "11",
              "fahrenheit": "51.8"
            },
            "max": {
              "celsius": "21",
              "fahrenheit": "69.8"
            }
          },
          "image": {
            "width": 50,
            "url": "http://weather.livedoor.com/img/icon/2.gif",
            "title": "晴時々曇",
            "height": 31
          }
        },
        {
          "dateLabel": "明後日",
          "telop": "曇のち雨",
          "date": "2020-04-17",
          "temperature": {
            "min": null,
            "max": null
          },
          "image": {
            "width": 50,
            "url": "http://weather.livedoor.com/img/icon/13.gif",
            "title": "曇のち雨",
            "height": 31
          }
        }
      ],
      "location": {
        "city": "大阪",
        "area": "近畿",
        "prefecture": "大阪府"
      },
      "publicTime": "2020-04-15T11:00:00+0900",
      "copyright": {
        "provider": [
          {
            "link": "http://tenki.jp/",
            "name": "日本気象協会"
          }
        ],
        "link": "http://weather.livedoor.com/",
        "title": "(C) LINE Corporation",
        "image": {
          "width": 118,
          "link": "http://weather.livedoor.com/",
          "url": "http://weather.livedoor.com/img/cmn/livedoor.gif",
          "title": "livedoor 天気情報",
          "height": 26
        }
      },
      "title": "大阪府 大阪 の天気",
      "description": {
        "text": " 大阪府は、高気圧に覆われておおむね晴れています。\n\n 15日の大阪府は、高気圧に覆われて晴れますが、気圧の谷の影響で昼過ぎから次第に曇るでしょう。\n\n 16日の大阪府は、高気圧に覆われておおむね晴れる見込みです。\n\n【近畿地方】\n 近畿地方は、高気圧に覆われておおむね晴れています。\n\n 15日の近畿地方は、高気圧に覆われておおむね晴れますが、気圧の谷の影響で昼過ぎから次第に曇るでしょう。\n\n 16日の近畿地方は、北部では気圧の谷や湿った空気の影響でおおむね曇る見込みです。中部と南部では高気圧に覆われておおむね晴れるでしょう。",
        "publicTime": "2020-04-15T10:33:00+0900"
      }
    }
    
[/code]

### Cの結果

検索したキーワード  
1.「getinputstream doesn't work」  
閲覧したサイト  
<https://stackoverflow.com/questions/40702774/httpurlconnection-
getinputstream-stop-working>  
setDoInputメソッドを呼んでいなかったことに気づき、追記した。

### Dの結果

もう一度、ブレークポイントを利用してisに何かが代入されていないか検証した。  
しかし、Aで行った時と同様にブレークポイントが機能しない。  
Android Developersの
[公式リファレンス](https://developer.android.com/studio/debug?hl=ja#breakPoints)
を参考にVariablesを参照したが、変数にカーソルを当てても変数を選択しても何の情報も表示されなくなってしまった。

### Eの結果

E-1.閲覧したサイト  
<https://stackoverflow.com/questions/43181813/android-urlconnection-
getinputstream-fails-inputstream-stays-null/43182270>  
→「メインスレッドでInputStreamを書いているので動作しない」だった。私はAsyncTaskをextendsしている。

E-2.検索キーワードを変更して閲覧したサイト  
[https://www.atmarkit.co.jp/bbs/phpBB/viewtopic.php?topic=10913&forum=12](https://www.atmarkit.co.jp/bbs/phpBB/viewtopic.php?topic=10913&forum=12)  
→プロキシ？が問題らしいが、情報が古すぎる。他にもあたってみてダメなら戻る。

<https://teratail.com/questions/115888>  
→今回の実装とは関係ない？と判断。この人が詰まっている原因は、getWriterとgetOutputStreamを同時に使ったことらしいので。

### Fの結果

追記内容(WeatherInfoActivity.javaのdoInbackgroundメソッド内のtry-catchのcatch(IOException
ex)以下に記述)

[code]

                catch(IOException ex) {
                    System.out.println("情報取得に失敗しました");
                }
    
[/code]

LogCatに、"情報取得に失敗しました"と出力された。当然。でもどう直せばいいのかは結局わからない。

# 最後に

詰まりました。どなたか助けてください。お願いいたします。  
粗方調べてもわからないので、[Asynctaskについての公式リファレンス](https://developer.android.com/reference/android/os/AsyncTask)
を読みながら、待っています。


CC BY-SA 4.0
2020-04-15T07:48:18.603
65642
2020-04-16T10:56:06.940
2020-06-17T08:14:45.997
-1
34348
question
java android-studio android-asynctask
Weather Hacks API を用いたJsonデータの取得に失敗する


con.connect()の後に、レスポンスコードを取得してみるのはどうでしょうか。

[code]

    con.connect();
    int responseCode = con.getResponseCode();
    Log.d("doInBackground", String.format("responseCode = %d", responseCode));
    switch(responseCode) {
      case: HttpURLConnection.HTTP_OK:
        //                ここで、nullにしておいたisに、conに対してgetInputStreamメソッドを使用したものを代入する。ここが問題だと思われる。InputStreamが機能していない。
        is = con.getInputStream();
        //                resultに、is2Stringメソッドに引数として、isを与えたものを代入する。この後に、以下の処理でそれぞれの接続等々を切断し、結果としてresultを返す。
        result = is2String(is);
        break;
      default:
        // responseCodeが200(HTTP OK)でない場合は何かのエラーでうまくいってません。
        break;
    }
    
[/code]


CC BY-SA 4.0
2020-04-16T03:20:23.797
65665
2020-04-16T03:20:23.797
39653
65642
answer