人升开发日志#9 | 8/30 数据库+数据填充

使用了Litepal作为数据库ORM框架,还有BRAVH来简化RecyclerView的适配器的写法。

这里记录下开发途中遇到的坑。

创建自己的Application类

因为LitePal和MobSDK都需要对Application进行修改,所以最好实现自己的Application:

1
2
3
4
5
6
7
8
9
10
11
import android.app.Application
import com.mob.MobSDK
import org.litepal.LitePal

class LifeUpApplication : Application() {
override fun onCreate() {
super.onCreate()
MobSDK.init(this)
LitePal.initialize(this);
}
}

LitePal最新版的一些用法

实体类继承LitePalSupport而不是原先的DataSupport。

另外Kotlin的var会自动实现getter和setter:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
import org.litepal.crud.LitePalSupport
import java.util.*

data class TaskModel(
var content: String,
var remark: String,
var taskExpireTime: Date?,
var taskRemindTime: Date?,
var relatedAttribute1: String?,
var relatedAttribute2: String?,
var relatedAttribute3: String?,
var taskUrgencyDegree: Int,
var taskDifficultyDegree: Int,
var taskFrequency: Int,
var userId: Int?,
var isShared: Boolean,
var taskType: Int?
) : LitePalSupport() {

var id: Long? = null
var taskId: Long? = null
var createdTime: Long = 0
var updatedTime: Long = 0
var expReward: Int = 0
var endDate: Date? = null
var taskStatus: Int = 0

}

而对数据库的操作方法也从调用DataSupport类的方法变成了调用LitePal类的方法。

如:

1
2
3
fun getFirstAttribute(): AttributeModel? {
return LitePal.findFirst(AttributeModel::class.java)
}

其他的话,没什么不一样。

刷新RecyclerView数据

需要注意的一个坑是,RecyclerView的Adapter用的List不能重新指向一个新的引用。

必须用回原本的引用更改数据,然后再调用notifyDataSetChanged()就能刷新数据了。

1
2
3
4
5
6
private fun refreshDataSet() {
mList.clear()
mList.addAll(todoService.getUncompletedTodoList())

mAdapter.notifyDataSetChanged()
}

当返回或是切换Fragment刷新数据

1
2
3
4
5
6
7
8
9
10
11
override fun onResume() {
super.onResume()
refreshDataSet() //刷新数据的操作
}

override fun onHiddenChanged(hidden: Boolean) {
super.onHiddenChanged(hidden)
if (!hidden) {
refreshDataSet() //刷新数据的操作
}
}

Lottie的动画回调调用多次的问题

原本在Lottie的结束和取消回调里调用一个对话框的显示的方法,实际使用发现这个回调会被调用数次?(有时候1次,有时候2次,3次。很是诡异。)

解决方法自然是加个boolean值标识:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
var isEverShowDialog = false

mView.addAnimatorListener(object : Animator.AnimatorListener {
override fun onAnimationRepeat(p0: Animator?) {

}

override fun onAnimationEnd(p0: Animator?) {
if (!isEverShowDialog) {
showDialogAbbr(item)
isEverShowDialog = true
}
//refreshHeaderView(mHeaderView)
}

override fun onAnimationCancel(p0: Animator?) {
if (!isEverShowDialog) {
showDialogAbbr(item)
isEverShowDialog = true
}
}

override fun onAnimationStart(p0: Animator?) {

}
})

获得经验值的进度条动画的实现

讲真,这个小小的动画实现可能是我花费时间最长的一个小模块了。

首先要解决无论是3个属性都选择了,还是只选择了1个,2个都能正确显示的问题。

其次,需要计算获得经验值前的经验值与等级的占比,来正确显示ProgressBar(进度条)的进度。

还需要判断会不会升级,如果升级要将进度条置为0再进行下一步操作。

还要保证进度增长的时间是大概一致的。

还需要用到多线程来实现进度的缓慢增长。

