+2

Gọi Weather API với Retrofit2 và Coroutines - Phần 1: Get API

Hi mọi người, hôm nay mình sẽ làm một bài post cơ bản về cách Get Api bằng Retrofit2 cùng với Coroutines. Trong bài viết này mình chỉ hướng dẫn các bạn cơ bản về cách để lấy được API bằng Retrofit thôi chứ không nói sâu về lý thuyết nhé, về lý thuyết Retrofit bạn có thể vào link này để tìm hiểu thêm

1. weather API

Về API thì mình sẽ dùng AccuWeather API để get nhé, Accuweather sẽ gọi được 50 lần một ngày với 1 key khi mình xài free nhé 😄, đây là link để mình lấy API Key.

2. Get API với Retrofit2

Bật ViewBinding

android {
    ...
    buildFeatures{
        viewBinding = true
    }
}

Implementation các thư viện vào

Version của retrofit bạn có thể vào link này để xem nhé. còn đây là version của Gson, và cuối cùng là OkHttp3

    implementation 'com.squareup.retrofit2:retrofit:2.9.0'
    // Thư viện này được dùng để parse dữ liệu từ json sang model nhé
    implementation 'com.squareup.retrofit2:converter-gson:2.3.0'
    implementation 'com.squareup.okhttp3:logging-interceptor:3.4.1'

Sau đó bấm Sync và chờ đợi project sync, sau khi đã sync xong thì bắt tay vào chiến thôi =D.

Setup Project

Đầu tiên thì cần cấp quyền internet trong file AndroidManifest.xml, vì gọi api thì cần mạng mà 😃

    <uses-permission android:name="android.permission.INTERNET"/>

Tiếp theo là vào đây để lấy cái url của accuweather, đây sẽ là base url của mình nhé.

    http://dataservice.accuweather.com/

Sau đó thì copy base url với api key vào app/buildGradle thôi

    android {
        ...
        buildTypes {
            ...

            debug {
                debuggable true
                applicationIdSuffix ".debug"
                buildConfigField("String", "BASE_URL", "\"http://dataservice.accuweather.com/\"")
                buildConfigField("String", "API_KEY", "\"xxxxxxxxxxxxxxxxxxxxx\"")
            }
        }
    }

Sau khi Sync thì bạn vào file BuildConfig để check xem 2 biến trên đã được add vào hay chưa nhé

Nếu Sync xong không thấy file này thì bạn vào Build -> Rebuild Project là sẽ có.

Tạo Model

Ok bây giờ tới phần tạo model để chứa dữ liệu được lấy về từ server, vào lại cái link api ở trên copy api key vào, nhập tên một thành phố mà mình muốn lấy dữ liệu và nhấn Send this request

và đây là dữ liệu được trả về

[
  {
    "Version": 1,
    "Key": "4-353981_1_AL",
    "Type": "City",
    "Rank": 11,
    "LocalizedName": "Ho Chi Minh",
    "EnglishName": "Ho Chi Minh City",
    "PrimaryPostalCode": "",
    "Region": {
      "ID": "ASI",
      "LocalizedName": "Asia",
      "EnglishName": "Asia"
    },
    "Country": {
      "ID": "VN",
      "LocalizedName": "Vietnam",
      "EnglishName": "Vietnam"
    },
    "AdministrativeArea": {
      "ID": "SG",
      "LocalizedName": "Ho Chi Minh",
      "EnglishName": "Ho Chi Minh",
      "Level": 1,
      "LocalizedType": "Municipality",
      "EnglishType": "Municipality",
      "CountryID": "VN"
    },
    "TimeZone": {
      "Code": "ICT",
      "Name": "Asia/Ho_Chi_Minh",
      "GmtOffset": 7,
      "IsDaylightSaving": false,
      "NextOffsetChange": null
    },
    "GeoPosition": {
      "Latitude": 10.775,
      "Longitude": 106.702,
      "Elevation": {
        "Metric": {
          "Value": 7,
          "Unit": "m",
          "UnitType": 5
        },
        "Imperial": {
          "Value": 22,
          "Unit": "ft",
          "UnitType": 0
        }
      }
    },
    "IsAlias": true,
    "ParentCity": {
      "Key": "353981",
      "LocalizedName": "Ho Chi Minh City",
      "EnglishName": "Ho Chi Minh City"
    },
    "SupplementalAdminAreas": [],
    "DataSets": [
      "AirQualityCurrentConditions",
      "AirQualityForecasts",
      "Alerts"
    ]
  }
]

rồi bước tiếp theo là tạo class model để chứa dữ liệu trên, nếu bạn là người đủ kiên nhẫn thì bạn có thể tạo model để chứa dữ liệu ở trên bằng cơm, nhưng riêng mình, mình sẽ dùng tool 😄 mình xài tool này nhé, bạn vào File -> Settings -> Plugins rồi kiếm tên tool -> install là xong.

Kết quả sau khi xài tool =) bạn nhớ bỏ 2 dấu [ ] này trong đoạn json khi mà copy vào nhé.

Setup Retrofit

Bây giờ đã có url, model bước tiếp theo sẽ là tạo retrofit để gọi API thôi.

Tạo 1 interface để định nghĩa các http request, cụ thể ở đây là mình sẽ Get API City Search

    interface WeatherService {
        @GET("locations/v1/cities/search")
        fun getLocation(
            @Query("apikey") apiKey: String,
            @Query("q") location: String
        ): Call<ArrayList<WeatherLocation>>
    }

Bây giờ chúng ta sẽ tạo 1 instance Retrofit để sử dụng.

    object RetrofitClient {
    private lateinit var retrofit: Retrofit
    
    fun createService(): WeatherService {
        retrofit = Retrofit.Builder()
            .baseUrl(BuildConfig.BASE_URL)
            .addConverterFactory(GsonConverterFactory.create())
            .build()
        return retrofit.create(WeatherService::class.java)
    }
}

và đây là code trong MainActivity.kt

    lateinit var weatherService: WeatherService
    lateinit var binding: ActivityMainBinding

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        //View binding
        binding = ActivityMainBinding.inflate(layoutInflater)
        setContentView(binding.root)

        //create Retrofit instance
        weatherService = RetrofitClient.createService()

        binding.apply {
            btnGetApi.setOnClickListener {
                val cityName = edtCitySearch.text.toString()
                if(cityName.trim().isNotBlank()) {
                    textInputCity.error = null
                    getLocation(cityName)
                } else {
                    textInputCity.error = "This field is required"
                }
            }
        }
    }

    private fun getLocation(cityName: String) {
        weatherService.getLocation(BuildConfig.API_KEY, cityName)
            .enqueue(object : Callback<ArrayList<WeatherLocation>> {
                override fun onResponse(
                    call: Call<ArrayList<WeatherLocation>>,
                    response: Response<ArrayList<WeatherLocation>>
                ) {
                    Toast.makeText(this@MainActivity, "Successed", Toast.LENGTH_SHORT).show()
                }

                override fun onFailure(call: Call<ArrayList<WeatherLocation>>, t: Throwable) {
                    Toast.makeText(this@MainActivity, "Failed", Toast.LENGTH_SHORT).show()
                }
            })
    }

enqueue() trong code được dùng để gọi api theo dạng bất đồng bộ nên api sẽ không block main thread của bạn và kết quả sẽ được trả về trong CallBack.

Bước tiếp theo là build app và chạy thôi 😄


All Rights Reserved

Viblo
Let's register a Viblo Account to get more interesting posts.