前不久Google IO 2017不僅將kotlin宣布為官方開發(fā)語言,還發(fā)布了谷歌官方 Android 應(yīng)用架構(gòu)庫(kù),這個(gè)新的架構(gòu)庫(kù)旨在幫助我們?cè)O(shè)計(jì)健壯菇肃、可測(cè)試的和可維護(hù)的應(yīng)用程序蜕着。新項(xiàng)目也打算采用這套架構(gòu),下面一步步介紹怎么去配置和使用這套架構(gòu)尚蝌。(最簡(jiǎn)單介紹,詳細(xì)內(nèi)容看官方文檔和其他參考資料)
總覽
簡(jiǎn)單說來充尉,該架構(gòu)由數(shù)據(jù)驅(qū)動(dòng)飘言, 徹底將UI和data分離,UI層很輕驼侠,不涉及任何數(shù)據(jù)的操作的內(nèi)容姿鸿。ViewModel將數(shù)據(jù)的變化的反映在UI上,本身也不持有數(shù)據(jù)倒源。官方推薦所有數(shù)據(jù)持久化苛预。viewmodel通過Repository來管理數(shù)據(jù),保存到數(shù)據(jù)庫(kù)或者從網(wǎng)絡(luò)獲取笋熬。
kotlin的配置
本次打算使用kotlin來進(jìn)行開發(fā)
新建一個(gè)項(xiàng)目热某,完成后在project/build.gradle添加以下內(nèi)容
//對(duì)照添加
buildscript {
ext.kotlin_version = '1.1.2-5'
repositories {
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:2.3.1'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
classpath "org.jetbrains.kotlin:kotlin-android-extensions:$kotlin_version"
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
}
}
在app/build.gradle的開頭添加:
apply plugin: 'kotlin-android'
apply plugin: 'kotlin-android-extensions'
apply plugin: 'kotlin-kapt'
簡(jiǎn)單解釋:
第二行表示kotlin擴(kuò)展,可以避免使用類似findviewbyid的很多內(nèi)容
第三行表示kotlin對(duì)注解的處理胳螟,感覺對(duì)databinding的支持不是很好苫拍。
到此為止, kotlin的配置已經(jīng)完成旺隙。
在android studio的插件中安裝kotlin后重啟绒极。
對(duì)Mainactivity.java執(zhí)行code--convert java file to koltin file。
編譯運(yùn)行成功的話蔬捷,說明kotlin配置成功
android architecture Component的配置
該架構(gòu)官方翻譯參考:https://juejin.im/post/5937b1d7a22b9d005810b877
簡(jiǎn)單配置如下
在project/build.gradle中添加:
allprojects {
repositories {
jcenter()
maven { url 'https://maven.google.com' }
}
}
在app/build.gradle中添加
/// Architecture Components
compile "android.arch.lifecycle:runtime:$ac_version"
compile "android.arch.lifecycle:extensions:$ac_version"
kapt "android.arch.lifecycle:compiler:$ac_version"
/// Room
compile "android.arch.persistence.room:runtime:$ac_version"
kapt "android.arch.persistence.room:compiler:$ac_version"
前面三行是關(guān)于lifecycle垄提,livedata榔袋, viewmodel的依賴,后面是關(guān)于Room的依賴铡俐。
后面用例子進(jìn)行說明凰兑。如有問題歡迎討論。
Room的使用
Room在sqlite之上提供了一個(gè)抽象層审丘。
將數(shù)據(jù)持久化到本地對(duì)于應(yīng)用程序處理大量結(jié)構(gòu)化數(shù)據(jù)有非常大的好處吏够。最常見的情況是緩存相關(guān)數(shù)據(jù)。這樣滩报,當(dāng)設(shè)備無法訪問網(wǎng)絡(luò)時(shí)锅知,用戶仍然可以在離線狀態(tài)下瀏覽內(nèi)容。然后脓钾,在設(shè)備重新上線后售睹,任何用戶發(fā)起的內(nèi)容變更都會(huì)同步到服務(wù)器。
其中有三個(gè)組件組成:
- DataBase
- Entity
- DAO
下面介紹最簡(jiǎn)單的使用方法:
項(xiàng)目結(jié)構(gòu):(https://github.com/yunshuipiao/SWBlog/blob/master/media/android%20architecture%20Component/%E9%A1%B9%E7%9B%AE%E7%BB%93%E6%9E%84.png)
如上圖所示可训,項(xiàng)目結(jié)構(gòu)對(duì)應(yīng)架構(gòu)圖昌妹,另外的base,App是一些基礎(chǔ)的ui握截, 項(xiàng)目的app單例飞崖,以后還會(huì)添加dagger2來分離模塊。
新建一個(gè)Story文件谨胞,內(nèi)容如下:
@Entity(tableName = "stories")
class Story {
@PrimaryKey
var id = 0
var data = ""
var displayData = ""
var title = ""
var image = ""
}
//story作為數(shù)據(jù)庫(kù)的一張表固歪,可以指定列名,主鍵
新建StoryDao文件:
@Dao
interface StoryDao {
@Query("select * from stories")
fun loadAllStories(): LiveData<List<Story>>
@Insert(onConflict = OnConflictStrategy.REPLACE)
fun insertStories(list: List<Story>)
}
//對(duì)數(shù)據(jù)的操作畜眨,這里涉及插入和查詢(查詢的返回值可以是LiveData,list术瓮, Rxjava2等)
新建AppDatabase文件:
@Database(entities = arrayOf(Story::class), version = 1)
abstract class AppDatabase: RoomDatabase() {
companion object {
val TAG = "sw_story_db"
}
abstract fun storyDao(): StoryDao
}
//數(shù)據(jù)庫(kù)康聂, 通過dao操作數(shù)據(jù)。
完成這三個(gè)文件胞四,表示Room組件已經(jīng)可以使用恬汁。
新建DataBaseManager文件:
object DatabaseManager {
lateinit var db: AppDatabase
fun initDb(context: Context) {
db = Room.databaseBuilder(context, AppDatabase::class.java, AppDatabase.TAG).build()
}
fun insertStories(storys: List<Story>) {
Flowable.just(storys)
.observeOn(Schedulers.io())
.subscribe {
db.beginTransaction()
try {
db.storyDao().insertStories(storys)
db.setTransactionSuccessful()
} finally {
db.endTransaction()
}
}
}
fun loadAllStories(): LiveData<List<Story>> {
return db.storyDao().loadAllStories()
}
fun simlutateInsertData() {
var list = ArrayList<Story>()
for (i in 1..20) {
var s = Story()
s.id = (i)
s.data = ((i * i).toString() + "--" + i.toString())
s.displayData = ((i * i).toString() + "--" + i.toString())
s.title = ((i * i).toString() + "--" + i.toString())
s.image = ((i * i).toString() + "--" + i.toString())
list.add(s)
}
insertStories(list)
}
}
//該單例對(duì)數(shù)據(jù)庫(kù)封裝了一層,方便處理db的各種操作(db初始化可使用依賴注入)
數(shù)據(jù)庫(kù)插入不能在主線程辜伟,涉及事務(wù)氓侧。
到此為止,該框架的數(shù)據(jù)庫(kù)部分已經(jīng)可以使用导狡。
下面作為例子說明怎么存數(shù)據(jù)约巷。
//繼承Appication,初始化并模擬插入數(shù)據(jù)
class ZhiJokeApplication : Application() {
override fun onCreate() {
super.onCreate()
DatabaseManager.initDb(this)
DatabaseManager.simlutateInsertData()
}
}
編譯項(xiàng)目運(yùn)行旱捧,此時(shí)真機(jī)上應(yīng)該保存有插入的數(shù)據(jù)独郎。
怎么查看
用一臺(tái)已經(jīng)root后的測(cè)試機(jī)踩麦,安裝root文件管理器后,在根目錄的 data/data/包名/database氓癌, 就能看到數(shù)據(jù)庫(kù)新建并插入的數(shù)據(jù)了谓谦。
數(shù)據(jù)(https://github.com/yunshuipiao/SWBlog/blob/master/media/android%20architecture%20Component/%E6%95%B0%E6%8D%AE%E5%BA%93%E8%A1%A8.png)
用DatabaseManage.loadAllStories()
即可取出數(shù)據(jù)。
未玩待續(xù)
完整代碼:github