Volley?
Volley 동작방식

Volley 사용법
https://mvnrepository.com/artifact/com.android.volley/volley
gradle.kts
dependencies {
implementation("com.android.volley:volley:1.2.1")
..
permission
<!-- 권한 허용 : 인터넷 접속 허용 -->
<uses-permission android:name="android.permission.INTERNET"/>
MainActivity.kt
package com.example.ex_volley
import android.os.Bundle
import android.util.Log
import android.widget.Button
import android.widget.EditText
import android.widget.TextView
import androidx.activity.enableEdgeToEdge
import androidx.appcompat.app.AppCompatActivity
import androidx.core.view.ViewCompat
import androidx.core.view.WindowInsetsCompat
import com.android.volley.Request
import com.android.volley.RequestQueue
import com.android.volley.toolbox.StringRequest
import com.android.volley.toolbox.Volley
class MainActivity : AppCompatActivity() {
// Volley : HTTP 통신 (Request, RequestQueue)
lateinit var request: StringRequest // 받아오는 응답값을 String 형식으로 받음
lateinit var queue: RequestQueue
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val etUrl:EditText = findViewById<EditText>(R.id.etUrl)
val btnReq:Button = findViewById<Button>(R.id.btnReq)
val tvResult:TextView = findViewById<TextView>(R.id.tvResult)
// RequestQueue 생성
queue = Volley.newRequestQueue(this)
// 버튼이 눌리면 해당 주소로 요청을 할 수 있는 Request 객체 생성
btnReq.setOnClickListener {
// 1. EditText에 작성된 주소 가져오기
val inputURL = etUrl.text.toString()
// 2. Request 객체 생성 - 요청방식(Get/Post), 요청Url, 요청/응답성공, 요청/응답실패(CallBack) 생성
request = StringRequest(
Request.Method.GET,
inputURL,
{
response ->
Log.d("result", response.toString())
tvResult.text = response
},
{
error ->
Log.d("result",error.toString())
}
)
// 캐싱(Cache) : 같은 요청을 여러번 할거 같을 때 응답값을 매번 서버에서
// 가져오는게 아니라 클라이언트 혹은 중간 지점에 저장해놓고 요청이 들어올 경우 저장된 값을 가져오는 것
// 장점 : 값을 빠르게 가져올 수 있다
// 단점 : 값이 업데이트가 안되어 있을 수도 있다
// 캐싱을 허용하지 않겠다
request.setShouldCache(false)
// 3. Request 객체를 RequestQueue에 추가
queue.add(request)
}
}
}
WeatherVO.kt
package com.example.ex_volley
data class WeatherVO(val city:String, val state:String, val temp: String,
val humid:String, val speed:String)
WeatherAdapter.kt
package com.example.ex_volley
import android.content.Context
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.TextView
import androidx.recyclerview.widget.RecyclerView
class WeatherAdapter ( val context: Context, val weatherList:ArrayList<WeatherVO>)
:RecyclerView.Adapter<WeatherAdapter.ViewHolder>(){
// Weather List 안에 들어있는 개별 데이터에 대응할 뷰 정의
// itemView = weather_item.xml => 객체화 (TextView 5개)
inner class ViewHolder(itemView: View):RecyclerView.ViewHolder(itemView) {
val tvCity:TextView
val tvState:TextView
val tvTemp:TextView
val tvHumid:TextView
val tvSpeed:TextView
// class가 처음 로딩될 때 초기화 용으로 딱한번 호출되는 블럭
init {
tvCity = itemView.findViewById(R.id.tvCity)
tvState = itemView.findViewById(R.id.tvState)
tvTemp = itemView.findViewById(R.id.tvTemp)
tvHumid = itemView.findViewById(R.id.tvHumid)
tvSpeed = itemView.findViewById(R.id.tvSpeed)
}
}
// 만약에 한 화면에 10개의 item이 보여진다 => View Holder는 13~15개 정도만 생성
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
// xml을 객체화 => ViewHolder 리턴
val inflater:LayoutInflater = LayoutInflater.from(context)
val view = inflater.inflate(R.layout.weather_item, parent, false)
return ViewHolder(view)
}
// WeatherList 안에 들어있는 아이템 개수
override fun getItemCount(): Int {
return weatherList.size
}
// ViewHolder - View만 가지고 있는 상태 <= 데이터 바인딩(weatherList)바인딩
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
// holder.tvCity.text =
holder.tvCity.setText("도시 : "+ weatherList.get(position).city)
holder.tvState.setText("상태 : "+ weatherList.get(position).state)
holder.tvTemp.setText("온도 : "+ weatherList.get(position).temp+"도")
holder.tvHumid.setText("습도 : "+ weatherList.get(position).humid+"%")
holder.tvSpeed.setText("풍속 : "+ weatherList.get(position).speed+"m/s")
}
}
activity_weather.kt
package com.example.ex_volley
import android.annotation.SuppressLint
import android.os.Bundle
import android.util.Log
import android.widget.Button
import androidx.activity.enableEdgeToEdge
import androidx.appcompat.app.AppCompatActivity
import androidx.core.view.ViewCompat
import androidx.core.view.WindowInsetsCompat
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import androidx.recyclerview.widget.RecyclerView.Recycler
import com.android.volley.Request
import com.android.volley.RequestQueue
import com.android.volley.toolbox.StringRequest
import com.android.volley.toolbox.Volley
import org.json.JSONObject
class activity_weather : AppCompatActivity() {
// Volley
// 라이브러리 추가, 인터넷접속 허용, http 옵션 추가
// Request 객체 정의, RequestQueue 생성
lateinit var request:StringRequest
lateinit var requestQueue: RequestQueue
// Recycler View (VO 설계, CustomAdapter 설계)
@SuppressLint("MissingInflatedId")
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_weather)
val rvWeather = findViewById<RecyclerView>(R.id.rvWeather)
val btnReq = findViewById<Button>(R.id.btnReq)
// RequestQueue 생성
requestQueue = Volley.newRequestQueue(this)
// Recycler View : itemList(ArrayList), Adapter
val weatherList = ArrayList<WeatherVO>()
val adapter = WeatherAdapter(this, weatherList)
rvWeather.adapter = adapter
rvWeather.layoutManager = LinearLayoutManager(this) // listview 형식
// 버튼 클릭 시 날씨 데이터 요청
btnReq.setOnClickListener{
// 1. 도시 이름 배열 생성
val cityList = ArrayList<String>()
cityList.add("Gwangju")
cityList.add("Seoul")
cityList.add("Jeju-do")
cityList.add("London")
cityList.add("New York")
cityList.add("Madrid")
// 2. 배열안에 있는 도시 개수만큼 요청할 수 있는 Request 객체 생성
for(i in 0 until cityList.size) {
request = StringRequest(
Request.Method.GET,
"https://api.openweathermap.org/data/2.5/weather?q=${cityList.get(i)}&appid=802e47a58a72c5ab41dc4409c5b54525",
{
response ->
Log.d("response", response.toString()) // String => 파싱 x => JSONObject, JSONArray 객체 형식으로 변환
val json = JSONObject(response) // String => JSONObject (파싱 O)
val weatherLists = json.getJSONArray("weather")
val weather = weatherLists.get(0) as JSONObject
val state = weather.getString("main")
Log.d("state", state)
val main = json.getJSONObject("main")
val temp = String.format("%.2f", main.getDouble("temp")-273.15)
val humidity = main.getString("humidity")
val wind = json.getJSONObject("wind")
val speed = wind.getString("speed")
// 습도 : main - humidity(String)
Log.d("state", temp)
// 온도 : main - temp (String)
Log.d("state", humidity)
// 풍속 : wind - speed (String)
Log.d("state", speed)
// WeatherVO 생성
WeatherArray.add(WeatherVO(cityList.get(i), state, temp, humidity, speed))
// 아이템리스트가 변화가 일어났다 ( 데이터가 추가됬다! ) 라고 어댑터한테 알려줘야함
adapter.notifyDataSetChanged()
},
{
error->
Log.d("response", error.toString())
}
)
requestQueue.add(request)
}
}
}
}