Retrofit test with interceptor, clear communication and show data to TextView
Retrofit is not a simplest way to create communication from Android and API, from .NET-developer point of View this is HttpClient with embedded deserializer like newtonsoft. In other case Retrofit can not allow analyze DISCO endpoint or /help endpoint of API and can not build interface and classes automatically, you must define and describe endpoint manually by own hand. This combination of function (compose JSON converter with HTTPClient to one package but automatically building API interface classes is absent at all) look strange for .NET Developer, but in Android platform this is standard point of view.
However, there are more familiar solution for .NET Developer - Volley, see detail instruction how to work with Volley for example in this video https://www.youtube.com/watch?v=xPi-z3nOcn8.
In this page I describe how to use Retrofit step-by-step. Full code has been published to github https://github.com/Alex-1347/RetrofitTest
- Create empty project.
- Set up project property.
- Add project to GIT tracking.
- Add Retrofit library to project https://github.com/square/retrofit.
1: plugins {
2: id 'com.android.application'
3: id 'kotlin-android'
4: }
5:
6: android {
7: compileSdkVersion 30
8: buildToolsVersion "30.0.3"
9:
10: defaultConfig {
11: applicationId "com.example.retrofittest"
12: minSdkVersion 30
13: targetSdkVersion 30
14: versionCode 1
15: versionName "1.0"
16:
17: testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
18: }
19:
20: buildTypes {
21: release {
22: minifyEnabled false
23: proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
24: }
25: }
26: compileOptions {
27: sourceCompatibility JavaVersion.VERSION_1_8
28: targetCompatibility JavaVersion.VERSION_1_8
29: }
30: kotlinOptions {
31: jvmTarget = '1.8'
32: }
33: }
34:
35: dependencies {
36:
37: implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
38: implementation 'androidx.core:core-ktx:1.3.2'
39: implementation 'androidx.appcompat:appcompat:1.2.0'
40: implementation 'com.google.android.material:material:1.3.0'
41: implementation 'androidx.constraintlayout:constraintlayout:2.0.4'
42: implementation 'com.squareup.retrofit2:retrofit:2.9.0'
43: implementation 'com.squareup.retrofit2:converter-gson:2.9.0'
44: implementation 'com.squareup.okhttp3:logging-interceptor:4.9.1'
45: testImplementation 'junit:junit:4.+'
46: androidTestImplementation 'androidx.test.ext:junit:1.1.2'
47: androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0'
48: }
- Set permission to application - clearCommunication and uses
1: <?xml version="1.0" encoding="utf-8"?>
2: <manifest xmlns:android="http://schemas.android.com/apk/res/android"
3: package="com.example.retrofittest">
4:
5: <application
6: android:allowBackup="true"
7: android:icon="@mipmap/ic_launcher"
8: android:label="@string/app_name"
9: android:roundIcon="@mipmap/ic_launcher_round"
10: android:supportsRtl="true"
11: android:usesCleartextTraffic="true"
12: android:theme="@style/Theme.RetrofitTest">
13: <activity android:name=".MainActivity">
14: <intent-filter>
15: <action android:name="android.intent.action.MAIN" />
16:
17: <category android:name="android.intent.category.LAUNCHER" />
18: </intent-filter>
19: </activity>
20: </application>
21: <uses-permission android:name="android.permission.INTERNET" />
22: <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
23: <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
24: <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
25: </manifest>
- Create activity (form)
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: android:padding="8dp"
8: tools:context=".MainActivity">
9:
10: <androidx.core.widget.NestedScrollView
11: android:layout_width="match_parent"
12: android:layout_height="match_parent">
13:
14: <TextView
15: android:id="@+id/text_view_result"
16: android:textColor="@color/black"
17: android:layout_width="wrap_content"
18: android:layout_height="wrap_content"
19: app:layout_constraintBottom_toBottomOf="parent"
20: app:layout_constraintLeft_toLeftOf="parent"
21: app:layout_constraintRight_toRightOf="parent"
22: app:layout_constraintTop_toTopOf="parent" />
23:
24: </androidx.core.widget.NestedScrollView>
25:
26: </androidx.constraintlayout.widget.ConstraintLayout>
- Check data and create interface.
1: package com.example.retrofittest
2:
3: public class OneItem {
4: public var City: String=""
5: public var CityID: String=""
6: public var Country: String=""
7: }
This is main point, this interface allow us Android Studio analyzing and intelliSense and support type reference to data.
1: package com.example.retrofittest
2:
3: import retrofit2.Call
4: import retrofit2.http.*
5:
6: interface JsonPlaceholder {
7: @GET("GetCities")
8: fun GetCities(): Call<MutableList<OneItem>>
9: }
- And finally create program.
- Start program and debug it.
1: package com.example.retrofittest
2:
3: import androidx.appcompat.app.AppCompatActivity
4: import android.os.Bundle
5: import android.widget.TextView
6: import okhttp3.OkHttpClient
7: import okhttp3.logging.HttpLoggingInterceptor
8: import retrofit2.Call
9: import retrofit2.Callback
10: import retrofit2.Response
11: import retrofit2.Retrofit
12: import retrofit2.converter.gson.GsonConverterFactory
13:
14: class MainActivity : AppCompatActivity() {
15:
16: override fun onCreate(savedInstanceState: Bundle?) {
17: super.onCreate(savedInstanceState)
18: setContentView(R.layout.activity_main)
19:
20: val Res = findViewById(R.id.text_view_result) as TextView
21:
22: //logging https://stackoverflow.com/questions/32514410/logging-with-retrofit-2
23: val Logger = HttpLoggingInterceptor()
24: Logger.setLevel(HttpLoggingInterceptor.Level.BODY)
25: val Client = OkHttpClient.Builder().addInterceptor(Logger).build()
26:
27: val RF: Retrofit = Retrofit.Builder()
28: .baseUrl("http://192.168.0.102/Backend/LocationService.svc/") //
29: .client(Client)
30: .addConverterFactory(GsonConverterFactory.create())
31: .build()
32:
33: Res.setText(RF.baseUrl().toString() + System.lineSeparator())
34:
35: val SRV = RF.create(JsonPlaceholder::class.java)
36:
37: val CityList = SRV.GetCities()
38:
39: //another way - https://stackoverflow.com/questions/43233025/use-retrofit-methods-more-expressive-way
40: CityList.enqueue(object : Callback<MutableList<OneItem>> {
41: override fun onFailure(call: Call<MutableList<OneItem>>?, t: Throwable?) {
42: if (t != null) {
43: Res.setText(t.message.toString())
44: }
45: }
46:
47: override fun onResponse(
48: call: Call<MutableList<OneItem>>?,
49: response: Response<MutableList<OneItem>>?
50: ) {
51: if (response != null) {
52: if (!response.isSuccessful) {
53: Res.setText(response.code().toString())
54: return
55: } else {
56: val DT = response.body()
57: if (DT != null) {
58: val Str1=StringBuilder()
59: //or more correctly StringBuilder
60: DT.forEach { one -> Str1.append( "${one.City}(${one.Country})${System.lineSeparator()}" )}
61: Res.setText(Str1.toString())
62: }
63: }
64: }
65: }
66: })
67: }
68: }
|