目次
レトロフィットの概要
RetrofitはSquare社が開発したネットワークライブラリですが、OkHttpとは位置づけが全く異なります。
OkHttp は基礎となる通信の実現に重点を置いているのに対し、Retrofit は上位インターフェイスのカプセル化に重点を置いています。
実際、Retrofit は、OkHttp に基づいて Square によってさらに開発されたアプリケーション層のネットワーク通信ライブラリであり、ネットワーク操作によりオブジェクト指向の考え方を使用できるようになります。
Retrofit プロジェクトのホームページのアドレスは次のとおりです。
https://github.com/square/retrofit
依存関係を追加する
implementation 'com.squareup.retrofit2:retrofit:2.9.0'
ネットワーク権限を追加する
<uses-permission android:name="android.permission.INTERNET" />
レトロフィットの基本的な使い方
1. Http インターフェースに基づいて kotlin インターフェースを作成します
interface HttpbinService {
@GET("get")
fun get(@Query("userName")userName: String,@Query("password") pwd: String):Call<ResponseBody>
@POST("post")
@FormUrlEncoded
fun post(@Field("userName")userName:String, @Field("password")pwd:String):Call<ResponseBody>
}
2. Retrofit オブジェクトを作成し、インターフェイス実装クラス オブジェクトを生成します。
val retrofit = Retrofit.Builder().baseUrl("https://www.httpbin.org/").build()
val httpbinService: HttpbinService = retrofit.create(HttpbinService::class.java)
3. インターフェース実装クラスオブジェクトは、対応するメソッドを呼び出して応答を取得します。
val call: retrofit2.Call<ResponseBody> = httpbinService.post("xxx", "xxx")
call.enqueue(object : retrofit2.Callback<ResponseBody> {
//请求完成
override fun onResponse(call: Call<ResponseBody>, response: Response<ResponseBody>) {
try {
Log.e("data", "${response.body()?.string()}")
} catch (e: Exception) {
e.printStackTrace()
}
}
//请求失败
override fun onFailure(call: Call<ResponseBody>, t: Throwable) {
TODO("Not yet implemented")
}
})
後付けに関する注意事項
メソッドのアノテーション: @GET、@POST、@PUT、@DELECTE、@PATH、@HEAD、@OPTIONS、@HTTP
マーカー注釈: @FormUrlEncoded、@Multiparty、@Streaming
パラメーターの注釈: @Query、@QueryMap、@Body、@Field、@FieldMap、@Part、@PartMap
その他のアノテーション: @Path、@Header、@Headers、@Url
(1) @GET
https://www.httpbin.org/get
@GET("get")
fun get():Call<ResponseBody>
ここでは @GET アノテーションが使用されています。これは、get() メソッドが呼び出されるときに、Retrofit が GET リクエストを開始し、リクエストのアドレスが @GET アノテーションで渡した特定のパラメータであることを意味します。さらに、get() メソッドの戻り値は、Retrofit の組み込み Call タイプとして宣言する必要があり、ジェネリック タイプは、サーバー応答データをどのオブジェクトに変換するかを指定するために使用されます。
(2) @GET、@Query
https://www.httpbin.org/get?userName=<ユーザー名>&パスワード=<パスワード>
@GET("get")
fun get(@Query("userName")userName: String,@Query("password") pwd: String):Call<ResponseBody>
ここでは、userName と pwd の 2 つのパラメータが get メソッドに追加され、@Query を使用してそれらの宣言が行われるため、ネットワーク リクエストが開始されると、Retrofit はこれら 2 つのパラメータを GET リクエストの形式でリクエスト アドレスに自動的に構築します。中間のパラメータを使用します。
(3)@POST、@FormUrlEncoded、@Field
@POST("post")
@FormUrlEncoded
fun post(@Field("userName")userName:String, @Field("password")pwd:String):Call<ResponseBody>
ここでは @POST アノテーションが使用されています。これは、post() メソッドが呼び出されるときに、Retrofit が POST リクエストを開始し、要求されたアドレスが @POST アノテーションで渡した特定のパラメータであることを意味します。POST リクエストにパラメータがある場合は、リクエスト エンティティがフォームであることを示す @FormUrlEncoded アノテーションを追加する必要があり、各キーと値のペアには @Field アノテーションを付ける必要があります。
@POST("post")
@FormUrlEncoded
fun post(@Field("userName")userName:String, @Field("password")pwd:String):Call<ResponseBody>
(4) @パス
@POST("{id}")
@FormUrlEncoded
fun postInPath(@Path("id")path:String,@Field("userName")userName:String, @Field("password")pwd:String):Call<ResponseBody>
POST アノテーションで指定されたインターフェイス アドレスでは、ここで {id} プレースホルダーが使用され、その後パス パラメーターが postInPath メソッドに追加され、@Path{"id"} アノテーションを使用してこのパラメーターが宣言されます。このようにして、リクエストを開始するために postInPath メソッドが呼び出されるとき、Retrofit は自動的に id パラメータの値をプレースホルダに置き換えて、正当なリクエスト アドレスを形成します。
(5)@HTTP
@HTTP(method = "GET", path = "get", hasBody = true)
fun http(@Query("username")userName: String,@Query("password") pwd: String):Call<ResponseBody>
@HTTP アノテーション、リクエスト メソッドをメソッド (大文字と小文字に注意) で設定、ネットワーク リクエスト アドレスをパスで設定、hasBody にリクエスト ボディがあるかどうか。
(6)@本体
@POST("post")
fun postBody(@Body body:RequestBody):Call<ResponseBody>
POST リクエストに @Body アノテーションを追加すると、@Body はカスタム タイプのデータをサーバーに渡すことができます。パラメータの型を宣言したらどうなるでしょうか?
@POST("post")
fun postBody(@Body body:Data):Call<ResponseBody>
postBody メソッドで Data タイプのパラメータを宣言することで、Retrofit が POST リクエストを送信すると、Data オブジェクト内のデータが自動的に JSON 形式のテキストに変換され、HTTP リクエストの本文部分に挿入されます。サーバーはリクエストを受信します。後でこの部分のみを解析する必要があります。
(@Body アノテーションは @FormUrlEncoded および @Multiparty では使用できません)
(7)@ヘッダー、@ヘッダー
@Headers("os:android","version:1.0")
@POST("post")
fun postWithHeaders( @Header("a") a:String):Call<ResponseBody>
ヘッダー宣言を静的に追加し、@Headers を使用します
ヘッダー宣言を動的に追加、@Header を使用
(8)@URL
@POST
fun postUrl(@Url url:String):Call<ResponseBody>
@Url アノテーションはネットワーク インターフェイス アドレスを書き換えます
後付け用コンバータ
サーバーからの応答を受信した後、OkHttp と Retrofit はどちらも String 型のデータしか受信できません。実際の開発では、文字列を解析して、サーバーの応答などのオブジェクトに変換する必要があることがよくあります。データは JSON の文字列です。フォーマットに変換したら、GSON ライブラリを使用してシリアル化操作を完了できます。Retrofit は、応答で自動データ変換を完了できるように複数のコンバーターを提供します。JSON 解析を例に挙げます。
依存関係を追加する
implementation 'com.squareup.retrofit2:converter-gson:2.6.1'
Retrofit では GSON を使用して JSON データをオブジェクトに変換するため、新しいクラスを作成する必要があります
class App(val id:String,val name:String,val price:Double,val imagePath:String) {
}
JSONデータを取得するための新しいインターフェースを作成します
interface AppService {
@GET("get_JsonArray.json")
fun getAppData(): Call<List<App>>
}
ここでのサーバーのインターフェイスは HTTP であるため、Android 9.0 システム以降、アプリケーションはデフォルトで HTTPS タイプのネットワーク リクエストの使用を許可しており、現在使用している Apache サーバーは HTTP を使用しているため、ネットワーク セキュリティの設定が必要です。
<アプリケーション
アンドロイド:allowBackup="true"
android:dataExtractionRules="@xml/data_extraction_rules"
android:fullBackupContent="@xml/backup_rules"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/Theme.OkhttpRetrofit"
ツール:targetApi="31"
android:networkSecurityConfig="@xml/network_config" >
新しいnetwork_config.xml ファイル を作成します
<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
<base-config cleartextTrafficPermitted="true">
<trust-anchors>
<certificates src="system" />
</trust-anchors>
</base-config>
</network-security-config>
最後に、次のコードを使用して Retrofit リクエストを開始します。
val retrofit=Retrofit.Builder()
.baseUrl("http://10.0.2.2/")
.addConverterFactory(GsonConverterFactory.create())
.build()
val appService:AppService=retrofit.create(AppService::class.java)
appService.getAppData().enqueue( object:retrofit2.Callback<List<App>>{
override fun onResponse(
call: retrofit2.Call<List<App>>,
response: retrofit2.Response<List<App>>
) {
val list=response.body()
if(list!=null){
for(a in list){
Log.e("data","id=${a.id} name=${a.name} price=${a.price} imagePath=${a.imagePath}")
}
}
}
override fun onFailure(call: retrofit2.Call<List<App>>, t: Throwable) {
t.printStackTrace()
}
})
ファイルのアップロードとダウンロード
ファイルをアップロードする
fun uploadFileTest(){
thread{
try {
val retrofit = Retrofit.Builder().baseUrl("https://www.httpbin.org/").build()
val uploadService: UploadService = retrofit.create(UploadService::class.java)
val file=File(externalCacheDir,"a.txt")
if (!file.exists()){
file.createNewFile();
}
val part:MultipartBody.Part=MultipartBody.Part.createFormData("file",file.name,file.asRequestBody("text/plain".toMediaType()))
val call=uploadService.upload(part)
Log.e("uploadFileTest","${call.execute().body()?.string()}")
}catch (e:Exception){
e.printStackTrace()
}
}
}
ダウンロードファイル
//下载文件
fun downloadTest(){
thread {
try {
val retrofit = Retrofit.Builder().baseUrl("https://www.httpbin.org/").build()
val uploadService: UploadService = retrofit.create(UploadService::class.java)
val response=uploadService.downloaduri("https://dl2.xmind.cn/Xmind-for-Windows-x64bit-22.11.2677.exe").execute()
val inputStream=response.body()?.byteStream()
val file=openFileOutput("data111",Context.MODE_PRIVATE)
val bis = BufferedInputStream(inputStream)
val buffer = ByteArray(4096)
var len: Int
while (((bis.read(buffer)).also { len = it }) != -1) {
file.write(buffer, 0, len)
}
bis.close()
}catch (e:Exception){
e.printStackTrace()
}
}
}