実現したいこと
- openweatherのAPIを用いて簡易天気情報アプリを作成する
発生している問題・エラーメッセージ
デバッグをして、一行ごとに実行しているがとある一行を実行するとアプリケーションがエラー落ちをしてしまう問題がある。 ソースコード100行目にある↓のコードを実行すると落ちてしまう //レスポンスデータであるInputStreamオブジェクトを文字列に変換 result = is2String(stream) ネットワーク接続が問題と考えております。 どなたかご相談させてください。 また以下のインポートされたクラスは使われていません import java.net.Socket
該当のソースコード
MainActivity.kt
1package com.example.asyncsample 2 3import androidx.appcompat.app.AppCompatActivity 4import android.os.Bundle 5import android.util.Log 6import android.view.View 7import android.widget.AdapterView 8import android.widget.ListView 9import android.widget.SimpleAdapter 10import android.widget.TextView 11import androidx.annotation.UiThread 12import androidx.annotation.WorkerThread 13import org.json.JSONObject 14import java.io.BufferedReader 15import java.io.InputStream 16import java.io.InputStreamReader 17import java.lang.StringBuilder 18import java.net.HttpURLConnection 19import java.net.Socket 20import java.net.SocketTimeoutException 21import java.net.URL 22import java.nio.charset.StandardCharsets 23import java.util.concurrent.Callable 24import java.util.concurrent.Executors 25 26class MainActivity : AppCompatActivity() { 27 //クラス内のprivate定数を宣言するためにcompanion objectブロックとする 28 companion object{ 29 //ログに記載するタグ用の文字列 30 private const val DEBUG_TAG = "AsyncSample" 31 //お天気情報のURL 32 private const val WEATHERINFO_URL = "https://openweathermap.org/data/2.5/weather?lang=ja" 33 //お天気APIにアクセスするためのAPIキー 34 private const val APP_ID = "c1a8424a8556a2fa057cffa058930173" 35 } 36 //お天気情報の取得処理を行うメソッド 37 @UiThread 38 private fun receiveWeatherInfo(urlFull: String){ 39 val backgroundReceiver = WeatherInfoBackgroundReceiver(urlFull) 40 val executeService = Executors.newSingleThreadExecutor() 41 val future = executeService.submit(backgroundReceiver) 42 val result = future.get() 43 showWeatherInfo(result) 44 } 45 @UiThread 46 private fun showWeatherInfo(result: String){ 47 //ルートJSONオブジェクトを生成 48 val rootJSON = JSONObject(result) 49 //都市名文字列を取得 50 val cityName = rootJSON.getString("name") 51 //緯度経度情報JSONオブジェクトを取得 52 val coordJSON = rootJSON.getJSONObject("coord") 53 //緯度文字列を取得 54 val latitude = coordJSON.getString("lat") 55 //経度文字列を取得 56 val longitude = coordJSON.getString("lon") 57 //天気情報JSON配列オブジェクトを取得 58 val weatherJSONArray = rootJSON.getJSONArray("weather") 59 //現在の天気情報JSONオブジェクトを取得 60 val weatherJSON = weatherJSONArray.getJSONObject(0) 61 //現在の天気情報文字列を取得 62 val weather = weatherJSON.getString("description") 63 //画面に表示する「〇〇の天気」文字列を形成 64 val telop = "${cityName}の天気" 65 //天気の詳細情報を表示するTextViewを取得 66 val desc = "現在は${weather}です。\n緯度は${latitude}度で経度は${longitude}度です。" 67 //天気情報を表示するTextViewを取得 68 val tvWeatherTelop = findViewById<TextView>(R.id.tvWeatherTelop) 69 val tvWeatherDesc= findViewById<TextView>(R.id.tvWeatherDesc) 70 //天気情報を表示 71 tvWeatherTelop.text = telop 72 tvWeatherDesc.text = desc 73 } 74 //非同期でお天気情報APIにアクセスするためのクラス 75 private inner class WeatherInfoBackgroundReceiver(url:String): Callable<String> { 76 //お天気情報を取得するURL 77 private val _url = url 78 79 @WorkerThread 80 override fun call(): String { 81 var result = "" 82 83 //ここにWebAPIにアクセスするコードを記述 84 //URLオブジェクトを生成 85 val url = URL(_url) 86 //URLオブジェクトからHttpURLConnectionオブジェクトを取得 87 val con = url.openConnection() as HttpURLConnection 88 //接続に使ってもよい時間を設定 89 con.connectTimeout = 1000 90 //データ取得に使ってもよい時間 91 con.readTimeout = 1000 92 //HTTP接続メソッドをGETに設定 93 con.requestMethod = "GET" 94 try{ 95 //接続 96 con.connect() 97 //HttpURLConnectionオブジェクトからレスポンスデータを取得 98 val stream = con.inputStream//実行時に落ちる 99 //レスポンスデータであるInputStreamオブジェクトを文字列に変換 100 result = is2String(stream) 101 //InputStreamオブジェクトを解放 102 stream.close() 103 } 104 catch (ex: SocketTimeoutException){ 105 Log.w(DEBUG_TAG,"通信タイムアウト",ex) 106 } 107 con.disconnect() 108 return result 109 } 110 111 private fun is2String(stream: InputStream): String{ 112 val sb = StringBuilder() 113 val reader = BufferedReader(InputStreamReader(stream, StandardCharsets.UTF_8)) 114 var line = reader.readLine() 115 while(line != null) 116 { 117 sb.append(line) 118 line = reader.readLine() 119 } 120 reader.close() 121 return sb.toString() 122 } 123 } 124 //リストビューに表示させるリストデータ 125 private var _list: MutableList<MutableMap<String,String>> = mutableListOf() 126 127 override fun onCreate(savedInstanceState: Bundle?) { 128 super.onCreate(savedInstanceState) 129 setContentView(R.layout.activity_main) 130 131 _list = createList() 132 133 val lvCityList = findViewById<ListView>(R.id.lvCityList) 134 val from = arrayOf("name") 135 val to = intArrayOf(android.R.id.text1) 136 val adapter = SimpleAdapter(this@MainActivity, _list,android.R.layout.simple_list_item_1, 137 from,to) 138 lvCityList.adapter = adapter 139 lvCityList.onItemClickListener = ListItemClickListener() 140 } 141 142 //リストビューに表示させる天気ポイントリストデータを生成するメソッド 143 private fun createList(): MutableList<MutableMap<String,String>>{ 144 var list:MutableList<MutableMap<String,String>> = mutableListOf() 145 146 var city = mutableMapOf("name" to "北海道", "q" to "Hokkaido") 147 list.add(city) 148 149 city = mutableMapOf("name" to "東京", "q" to "Tokyo") 150 list.add(city) 151 152 city = mutableMapOf("name" to "山梨", "q" to "Yamanashi") 153 list.add(city) 154 155 city = mutableMapOf("name" to "大阪", "q" to "Osaka") 156 list.add(city) 157 158 city = mutableMapOf("name" to "神戸", "q" to "Kobe") 159 list.add(city) 160 161 city = mutableMapOf("name" to "鹿児島", "q" to "Kagoshima") 162 list.add(city) 163 164 return list 165 } 166 167 168 169 //リストがタップされた時の処理が記述されたリスナクラス 170 private inner class ListItemClickListener: AdapterView.OnItemClickListener{ 171 override fun onItemClick(parent: AdapterView<*>, view: View, position: Int, id: Long) { 172 val item = _list.get(position) 173 val q = item.get("q") 174 q?.let{ 175 val urlFull = "$WEATHERINFO_URL&q=$q&appid=$APP_ID" 176 receiveWeatherInfo(urlFull) 177 } 178 } 179 } 180 181}
activity_main.xml
1<?xml version="1.0" encoding="utf-8"?> 2<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" 3 xmlns:app="http://schemas.android.com/apk/res-auto" 4 xmlns:tools="http://schemas.android.com/tools" 5 android:layout_width="match_parent" 6 android:layout_height="match_parent" 7 tools:context=".MainActivity"> 8 9 <TextView 10 android:id="@+id/tvWinfoTitle" 11 android:layout_width="wrap_content" 12 android:layout_height="wrap_content" 13 android:layout_marginStart="8dp" 14 android:layout_marginTop="8dp" 15 android:layout_marginEnd="8dp" 16 android:text="@string/tv_winfo_title" 17 android:textSize="24sp" 18 app:layout_constraintEnd_toEndOf="parent" 19 app:layout_constraintStart_toStartOf="parent" 20 app:layout_constraintTop_toTopOf="@+id/glLvCityList" /> 21 22 <androidx.constraintlayout.widget.Guideline 23 android:id="@+id/glLvCityList" 24 android:layout_width="wrap_content" 25 android:layout_height="wrap_content" 26 android:orientation="horizontal" 27 app:layout_constraintGuide_percent="0.5" /> 28 29 <ListView 30 android:id="@+id/lvCityList" 31 android:layout_width="0dp" 32 android:layout_height="0dp" 33 app:layout_constraintBottom_toTopOf="@+id/glLvCityList" 34 app:layout_constraintEnd_toEndOf="parent" 35 app:layout_constraintStart_toStartOf="parent" 36 app:layout_constraintTop_toTopOf="parent" /> 37 38 <TextView 39 android:id="@+id/tvWeatherTelop" 40 android:layout_width="wrap_content" 41 android:layout_height="wrap_content" 42 android:layout_marginStart="8dp" 43 android:layout_marginTop="8dp" 44 android:textSize="20sp" 45 app:layout_constraintStart_toStartOf="parent" 46 app:layout_constraintTop_toBottomOf="@+id/tvWinfoTitle" /> 47 48 <TextView 49 android:id="@+id/tvWeatherDesc" 50 android:layout_width="0dp" 51 android:layout_height="0dp" 52 android:layout_marginStart="8dp" 53 android:layout_marginTop="8dp" 54 android:layout_marginEnd="8dp" 55 android:layout_marginBottom="8dp" 56 app:layout_constraintBottom_toBottomOf="parent" 57 app:layout_constraintEnd_toEndOf="parent" 58 app:layout_constraintStart_toStartOf="parent" 59 app:layout_constraintTop_toBottomOf="@+id/tvWeatherTelop" /> 60 61</androidx.constraintlayout.widget.ConstraintLayout>
strings.xml
1<resources> 2 <string name="app_name">お天気情報</string> 3 <string name="tv_winfo_title">お天気詳細</string> 4</resources>
試したこと
デバッグをしながら検証したところ、タップしたリストの値は読み取れている
ネットワークに接続が出来ていないことが原因と考えたが、スマホをネットワークに接続しても同様に落ちてしまった
回答2件
あなたの回答
tips
プレビュー