關於android architecture Component的最簡單實踐
前不久Google IO 2017不僅將kotlin宣布為官方開發語言,還發布了谷歌官方 Android 應用架構庫,這個新的架構庫旨在幫助我們設計健壯、可測試的和可維護的應用程序。新項目也打算採用這套架構,下面一步步介紹怎麼去配置和使用這套架構。(最簡單介紹,詳細內容看官方文檔和其他參考資料)
總覽
簡單說來,該架構由數據驅動, 徹底將UI和data分離,UI層很輕,不涉及任何數據的操作的內容。ViewModel將數據的變化的反映在UI上,本身也不持有數據。官方推薦所有數據持久化。viewmodel通過Repository來管理數據,保存到資料庫或者從網路獲取。
kotlin的配置
本次打算使用kotlin來進行開發
新建一個項目,完成後在project/build.gradle添加以下內容
//對照添加
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
簡單解釋:
第二行表示kotlin擴展,可以避免使用類似findviewbyid的很多內容
第三行表示kotlin對註解的處理,感覺對databinding的支持不是很好。到此為止, kotlin的配置已經完成。在android studio的插件中安裝kotlin後重啟。
對Mainactivity.java執行code—convert java file to koltin file。編譯運行成功的話,說明kotlin配置成功
android architecture Component的配置
該架構官方翻譯參考:https://juejin.im/post/5937b1d7a22b9d005810b877
簡單配置如下
在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"
前面三行是關於lifecycle,livedata, viewmodel的依賴,後面是關於Room的依賴。
後面用例子進行說明。如有問題歡迎討論。Room的使用
Room在sqlite之上提供了一個抽象層。
將數據持久化到本地對於應用程序處理大量結構化數據有非常大的好處。最常見的情況是緩存相關數據。這樣,當設備無法訪問網路時,用戶仍然可以在離線狀態下瀏覽內容。然後,在設備重新上線後,任何用戶發起的內容變更都會同步到伺服器。其中有三個組件組成:
- DataBase
- Entity
- DAO
下面介紹最簡單的使用方法:
如上圖所示,項目結構對應架構圖,另外的base,App是一些基礎的ui, 項目的app單例,以後還會添加dagger2來分離模塊。
新建一個Story文件,內容如下:@Entity(tableName = "stories")
class Story {
@PrimaryKey
var id = 0
var data = ""
var displayData = ""
var title = ""
var image = ""
}
//story作為資料庫的一張表,可以指定列名,主鍵
新建StoryDao文件:
@Dao
interface StoryDao {
@Query("select * from stories")
fun loadAllStories(): LiveData<List<Story>>
@Insert(onConflict = OnConflictStrategy.REPLACE)
fun insertStories(list: List<Story>)
}
//對數據的操作,這裡涉及插入和查詢(查詢的返回值可以是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
}
//資料庫, 通過dao操作數據。
完成這三個文件,表示Room組件已經可以使用。
新建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)
}
}
//該單例對資料庫封裝了一層,方便處理db的各種操作(db初始化可使用依賴注入)
資料庫插入不能在主線程,涉及事務。
到此為止,該框架的資料庫部分已經可以使用。
下面作為例子說明怎麼存數據。//繼承Appication,初始化並模擬插入數據
class ZhiJokeApplication : Application() {
override fun onCreate() {
super.onCreate()
DatabaseManager.initDb(this)
DatabaseManager.simlutateInsertData()
}
}
編譯項目運行,此時真機上應該保存有插入的數據。
怎麼查看
用一台已經root後的測試機,安裝root文件管理器後,在根目錄的 data/data/包名/database, 就能看到資料庫新建並插入的數據了。
用DatabaseManage.loadAllStories()即可取出數據。
未玩待續
完整代碼: github
推薦閱讀: