日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

android上传头像 sockettimeoutexception,Kotlin - Retrofit2和Rxjava2封装的网络请求类(含图片上传)...

發(fā)布時間:2025/3/20 编程问答 35 豆豆
生活随笔 收集整理的這篇文章主要介紹了 android上传头像 sockettimeoutexception,Kotlin - Retrofit2和Rxjava2封装的网络请求类(含图片上传)... 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

閱讀建議:本文適合熟悉Retrofit與Rxjava2的同學(xué)閱讀,其中也包含一丟丟的RxLifecycle,文中不包含這兩個庫的使用說明。不熟悉RxJava的同學(xué),建議去這里了解,里面包含3篇文章,均通俗易懂。

提示:文中使用的RxJava2的類均是不支持背壓的,即Observable(被觀察者)與Observer(觀察者)。需要背壓策略,請自行替換為對應(yīng)的Flowable(被觀察者)與Subscriber(觀察者)即可。如果想使用Kotlin的一些便利的語法,可以將RxJava依賴換成RxKotlin即可。

開始

1.按慣例先添加依賴:

//Retrofit相關(guān)

compile(['com.squareup.okhttp3:logging-interceptor:3.9.0',//用于查看http請求時的log

'com.squareup.retrofit2:retrofit:2.3.0',

'com.squareup.retrofit2:adapter-rxjava2:2.3.0',

'com.squareup.retrofit2:converter-gson:2.3.0'])

//RxJava相關(guān)

compile(['io.reactivex.rxjava2:rxandroid:2.0.1',

'io.reactivex.rxjava2:rxjava:2.1.3']) //此處可換成'io.reactivex.rxjava2:rxkotlin:2.1.0'

//RxLifecycle相關(guān)

compile(['com.trello.rxlifecycle2:rxlifecycle-kotlin:2.2.0',

'com.trello.rxlifecycle2:rxlifecycle-components:2.2.0'])

2.封裝請求類

為了秉承RxJava的鏈式調(diào)用風格,也為了方便每一個API的調(diào)用操作,創(chuàng)建了一個單例類ApiClient,具體如下:

class ApiClient private constructor() {

lateinit var service: GitHubService

private object Holder {

val INSTANCE = ApiClient()

}

companion object {

val instance by lazy { Holder.INSTANCE }

}

fun init() { //在Application的onCreate中調(diào)用一次即可

val okHttpClient = OkHttpClient().newBuilder()

//輸入http連接時的log,也可添加更多的Interceptor

.addInterceptor(HttpLoggingInterceptor().setLevel(

if (BuildConfig.DEBUG) HttpLoggingInterceptor.Level.BODY

else HttpLoggingInterceptor.Level.NONE

))

.build()

val retrofit = Retrofit.Builder()

.baseUrl("https://api.github.com/") //本文以GitHub API為例

.addConverterFactory(GsonConverterFactory.create())

.addCallAdapterFactory(RxJava2CallAdapterFactory.create())

.client(okHttpClient)

.build()

service = retrofit.create(GitHubService::class.java)

}

}

其中使用GitHub的的API作為測試,GitHubService如下:

interface GitHubService {

//請?zhí)砑酉鄳?yīng)的`API`調(diào)用方法

@GET("users/{user}/repos")

fun listRepos(@Path("user") user: String): Observable> //每個方法的返回值即一個Observable

}

上面的Repo即一個簡單的Kotlin數(shù)據(jù)類,由于字較多,就不貼出來了,具體可去文末Demo地址查找。

3.RESTful API請求響應(yīng)的處理

API的響應(yīng)返回形式有很多種,此處介紹最常見的兩種形式的處理:標準RESTful API與任性的后端寫的API。GitHub提供的API即標準RESTful API。

RESTful API的請求響應(yīng)主要處理狀態(tài)碼與數(shù)據(jù)體,具體封裝如下:

abstract class ApiResponse(private val context: Context) : Observer {

abstract fun success(data: T)

abstract fun failure(statusCode: Int, apiErrorModel: ApiErrorModel)

override fun onSubscribe(d: Disposable) {

LoadingDialog.show(context)

}

override fun onNext(t: T) {

success(t)

}

override fun onComplete() {

LoadingDialog.cancel()

}

override fun onError(e: Throwable) {

LoadingDialog.cancel()

if (e is HttpException) { //連接服務(wù)器成功但服務(wù)器返回錯誤狀態(tài)碼

val apiErrorModel: ApiErrorModel = when (e.code()) {

ApiErrorType.INTERNAL_SERVER_ERROR.code ->

ApiErrorType.INTERNAL_SERVER_ERROR.getApiErrorModel(context)

ApiErrorType.BAD_GATEWAY.code ->

ApiErrorType.BAD_GATEWAY.getApiErrorModel(context)

ApiErrorType.NOT_FOUND.code ->

ApiErrorType.NOT_FOUND.getApiErrorModel(context)

else -> otherError(e)

}

failure(e.code(), apiErrorModel)

return

}

val apiErrorType: ApiErrorType = when (e) { //發(fā)送網(wǎng)絡(luò)問題或其它未知問題,請根據(jù)實際情況進行修改

is UnknownHostException -> ApiErrorType.NETWORK_NOT_CONNECT

is ConnectException -> ApiErrorType.NETWORK_NOT_CONNECT

is SocketTimeoutException -> ApiErrorType.CONNECTION_TIMEOUT

else -> ApiErrorType.UNEXPECTED_ERROR

}

failure(apiErrorType.code, apiErrorType.getApiErrorModel(context))

}

private fun otherError(e: HttpException) =

Gson().fromJson(e.response().errorBody()?.charStream(), ApiErrorModel::class.java)

}

