author:wangyimiao

desc:添加网络请求库
master
yimiao 3 years ago
parent d4b6a8a119
commit e7aa8f71cd

@ -1,17 +1,19 @@
plugins { plugins {
id 'com.android.application' id 'com.android.application'
id 'kotlin-android'
id 'kotlin-android-extensions'
id 'kotlin-kapt'
} }
android { android {
compileSdkVersion 30 compileSdkVersion rootProject.ext.android.compileSdkVersion
buildToolsVersion "30.0.3" buildToolsVersion rootProject.ext.android.buildToolsVersion
defaultConfig { defaultConfig {
applicationId "com.yinuo.commonlibtest" minSdkVersion rootProject.ext.android.minSdkVersion
minSdkVersion 23 targetSdkVersion rootProject.ext.android.targetSdkVersion
targetSdkVersion 30 versionCode rootProject.ext.android.versionCode
versionCode 1 versionName rootProject.ext.android.versionName
versionName "1.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
} }
@ -26,6 +28,14 @@ android {
sourceCompatibility JavaVersion.VERSION_1_8 sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8 targetCompatibility JavaVersion.VERSION_1_8
} }
dataBinding {
enabled = true
}
viewBinding {
enabled = true
}
} }
dependencies { dependencies {
@ -34,7 +44,4 @@ dependencies {
implementation 'com.google.android.material:material:1.2.1' implementation 'com.google.android.material:material:1.2.1'
implementation 'androidx.constraintlayout:constraintlayout:2.0.1' implementation 'androidx.constraintlayout:constraintlayout:2.0.1'
implementation project(path: ':commonLib') implementation project(path: ':commonLib')
testImplementation 'junit:junit:4.+'
androidTestImplementation 'androidx.test.ext:junit:1.1.2'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0'
} }

@ -1,26 +0,0 @@
package com.yinuo.commonlibtest;
import android.content.Context;
import androidx.test.platform.app.InstrumentationRegistry;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import org.junit.Test;
import org.junit.runner.RunWith;
import static org.junit.Assert.*;
/**
* Instrumented test, which will execute on an Android device.
*
* @see <a href="http://d.android.com/tools/testing">Testing documentation</a>
*/
@RunWith(AndroidJUnit4.class)
public class ExampleInstrumentedTest {
@Test
public void useAppContext() {
// Context of the app under test.
Context appContext = InstrumentationRegistry.getInstrumentation().getTargetContext();
assertEquals("com.yinuo.commonlibtest", appContext.getPackageName());
}
}

@ -4,11 +4,14 @@ import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle; import android.os.Bundle;
import com.yinuo.commonlibtest.databinding.ActivityMainBinding;
public class MainActivity extends AppCompatActivity { public class MainActivity extends AppCompatActivity {
@Override @Override
protected void onCreate(Bundle savedInstanceState) { protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main); ActivityMainBinding binding = ActivityMainBinding.inflate(getLayoutInflater());
setContentView(binding.getRoot());
} }
} }

@ -1,17 +0,0 @@
package com.yinuo.commonlibtest;
import org.junit.Test;
import static org.junit.Assert.*;
/**
* Example local unit test, which will execute on the development machine (host).
*
* @see <a href="http://d.android.com/tools/testing">Testing documentation</a>
*/
public class ExampleUnitTest {
@Test
public void addition_isCorrect() {
assertEquals(4, 2 + 2);
}
}

