天天看點

安卓系列之 kotlin 項目實戰--基礎 demo

本章記錄一個基礎的 demo 項目,使用 kotlin+協程+retrofit+okhttp3+MVVM 實作。

功能需求

調用天氣 api,在首頁顯示天氣情況。

大緻流程

  1. api 申請及實體分析
  2. 網絡請求權限
  3. 添加 kotlin,協程,網絡架構等依賴
  4. 網絡架構 Retrofit+okhttp3
  5. 首頁頁面繪制
  6. 基礎類建構
  7. 調用接口并顯示在目前頁面

api 申請及實體分析

這裡使用萬維易源的資料源,首先注冊并登入賬号。

  1. 進入天氣預報入口。
安卓系列之 kotlin 項目實戰--基礎 demo
  1. 購買一個月的天氣預報 api ,這裡使用位址查詢目前天氣作為例子。
安卓系列之 kotlin 項目實戰--基礎 demo
  1. api 請求示例。

    http[s]😕/route.showapi.com/9-2?showapi_appid=替換自己的值&showapi_sign=替換自己的值&area=“杭州”

  2. 進入控制台,可以檢視自己的 appId 和 sign。
安卓系列之 kotlin 項目實戰--基礎 demo
  1. 若是沒有,則添加,并建立 app,可調用接口選擇全部。
安卓系列之 kotlin 項目實戰--基礎 demo
  1. 建構 api 接口,通路得到傳回資料如下所示。
安卓系列之 kotlin 項目實戰--基礎 demo
  1. 分析傳回資料。

    外層是固定格式,可以統一封裝,需要擷取目前的天氣情況,取關鍵字 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 的方法。

  1. 首先需要一個類,存放靜态常量,例如基礎通路位址,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"
}
           
  1. 從請求位址分析,有兩個公共參數(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)
    }
}
           
  1. 建構 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>
           

基礎類建構

在項目構架過程中,都會習慣性地将一些公共方法或者屬性進行封裝操作,友善後續使用。

  1. 抽象類 BaseViewModel,繼承 ViewModel(),定義一個初始化資料的方法。
/**
 * 基礎ViewModel
 */
abstract class BaseViewModel : ViewModel() {
    /** 初始化資料 */
    abstract fun start()
}
           
  1. 抽象類 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()
}
           

調用接口并顯示在目前頁面

  1. 接口檔案 Api,這裡是挂起函數。
/**
 * api接口
 */
interface Api {

    /**
     * 請求天氣
     * @param area 位址 eg:杭州
     */
    @FormUrlEncoded
    @POST("/9-2")
    suspend fun getWeather(
        @Field("area") area: String,
    ): CResponse<Weather>
}
           
  1. 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)
    }
}
           
  1. 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
        }
    }

}
           
  1. 首頁 MainActivity,首頁就是請求接口即可。
/**
 * 首頁
 */
class MainActivity : BaseActivity<MainViewModel, ActivityMainBinding>(R.layout.activity_main) {

    override fun initView() {

    }

    override fun initData() {
        getData()
    }

    /**
     * 擷取資料
     */
    private fun getData() {
        mViewModel.getWeather()
    }

}
           

項目效果

安卓系列之 kotlin 項目實戰--基礎 demo

項目 github 位址

github.com/ElaineTaylo…

具體内容在 little_project 項目中

作者:木子閑集

連結:https://juejin.cn/post/7142775573385838606

最後

附贈一套由阿裡進階架構師編寫的《Android八大子產品進階筆記》,幫大家将雜亂、零散、碎片化的知識進行體系化的整理,讓大家系統而高效地掌握Android開發的各個知識點。

安卓系列之 kotlin 項目實戰--基礎 demo

相對于我們平時看的碎片化内容,這份筆記的知識點更系統化,更容易了解和記憶,是嚴格按照知識體系編排的。

一、架構師築基必備技能

1、深入了解Java泛型

2、注解深入淺出

3、并發程式設計

4、資料傳輸與序列化

5、Java虛拟機原理

6、高效IO

……

安卓系列之 kotlin 項目實戰--基礎 demo

二、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 源碼分析——圖檔加載流程

安卓系列之 kotlin 項目實戰--基礎 demo

三、Android性能優化實戰解析

  • 騰訊Bugly:對字元串比對算法的一點了解
  • 愛奇藝:安卓APP崩潰捕獲方案——xCrash
  • 位元組跳動:深入了解Gradle架構之一:Plugin, Extension, buildSrc
  • 百度APP技術:Android H5首屏優化實踐
  • 支付寶用戶端架構解析:Android 用戶端啟動速度優化之「垃圾回收」
  • 攜程:從智行 Android 項目看元件化架構實踐
  • 網易新聞建構優化:如何讓你的建構速度“勢如閃電”?
安卓系列之 kotlin 項目實戰--基礎 demo

四、進階kotlin強化實戰

1、Kotlin入門教程

2、Kotlin 實戰避坑指南

3、項目實戰《Kotlin Jetpack 實戰》

  • 從一個膜拜大神的 Demo 開始
  • Kotlin 寫 Gradle 腳本是一種什麼體驗?
  • Kotlin 程式設計的三重境界
  • Kotlin 高階函數
  • Kotlin 泛型
  • Kotlin 擴充
  • Kotlin 委托
  • 協程“不為人知”的調試技巧
  • 圖解協程:suspend
安卓系列之 kotlin 項目實戰--基礎 demo

五、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使用指南

安卓系列之 kotlin 項目實戰--基礎 demo

六、NDK子產品開發

1、NDK 子產品開發

2、JNI 子產品

3、Native 開發工具

4、Linux 程式設計

5、底層圖檔處理

6、音視訊開發

7、機器學習

安卓系列之 kotlin 項目實戰--基礎 demo

七、Flutter技術進階

1、Flutter跨平台開發概述

2、Windows中Flutter開發環境搭建

3、編寫你的第一個Flutter APP

4、Flutter開發環境搭建和調試

5、Dart文法篇之基礎文法(一)

6、Dart文法篇之集合的使用與源碼解析(二)

7、Dart文法篇之集合操作符函數與源碼分析(三)

安卓系列之 kotlin 項目實戰--基礎 demo

八、微信小程式開發

1、小程式概述及入門

2、小程式UI開發

3、API操作

4、購物商場項目實戰……

安卓系列之 kotlin 項目實戰--基礎 demo

全套視訊資料:

一、面試合集

安卓系列之 kotlin 項目實戰--基礎 demo

二、源碼解析合集

安卓系列之 kotlin 項目實戰--基礎 demo

三、開源架構合集

安卓系列之 kotlin 項目實戰--基礎 demo

歡迎大家一鍵三連支援,若需要文中資料,直接點選文末CSDN官方認證微信卡片免費領取↓↓↓

安卓系列之 kotlin 項目實戰--基礎 demo

繼續閱讀