Volley 이용하여 날씨 api

tpids·2024년 9월 2일

Android

목록 보기
28/29

Volley?

  • Android App의 네트워킹을 더 쉽고,
    무엇보다도 더 빠르게 하는 HTTP 라이브러리

Volley 동작방식

Volley 사용법

  • Manifest에 인터넷 접속 허용 설정
  • build.gradle의 dependencies에 Volley 라이브러리 추가
  • RequestQueue 객체 생성
  • StringRequest 객체 생성
  • 여러 번 요청 시 캐시가 누적되므로 캐시 저장소 비워주는 기능 추가
    ( request.setShouldCache(false) )
  • RequestQueue에 StringRequest 추가
    ( queue.add(request) )

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)
            }
        }
    }
}

profile
개발자

0개의 댓글