@ -23,16 +23,23 @@ android {
debug { debug {
minifyEnabled false minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
buildConfigField 'String', 'BASE_URL_CONFIG_PATH', '"baseUrl.properties"'
} }
release { release {
minifyEnabled true minifyEnabled true
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
buildConfigField 'String', 'BASE_URL_CONFIG_PATH', '"baseUrl.properties"'
} }
} }
compileOptions { compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8 sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8 targetCompatibility JavaVersion.VERSION_1_8
} }
androidExtensions {
// kotlin
experimental = true
}
} }
dependencies { dependencies {
@ -47,6 +54,18 @@ dependencies {
// kotlin // kotlin
implementation rootProject.ext.dependencies.kotlin implementation rootProject.ext.dependencies.kotlin
implementation rootProject.ext.dependencies.kotlin_android implementation rootProject.ext.dependencies.kotlin_android
// okhttp
implementation rootProject.ext.dependencies.okhttp
// retrofit
implementation rootProject.ext.dependencies.retrofit
// retrofitgson
implementation rootProject.ext.dependencies.converter_gson
// rxjava
implementation rootProject.ext.dependencies.rxjava
// rxAndroid
implementation rootProject.ext.dependencies.rxandroid
// retrofitrxjava
implementation rootProject.ext.dependencies.retrofit_rxjava
//luban //luban
implementation rootProject.ext.dependencies.luban implementation rootProject.ext.dependencies.luban

@ -0,0 +1,2 @@
debug1 = https://www.wanandroid.com
debug2 = https://www.baidu.com

@ -0,0 +1,17 @@
package com.yinuo.commonlib
import android.annotation.SuppressLint
import android.content.Context
@SuppressLint("StaticFieldLeak")
object CommonApplication {
private var commonContext: Context? = null
fun intLibs(context: Context) {
commonContext = context
}
fun getContext(): Context? {
return commonContext
}
}

@ -0,0 +1,98 @@
package com.common.commonlib.net
import android.net.ParseException
import android.util.Log
import com.google.gson.JsonParseException
import io.reactivex.Observable
import io.reactivex.Observer
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.disposables.Disposable
import io.reactivex.schedulers.Schedulers
import org.json.JSONException
import retrofit2.HttpException
import java.net.ConnectException
import java.net.SocketTimeoutException
import java.net.UnknownHostException
import javax.net.ssl.SSLHandshakeException
/**
* 请求基类
*/
open class BaseObserve<T> {
/**
* 初始化服务类
*/
fun initService(clazz: Class<T>): T {
return RequestManager.INSTANCE.create(clazz)
}
/**
* 调用接口
* @param observable 可订阅
* @param callBack 请求回调
*/
fun <R> observe(observable: Observable<R>, callBack: RequestCallBack<R>?) {
observable
.subscribeOn(Schedulers.io())
.unsubscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(object : Observer<R> {
override fun onSubscribe(d: Disposable) {
}
override fun onNext(t: R) {
callBack?.onResult(t)
}
override fun onError(e: Throwable) {
e.message?.let { Log.e(TAG, it) }
callBack?.onError(dealError(e))
}
override fun onComplete() {
callBack?.onComplete()
}
})
}
/**
* 处理错误
* @param e 异常
*/
private fun dealError(e: Throwable): String? {
if (e is HttpException) {
return when (e.code()) {
UNAUTHORIZED -> "登录验证过期"
INTERNAL_SERVER_ERROR -> "服务器错误"
FORBIDDEN, NOT_FOUND -> "无效的请求"
REQUEST_TIMEOUT, GATEWAY_TIMEOUT, BAD_GATEWAY, SERVICE_UNAVAILABLE -> e.message()
else -> e.message()
}
} else if (e is ConnectException) {
return "网络连接异常,请检查您的网络状态"
} else if (e is SocketTimeoutException) {
return "网络连接超时,请检查您的网络状态,稍后重试"
} else if (e is UnknownHostException) {
return "网络异常,请检查您的网络状态"
} else if (e is JsonParseException || e is JSONException || e is ParseException) {
return "数据解析错误"
} else if (e is SSLHandshakeException) {
return "网络异常,请检查您的网络状态"
} else if (e is RuntimeException) {
return "运行时异常"
}
return e.message
}
companion object {
const val TAG: String = "BaseLoader"
const val UNAUTHORIZED = 401
const val FORBIDDEN = 403
const val NOT_FOUND = 404
const val REQUEST_TIMEOUT = 408
const val INTERNAL_SERVER_ERROR = 500
const val BAD_GATEWAY = 502
const val SERVICE_UNAVAILABLE = 503
const val GATEWAY_TIMEOUT = 504
}
}

@ -0,0 +1,10 @@
package com.common.commonlib.net
/**
* 请求回调
*/
interface RequestCallBack<T> {
fun onResult(result: T)
fun onError(error: String?)
fun onComplete()
}

@ -0,0 +1,51 @@
package com.common.commonlib.net
import com.yinuo.commonlib.net.interceptor.BaseUrlInterceptor
import com.yinuo.commonlib.net.interceptor.HttpCommonInterceptor
import okhttp3.OkHttpClient
import retrofit2.Retrofit
import retrofit2.adapter.rxjava2.RxJava2CallAdapterFactory
import retrofit2.converter.gson.GsonConverterFactory
import java.util.concurrent.TimeUnit
/**
* 网络请求管理器
*/
enum class RequestManager {
INSTANCE;
/**
* 默认超时时间
*/
private val defaultTimeOut: Long = 5
/**
* 默认读取超时时间
*/
private val defaultReadTimeOut: Long = 10
private var mRetrofit: Retrofit? = null
init {
val builder: OkHttpClient.Builder = OkHttpClient.Builder()
builder.connectTimeout(defaultTimeOut, TimeUnit.SECONDS)
builder.readTimeout(defaultReadTimeOut, TimeUnit.SECONDS)
val commonInterceptor: HttpCommonInterceptor = HttpCommonInterceptor.Builder().build()
builder.addInterceptor(commonInterceptor)
builder.addInterceptor(BaseUrlInterceptor())
mRetrofit = Retrofit.Builder()
.client(builder.build())
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.addConverterFactory(GsonConverterFactory.create())
.baseUrl("https://www.wanandroid.com")
.build()
}
/**
* 创建service
*/
fun <T> create(service: Class<T>): T {
return mRetrofit!!.create(service)
}
}

@ -0,0 +1,21 @@
package com.yinuo.commonlib.net.bean
import android.os.Parcelable
import kotlinx.android.parcel.Parcelize
/**
* 基础响应类
*/
@Parcelize
open class BaseResponse : Parcelable {
var errorCode: Int = 0
var errorMessage: String = ""
fun getMErrorCode(): Int {
return errorCode
}
fun getMErrorMessage(): String {
return errorMessage
}
}

@ -0,0 +1,9 @@
package com.yinuo.commonlib.net.bean
/**
* 请求参数
*/
data class RequestParam(var baseUrl: String) {
var params: Map<String, String>? = null
}

@ -0,0 +1,83 @@
package com.yinuo.commonlib.net.interceptor
import android.text.TextUtils
import android.util.Log
import com.yinuo.commonlib.BuildConfig
import com.yinuo.commonlib.CommonApplication
import okhttp3.HttpUrl
import okhttp3.HttpUrl.Companion.toHttpUrlOrNull
import okhttp3.Interceptor
import okhttp3.Request
import okhttp3.Response
import java.io.BufferedInputStream
import java.util.*
/**
* BaseUrl链接拦截器
*/
class BaseUrlInterceptor : Interceptor {
/**
* 拦截替换BaseUrl
*/
override fun intercept(chain: Interceptor.Chain): Response {
val oldRequest: Request = chain.request()
val requestBuilder: Request.Builder = oldRequest.newBuilder()
val headKey = BASE_URL_KEY
val headValue: String? = oldRequest.header(headKey)
// 判断是否需要替换BaseUrl,不需要则直接跳转
if (TextUtils.isEmpty(headValue)) {
return chain.proceed(chain.request())
}
// 该HEAD只用于替换BaseUrl,将对应的自定义HEAD去除
requestBuilder.removeHeader(headKey)
// 尝试获取新BaseUrl
val newUrlValue = getValueFromProperties(headValue)
val newBaseUrl: HttpUrl? = newUrlValue.toHttpUrlOrNull()
// 获取到新BaseUrl进行替换
return if (newBaseUrl != null) {
val oldHttpUrl: HttpUrl = oldRequest.url
val newUrl = oldHttpUrl.newBuilder()
.scheme(newBaseUrl.scheme)
.host(newBaseUrl.host)
.port(newBaseUrl.port)
.build()
chain.proceed(requestBuilder.url(newUrl).build())
} else {
chain.proceed(chain.request())
}
}
/**
* 通过KEY从配置文件中获取值
*/
private fun getValueFromProperties(key: String?): String {
val prop = Properties()
var value = ""
try {
val context = CommonApplication.getContext()
if (context == null) {
Log.e(TAG, "got context null, please init context!")
return value
}
val mAssets = context.assets
if (mAssets == null) {
Log.e(TAG, "got assets null, please check the assets folder")
}
// 通过输入缓冲流进行读取配置文件
val inputStream =
BufferedInputStream(mAssets.open((BuildConfig.BASE_URL_CONFIG_PATH)))
// 加载输入流
prop.load(inputStream)
// 根据关键字获取value值
value = prop.getProperty(key);
} catch (e: Exception) {
Log.e(TAG, e.toString())
}
return value
}
companion object {
const val TAG = "BaseUrlInterceptor"
const val BASE_URL_KEY = "baseurl"
}
}

@ -0,0 +1,70 @@
package com.yinuo.commonlib.net.interceptor
import okhttp3.Interceptor
import okhttp3.Request
import okhttp3.Response
/**
* 公共请求拦截器
*/
class HttpCommonInterceptor : Interceptor {
/**
* 请求头部参数
*/
var mHeaderHashMap: HashMap<String, String>? = null
/**
* 拦截请求并添加参数
*/
override fun intercept(chain: Interceptor.Chain): Response {
val oldRequest: Request = chain.request()
val requestBuilder: Request.Builder = oldRequest.newBuilder()
requestBuilder.method(oldRequest.method, oldRequest.body)
if (mHeaderHashMap != null && mHeaderHashMap!!.size > 0) {
for (item: Map.Entry<String, String> in mHeaderHashMap!!.entries) {
requestBuilder.addHeader(item.key, item.value)
}
}
return chain.proceed(requestBuilder.build())
}
/**
* builder构造函数
*/
class Builder {
private var mHttpCommonInterceptor: HttpCommonInterceptor? = null
init {
mHttpCommonInterceptor = HttpCommonInterceptor()
}
fun addHeadParams(key: String, value: String): Builder {
mHttpCommonInterceptor?.mHeaderHashMap?.set(key, value)
return this
}
fun addHeadParams(key: String, value: Int): Builder {
mHttpCommonInterceptor?.mHeaderHashMap?.set(key, value.toString())
return this
}
fun addHeadParams(key: String, value: Long): Builder {
mHttpCommonInterceptor?.mHeaderHashMap?.set(key, value.toString())
return this
}
fun addHeadParams(key: String, value: Float): Builder {
mHttpCommonInterceptor?.mHeaderHashMap?.set(key, value.toString())
return this
}
fun addHeadParams(key: String, value: Double): Builder {
mHttpCommonInterceptor?.mHeaderHashMap?.set(key, value.toString())
return this
}
fun build(): HttpCommonInterceptor {
return mHttpCommonInterceptor!!
}
}
}

Binary file not shown.
Loading…
Cancel
Save