Skip to content

Commit 50cf153

Browse files
authored
Create README.md
1 parent deaafef commit 50cf153

File tree

1 file changed

+347
-0
lines changed

1 file changed

+347
-0
lines changed

README.md

Lines changed: 347 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,347 @@
1+
# KotlinFrameWork
2+
> 本实例封装网络核心库以及重要核心逻辑
3+
4+
## 开始
5+
6+
### 1.app模块:
7+
#### 添加依赖
8+
```gradle
9+
###### retrofit相关
10+
implementation 'com.squareup.okhttp3:logging-interceptor:3.10.0'
11+
implementation 'com.squareup.retrofit2:adapter-rxjava2:2.5.0'
12+
implementation 'com.squareup.retrofit2:retrofit:2.5.0'
13+
###### rxjava2
14+
implementation 'io.reactivex.rxjava2:rxandroid:2.1.1'
15+
###### rxlifecycle
16+
implementation 'com.trello.rxlifecycle2:rxlifecycle-kotlin:2.2.0'
17+
implementation 'com.trello.rxlifecycle2:rxlifecycle-components:2.2.0'
18+
```
19+
20+
**NOTE**:可以去[Retrofit](https://github.com/square/retrofit)[Rxjava2(RxAndroid)](https://github.com/ReactiveX/RxAndroid)[okhttp](https://github.com/square/okhttp)[RxLifecycle](https://github.com/trello/RxLifecycle),查询最新版本号。
21+
22+
### 2.net库之封装请求类
23+
为了秉承`RxJava`的链式调用风格,也为了方便每一个`API`的调用操作,创建了一个单例类`ApiClient`,具体如下:
24+
```kotlin
25+
class RetrofitManager private constructor() {
26+
27+
// lateinit var apiService: ApiService
28+
lateinit var retrofit:Retrofit
29+
30+
/**
31+
* 单例模式
32+
*/
33+
companion object {
34+
val instance: RetrofitManager by lazy(mode = LazyThreadSafetyMode.SYNCHRONIZED) {
35+
36+
RetrofitManager()
37+
}
38+
}
39+
40+
fun init(string: String) {
41+
val okHttpClient =
42+
OkHttpClient.Builder()
43+
.addInterceptor(HttpLoggingInterceptor().setLevel(
44+
if (BuildConfig.DEBUG) HttpLoggingInterceptor.Level.BODY
45+
else HttpLoggingInterceptor.Level.NONE))
46+
.connectTimeout(5,TimeUnit.SECONDS)
47+
.readTimeout(5,TimeUnit.SECONDS)
48+
.writeTimeout(5,TimeUnit.SECONDS)
49+
.build()
50+
retrofit = Retrofit.Builder()
51+
.baseUrl(string)
52+
.addConverterFactory(GsonConverterFactory.create())
53+
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
54+
.client(okHttpClient)
55+
.build()
56+
57+
// apiService = retrofit.create(ApiService::class.java)
58+
59+
}
60+
61+
/**
62+
* 动态代理模式,创建请求接口类
63+
* @param tClass
64+
* @param <T>
65+
* @return
66+
</T> */
67+
fun <T> createService(tClass: Class<T>): T {
68+
69+
return retrofit.create(tClass)
70+
}
71+
}
72+
```
73+
其中接口声明类:GitHubService如下:
74+
```kotlin
75+
/**
76+
* 接口声明类
77+
*/
78+
interface ApiService{
79+
/**
80+
* 登录
81+
*/
82+
@POST
83+
@FormUrlEncoded
84+
fun login(@Url string: String, @Field("phone") mobile:String, @Field("pwd")pwd: String): Observable<UserBean>
85+
86+
}
87+
```
88+
上面的`UserBean`即一个简单的`Kotlin`数据类,可以去[这里](https://github.com/ZYRzyr/ApiClient/tree/master/app/src/main/java/com/zyr/apiclient/data)查看。
89+
90+
### 3.支持`RESTful API`请求响应的处理
91+
`API`的响应返回形式有很多种,此处介绍最常见的两种形式的处理:标准`RESTful API``任性的后端写的API`
92+
93+
请求响应主要处理状态码与数据体,具体封装如下:
94+
```kotlin
95+
/**
96+
* 封装响应数据,统一异常处理
97+
*/
98+
abstract class NetResponseObserver<T>(private val context: Context):Observer<T>{
99+
100+
/**
101+
* 事件接收完毕
102+
*/
103+
override fun onComplete() {
104+
LoadingDialog.cancel()
105+
}
106+
107+
/**
108+
* 订阅事件的回调
109+
*/
110+
override fun onSubscribe(d: Disposable) {
111+
LoadingDialog.show(context)
112+
}
113+
114+
/**
115+
* 接收事件
116+
*/
117+
override fun onNext(t: T) {
118+
success(t)
119+
}
120+
121+
/**
122+
* 成功的回调
123+
*/
124+
abstract fun success(data: T)
125+
126+
/**
127+
* 失败的回调
128+
*/
129+
abstract fun failure(statusCode: Int, apiErrorModel: ApiErrorModel)
130+
131+
/**
132+
* 异常处理
133+
*/
134+
override fun onError(e: Throwable) {
135+
LoadingDialog.cancel()
136+
if (e is HttpException) {
137+
val apiErrorModel: ApiErrorModel = when (e.code()) {
138+
ApiErrorType.INTERNAL_SERVER_ERROR.code ->
139+
ApiErrorType.INTERNAL_SERVER_ERROR.getApiErrorModel(context)
140+
ApiErrorType.BAD_GATEWAY.code ->
141+
ApiErrorType.BAD_GATEWAY.getApiErrorModel(context)
142+
ApiErrorType.NOT_FOUND.code ->
143+
ApiErrorType.NOT_FOUND.getApiErrorModel(context)
144+
else -> otherError(e)
145+
146+
}
147+
failure(e.code(), apiErrorModel)
148+
return
149+
}
150+
151+
val apiErrorType: ApiErrorType = when (e) {
152+
is UnknownHostException -> ApiErrorType.NETWORK_NOT_CONNECT
153+
is ConnectException -> ApiErrorType.NETWORK_NOT_CONNECT
154+
is SocketTimeoutException -> ApiErrorType.CONNECTION_TIMEOUT
155+
else -> ApiErrorType.UNEXPECTED_ERROR
156+
}
157+
failure(apiErrorType.code, apiErrorType.getApiErrorModel(context))
158+
159+
}
160+
private fun otherError(e: HttpException) =
161+
Gson().fromJson(e.response().errorBody()?.charStream(), ApiErrorModel::class.java)
162+
163+
}
164+
```
165+
**说明** :
166+
167+
1.每个响应继承`Observer`,其中的`泛型`以适配返回的不同的数据体;
168+
169+
2.定义两个抽象方法`success``failure`,在使用的时候只需关注成功和失败这两种情况;
170+
171+
3.在`onSubscribe`即开始请求的时候显示`Loading`,在请求完成或出错时隐藏;
172+
173+
4.在`onNext``Observer`成功接收数据后直接调用`success`,在调用处可直接使用返回的数据;
174+
175+
5.在`onError`即请求出错时处理,此处包含两种情况:连接服务器成功但服务器返回错误状态码、网络或其它问题。
176+
177+
在错误处理中,定义了一个枚举类`ApiErrorType`,用于列举出服务器定义的错误状态码情况:
178+
```kotlin
179+
/**
180+
* 响应状态码处理
181+
*/
182+
enum class ApiErrorType(val code: Int, @param: StringRes private val messageId: Int) {
183+
//灵活定制
184+
INTERNAL_SERVER_ERROR(500, R.string.service_error),
185+
BAD_GATEWAY(502, R.string.service_error),
186+
NOT_FOUND(404, R.string.not_found),
187+
CONNECTION_TIMEOUT(408, R.string.timeout),
188+
NETWORK_NOT_CONNECT(499, R.string.network_wrong),
189+
UNEXPECTED_ERROR(700, R.string.unexpected_error);
190+
191+
private val DEFAULT_CODE = 1
192+
193+
fun getApiErrorModel(context: Context): ApiErrorModel {
194+
return ApiErrorModel(DEFAULT_CODE, context.getString(messageId))
195+
}
196+
}
197+
```
198+
还定义了一个错误消息的的实体类`ApiErrorModel`(在`Kotlin`中即为一个数据类),用于包含错误信息提示用户或服务器返回的错误信息以提示开发人员:
199+
```kotlin
200+
data class ApiErrorModel(var status: Int, var message: String)
201+
```
202+
203+
### 4.线程与生命周期
204+
`RxJava`的一大特色即方便的线程切换操作,在请求`API`中需要进行线程的切换,通常是以下形式(伪代码):
205+
```kotlin
206+
observable.subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread())
207+
```
208+
但每个请求都写一段这个,显得特别麻烦,所以进行以下简单封装:
209+
```kotlin
210+
/**
211+
* 线程调度器
212+
*/
213+
object NetScheduler{
214+
fun <T> compose():ObservableTransformer<T,T>{
215+
216+
return ObservableTransformer {
217+
observable -> observable.subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread())
218+
}
219+
}
220+
}
221+
```
222+
使用的时候简单搞定,伪代码如下:
223+
```kotlin
224+
observable.compose(NetScheduler.compose())
225+
```
226+
`Android`中,当一个`Activity`在调`API``onDestroy`了,需要取消请求,所以此处引入了`RxLifecycle`进行管理:
227+
`Activity`继承`RxAppCompatActivity`后,在`observable`的调用链中加入`.bindUntilEvent(this, ActivityEvent.DESTROY)`即可,伪代码如下:
228+
```kotlin
229+
observable.compose(NetScheduler.compose())
230+
.bindUntilEvent(this, ActivityEvent.DESTROY) //加入这句
231+
.subscribe(...)
232+
```
233+
234+
### 5.使用
235+
在以上准备工作完成后,即可开始使用:
236+
237+
首先在`Application`中初始化`ApiClient`
238+
```kotlin
239+
class App : Application() {
240+
override fun onCreate() {
241+
super.onCreate()
242+
RetrofitManager.instance.init(Api.BASE_URL)
243+
}
244+
}
245+
```
246+
247+
在需要的地方使用`ApiClient`,点击按钮时,请求数据,成功后用`TextView`显示出来:
248+
```kotlin
249+
class MainActivity : RxAppCompatActivity(), View.OnClickListener {
250+
251+
252+
253+
override fun onCreate(savedInstanceState: Bundle?) {
254+
super.onCreate(savedInstanceState)
255+
setContentView(R.layout.activity_main)
256+
initView()
257+
258+
}
259+
260+
private fun initView() {
261+
262+
login.setOnClickListener(this)
263+
264+
}
265+
266+
/**
267+
* 登录测试
268+
*/
269+
fun login() {
270+
271+
//链式调用
272+
RetrofitManager.instance.createService(ApiService::class.java).login(Api.LOGIN_URL,"18612991023","111111")
273+
.compose(NetScheduler.compose())
274+
.bindUntilEvent(this, ActivityEvent.DESTROY)
275+
.subscribe(object : NetResponseObserver<UserBean>(this){
276+
override fun success(data: UserBean) {
277+
Toast.makeText(this@MainActivity,data.result.phone,Toast.LENGTH_SHORT).show()
278+
}
279+
280+
override fun failure(statusCode: Int, apiErrorModel: ApiErrorModel) {
281+
282+
}
283+
284+
})
285+
286+
}
287+
288+
/**
289+
* 点击事件
290+
*/
291+
override fun onClick(v: View?) {
292+
when (v!!.id) {
293+
R.id.login -> login()
294+
R.id.reg -> reg()
295+
}
296+
}
297+
298+
/**
299+
* 注册测试
300+
*/
301+
private fun reg() {
302+
TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
303+
}
304+
}
305+
```
306+
307+
308+
### 6.`任性的后端写的API`请求响应的处理
309+
这种情况只需要对数据类和响应处理进行修改即可。有些后端开发者们,可能将返回体写成如下形式:
310+
```json
311+
{
312+
"result": {
313+
"headPic": "http://mobile.bwstudent.com/images/small/head_pic/2019-02-26/20190226233015.jpeg",
314+
"nickName": "Jr_09b24",
315+
"phone": "18612991023",
316+
"sessionId": "1553950250180251",
317+
"sex": 1,
318+
"userId": 251
319+
},
320+
"message": "登录成功",
321+
"status": "0000"
322+
}
323+
```
324+
所有返回的数据中,最外层都包裹了一层信息,以表示请求成功或失败,中间`data`才是具体数据,所以定义数据类(实体类)时,需要定义成如下形式:
325+
```kotlin
326+
/**
327+
* 实体类:通过jsontokotlin插件生成
328+
*/
329+
data class UserBean(
330+
val message: String,
331+
val result: Result,
332+
val status: String
333+
)
334+
335+
data class Result(
336+
val headPic: String,
337+
val nickName: String,
338+
val phone: String,
339+
val sessionId: String,
340+
val sex: Int,
341+
val userId: Int
342+
)
343+
```
344+
345+
**2019年3月31日更新**
346+
347+
后续新增上传图片的方法,敬请期待

0 commit comments

Comments
 (0)