說明:

1.每個響應(yīng)繼承Observer,其中的泛型以適配返回的不同的數(shù)據(jù)體;

2.定義兩個抽象方法success和failure,在使用的時候只需關(guān)注成功和失敗這兩種情況;

3.在onSubscribe即開始請求的時候顯示Loading,在請求完成或出錯時隱藏;

4.在onNext即Observer成功接收數(shù)據(jù)后直接調(diào)用success,在調(diào)用處可直接使用返回的數(shù)據(jù);

5.在onError即請求出錯時處理,此處包含兩種情況:連接服務(wù)器成功但服務(wù)器返回錯誤狀態(tài)碼、網(wǎng)絡(luò)或其它問題。

在錯誤處理中,定義了一個枚舉類ApiErrorType,用于列舉出服務(wù)器定義的錯誤狀態(tài)碼情況:

enum class ApiErrorType(val code: Int, @param: StringRes private val messageId: Int) {

//根據(jù)實際情況進行增刪

INTERNAL_SERVER_ERROR(500, R.string.service_error),

BAD_GATEWAY(502, R.string.service_error),

NOT_FOUND(404, R.string.not_found),

CONNECTION_TIMEOUT(408, R.string.timeout),

NETWORK_NOT_CONNECT(499, R.string.network_wrong),

UNEXPECTED_ERROR(700, R.string.unexpected_error);

private val DEFAULT_CODE = 1

fun getApiErrorModel(context: Context): ApiErrorModel {

return ApiErrorModel(DEFAULT_CODE, context.getString(messageId))

}

}

還定義了一個錯誤消息的的實體類ApiErrorModel(在Kotlin中即為一個數(shù)據(jù)類),用于包含錯誤信息提示用戶或服務(wù)器返回的錯誤信息以提示開發(fā)人員:

data class ApiErrorModel(var status: Int, var message: String)

4.線程與生命周期

RxJava的一大特色即方便的線程切換操作,在請求API中需要進行線程的切換,通常是以下形式(偽代碼):

observable.subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread())

但每個請求都寫一段這個,顯得特別麻煩,所以進行以下簡單封裝:

object NetworkScheduler {

fun compose(): ObservableTransformer {

return ObservableTransformer { observable ->

observable.subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread())

}

}

}

使用的時候簡單搞定,偽代碼如下:

observable.compose(NetworkScheduler.compose())

在Android中,當一個Activity在調(diào)API時onDestroy了,需要取消請求,所以此處引入了RxLifecycle進行管理:

Activity繼承RxAppCompatActivity后,在observable的調(diào)用鏈中加入.bindUntilEvent(this, ActivityEvent.DESTROY)即可,偽代碼如下:

observable.compose(NetworkScheduler.compose())

.bindUntilEvent(this, ActivityEvent.DESTROY) //加入這句

.subscribe(...)

5.使用

以上準備工作完成后,即可開始使用:

首先在Application中初始化ApiClient:

class App : Application() {

override fun onCreate() {

super.onCreate()

ApiClient.instance.init() //這里

}

}

在需要的地方使用ApiClient,如本文Demo,點擊按鈕時,請求數(shù)據(jù),成功后用TextView顯示出來:

class MainActivity : RxAppCompatActivity() {

override fun onCreate(savedInstanceState: Bundle?) {

super.onCreate(savedInstanceState)

setContentView(R.layout.activity_main)

submit.setOnClickListener { fetchRepo() } //按鈕點擊事件

}

private fun fetchRepo() {

//鏈式調(diào)用

ApiClient.instance.service.listRepos(inputUser.text.toString()) //GitHubService中的方法

.compose(NetworkScheduler.compose()) //線程切換處理

.bindUntilEvent(this, ActivityEvent.DESTROY) //生命周期管理

.subscribe(object : ApiResponse>(this) { //對象表達式約等于Java中的匿名內(nèi)部類

override fun success(data: List) { //請求成功,此處顯示一些返回的數(shù)據(jù)

userName.text = data[0].owner.login

repoName.text = data[0].name

description.text = data[0].description

url.text = data[0].html_url

}

override fun failure(statusCode: Int, apiErrorModel: ApiErrorModel) { //請求失敗,此處直接顯示Toast

Toast.makeText(this@MainActivity, apiErrorModel.message, Toast.LENGTH_SHORT).show()

}

})

}

}

