本章記錄一個基礎的 demo 項目,使用 kotlin+協程+retrofit+okhttp3+MVVM 實作。
功能需求
調用天氣 api,在首頁顯示天氣情況。
大緻流程
- api 申請及實體分析
- 網絡請求權限
- 添加 kotlin,協程,網絡架構等依賴
- 網絡架構 Retrofit+okhttp3
- 首頁頁面繪制
- 基礎類建構
- 調用接口并顯示在目前頁面
api 申請及實體分析
這裡使用萬維易源的資料源,首先注冊并登入賬号。
- 進入天氣預報入口。
- 購買一個月的天氣預報 api ,這裡使用位址查詢目前天氣作為例子。
-
api 請求示例。
http[s]😕/route.showapi.com/9-2?showapi_appid=替換自己的值&showapi_sign=替換自己的值&area=“杭州”
- 進入控制台,可以檢視自己的 appId 和 sign。
- 若是沒有,則添加,并建立 app,可調用接口選擇全部。
- 建構 api 接口,通路得到傳回資料如下所示。
-
分析傳回資料。
外層是固定格式,可以統一封裝,需要擷取目前的天氣情況,取關鍵字 now 的内容即可。歸納總結為三個實體,具體内容如下:
通用網絡請求實體 CResponse
/**
* 通用網絡請求
*/
data class CResponse<T>(
@SerializedName("showapi_res_error")
val msg: String,//錯誤提示
@SerializedName("showapi_res_code")
val code: Int,//錯誤碼
@SerializedName("showapi_res_body")
val data: T//資料
)
天氣實體
/**
* 天氣
*/
data class Weather(
val time: Long,//預報釋出時間
val now: WeatherDetail//天氣詳情
)
天氣詳情實體
/**
* 天氣詳情
*/
data class WeatherDetail(
val aqi: String,//空氣指數
val rain: String,//下雨時間點
val sd: String,//空氣濕度
val temperature: String,//氣溫
@SerializedName("temperature_time")
val temperatureTime: String,//獲得氣溫的時間
val weather: String,//天氣
@SerializedName("weather_pic")
val weatherPic: String,//天氣小圖示
@SerializedName("wind_direction")
val windDirection: String,//風向
@SerializedName("windPower")
val windPower: String//風力
)
網絡請求權限
在 AndroidManifest.xml 中添加網絡請求權限,代碼如下:
<!--網絡權限-->
<uses-permission android:name="android.permission.INTERNET" />
添加 kotlin,協程,網絡架構等依賴
在 build.gradle 檔案中添加依賴,代碼如下:
// Kotlin
implementation "org.jetbrains.kotlin:kotlin-stdlib:1.7.10"
// 協程核心庫
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:1.6.0"
// 協程Android支援庫
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.6.0"
implementation "androidx.activity:activity-ktx:1.2.3"
implementation "androidx.fragment:fragment-ktx:1.3.5"
implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:2.3.1"
implementation "androidx.lifecycle:lifecycle-runtime-ktx:2.4.0"
implementation "androidx.lifecycle:lifecycle-livedata-ktx:2.3.1"
// okhttp
implementation "com.squareup.okhttp3:okhttp:4.9.0"
implementation 'com.squareup.okhttp3:logging-interceptor:4.9.0'//日志攔截器
// retrofit
implementation "com.squareup.retrofit2:retrofit:2.9.0"
implementation "com.squareup.retrofit2:converter-scalars:2.9.0"//支援傳回結果是string
implementation "com.squareup.retrofit2:converter-gson:2.9.0"//支援傳回結果是實體
網絡架構 Retrofit+okhttp3
網絡請求封裝,添加基礎通路位址,攔截器等,最後目的是能有個可以得到 service 的方法。
- 首先需要一個類,存放靜态常量,例如基礎通路位址,appId 以及 sign。
/**
* 通用資料
*/
object HttpConstant {
/**
* 通路位址
*/
const val BASE_HTTP = "https://route.showapi.com"
/**
* appID
*/
const val APP_ID = "替換為萬維易源的appId"
/**
* app_sign
*/
const val APP_SIGN = "替換為萬維易源的sign"
}
-
從請求位址分析,有兩個公共參數(showapi_appid 和 showapi_sign)可以封裝,建構通用參數攔截器。
請求位址
http[s]😕/route.showapi.com/9-2?showapi_appid=替換自己的值&showapi_sign=替換自己的值&area=“杭州”
/**
* 通用參數攔截器
*/
class CommonInterceptor : Interceptor {
override fun intercept(chain: Interceptor.Chain): Response {
val oldRequest = chain.request()
val httUrl = oldRequest.url
val urlBuilder = httUrl.newBuilder()
/** 添加公共參數 */
urlBuilder.addQueryParameter("showapi_appid", HttpConstant.APP_ID)
urlBuilder.addQueryParameter("showapi_sign", HttpConstant.APP_SIGN)
val request = oldRequest
.newBuilder()
.url(urlBuilder.build())
.build()
return chain.proceed(request)
}
}
- 建構 Retrofit 管理類,得到 service 方法。
/**
* Retrofit管理類
*/
object RetrofitManager {
/**
* okhttpClient
*/
private val okhttpClient: OkHttpClient
get() = OkHttpClient.Builder()
.addInterceptor(CommonInterceptor())//通用參數攔截器
.addInterceptor(HttpLoggingInterceptor())//日志攔截器
.followRedirects(true)
.build()
/**
* 建構service
*/
fun <T> getService(serviceClass: Class<T>): T {
val retrofit = Retrofit.Builder().apply {
baseUrl(HttpConstant.BASE_HTTP)//基礎通路位址
client(okhttpClient)
addConverterFactory(GsonConverterFactory.create())//Gson轉換工廠
addConverterFactory(ScalarsConverterFactory.create())//String轉換工廠
}.build()
return retrofit.create(serviceClass)
}
}
首頁頁面繪制
主界面顯示目前的天氣情況即可,使用 databinding 方式,代碼如下。
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools">
<data>
<variable
name="viewModel"
type="com.elaine.little_project.MainViewModel" />
</data>
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<TextView
android:id="@+id/tv"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@{viewModel.weatherData.weather}"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>
基礎類建構
在項目構架過程中,都會習慣性地将一些公共方法或者屬性進行封裝操作,友善後續使用。
- 抽象類 BaseViewModel,繼承 ViewModel(),定義一個初始化資料的方法。
/**
* 基礎ViewModel
*/
abstract class BaseViewModel : ViewModel() {
/** 初始化資料 */
abstract fun start()
}
- 抽象類 BaseActivity,自定綁定 ViewModel 和 databinding,避免過多重複代碼,其他的 Activity 繼承 BaseActivity 即可。
/**
* 基礎類Activity
*/
abstract class BaseActivity<VM : BaseViewModel, VB : ViewDataBinding>(private val contentViewResId: Int) :
AppCompatActivity() {
lateinit var mViewModel: VM
lateinit var mBinding: VB
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
initViewModel()
initDataBinding()
initView()
initData()
}
/**
* 初始化ViewModel
*/
private fun initViewModel() {
//注意:actualTypeArguments[0] 0-->指上面BaseActivity<VM : BaseViewModel, VB : ViewDataBinding>的VM放在第一個
val type: Class<VM> =
(this.javaClass.genericSuperclass as ParameterizedType).actualTypeArguments[0] as Class<VM>
mViewModel = ViewModelProvider(this).get(type)
mViewModel.start()
}
/**
* 初始化dataBinding
*/
private fun initDataBinding() {
mBinding = DataBindingUtil.setContentView(this, contentViewResId)
mBinding.apply {
//綁定生命周期
lifecycleOwner = [email protected]
//mBinding綁定viewModel
setVariable(BR.viewModel, mViewModel)
}
}
/**
* 初始化UI
*/
abstract fun initView()
/**
* 初始化資料
*/
abstract fun initData()
}
調用接口并顯示在目前頁面
- 接口檔案 Api,這裡是挂起函數。
/**
* api接口
*/
interface Api {
/**
* 請求天氣
* @param area 位址 eg:杭州
*/
@FormUrlEncoded
@POST("/9-2")
suspend fun getWeather(
@Field("area") area: String,
): CResponse<Weather>
}
- api 接口實作類 WeatherRepository,通過 Retrofit 管理器擷取 service,然後調用天氣接口。
/**
* api接口實作類
*/
object WeatherRepository : Api {
/** 擷取service */
private val service by lazy { RetrofitManager.getService(Api::class.java) }
/**
* 請求天氣
* @param area 位址 eg:杭州
*/
override suspend fun getWeather(area: String): CResponse<Weather> {
return service.getWeather(area)
}
}
- MainActivity 對應的 MainViewModel,利用 viewModelScope 進行網絡請求,其是一個協程。
/**
* viewModel
*/
class MainViewModel : BaseViewModel() {
/** 天氣資料 */
var weatherData: MutableLiveData<WeatherDetail> = MutableLiveData()
override fun start() {
}
/**
* 擷取天氣資料
*/
fun getWeather() {
viewModelScope.launch {
val result = WeatherRepository.getWeather("杭州")
weatherData.value = result.data.now
}
}
}
- 首頁 MainActivity,首頁就是請求接口即可。
/**
* 首頁
*/
class MainActivity : BaseActivity<MainViewModel, ActivityMainBinding>(R.layout.activity_main) {
override fun initView() {
}
override fun initData() {
getData()
}
/**
* 擷取資料
*/
private fun getData() {
mViewModel.getWeather()
}
}
項目效果
項目 github 位址
github.com/ElaineTaylo…
具體内容在 little_project 項目中
作者:木子閑集
連結:https://juejin.cn/post/7142775573385838606
最後
附贈一套由阿裡進階架構師編寫的《Android八大子產品進階筆記》,幫大家将雜亂、零散、碎片化的知識進行體系化的整理,讓大家系統而高效地掌握Android開發的各個知識點。
相對于我們平時看的碎片化内容,這份筆記的知識點更系統化,更容易了解和記憶,是嚴格按照知識體系編排的。
一、架構師築基必備技能
1、深入了解Java泛型
2、注解深入淺出
3、并發程式設計
4、資料傳輸與序列化
5、Java虛拟機原理
6、高效IO
……
二、Android百大架構源碼解析
1.Retrofit 2.0源碼解析
2.Okhttp3源碼解析
3.ButterKnife源碼解析
4.MPAndroidChart 源碼解析
5.Glide源碼解析
6.Leakcanary 源碼解析
7.Universal-lmage-Loader源碼解析
8.EventBus 3.0源碼解析
9.zxing源碼分析
10.Picasso源碼解析
11.LottieAndroid使用詳解及源碼解析
12.Fresco 源碼分析——圖檔加載流程
三、Android性能優化實戰解析
- 騰訊Bugly:對字元串比對算法的一點了解
- 愛奇藝:安卓APP崩潰捕獲方案——xCrash
- 位元組跳動:深入了解Gradle架構之一:Plugin, Extension, buildSrc
- 百度APP技術:Android H5首屏優化實踐
- 支付寶用戶端架構解析:Android 用戶端啟動速度優化之「垃圾回收」
- 攜程:從智行 Android 項目看元件化架構實踐
- 網易新聞建構優化:如何讓你的建構速度“勢如閃電”?
- …
四、進階kotlin強化實戰
1、Kotlin入門教程
2、Kotlin 實戰避坑指南
3、項目實戰《Kotlin Jetpack 實戰》
- 從一個膜拜大神的 Demo 開始
- Kotlin 寫 Gradle 腳本是一種什麼體驗?
- Kotlin 程式設計的三重境界
- Kotlin 高階函數
- Kotlin 泛型
- Kotlin 擴充
- Kotlin 委托
- 協程“不為人知”的調試技巧
- 圖解協程:suspend
五、Android進階UI開源架構進階解密
1.SmartRefreshLayout的使用
2.Android之PullToRefresh控件源碼解析
3.Android-PullToRefresh下拉重新整理庫基本用法
4.LoadSir-高效易用的加載回報頁管理架構
5.Android通用LoadingView加載架構詳解
6.MPAndroidChart實作LineChart(折線圖)
7.hellocharts-android使用指南
8.SmartTable使用指南
9.開源項目android-uitableview介紹
10.ExcelPanel 使用指南
11.Android開源項目SlidingMenu深切解析
12.MaterialDrawer使用指南
六、NDK子產品開發
1、NDK 子產品開發
2、JNI 子產品
3、Native 開發工具
4、Linux 程式設計
5、底層圖檔處理
6、音視訊開發
7、機器學習
七、Flutter技術進階
1、Flutter跨平台開發概述
2、Windows中Flutter開發環境搭建
3、編寫你的第一個Flutter APP
4、Flutter開發環境搭建和調試
5、Dart文法篇之基礎文法(一)
6、Dart文法篇之集合的使用與源碼解析(二)
7、Dart文法篇之集合操作符函數與源碼分析(三)
…
八、微信小程式開發
1、小程式概述及入門
2、小程式UI開發
3、API操作
4、購物商場項目實戰……
全套視訊資料:
一、面試合集
二、源碼解析合集
三、開源架構合集
歡迎大家一鍵三連支援,若需要文中資料,直接點選文末CSDN官方認證微信卡片免費領取↓↓↓