等等……

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
private fun doProgressOrigin(dialogView: View, item: TaskModel, index: Int) {
val relatedAttribute = when (index) {
1 -> item.relatedAttribute1
2 -> item.relatedAttribute2
3 -> item.relatedAttribute3
else -> return
}

if (relatedAttribute.isNullOrBlank()) return

//完成前的
val nowExpTotal = when (index) {
1 -> attributeService.getAttributeExpByString(relatedAttribute ?: "") - item.expReward
2 -> attributeService.getAttributeExpByString(item.relatedAttribute2
?: "") - item.expReward
3 -> attributeService.getAttributeExpByString(item.relatedAttribute3
?: "") - item.expReward
else -> return
}


var nowExp = nowExpTotal - attributeLevelService.getAttributeLevelByExp(nowExpTotal).startExpValue
val levelMaxExp = attributeLevelService.getAttributeLevelByExp(nowExpTotal).endExpValue - attributeLevelService.getAttributeLevelByExp(nowExpTotal).startExpValue

val progressBar = when (index) {
1 -> dialogView.npb_first
2 -> dialogView.npb_Sec
3 -> dialogView.npb_thr
else -> return
}

progressBar.progress = nowExp * 100 / levelMaxExp
var finalProgress = (nowExp + item.expReward) * 100 / levelMaxExp


if (finalProgress >= 100) {
//要升级的情况
thread = Thread {
try {
//先走到尾巴
val toMax = progressBar.max - progressBar.progress
while (threadRunning == true && progressBar.progress != progressBar.max) {
activity?.runOnUiThread { progressBar.incrementProgressBy(if (toMax / 20 > 0) toMax / 20 else 1) }
Thread.sleep(40)
}

//升级,进度条重置为0
val newLevelModel = attributeLevelService.getAttributeLevelByExp(nowExpTotal + item.expReward)
val textViewLevel = when (index) {
1 -> dialogView.tv_levelFirst
2 -> dialogView.tv_levelSec
3 -> dialogView.tv_expThr
else -> return@Thread
}
activity?.runOnUiThread {
progressBar.progress = 0
textViewLevel.text = "LV${newLevelModel.levelNum}"
}

nowExp = nowExpTotal + item.expReward - newLevelModel.startExpValue
val nextMaxExpTotal = newLevelModel.endExpValue
val nextMaxExp = newLevelModel.endExpValue - newLevelModel.startExpValue
finalProgress = nowExp * 100 / nextMaxExp
Thread.sleep(40)

while (threadRunning == true && progressBar.progress != finalProgress) {
activity?.runOnUiThread { progressBar.incrementProgressBy(if (finalProgress / 30 > 0) finalProgress / 30 else 1) }
Thread.sleep(40)
}

} catch (e: InterruptedException) {
e.printStackTrace()
}
}
thread?.start()
} else {
//不需要升级
thread = Thread {
try {
var progressToGo = finalProgress - progressBar.progress

while (threadRunning == true && progressBar.progress != finalProgress) {
activity?.runOnUiThread { progressBar.incrementProgressBy(if (progressToGo / 30 > 0) progressToGo / 30 else 1) }
Thread.sleep(40)
}
} catch (e: InterruptedException) {
e.printStackTrace()
}
}
thread?.start()
}

自定义View对话框的宽和高

用了网上各种改跟View,getWindow然后setLayout的方法通通行不通。

最后发现在自定义View的根View里加上android:minHeightandroid:minWidth两个属性就好了。

ToolBar最右侧显示按钮图标

其实那个按钮是OptionMenu里面的Item。

设置Menu的时候将app:showAsAction设为always就可以强制显示图标了。

Menu布局文件:

1
2
3
4
5
6
7
8
9
10
11
12
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
tools:context="net.sarasarasa.lifeup.activities.AddToDoItemActivity">
<item
android:id="@+id/action_finish"
android:icon="@drawable/ic_done_white_24dp"
android:orderInCategory="100"
android:title="完成"
app:showAsAction="always" />
</menu>

Activity代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
override fun onCreateOptionsMenu(menu: Menu): Boolean {
menuInflater.inflate(R.menu.menu_add_to_do_item, menu)
return true
}

override fun onOptionsItemSelected(item: MenuItem): Boolean {
when (item.itemId) {
R.id.action_finish -> {
if (check()) {
addItem(getItem())
}
return true
}
else -> return super.onOptionsItemSelected(item)
}
}

人升开发日志#9 | 8/30 数据库+数据填充

http://sarasarasa.net/post/e7c566a6.html

作者

AyagiKei

发布于

2018-08-30

更新于

2021-08-10

许可协议

评论