본문 바로가기

major/Android

[Kotlin] 공공 데이터 - 공적 마스크 데이터 구글맵에 띄우기

이전 포스팅에서 공적 마스크 데이터를 가져오고 ListView로 화면에 보여주는 것 까지 했습니다.

이전 포스팅 ☛ [Kotlin] 공공 데이터 사용하기 - 공적 마스크

이번 포스팅에서는 가져온 공적 마스크 판매처 및 재고 정보를 구글맵에 마커로 표시해보겠습니다.

구글맵 사용방법은 아래 포스팅에 정리되어 있으므로 생략하겠습니다.

구글맵 사용방법 ☛ [Android] Google Map 사용하기

 

ApiPublicMask.kt 파일을 수정합니다.

가져온 jsonArray에서 판매처의 경도, 위도 정보를 뽑아내서 ArrayList에 저장합니다.

// ApiPublicMask.kt
class ApiPublicMask(addr: String){

    var addr: String

    init{
        this.addr = addr
    }

    var lats = ArrayList<String>()
    var lngs = ArrayList<String>()
    var name = ArrayList<String>()
    var adapter : ListViewAdapter = ListViewAdapter()
    val storesURL = "https://8oi9s0nnth.apigw.ntruss.com/corona19-masks/v1/stores/json"
    val salesURL = "https://8oi9s0nnth.apigw.ntruss.com/corona19-masks/v1/sales/json"
    val storesbyaddrURL = "https://8oi9s0nnth.apigw.ntruss.com/corona19-masks/v1/storesByAddr/json"

    fun main(): ListViewAdapter{

        var text: String? = null
        try {
            text = URLEncoder.encode(addr, "UTF-8")
        } catch (e: UnsupportedEncodingException) {
            throw RuntimeException("검색어 인코딩 실패", e)
        }

        val url = "$storesbyaddrURL?address=$text"
        val responseBody = get(url)
        parseData(responseBody)

        return adapter
    }

    private operator fun get(apiUrl: String): String {
        var responseBody: String = ""
        try {
            val url = URL(apiUrl)
            val `in` = url.openStream()
            responseBody = readBody(`in`)

        } catch (e: MalformedURLException) {
            e.printStackTrace()
        } catch (e: IOException) {
            e.printStackTrace()
        }

        return responseBody
    }

    private fun readBody(body: InputStream): String {
        val streamReader = InputStreamReader(body)

        try {
            BufferedReader(streamReader).use({ lineReader ->
                val responseBody = StringBuilder()

                var line: String? = lineReader.readLine()
                while ( line != null) {
                    responseBody.append(line)
                    line = lineReader.readLine()
                }
                return responseBody.toString()
            })
        } catch (e: IOException) {
            throw RuntimeException("API 응답을 읽는데 실패했습니다.", e)
        }

    }

    private fun parseData(responseBody: String) {
        var storeName: String
        var remain_stat: String
        var lat: String
        var lng: String
        var jsonObject = JSONObject()
        try {
            jsonObject = JSONObject(responseBody)
            val jsonArray = jsonObject.getJSONArray("stores")

            for (i in 0 until jsonArray.length()) {
                val item = jsonArray.getJSONObject(i)
                storeName = item.getString("name")
                remain_stat = item.getString("remain_stat")
                lat = item.getString("lat")
                lng = item.getString("lng")
                name.add(storeName)
                lats.add(lat)
                lngs.add(lng)
                adapter.addItem(storeName, remain_stat)

            }
        } catch (e: JSONException) {
            e.printStackTrace()
        }
    }
}

그리고 activity_main.xml에 Button을 하나 더 추가해서 버튼을 누르면 구글맵 화면으로 넘어가게 했습니다.

<!-- activity_main.xml -->
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout 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"
    android:orientation="vertical"
    tools:context=".MainActivity">

    <EditText
        android:id="@+id/edittext"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="부산광역시 금정구 장전동"/>

    <Button
        android:id="@+id/button"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Button"
        android:onClick="onClickButton"/>

    <ListView
        android:id="@+id/listview"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_weight="1"/>

    <Button
        android:id="@+id/button2"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Button"
        android:onClick="onClickButton2"/>

