Kotlin在2017年Google開發(fā)者大會(huì)的時(shí)候捏浊,被指定為Android的官方語言⊙么現(xiàn)在使用Kotlin來開發(fā)Android也越來越火徽缚,如果你還沒有接觸過Kotlin星虹,那么肯定是慢人一步了。
其實(shí)我在今年寒假之前就已經(jīng)看完了《Kotlin實(shí)戰(zhàn)》這本書灾螃,但奈于工作和生活上的事情太多题翻,之后一直沒有去關(guān)注這一部分。最近也是難得有時(shí)間腰鬼,所以重新看了遍Kotlin的語法知識(shí)以及對(duì)比和Java的不同嵌赠。于是就想趁熱用Kotlin來寫一個(gè)小demo。
demo雖然很簡(jiǎn)單熄赡,但是涵蓋的內(nèi)容還是很實(shí)用的姜挺。下面是demo中用到的技術(shù):
先來看一下demo目錄結(jié)構(gòu):
以下是我們的正文部分,一步步來完成這個(gè)demo:
1.創(chuàng)建Kotlin項(xiàng)目彼硫,引入開發(fā)用到的庫(kù)
項(xiàng)目創(chuàng)建沒什么好說的炊豪,創(chuàng)建時(shí)注意勾上“Include Kotlin support"
demo中用到的開源庫(kù):
implementation 'com.squareup.retrofit2:retrofit:2.3.0'
implementation 'com.squareup.retrofit2:converter-gson:2.3.0'
implementation 'com.squareup.retrofit2:adapter-rxjava2:2.3.0'
implementation "io.reactivex.rxjava2:rxjava:2.1.6"
implementation 'io.reactivex.rxjava2:rxandroid:2.0.1'
//OKHttp的日志攔截器凌箕,可以打印網(wǎng)絡(luò)請(qǐng)求結(jié)果
implementation 'com.squareup.okhttp3:logging-interceptor:3.10.0'
implementation 'org.jetbrains.anko:anko:0.10.5'
}
2.activity_main.xml界面編寫
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.wbb.kotlinapp.mvp.ui.MainActivity">
<DatePicker
android:id="@+id/datePicker"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:visibility="gone"
android:layout_centerInParent="true"/>
<Button
android:id="@+id/selectButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="日期選擇"
android:layout_centerHorizontal="true"
android:layout_marginTop="50dp"/>
<TextView
android:id="@+id/titleTextView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="當(dāng)天詳情"
android:layout_below="@id/selectButton"
android:layout_centerHorizontal="true"
android:layout_marginTop="20dp"/>
<TextView
android:id="@+id/contentTextView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@id/titleTextView"
android:layout_marginTop="20dp"
android:gravity="center"/>
</RelativeLayout>
3.根據(jù)json來編寫實(shí)體類
{
"reason":"Success",
"result":
{
"data":{
"date":"2018-8-9",
"weekday":"星期四",
"animalsYear":"狗",
"suit":"解除.祭祀.祈福.求嗣.修造.動(dòng)土.豎柱.上梁.安床.納畜.造屋.合脊.起基.入殮.破土.安葬.",
"avoid":"出火.嫁娶.開光.進(jìn)人口.出行.詞訟.開市.入宅.移徙.赴任.",
"year-month":"2018-8",
"lunar":"六月廿八",
"lunarYear":"戊戌年"}
},
"error_code":0
}
這里可以根據(jù)json的結(jié)構(gòu)可以寫一個(gè)通用的ApiResult,但我這里為了讀者清晰,寫成了CalentarDayBean
3個(gè)實(shí)體類如下:
data class CalentarDayBean<T>(val reason: String, val result: T, val error_code: Int)
data class CalentarDayResult<T>(val data: T)
data class CalentarDayData(
val date: String,
val weekday: String,
val animalsYear: String,
val suit: String,
val avoid: String,
val yearMonth: String,
val holiday: String,
val lunar: String,
val lunarYear: String,
val desc: String
)
看到這里是不是覺得Kotlin語言的簡(jiǎn)潔性词渤,沒錯(cuò)Kotlin用data定義一個(gè)class可以省去java的一大堆getter陌知、setter
4.Retrofit封裝和接口編寫
請(qǐng)求接口RetrofitService
interface RetrofitService {
/**
* 獲取當(dāng)天的詳細(xì)信息
*/
@GET("calendar/day")
fun calenderDay(
@Query("date") date: String,
@Query("key") key: String
): Observable<CalentarDayBean<CalentarDayResult<CalentarDayData>>>
}
Retrofit封裝
class RetrofitUtil {
companion object {
const val TAG="RetrofitUtil"
/**
* 創(chuàng)建Retrofit
*/
fun create(url: String): Retrofit {
//顯示日志級(jí)別
val level: HttpLoggingInterceptor.Level = HttpLoggingInterceptor.Level.BODY
//新建log攔截器
val loggingInterceptor: HttpLoggingInterceptor = HttpLoggingInterceptor(HttpLoggingInterceptor.Logger { message ->
Log.e(TAG,"OkHttp:$message")
})
loggingInterceptor.level = level
//okHttpClientBuilder
val okHttpClientBuilder = OkHttpClient.Builder()
okHttpClientBuilder.connectTimeout(60, TimeUnit.SECONDS)
okHttpClientBuilder.readTimeout(10, TimeUnit.SECONDS)
//OkHttp進(jìn)行添加攔截器loggingInterceptor
okHttpClientBuilder.addInterceptor(loggingInterceptor)
return Retrofit.Builder()
.baseUrl(url)
.client(okHttpClientBuilder.build())
.addConverterFactory(GsonConverterFactory.create())
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.build()
}
/**
* 獲取ServiceApi
*/
fun <T> getService(url: String, service: Class<T>): T {
return create(url).create(service)
}
val retrofitService: RetrofitService = RetrofitUtil.getService(Constants.REQUEST_BASE_URL, RetrofitService::class.java)
}
}
全局常量Constants
object Constants{
val REQUEST_BASE_URL="http://v.juhe.cn/"
val KEY="1be865c0e67e3"
}
在Kotlin里是沒有靜態(tài)方法
和靜態(tài)變量、常量
這一說法的掖肋,一般都是用companion伴生對(duì)象代替Java中的static
5.MVP構(gòu)建
demo的mvp模式是參考谷歌的todo-mvp-kotlin,但是我省去了respoistory這一部分赏参。這一部分的邏輯較為復(fù)雜志笼,講解這一部分的話對(duì)于我們的demo來說其實(shí)是本末倒置了,有興趣的同學(xué)可以去參考以下博文:
interface CalentarContract {
interface View : BaseView<Presenter> {
fun showDayCalentarData(calentarDayBean: CalentarDayBean<CalentarDayResult<CalentarDayData>>)
fun showError(errorMsg: String)
}
interface Presenter : BasePresenter {
fun getDayCalentarData(date: String)
}
}
MainActivity實(shí)現(xiàn)CalentarContract.View接口把篓,CalentarPresenter實(shí)現(xiàn)CalentarContract.Presenter接口
class CalentarPresenter(val view: CalentarContract.View) : CalentarContract.Presenter {
var compositeDisposable:CompositeDisposable
companion object {
const val TAG = "CalentarPresenter"
}
init {
view.presenter = this
compositeDisposable= CompositeDisposable()
}
override fun subscribe() {
}
override fun unsubscribe() {
compositeDisposable.clear()
}
override fun getDayCalentarData(date: String) {
val disposable = RetrofitUtil
.retrofitService
.calenderDay(date, "933dc930886c8c0717607f9f8bae0b48")
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe({ result ->
view.showDayCalentarData(result)
Log.e(TAG, result.toString())
}, { error ->
view.showError(error.message.toString())
Log.e(TAG, error.message.toString())
})
compositeDisposable.add(disposable)
}
}
class MainActivity : AppCompatActivity(), CalentarContract.View {
override lateinit var presenter: CalentarContract.Presenter
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
presenter = CalentarPresenter(this)
selectButton.setOnClickListener {
titleTextView.visibility = View.GONE
selectButton.visibility = View.GONE
contentTextView.visibility = View.GONE
datePicker.visibility = View.VISIBLE
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
datePicker.setOnDateChangedListener { view, year, month, day ->
var date: String = "${year}-${month+1}-${day}"
presenter.getDayCalentarData(date)
}
}
}
override fun onResume() {
super.onResume()
presenter.subscribe()
}
override fun onDestroy() {
super.onDestroy()
presenter.unsubscribe()
}
override fun showDayCalentarData(calentarDayBean: CalentarDayBean<CalentarDayResult<CalentarDayData>>) {
datePicker.visibility=View.GONE
titleTextView.visibility = View.VISIBLE
selectButton.visibility = View.VISIBLE
contentTextView.visibility = View.VISIBLE
titleTextView.text=calentarDayBean.result.data.date
contentTextView.text = calentarDayBean.result.data.toString()
}
override fun showError(errorMsg: String) {
toast(errorMsg)
}
}