效果如下:

效果.gif

6.任性的后端寫的API請求響應(yīng)的處理

這種情況只需要對數(shù)據(jù)類和響應(yīng)處理進行修改即可。有些后端開發(fā)者們,可能將返回體寫成如下形式:

{

"code": "200",

"data": [

{

"name": "Tom",

"age": 12,

"money": 100.5

},

{

"name": "Bob",

"age": 13,

"money": 200.5

}

],

"message": "客戶端請求成功"

}

所有返回的數(shù)據(jù)中,最外層都包裹了一層信息,以表示請求成功或失敗,中間data才是具體數(shù)據(jù),所以定義數(shù)據(jù)類(實體類)時,需要定義成如下形式:

data class ResponseWrapper(var code: Int, var data: T, var message: String)

其中data為泛型,以適配不同的數(shù)據(jù)體。

然后將上文第3點中的ApiResponse修改如下:

abstract class RequestCallback(private val context: Context) : Observer> {

abstract fun success(data: T)

abstract fun failure(statusCode: Int, apiErrorModel: ApiErrorModel)

private object Status {

val SUCCESS = 200

}

override fun onSubscribe(d: Disposable) {

LoadingDialog.show(context)

}

override fun onNext(t: ResponseWrapper) {

if (t.code == Status.SUCCESS) {

success(t.data)

return

}

val apiErrorModel: ApiErrorModel = when (t.code) {

ApiErrorType.INTERNAL_SERVER_ERROR.code ->

ApiErrorType.INTERNAL_SERVER_ERROR.getApiErrorModel(context)

ApiErrorType.BAD_GATEWAY.code ->

ApiErrorType.BAD_GATEWAY.getApiErrorModel(context)

ApiErrorType.NOT_FOUND.code ->

ApiErrorType.NOT_FOUND.getApiErrorModel(context)

else -> ApiErrorModel(t.code, t.message)

}

failure(t.code, apiErrorModel)

}

override fun onComplete() {

LoadingDialog.cancel()

}

override fun onError(e: Throwable) {

LoadingDialog.cancel()

val apiErrorType: ApiErrorType = when (e) {

is UnknownHostException -> ApiErrorType.NETWORK_NOT_CONNECT

is ConnectException -> ApiErrorType.NETWORK_NOT_CONNECT

is SocketTimeoutException -> ApiErrorType.CONNECTION_TIMEOUT

else -> ApiErrorType.UNEXPECTED_ERROR

}

failure(apiErrorType.code, apiErrorType.getApiErrorModel(context))

}

}

使用方式:

1.先在GitHubService.kt中新增如下方法:

@GET("xxx/xxx")

fun repos(@Path("user") user: String): Observable>>

2.之后與上文第5點相同。

2017年10月13日更新—增加上傳圖片的方法

新增OkHttpUtil.kt,用于上傳圖片,代碼如下:

object OkHttpUtil {

fun createTextRequestBody(source: String): RequestBody

= RequestBody.create(MediaType.parse("text/plain"), source)

fun createPartWithAllImageFormats(requestKey: String, file: File): MultipartBody.Part

= MultipartBody.Part

.createFormData(requestKey, file.name, RequestBody.create(MediaType.parse("image/*"), file))

}

使用方式:

1.先在GitHubService.kt中新增如下方法:

@Multipart

@POST("xxxx/xxxx") //This is imaginary URL

fun updateImage(@Part("name") name: RequestBody,

@Part image: MultipartBody.Part): Observable

2.在需要的地方使用:

ApiClient.instance.service.updateImage(OkHttpUtil.createTextRequestBody("Bob"),

OkHttpUtil.createPartWithAllImageFormats("avatar",file)) //此處調(diào)用OkHttpUtil中的方法

.compose(NetworkScheduler.compose())

.bindUntilEvent(this,ActivityEvent.DESTROY)

.subscribe(object : ApiResponse(this) {

override fun success(data: UserInfo) {

//Do something

}

override fun failure(statusCode: Int, apiErrorModel: ApiErrorModel) {

//Do something

}

})

最后

希望本文對您有所幫助。如果文中有什么表述不當?shù)牡胤?#xff0c;請在下方評論,以幫助我改正。

總結(jié)

以上是生活随笔為你收集整理的android上传头像 sockettimeoutexception,Kotlin - Retrofit2和Rxjava2封装的网络请求类(含图片上传)...的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。