</LinearLayout>

ApiPublicMask에서 가져온 정보를 putExtra를 통해 구글맵 Activity에 넘겨줬습니다.

// MainActivity.kt
class MainActivity : AppCompatActivity() {

    private lateinit var editText: EditText
    private lateinit var listView: ListView
    lateinit var adapter: ListViewAdapter
    lateinit var lats: ArrayList<String>
    lateinit var lngs: ArrayList<String>
    lateinit var name: ArrayList<String>

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        listView = findViewById(R.id.listview)
        editText = findViewById(R.id.edittext)
    }

    fun onClickButton(view: View){
        val thread = Thread({
            var apiPublicMask = ApiPublicMask(editText.text.toString())
            adapter = apiPublicMask.main()
            name = apiPublicMask.name
            lats = apiPublicMask.lats
            lngs = apiPublicMask.lngs
            runOnUiThread {
                listView.adapter = adapter
            }
        }).start()
    }

    fun onClickButton2(view: View){
        var intent = Intent(this, MapsActivity::class.java)
        intent.putExtra("lats",lats)
        intent.putExtra("lngs",lngs)
        intent.putExtra("name",name)
        startActivity(intent)
    }

}

그리고 마우스 우클릭>NEW>Activity>Gallery> Google Maps Activity를 생성합니다.

MapsActivity.kt 파일을 아래와 같이 수정합니다.

class MapsActivity : AppCompatActivity(), OnMapReadyCallback {

    private lateinit var mMap: GoogleMap
    lateinit var lats: ArrayList<String>
    lateinit var lngs: ArrayList<String>
    lateinit var names: ArrayList<String>


    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_maps)
        // Obtain the SupportMapFragment and get notified when the map is ready to be used.
        val mapFragment = supportFragmentManager
            .findFragmentById(R.id.map) as SupportMapFragment
        mapFragment.getMapAsync(this)

        lats = intent.getStringArrayListExtra("lats")
        lngs = intent.getStringArrayListExtra("lngs")
        names = intent.getStringArrayListExtra("name")
    }

    override fun onMapReady(googleMap: GoogleMap) {
        mMap = googleMap

        var latlng : LatLng? = null
        for(i in 0..lats.size-1){
            latlng = LatLng(lats[i].toDouble(),lngs[i].toDouble())
            mMap.addMarker(MarkerOptions().position(latlng).title(names[i]))

        }
        mMap.moveCamera(CameraUpdateFactory.newLatLng(latlng))
    }
}

실행 화면 캡쳐

실행하면 위와 같습니다.

첫 화면에서 첫번째 버튼을 누르면 API를 가져와서 장전동안에 있는 공적 마스크 판매처를 ListView로 보여줍니다.

그리고 두번째 버튼을 누르면 가져온 공적 마스크 판매처를 구글 맵에 띄워줍니다.

zoom을 설정안해서 첫화면은 크게 보이는데, 확대하면 맨 오른쪽 캡쳐화면과 같이 공적마스크 판매처마다 마커가 표시되어있습니다.

 

공적 마스크 데이터를 사용하면서 코틀린+파이썬+구글맵 3개를 한꺼번에 다뤄봤습니다.

코로나로 집에서만 늘어지다가 오랜만에 재미있게 코딩했습니다.

예쁘게 앱을 하나 만들어서 출시해볼까 생각도 했는데 이미 많은 서비스가 개발되어서 저까지 개발 안해도 될 것 같고 출시한 앱 버그 고치느라 정신이 없어서 포기했습니다.

모두들 노력중인만큼, 빨리 상황이 종식되었으면 합니다🙏


잘못된 내용이 있다면 언제든지 댓글이나 메일로 알려주시면 감사하겠습니다.

이 포스팅이 도움이 되었다면 공감 부탁드립니다.

궁금한 점은 언제든지 댓글 남겨주시면 답변해드리겠습니다:D