重慶優(yōu)化網(wǎng)站推廣seo點(diǎn)擊
一、Retrofit2
Square公司推出的Retrofit2庫(kù)(https://square.github.io/retrofit/),改變了網(wǎng)絡(luò)訪問的方式。它實(shí)現(xiàn)了網(wǎng)絡(luò)請(qǐng)求的封裝。Retrofit庫(kù)采用回調(diào)處理方式,使得通過接口提交請(qǐng)求和相應(yīng)的參數(shù)的配置,就可以獲得對(duì)應(yīng)的響應(yīng),并可以將響應(yīng)獲得的數(shù)據(jù)解析成特定的數(shù)據(jù)格式,例如將JSON數(shù)據(jù)解析成對(duì)象。
Retrofit訪問網(wǎng)絡(luò)資源的流程:
二、RxJava3
RxJava3(https://github.com/ReactiveX/RxJava)是響應(yīng)式編程(Reactive Extensions)的java實(shí)現(xiàn),它基于觀察者模式的實(shí)現(xiàn)了異步編程接口。RxJava庫(kù)通過使用可觀察的序列來組成異步和基于事件的程序。
Observable可觀察
即是一個(gè)主題,可以表示任何對(duì)象,它可以從數(shù)據(jù)源中獲得數(shù)據(jù)或者其他的狀態(tài)值。Observable對(duì)象發(fā)出數(shù)據(jù)流。只要有觀察者開始接受,Observable就會(huì)提供數(shù)據(jù),發(fā)出數(shù)據(jù)流??捎^察者可以有多個(gè)訂閱者。
在RxJava3中常見的可觀察流如下表所示:
類 | 說明 |
---|---|
io.reactivex.rxjava3.core.Flowable | 0…N流,支持響應(yīng)式流和背壓按照onSubscribe onNext (onError 或onComplete)屬性執(zhí)行,其中onNext可以執(zhí)行多次,onError和onComplete是互斥的。 |
io.reactivex.rxjava3.core.Observable | 0…N流,不支持背壓按照onSubscribe onNext (onError或onComplete)的順序執(zhí)行,onNext可以執(zhí)行多次,onError與onComplete是互斥的。 |
Operator操作符
承擔(dān)了對(duì) Observable 可觀察對(duì)象發(fā)出的事件進(jìn)行修改和變換。每個(gè)Operator操作實(shí)際上是一個(gè)方法/函數(shù),Observable對(duì)象作為輸入?yún)?shù),對(duì)于Observable對(duì)象發(fā)射的每一項(xiàng)數(shù)據(jù),它會(huì)將在Operator方法/函數(shù)中應(yīng)用這些數(shù)據(jù),然后將處理結(jié)果以O(shè)bservable對(duì)象形式返回。因此返回的是另外一個(gè)Observable對(duì)象。這個(gè)Observable對(duì)象可以繼續(xù)向后發(fā)射或結(jié)束。
操作符Operator可以有若干個(gè),形式如下:
dataSource.operator1()
.operator2()
.operator3()
這些操作符之間構(gòu)成了上下流的關(guān)系。
Observer觀察者
Observer觀察者訂閱可觀察Observable對(duì)象的序列數(shù)據(jù),并對(duì)可觀察對(duì)象的每一項(xiàng)做出反應(yīng)。觀察者負(fù)責(zé)處理事件,它是事件的消費(fèi)者。每當(dāng)關(guān)聯(lián)的Observable發(fā)出數(shù)據(jù)時(shí),通知觀察者。觀察者一個(gè)接一個(gè)地處理數(shù)據(jù)。
背壓策略
由于可觀察者(Observable)和觀察者(Observer)是在不同線程中分別實(shí)現(xiàn)發(fā)送數(shù)據(jù)和接受數(shù)據(jù)。由于不同線程中處理的時(shí)間伴隨著問題的復(fù)雜度,會(huì)導(dǎo)致二者處理數(shù)據(jù)的速度出現(xiàn)不同。如果被觀察者對(duì)象發(fā)射的數(shù)據(jù)的速度遠(yuǎn)遠(yuǎn)快于觀察者對(duì)象處理數(shù)據(jù)的速度的話,會(huì)將數(shù)據(jù)放入到緩存暫存或者直接放棄這些數(shù)據(jù)。這兩種方法的處理都有不妥之處。因此,需要制定“背壓(Back Pressure)”策略,來解決二者在異步場(chǎng)景下,被觀察者發(fā)射數(shù)據(jù)和觀察者處理數(shù)據(jù)速度不一致的問題。因此,通常所說的背壓是在異步環(huán)境下,控制流速的一種策略。常見的背壓策略方式如下表所示:
背壓策略 | 說明 |
---|---|
MISSING | 表示通過 create 方法創(chuàng)建的 Flowable 沒有指定背壓策略,不會(huì)對(duì)通過 OnNext 發(fā)射的數(shù)據(jù)做緩存或丟棄處理,下游必須處理操作符 |
ERROR | 發(fā)生背壓,會(huì)發(fā)送MissingBackpressureException信號(hào),以免下游不能消費(fèi)繼續(xù)。 |
BUFFER | 發(fā)生背壓,會(huì)緩存數(shù)據(jù),直至下游消化數(shù)據(jù)完成 |
DROP | 發(fā)生背壓,會(huì)如果下游不能繼續(xù)消費(fèi)數(shù)據(jù),將最近發(fā)射的值丟棄 |
三、網(wǎng)絡(luò)訪問處理實(shí)例
假設(shè)已經(jīng)有網(wǎng)絡(luò)資源 http://127.0.0.1:5000/json/students.json(也可以寫成:http://localhost:5000/json/students.json),訪問的內(nèi)容如下所示:
在下面的例子中,將結(jié)合Retrofit2+RxJava3+Compose組件實(shí)現(xiàn)對(duì)上述資源的訪問,并以列表的方式顯示。運(yùn)行結(jié)果類似下圖:
1.AndroidManifest.xml配置網(wǎng)絡(luò)訪問
要訪問網(wǎng)絡(luò)需要設(shè)置互聯(lián)網(wǎng)的訪問權(quán)限,以及在應(yīng)用中設(shè)置明文訪問許可:
<uses-permission android:name="android.permission.INTERNET" /> <applicationandroid:usesCleartextTraffic="true" ...> </application>
2.增加依賴
在項(xiàng)目模塊的build.gradle.kt中增加如下依賴:
//retrofit框架
implementation (“com.squareup.retrofit2:retrofit:2.9.0”)
implementation (“com.squareup.retrofit2:converter-gson:2.9.0”)//增加RxJava庫(kù)的依賴
implementation (“io.reactivex.rxjava3:rxjava:3.1.5”)//增加在Android對(duì)RxJava庫(kù)的支持
implementation(“io.reactivex.rxjava3:rxandroid:3.0.2”)//增加Retrofit支持RxJava3的CallAdapter
implementation(“com.squareup.retrofit2:adapter-rxjava3:2.9.0”)implementation(“androidx.lifecycle:lifecycle-viewmodel-compose:2.5.1”)
也可以根據(jù)最新的版本重新調(diào)整版本號(hào)。
3.定義實(shí)體類
data class Student(val id:String,
val name:String,
val gender:String,
val age:Int)
4.定義網(wǎng)絡(luò)訪問
(1)定義網(wǎng)絡(luò)服務(wù)訪問接口
interface StudentService{@GET("students.json")fun getStudents(): Flowable<List<Student>>
}
表示訪問students.json資源獲取一個(gè)RxJava3的Flowable可觀察者對(duì)象。這個(gè)可觀察者對(duì)象封裝了包含學(xué)生記錄的列表。
(2)定義網(wǎng)絡(luò)服務(wù)創(chuàng)建類
object StudentServiceCreator{private val urlStr="http://10.0.2.2:5000/json/"private val retrofit = Retrofit.Builder().baseUrl(urlStr).addConverterFactory(GsonConverterFactory.create()).addCallAdapterFactory(RxJava3CallAdapterFactory.create()).build()fun <T> createService(serviceClass:Class<T>):T = retrofit.create(serviceClass)
}
Web服務(wù)器是本地服務(wù)器,由于移動(dòng)模擬器的127.0.0.1已經(jīng)被占用,因此要在移動(dòng)端訪問本地服務(wù)器,可以通過10.0.2.2來訪問。
定義Retrofit對(duì)象,并在該對(duì)象中設(shè)置了解析JSON數(shù)據(jù)的轉(zhuǎn)換對(duì)象和并發(fā)處理的適配器。
5.定義定義視圖模型
定義視圖模型,調(diào)用的網(wǎng)絡(luò)訪問處理的相關(guān)類,獲取網(wǎng)絡(luò)資源。
class StudentViewModel: ViewModel() {private val students:SnapshotStateList<Student> = mutableStateListOf()private val creator = StudentServiceCreator.createService(StudentService::class.java)fun doNetwork(urlStr:String){creator.getStudents().observeOn(AndroidSchedulers.mainThread()).subscribe{it:List<Student>->if(students.isEmpty()){students.addAll(it)}}}fun getData() = students
}
6.定義界面
(1)定義列表的顯示學(xué)生記錄單項(xiàng)的可組合函數(shù)
@Composable
fun StudentItemCard(student: Student){Card(modifier = Modifier.fillMaxWidth().wrapContentHeight().padding(5.dp),elevation = CardDefaults.cardElevation(defaultElevation = 5.dp),colors = CardDefaults.cardColors(containerColor = Color.Blue,contentColor = Color.White)){Column(modifier= Modifier.fillMaxWidth().wrapContentHeight().padding(5.dp)){Text(text = "${student.id}",fontSize = 24.sp)Row(modifier = Modifier.padding(15.dp)){Text(text = "${student.name}",fontSize = 24.sp)Spacer(modifier = Modifier.padding(5.dp))Text(text = "${student.gender}",fontSize = 24.sp)Spacer(modifier = Modifier.padding(5.dp))Text(text = "${student.age}",fontSize = 24.sp)}}}
}
(2)定義學(xué)生記錄的列表
@SuppressLint("UnusedMaterial3ScaffoldPaddingParameter")
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun MainScreen(stuVM: StudentViewModel = viewModel()){var students = stuVM.getData()val displayState = remember{ mutableStateOf(false) }Scaffold(floatingActionButton = {FloatingActionButton(onClick = {displayState.value = true//訪問網(wǎng)絡(luò)資源stuVM.doNetwork("http://10.0.2.2:5000/json/students.json")//獲取學(xué)生記錄students = stuVM.getData()}) {Icon(Icons.Filled.Refresh,contentDescription = null)}}){Column(horizontalAlignment = Alignment.CenterHorizontally){Text(modifier = Modifier.fillMaxWidth(),text = "學(xué)生記錄列表",textAlign = TextAlign.Center,fontSize = 28.sp)if(displayState.value){LazyColumn{items(students){it: Student ->StudentItemCard(student = it)}}}}}
}
7.定義主活動(dòng)MainActivity
在主活動(dòng)中調(diào)用界面
class MainActivity : ComponentActivity() {override fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)setContent {Ch09_DemoTheme {// A surface container using the 'background' color from the themeSurface(modifier = Modifier.fillMaxSize(),color = MaterialTheme.colorScheme.background) {MainScreen()}}}}
}
參考文獻(xiàn)
陳軼 第8章 Android網(wǎng)絡(luò)應(yīng)用《Android移動(dòng)應(yīng)用開發(fā)(微課版)》P258-P293 清華大學(xué)出版社