请看 WiKi
- 修复Fragment存在的内存泄漏问题 1.binding 2.livedata.observe
- 删除测试用例
- 增加flow替换livedata的示例代码,收藏界面仍旧保留livedata的示例
- 首页水果详情增加取消收藏功能
- 调整viewModel目录到具体的fragment目录或activity目录下:
├── ui //UI层
│ ├── BaseActivity.kt
│ ├── BindingAdapter.kt
│ ├── MainActivity.kt
│ ├── fragment
│ ├ viewmodels
│ │ └── LoggerInfoViewModel.kt
│ │ ├── BaseFragment.kt
│ │ ├── FruitPicDetailFragment.kt
│ ├── activity
│ ├ viewmodels
│ │ └── xxx.kt
│ │ ├── BaseActivity.kt
│ │ ├── Activity.kt
│ ├── recycler
│ │ ├── DividerItemDecoration.java
│ │ └── adapter
│ │ ├── FruitListAdapter.kt
│ │ └── LikeFruitsAdapter.kt
│ └── views
│ └── LoadingDialog.kt
- 不导入第三方依赖注入工具,以RepositoryLoader为上层提供数据接口,以符合依赖导致原则
- MainActivityTest : 该用例测试软件的展示功能,收藏功能是否正常
- FruitsRepositoryTest
- LikeFruitsRepositoryTest
- LogInfoRepositoryTest
.
├── App.kt
├── extensions
│ └── MutableList.kt
├── log //业务单元
├── repository // 数据存储区
│ ├── data
│ ├── database
│ └── impl
│ └── FruitsRepository.kt
│ ├── IFruitsRepository.kt
├── ui //UI层
│ ├── BaseActivity.kt
│ ├── BindingAdapter.kt
│ ├── MainActivity.kt
│ ├── fragment
│ │ ├── BaseFragment.kt
│ │ ├── FruitPicDetailFragment.kt
│ ├── recycler
│ │ ├── DividerItemDecoration.java
│ │ └── adapter
│ │ ├── FruitListAdapter.kt
│ │ └── LikeFruitsAdapter.kt
│ ├── viewmodels
│ │ └── LoggerInfoViewModel.kt
│ └── views
│ └── LoadingDialog.kt
└── utils
└── ProcessUtils.java
-
根目录:放App类,主服务类
-
extensions :存放扩展方法的文件,命名规范:扩展哪个类的方法就以该类名称命名
-
log:存放的是日志收集器的业务实现,属于业务层
-
repository: 数据存储区存放向ViewModel提供数据的Repository接口,
-
- data:存放data class
- database :存放本地数据库相关内容
- impl:Repository 具体实现
- IFruitsRepository.kt Repository接口
-
ui : view层和viewModel层。
-
- Activity、BindingAdapter存放在该层根目录
- fragment : 存放fragment类
- recycler: 存放recycler的adapter,分割线样式相关类
-
views: 存放自定义View
-
utils:存放全局工具类
-
基础
-核心系统功能,Kotlin扩展以及对Multidex和自动化测试的支持的组件。
- AppCompat-在旧版Android上优雅降级。
- Android KTX-编写更简洁,惯用的Kotlin代码。
- Test -用于单元和运行时UI测试的Android测试框架。
-
体系结构
- Data Binding -以声明方式将可观察的数据绑定到UI元素。
- Lifecycles -创建一个自动响应生命周期事件的UI。
- LiveData-构建数据对象,这些数据对象在基础数据库更改时通知视图。
- Navigation -处理应用Fragment和Activity导航所需的一切。
- Room -使用应用内对象和编译时检查来访问应用的SQLite数据库。
- ViewModel-存储与用户界面相关的数据,这些数据在应用程序旋转时不会被破坏。轻松安排异步任务以实现最佳执行。
- WorkManager-管理您的Android后台作业。
-
第三方
- Glide以加载图像
- Kotlin Coroutines 通过简化的代码管理后台线程并减少了对回调的需求
- Logger 打印漂亮的日志
- Gson Json转换的支持
下面给出两种获取ViewModel的示例,由于篇幅问题,其他库的使用示例请看代码
class LikeFruitsViewModel(
private val likeFruitsRepository: LikeFruitsRepository
) : ViewModel() {
//模拟该数据是向数据库获取,数据库为唯一数据源
var fruits: LiveData<List<Fruit>> = likeFruitsRepository.load()
suspend fun deleteFromDataBase(fruit: Fruit) {
fruits.value?.let {
likeFruitsRepository.deleteFromDataBase(fruit)
}
}
fun getFruit(id: String): Fruit? {
return likeFruitsRepository.getFruit(id)
}
suspend fun deleteFromDataBase(position: Int) {
fruits.value?.let {
likeFruitsRepository.deleteFromDataBase(it[position])
}
}
suspend fun saveToDataBase(fruits: List<Fruit>): List<Long> {
return likeFruitsRepository.saveToDataBase(fruits)
}
}
class LikeFruitFragment : BaseFragment<FragmentLikeFruitsBinding>() {
//委托生成ViewModel,获取的viewModel不是共享的
private val likeFruitsViewModel: LikeFruitsViewModel by viewModels ()
override fun onBinding(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): FragmentLikeFruitsBinding = FragmentLikeFruitsBinding.inflate(
inflater, container, false
)
override fun setupUI(binding: FragmentLikeFruitsBinding) {
//使用ViewModelProvider生成ViewModel,获取共享的ViewModel
likeFruitsViewModel = ViewModelProvider(
requireActivity(), ViewModelProvider.NewInstanceFactory()
).get(LikeFruitsViewModel::class.java)
}
//订阅数据更新
private fun subscribeUI() {
likeFruitsViewModel.fruits.observe(viewLifecycleOwner) {
Logger.d("LikeFruitsActivity observe = $it")
}
}
}
ext {
kotlinVersion = '1.3.50'
navigationVersion = '2.0.0'
}
dependencies {
classpath 'com.android.tools.build:gradle:3.5.1'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlinVersion"
classpath "androidx.navigation:navigation-safe-args-gradle-plugin:$navigationVersion"
}
//jetpack,kotlin需要添加如下插件
apply plugin: 'kotlin-android'
apply plugin: 'kotlin-android-extensions'
apply plugin: 'kotlin-kapt'
apply plugin: 'androidx.navigation.safeargs'
android {
...
//启用dataBinding
dataBinding {
enabled = true
}
defaultConfig {
...
//单元测试
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
//设置room输出描述数据库结构文件的目录
javaCompileOptions {
annotationProcessorOptions {
arguments = ["room.schemaLocation":
"$projectDir/schemas".toString()]
}
}
}
...
// work-runtime-ktx 2.1.0 and above now requires Java 8
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
// work-runtime-ktx 2.1.0 and above now requires Java 8
kotlinOptions {
jvmTarget = "1.8"
}
//Kotlin-Android-Extensions
androidExtensions {
experimental = true
}
}
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.5.0"
implementation 'androidx.appcompat:appcompat:1.3.1'
implementation "androidx.fragment:fragment-ktx:1.3.6"
implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:2.4.0-alpha01"
implementation "androidx.lifecycle:lifecycle-livedata-ktx:2.4.0-alpha01"
implementation "androidx.lifecycle:lifecycle-runtime-ktx:2.4.0-alpha01"
implementation "androidx.navigation:navigation-fragment-ktx:2.3.5"
implementation "androidx.navigation:navigation-ui-ktx:2.3.5"
kapt "androidx.room:room-compiler:2.3.0"
implementation "androidx.room:room-runtime:2.3.0"
implementation "androidx.room:room-ktx:2.3.0"
implementation 'androidx.core:core-ktx:1.6.0'
implementation 'androidx.legacy:legacy-support-v4:1.0.0'
implementation 'androidx.recyclerview:recyclerview:1.2.1'
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.5.0"
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:1.5.0"
implementation "androidx.work:work-runtime-ktx:2.5.0"
// implementation "com.squareup.okhttp3:okhttp:4.1.0"
implementation 'com.google.android.material:material:1.4.0'
implementation 'com.orhanobut:logger:2.2.0'
implementation "com.google.code.gson:gson:2.8.6"
implementation "com.github.bumptech.glide:glide:4.10.0"
implementation 'androidx.constraintlayout:constraintlayout:2.1.0'
testImplementation 'junit:junit:4.12'
androidTestImplementation 'androidx.test.ext:junit:1.1.2'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0'
androidTestImplementation 'com.android.support.test.espresso:espresso-contrib:3.0.2'
androidTestImplementation 'com.android.support.test:rules:1.0.2'
androidTestImplementation "androidx.work:work-testing:2.5.0"
}