Skip to content
Toggle navigation
P
Projects
G
Groups
S
Snippets
Help
huangzhicong
/
SmartCanteen
This project
Loading...
Sign in
Toggle navigation
Go to a project
Project
Repository
Issues
0
Merge Requests
0
Pipelines
Wiki
Snippets
Members
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Commit
c6dbb993
authored
Jul 10, 2020
by
pye52
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
QRCodeVIewModel重构Kotlin完毕
parent
bc5f9705
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
150 additions
and
171 deletions
+150
-171
app/src/main/java/com/bgycc/smartcanteen/activity/MainActivity.java
+4
-0
app/src/main/java/com/bgycc/smartcanteen/viewModel/CommandViewModel.kt
+8
-19
app/src/main/java/com/bgycc/smartcanteen/viewModel/QRCodeViewModel.java
+0
-152
app/src/main/java/com/bgycc/smartcanteen/viewModel/QRCodeViewModel.kt
+138
-0
No files found.
app/src/main/java/com/bgycc/smartcanteen/activity/MainActivity.java
View file @
c6dbb993
...
@@ -243,6 +243,10 @@ public class MainActivity extends AppCompatActivity implements View.OnClickListe
...
@@ -243,6 +243,10 @@ public class MainActivity extends AppCompatActivity implements View.OnClickListe
@Override
@Override
public
void
onChanged
(
Command
command
)
{
public
void
onChanged
(
Command
command
)
{
if
(
command
==
null
)
{
reset
();
return
;
}
// 若为debug模式切换命令,则直接执行即可
// 若为debug模式切换命令,则直接执行即可
if
(
CommandHelper
.
isLogConfig
(
command
))
{
if
(
CommandHelper
.
isLogConfig
(
command
))
{
toggleDebugLayout
();
toggleDebugLayout
();
...
...
app/src/main/java/com/bgycc/smartcanteen/viewModel/CommandViewModel.kt
View file @
c6dbb993
...
@@ -15,35 +15,24 @@ import com.google.gson.Gson
...
@@ -15,35 +15,24 @@ import com.google.gson.Gson
import
com.google.gson.JsonObject
import
com.google.gson.JsonObject
import
kotlinx.coroutines.launch
import
kotlinx.coroutines.launch
/**
* 监听本地扫码、服务器下发的设置指令 <br/>
* 监听Command数据库的变动,按如下流程进行处理: <br/>
* 从数据库读取 -> 解析执行 -> 更新到数据库
*/
class
CommandViewModel
(
class
CommandViewModel
(
private
var
commandRepository
:
CommandRepository
,
private
var
commandRepository
:
CommandRepository
,
private
var
gson
:
Gson
,
private
var
gson
:
Gson
,
private
var
deviceSN
:
String
private
var
deviceSN
:
String
)
:
ViewModel
()
{
)
:
ViewModel
()
{
val
commandWorker
=
MutableLiveData
<
Command
>()
val
commandTask
=
Transformations
.
map
(
private
val
dataLiveData
:
LiveData
<
List
<
Command
>>
=
commandRepository
.
queryUndoneCommand
()
commandRepository
.
queryUndoneCommand
()
)
{
it
?.
firstOrNull
()
}
private
val
dataObserver
=
Observer
<
List
<
Command
>>
{
commands
:
List
<
Command
>?
->
if
(
commands
==
null
||
commands
.
isEmpty
())
{
return
@Observer
}
commandWorker
.
postValue
(
commands
.
first
())
}
init
{
// 监听数据库的变动,并执行未完成的指令
dataLiveData
.
observeForever
(
dataObserver
)
}
fun
initialize
()
{
fun
initialize
()
{
SCWebSocketClient
.
getInstance
().
addListener
(
listener
)
SCWebSocketClient
.
getInstance
().
addListener
(
listener
)
}
}
override
fun
onCleared
()
{
super
.
onCleared
()
dataLiveData
.
removeObserver
(
dataObserver
)
}
fun
getCommandWorker
(
command
:
Command
?):
OneTimeWorkRequest
?
{
fun
getCommandWorker
(
command
:
Command
?):
OneTimeWorkRequest
?
{
return
CommandHelper
.
createWorker
(
gson
,
command
,
deviceSN
)
return
CommandHelper
.
createWorker
(
gson
,
command
,
deviceSN
)
}
}
...
...
app/src/main/java/com/bgycc/smartcanteen/viewModel/QRCodeViewModel.java
deleted
100644 → 0
View file @
bc5f9705
package
com
.
bgycc
.
smartcanteen
.
viewModel
;
import
android.text.TextUtils
;
import
androidx.lifecycle.LiveData
;
import
androidx.lifecycle.MutableLiveData
;
import
androidx.lifecycle.ViewModel
;
import
com.bgycc.smartcanteen.entity.Command
;
import
com.bgycc.smartcanteen.entity.PayData
;
import
com.bgycc.smartcanteen.qrcode.IQRCodeScan
;
import
com.bgycc.smartcanteen.state.QRCodeState
;
import
com.bgycc.smartcanteen.executor.SCTaskExecutor
;
import
com.bgycc.smartcanteen.repository.CommandRepository
;
import
com.bgycc.smartcanteen.repository.PayDataRepository
;
import
com.bgycc.smartcanteen.utils.DeviceProxy
;
import
com.bgycc.smartcanteen.utils.SmartCanteenUtils
;
import
com.blankj.utilcode.util.LogUtils
;
import
com.google.gson.JsonObject
;
import
com.google.gson.JsonParser
;
import
java.util.concurrent.ScheduledFuture
;
import
java.util.concurrent.TimeUnit
;
import
static
com
.
bgycc
.
smartcanteen
.
entity
.
PayData
.
TYPE_COMMAND
;
import
static
com
.
bgycc
.
smartcanteen
.
utils
.
SmartCanteenUtils
.
TAG
;
/**
* 负责读取串口数据,并将串口数据识别为设备指令或支付订单,保存到本地数据库中。<br/><br/>
* 串口状态(空闲、读取中、读取成功、读取失败)都会通过{@link QRCodeState}发出通知 <br/><br/>
* 调用{@link #initialize()}进行初始化,初始化完毕后,将在子线程中执行串口读取 <br/><br/>
* 当串口数据读取异常后,会在{@link #DELAY}毫秒后重新进入读取状态,若读取成功后,需要手动调用{@link #scan()}方法进入读取状态 <br/><br/>
*/
public
class
QRCodeViewModel
extends
ViewModel
{
private
static
final
String
RESPONSE_ACTION
=
"action"
;
private
static
final
long
DELAY
=
1500
;
private
PayDataRepository
payDataRepository
;
private
CommandRepository
commandRepository
;
private
String
deviceSN
;
private
ScheduledFuture
<?>
scanFuture
;
private
IQRCodeScan
scan
;
private
MutableLiveData
<
QRCodeState
>
qrCodeState
=
new
MutableLiveData
<>();
public
QRCodeViewModel
(
PayDataRepository
payDataRepository
,
CommandRepository
commandRepository
,
String
deviceSN
)
{
this
.
payDataRepository
=
payDataRepository
;
this
.
commandRepository
=
commandRepository
;
this
.
deviceSN
=
deviceSN
;
}
public
LiveData
<
QRCodeState
>
getQRCodeStateEvent
()
{
return
qrCodeState
;
}
public
void
initialize
()
{
try
{
scan
=
DeviceProxy
.
createQRCodeScan
();
scan
();
}
catch
(
Exception
e
)
{
LogUtils
.
e
(
TAG
,
"串口初始化失败: "
+
e
.
getMessage
(),
e
);
scan
=
null
;
qrCodeState
.
postValue
(
new
QRCodeState
(
QRCodeState
.
INIT_FAILED
));
}
}
public
void
scan
()
{
if
(
scan
==
null
)
return
;
if
(
scanFuture
==
null
||
scanFuture
.
isDone
())
{
scanFuture
=
SCTaskExecutor
.
getInstance
().
schedule
(
scanRunnable
,
DELAY
,
TimeUnit
.
MILLISECONDS
);
}
}
private
Runnable
scanRunnable
=
()
->
{
qrCodeState
.
postValue
(
new
QRCodeState
(
QRCodeState
.
IDLE
));
LogUtils
.
i
(
TAG
,
"开始扫描二维码"
);
while
(!
scan
.
available
())
{}
qrCodeState
.
postValue
(
new
QRCodeState
(
QRCodeState
.
SCANNING
));
// 读取串口扫描的二维码数据
String
scanData
;
try
{
scanData
=
scan
.
scan
();
}
catch
(
Exception
e
)
{
LogUtils
.
e
(
TAG
,
"读取串口数据失败: "
+
e
.
getMessage
(),
e
);
qrCodeState
.
postValue
(
new
QRCodeState
(
QRCodeState
.
FAILED
));
return
;
}
// 若存在测试数据,则使用测试数据覆盖
if
(!
TextUtils
.
isEmpty
(
SmartCanteenUtils
.
testQRCode
))
{
scanData
=
SmartCanteenUtils
.
testQRCode
;
}
// 需要识别二维码的类型
String
terminalType
=
PayData
.
matchTerminalType
(
scanData
);
if
(
terminalType
.
equals
(
TYPE_COMMAND
))
{
// 设备指令需要单独处理(由CommandViewModel处理)
JsonObject
jsonObject
;
try
{
jsonObject
=
JsonParser
.
parseString
(
scanData
).
getAsJsonObject
();
}
catch
(
Exception
e
)
{
LogUtils
.
e
(
TAG
,
"非法的指令格式: "
+
scanData
,
e
);
qrCodeState
.
postValue
(
new
QRCodeState
(
QRCodeState
.
FAILED
));
return
;
}
if
(
jsonObject
.
has
(
RESPONSE_ACTION
))
{
String
action
=
jsonObject
.
get
(
RESPONSE_ACTION
).
getAsString
();
Command
command
=
new
Command
(
scanData
,
action
);
commandRepository
.
insertCommand
(
command
);
LogUtils
.
d
(
TAG
,
"扫码结果: "
+
command
.
toString
());
// 任务写入数据库成功后,主动发送一次IDLE,以重置界面提示语
qrCodeState
.
postValue
(
new
QRCodeState
(
QRCodeState
.
SUCCESS
,
scanData
));
againDelay
();
}
else
{
qrCodeState
.
postValue
(
new
QRCodeState
(
QRCodeState
.
FAILED
));
}
return
;
}
PayData
newPay
=
new
PayData
(
deviceSN
,
scanData
,
terminalType
);
// 扫描到的二维码,先检查该订单是否已存在
PayData
existsPay
=
payDataRepository
.
queryPayDataByPayCode
(
scanData
);
if
(
existsPay
!=
null
)
{
LogUtils
.
w
(
TAG
,
"该订单已存在: "
+
scanData
);
qrCodeState
.
postValue
(
new
QRCodeState
(
QRCodeState
.
SCAN_REPEAT
));
return
;
}
// 扫描到的二维码保存到数据库
long
lastInsertId
=
payDataRepository
.
insertPayData
(
newPay
);
if
(
lastInsertId
==
-
1
)
{
LogUtils
.
e
(
TAG
,
"数据库插入失败: "
+
newPay
.
toString
());
}
LogUtils
.
d
(
TAG
,
"扫码结果: "
+
newPay
.
toString
());
qrCodeState
.
postValue
(
new
QRCodeState
(
QRCodeState
.
SUCCESS
,
newPay
,
newPay
.
getPayCode
()));
};
private
void
againDelay
()
{
SCTaskExecutor
.
getInstance
().
schedule
(
scanRunnable
,
DELAY
,
TimeUnit
.
MILLISECONDS
);
}
@Override
protected
void
onCleared
()
{
super
.
onCleared
();
if
(
scanFuture
!=
null
)
{
scanFuture
.
cancel
(
true
);
scanFuture
=
null
;
}
if
(
scan
!=
null
)
{
scan
.
close
();
}
}
}
app/src/main/java/com/bgycc/smartcanteen/viewModel/QRCodeViewModel.kt
0 → 100644
View file @
c6dbb993
package
com.bgycc.smartcanteen.viewModel
import
androidx.lifecycle.MutableLiveData
import
androidx.lifecycle.ViewModel
import
androidx.lifecycle.viewModelScope
import
com.bgycc.smartcanteen.entity.Command
import
com.bgycc.smartcanteen.entity.PayData
import
com.bgycc.smartcanteen.executor.coroutinesDispatcher
import
com.bgycc.smartcanteen.qrcode.IQRCodeScan
import
com.bgycc.smartcanteen.repository.CommandRepository
import
com.bgycc.smartcanteen.repository.PayDataRepository
import
com.bgycc.smartcanteen.state.QRCodeState
import
com.bgycc.smartcanteen.utils.DeviceProxy
import
com.bgycc.smartcanteen.utils.SmartCanteenUtils
import
com.bgycc.smartcanteen.utils.SmartCanteenUtils.TAG
import
com.blankj.utilcode.util.LogUtils
import
com.google.gson.JsonObject
import
com.google.gson.JsonParser
import
kotlinx.coroutines.*
/**
* 负责读取串口数据,并将串口数据识别为设备指令或支付订单,保存到本地数据库中。
*
* 串口状态(空闲、读取中、读取成功、读取失败)都会通过[QRCodeState]发出通知
*
* 调用[.initialize]进行初始化,初始化完毕后,将在子线程中执行串口读取
*
* 当串口数据读取异常后,会在[.DELAY]毫秒后重新进入读取状态,若读取成功后,需要手动调用[.scan]方法进入读取状态
*/
class
QRCodeViewModel
(
private
val
payDataRepository
:
PayDataRepository
,
private
val
commandRepository
:
CommandRepository
,
private
val
deviceSN
:
String
)
:
ViewModel
()
{
companion
object
{
private
const
val
RESPONSE_ACTION
=
"action"
private
const
val
SCAN_CHECK_DELAY
=
100L
private
const
val
DELAY
=
1500L
}
private
var
scanFuture
:
Job
?
=
null
private
var
scan
:
IQRCodeScan
?
=
null
val
qrCodeState
=
MutableLiveData
<
QRCodeState
>()
fun
initialize
()
{
try
{
scan
=
DeviceProxy
.
createQRCodeScan
()
scan
()
}
catch
(
e
:
Exception
)
{
LogUtils
.
e
(
TAG
,
"串口初始化失败: "
+
e
.
message
,
e
)
scan
=
null
qrCodeState
.
postValue
(
QRCodeState
.
INIT_FAILED
.
instance
())
}
}
fun
scan
()
{
val
scan
=
scan
?:
return
scanFuture
?.
cancel
()
scanFuture
=
viewModelScope
.
launch
(
coroutinesDispatcher
)
{
delay
(
DELAY
)
qrCodeState
.
postValue
(
QRCodeState
(
QRCodeState
.
IDLE
))
LogUtils
.
i
(
TAG
,
"开始扫描二维码"
)
while
(!
scan
.
available
())
{
delay
(
SCAN_CHECK_DELAY
)
qrCodeState
.
postValue
(
QRCodeState
.
SCANNING
.
instance
())
}
// 读取串口扫描的二维码数据
var
scanData
:
String
try
{
scanData
=
withContext
(
Dispatchers
.
IO
)
{
scan
.
scan
()
}
}
catch
(
e
:
Exception
)
{
LogUtils
.
e
(
TAG
,
"读取串口数据失败: "
+
e
.
message
,
e
)
qrCodeState
.
postValue
(
QRCodeState
.
FAILED
.
instance
())
return
@launch
}
// 若存在测试数据,则使用测试数据覆盖
if
(
SmartCanteenUtils
.
testQRCode
.
isNotBlank
())
{
scanData
=
SmartCanteenUtils
.
testQRCode
}
// 若二维码是设备指令,则需要单独处理
val
terminalType
=
PayData
.
matchTerminalType
(
scanData
)
if
(
terminalType
==
PayData
.
TYPE_COMMAND
)
{
parseAndGetAction
(
scanData
)
return
@launch
}
val
newPay
=
PayData
(
deviceSN
,
scanData
,
terminalType
)
// 扫描到的二维码,先检查该订单是否已存在
payDataRepository
.
queryPayDataByPayCode
(
scanData
)
?.
let
{
// 扫描到的二维码保存到数据库
if
(
payDataRepository
.
insertPayData
(
newPay
)
==
-
1L
)
{
LogUtils
.
e
(
TAG
,
"数据库插入失败: $newPay"
)
}
LogUtils
.
d
(
TAG
,
"扫码结果: $newPay"
)
qrCodeState
.
postValue
(
QRCodeState
.
SUCCESS
.
instance
(
newPay
,
newPay
.
payCode
))
}
?:
let
{
LogUtils
.
w
(
TAG
,
"该订单已存在: $scanData"
)
qrCodeState
.
postValue
(
QRCodeState
.
SCAN_REPEAT
.
instance
())
}
}
}
private
suspend
fun
parseAndGetAction
(
scanData
:
String
)
{
// 设备指令需要单独处理(由CommandViewModel处理)
val
jsonObject
:
JsonObject
try
{
jsonObject
=
JsonParser
.
parseString
(
scanData
).
asJsonObject
}
catch
(
e
:
Exception
)
{
LogUtils
.
e
(
TAG
,
"非法的指令格式: $scanData"
,
e
)
qrCodeState
.
postValue
(
QRCodeState
.
FAILED
.
instance
())
return
}
jsonObject
[
RESPONSE_ACTION
]
?.
asString
?.
let
{
action
->
val
command
=
Command
(
scanData
,
action
)
commandRepository
.
insertCommand
(
command
)
LogUtils
.
d
(
TAG
,
"扫码结果: $command"
)
// 任务写入数据库成功后,主动发送一次IDLE,以重置界面提示语
qrCodeState
.
postValue
(
QRCodeState
.
SUCCESS
.
instance
(
scanData
))
delay
(
DELAY
)
scan
()
}
?:
qrCodeState
.
postValue
(
QRCodeState
.
FAILED
.
instance
())
}
override
fun
onCleared
()
{
super
.
onCleared
()
scanFuture
?.
cancel
()
scan
?.
close
()
}
private
fun
Int
.
instance
()
=
QRCodeState
(
this
)
private
fun
Int
.
instance
(
message
:
String
)
=
QRCodeState
(
this
,
message
)
private
fun
Int
.
instance
(
data
:
PayData
,
message
:
String
)
=
QRCodeState
(
this
,
data
,
message
)
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment