前言
本人Android小菜雞一枚,開發該app的主要目的是為了鞏固kotlin語法,學習使用JetPack進行一個完整App的開發,不得不說,Kotlin+JetPack開發起來真是無敵絲滑(末尾附上專案地址)
介紹
😄時刻是一個使用純kotlin和Jetpack實作的具有簡單增刪改查功能的日記App
效果圖






使用的相關技術
- DataBinding :省去了繁瑣的findViewById作業,而且通過和ViewMode配合,可以直接把ViewModel的資料渲染到界面上
- Paging:分頁加載庫
郭神的博客 - Room:封裝了sqlite,將表映射成Java或Kotlin物件,我覺得相比于之前使用的greendao,room最大的優勢是支持了kotlin的flow,通過和paging配合,實作自動的重繪資料鏈接
- dataStore:用來代替SP的資料持久化方案,最大的優勢是支持異步獲取保存資料,通過一個PreferencesKey保存對應型別泛型的方法保證了型別安全
- ViewModel:用于保存actvity的資料中轉
- Glide:圖片加載,這個太牛皮了就不介紹了
- liveData:代替EventBus用于進行事件分發
部分代碼展示
- 日記的主題顏色更改
/**
* 設定日記編輯的背景主題
* 判斷顏色是否是亮色,設定對應主題字體
*
* todo 自定義背景功能
*/
private fun setThemeBackGround(@ColorRes colorRes: Int) {
val color: Int = ContextCompat.getColor(this, colorRes)
mBinding.clEditDairy.setBackgroundResource(colorRes)
setStatusBarColor(color)
if (ColorUtils.calculateLuminance(color) > 0.6) {
// 亮色
setAndroidNativeLightStatusBar(this, true)
} else {
// 暗色
setAndroidNativeLightStatusBar(this, false)
}
val shape = GradientDrawable()
shape.color = ColorStateList.valueOf(addColorDepth(color))
shape.cornerRadius = dp2px(baseContext, 5f)
ripperDrawable =
RippleDrawable(ColorStateList.valueOf(ContextCompat.getColor(this, R.color.DairyEditHintText)), shape, null)
}
/**
* 將原有顏色的R,G,B值依次減去20得到一個更深的顏色
*/
private fun addColorDepth(color: Int): Int {
var red = color and 0xff0000 shr 16
var green = color and 0x00ff00 shr 8
var blue = color and 0x0000ff
red = if (red - 25 > 0) red - 25 else 0
green = if (green - 25 > 0) green - 25 else 0
blue = if (blue - 25 > 0) blue - 25 else 0
return Color.rgb(red, green, blue)
}
- 日記意外退出恢復功能
/**
這里把保存操作寫在onPause里,因為不管是手動退出app還是意外終止app都一定會走到該方法,然后增加一個標記表示是意外中止
**/
override fun onPause() {
super.onPause()
if (!TextUtils.isEmpty(viewModel.dairyContent.value) && isNeedToSaved) {
DataStoreUtils.saveSyncStringData(RECOVER_CONTENT, viewModel.dairyContent.value!!)
DataStoreUtils.saveSyncStringData(RECOVER_TITLE, mBinding.appBar.getTitle())
}
}
/**
恢復操作,開始一個協程,異步獲取
**/
private fun tryToRecoverDairy() {
lifecycleScope.launch(Dispatchers.Main) {
DataStoreUtils.readStringFlow(RECOVER_CONTENT).first {
if (it.isNotEmpty()) {
recoveredContent = it
}
true
}
DataStoreUtils.readStringFlow(RECOVER_TITLE).first {
if (it.isNotEmpty()) {
recoveredTitle = it
}
true
}
}
- 主界面獲取日記串列的操作
/**
Activity層
Activity里呼叫到viewModel
**/
private fun getDairyData() {
lifecycleScope.launch(Dispatchers.Main) {
viewModel.getAllDairy().collect {
dairyAdapter.submitData(it)
}
}
}
/**
ViewModel層
ViewModel當作中轉站,通過持有的倉庫物件repository訪問到資料庫
**/
fun getAllDairy(): Flow<PagingData<DairyItem>> {
return repository.getAllDairyData().cachedIn(viewModelScope)
}
/**
repository層
查找表獲得所有日記
**/
fun getAllDairyData(): Flow<PagingData<DairyItem>> {
return Pager(
config = PagingConfig(PAGE_SIZE, maxSize = 150),
pagingSourceFactory = dairyDao.getAllDairy().asPagingSourceFactory()
).flow
}
/**
* Dao層 這里通過和Paging的factory系結,資料庫變動后會自動的重繪到paging中
* 用DataSource把資料系結到Paging 回應式
* 根據時間降序查找
*/
@Query("SELECT * FROM DairyEntity order by createTime desc")
fun getAllDairy(): DataSource.Factory<Int, DairyItem>
- 調起手機的相冊和相機
/**
這里我使用了新版的啟動器方式來調起,只需要寫一個啟動器和一個啟動協議
* 初始化相冊啟動器
*/
private val toAlbumLauncher =
registerForActivityResult(ToSystemAlbumResultContract()) {
if (it != null) {
viewModel.pictureList.add(it)
viewModel.isChanged.value = true
// 只需要重繪新增的一個和尾部,也是就itemCount為2
pictureSelectAdapter.notifyItemRangeChanged(viewModel.pictureList.size, 2)
}
}
/**
* 初始化相機啟動器
*/
private val toCameraLauncher =
registerForActivityResult(ActivityResultContracts.TakePicture()) {
if (it) {
viewModel.pictureList.add(currentUri)
viewModel.isChanged.value = true
pictureSelectAdapter.notifyItemRangeChanged(viewModel.pictureList.size, 2)
galleryAddPic()
}
}
/**
* 跳轉到系統相冊
* 傳入引數 ArrayList<Bitmap> 圖片串列
* 回傳引數 Int 標識哪一張圖片被洗掉
*/
inner class ToSystemAlbumResultContract : ActivityResultContract<Unit, Uri?>() {
override fun createIntent(context: Context, input: Unit?): Intent {
val intent = Intent(
Intent.ACTION_PICK,
MediaStore.Images.Media.EXTERNAL_CONTENT_URI
)
intent.type = "image/*"
return intent
}
override fun parseResult(resultCode: Int, intent: Intent?): Uri? {
return intent?.data
}
}
最后
原始碼中代碼的注釋非常詳細,有興趣的大佬可以進去看看吶
Kotlin的擴展函式用起來賊爽
github地址:LongerRelationShip
有興趣的大佬可以下載提提建議
時刻下載地址

后期開發功能
- 記賬功能
- 錄音筆記功能
- App的圖庫功能
- 日記的收藏和設定私密
感謝
- 界面設計很大部分參考了該設計
美貼 記事原型 - 代碼的學習參考
Eyepetizer
官方的代碼示例
Sunflower
轉載請註明出處,本文鏈接:https://www.uj5u.com/yidong/299365.html
標籤:其他
下一篇:微信人臉SDK集成踩坑
