diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index e822df6..d72c1a5 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -7,6 +7,9 @@
+
+
+
@@ -46,5 +49,8 @@
+
+
+
\ No newline at end of file
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index e822df6..d72c1a5 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -7,6 +7,9 @@
+
+
+
@@ -46,5 +49,8 @@
+
+
+
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/br/ktd/base/KotlinBaseFragment.kt b/app/src/main/java/com/casic/br/ktd/base/KotlinBaseFragment.kt
new file mode 100644
index 0000000..2dac61c
--- /dev/null
+++ b/app/src/main/java/com/casic/br/ktd/base/KotlinBaseFragment.kt
@@ -0,0 +1,51 @@
+package com.casic.br.ktd.base
+
+import android.os.Bundle
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import androidx.annotation.LayoutRes
+import androidx.fragment.app.Fragment
+
+abstract class KotlinBaseFragment : Fragment() {
+
+ lateinit var bv: View
+
+ override fun onCreateView(
+ inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?
+ ): View? {
+ bv = inflater.inflate(initLayoutRes(), container, false)
+ initView(savedInstanceState)
+ setupTopBarLayout()
+ return bv
+ }
+
+ override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
+ super.onViewCreated(view, savedInstanceState)
+ observeRequestState()
+ initEvent()
+ }
+
+ @LayoutRes
+ abstract fun initLayoutRes(): Int
+
+ /**
+ * 沉浸式状态栏
+ */
+ abstract fun setupTopBarLayout()
+
+ /**
+ * 初始化布局以及控件
+ */
+ abstract fun initView(savedInstanceState: Bundle?)
+
+ /**
+ * 网络请求状态监听
+ */
+ abstract fun observeRequestState()
+
+ /**
+ * 业务逻辑,按钮等事件
+ */
+ abstract fun initEvent()
+}
\ No newline at end of file
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index e822df6..d72c1a5 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -7,6 +7,9 @@
+
+
+
@@ -46,5 +49,8 @@
+
+
+
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/br/ktd/base/KotlinBaseFragment.kt b/app/src/main/java/com/casic/br/ktd/base/KotlinBaseFragment.kt
new file mode 100644
index 0000000..2dac61c
--- /dev/null
+++ b/app/src/main/java/com/casic/br/ktd/base/KotlinBaseFragment.kt
@@ -0,0 +1,51 @@
+package com.casic.br.ktd.base
+
+import android.os.Bundle
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import androidx.annotation.LayoutRes
+import androidx.fragment.app.Fragment
+
+abstract class KotlinBaseFragment : Fragment() {
+
+ lateinit var bv: View
+
+ override fun onCreateView(
+ inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?
+ ): View? {
+ bv = inflater.inflate(initLayoutRes(), container, false)
+ initView(savedInstanceState)
+ setupTopBarLayout()
+ return bv
+ }
+
+ override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
+ super.onViewCreated(view, savedInstanceState)
+ observeRequestState()
+ initEvent()
+ }
+
+ @LayoutRes
+ abstract fun initLayoutRes(): Int
+
+ /**
+ * 沉浸式状态栏
+ */
+ abstract fun setupTopBarLayout()
+
+ /**
+ * 初始化布局以及控件
+ */
+ abstract fun initView(savedInstanceState: Bundle?)
+
+ /**
+ * 网络请求状态监听
+ */
+ abstract fun observeRequestState()
+
+ /**
+ * 业务逻辑,按钮等事件
+ */
+ abstract fun initEvent()
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/br/ktd/fragment/AlarmPageFragment.kt b/app/src/main/java/com/casic/br/ktd/fragment/AlarmPageFragment.kt
index 6c98a3b..9418169 100644
--- a/app/src/main/java/com/casic/br/ktd/fragment/AlarmPageFragment.kt
+++ b/app/src/main/java/com/casic/br/ktd/fragment/AlarmPageFragment.kt
@@ -2,28 +2,29 @@
import android.os.Bundle
import com.casic.br.ktd.R
+import com.casic.br.ktd.base.KotlinBaseFragment
import com.casic.br.ktd.widgets.DateRangeActionSheet
-import com.pengxh.kt.lite.base.KotlinBaseFragment
import kotlinx.android.synthetic.main.fragment_alarm.view.*
class AlarmPageFragment : KotlinBaseFragment() {
- override fun initData(savedInstanceState: Bundle?) {
+
+ override fun initView(savedInstanceState: Bundle?) {
}
override fun initEvent() {
- baseView.calendarView.setOnClickListener {
+ bv.calendarView.setOnClickListener {
DateRangeActionSheet.Builder().setContext(requireContext())
.setOnActionSheetListener(object :
DateRangeActionSheet.OnDateRangeSelectedListener {
override fun onDateRangeSelected(startDate: String, endDate: String) {
- baseView.selectedDateView.text = "$startDate ~ $endDate"
+ bv.selectedDateView.text = "$startDate ~ $endDate"
}
}).build().show()
}
}
- override fun initLayoutView(): Int = R.layout.fragment_alarm
+ override fun initLayoutRes(): Int = R.layout.fragment_alarm
override fun observeRequestState() {
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index e822df6..d72c1a5 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -7,6 +7,9 @@
+
+
+
@@ -46,5 +49,8 @@
+
+
+
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/br/ktd/base/KotlinBaseFragment.kt b/app/src/main/java/com/casic/br/ktd/base/KotlinBaseFragment.kt
new file mode 100644
index 0000000..2dac61c
--- /dev/null
+++ b/app/src/main/java/com/casic/br/ktd/base/KotlinBaseFragment.kt
@@ -0,0 +1,51 @@
+package com.casic.br.ktd.base
+
+import android.os.Bundle
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import androidx.annotation.LayoutRes
+import androidx.fragment.app.Fragment
+
+abstract class KotlinBaseFragment : Fragment() {
+
+ lateinit var bv: View
+
+ override fun onCreateView(
+ inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?
+ ): View? {
+ bv = inflater.inflate(initLayoutRes(), container, false)
+ initView(savedInstanceState)
+ setupTopBarLayout()
+ return bv
+ }
+
+ override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
+ super.onViewCreated(view, savedInstanceState)
+ observeRequestState()
+ initEvent()
+ }
+
+ @LayoutRes
+ abstract fun initLayoutRes(): Int
+
+ /**
+ * 沉浸式状态栏
+ */
+ abstract fun setupTopBarLayout()
+
+ /**
+ * 初始化布局以及控件
+ */
+ abstract fun initView(savedInstanceState: Bundle?)
+
+ /**
+ * 网络请求状态监听
+ */
+ abstract fun observeRequestState()
+
+ /**
+ * 业务逻辑,按钮等事件
+ */
+ abstract fun initEvent()
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/br/ktd/fragment/AlarmPageFragment.kt b/app/src/main/java/com/casic/br/ktd/fragment/AlarmPageFragment.kt
index 6c98a3b..9418169 100644
--- a/app/src/main/java/com/casic/br/ktd/fragment/AlarmPageFragment.kt
+++ b/app/src/main/java/com/casic/br/ktd/fragment/AlarmPageFragment.kt
@@ -2,28 +2,29 @@
import android.os.Bundle
import com.casic.br.ktd.R
+import com.casic.br.ktd.base.KotlinBaseFragment
import com.casic.br.ktd.widgets.DateRangeActionSheet
-import com.pengxh.kt.lite.base.KotlinBaseFragment
import kotlinx.android.synthetic.main.fragment_alarm.view.*
class AlarmPageFragment : KotlinBaseFragment() {
- override fun initData(savedInstanceState: Bundle?) {
+
+ override fun initView(savedInstanceState: Bundle?) {
}
override fun initEvent() {
- baseView.calendarView.setOnClickListener {
+ bv.calendarView.setOnClickListener {
DateRangeActionSheet.Builder().setContext(requireContext())
.setOnActionSheetListener(object :
DateRangeActionSheet.OnDateRangeSelectedListener {
override fun onDateRangeSelected(startDate: String, endDate: String) {
- baseView.selectedDateView.text = "$startDate ~ $endDate"
+ bv.selectedDateView.text = "$startDate ~ $endDate"
}
}).build().show()
}
}
- override fun initLayoutView(): Int = R.layout.fragment_alarm
+ override fun initLayoutRes(): Int = R.layout.fragment_alarm
override fun observeRequestState() {
diff --git a/app/src/main/java/com/casic/br/ktd/fragment/HomePageFragment.kt b/app/src/main/java/com/casic/br/ktd/fragment/HomePageFragment.kt
index 9961935..f3eba5c 100644
--- a/app/src/main/java/com/casic/br/ktd/fragment/HomePageFragment.kt
+++ b/app/src/main/java/com/casic/br/ktd/fragment/HomePageFragment.kt
@@ -1,32 +1,62 @@
package com.casic.br.ktd.fragment
+import android.graphics.Color
import android.os.Bundle
import com.amap.api.maps.AMap
import com.amap.api.maps.AMapOptions
+import com.amap.api.maps.CameraUpdateFactory
+import com.amap.api.maps.model.*
import com.casic.br.ktd.R
-import com.pengxh.kt.lite.base.KotlinBaseFragment
+import com.casic.br.ktd.base.KotlinBaseFragment
import kotlinx.android.synthetic.main.fragment_home.view.*
class HomePageFragment : KotlinBaseFragment() {
private lateinit var aMap: AMap
- override fun initData(savedInstanceState: Bundle?) {
- baseView.mapView.onCreate(savedInstanceState)
- aMap = baseView.mapView.map
+ override fun initView(savedInstanceState: Bundle?) {
+ bv.mapView.onCreate(savedInstanceState)
+ aMap = bv.mapView.map
val uiSettings = aMap.uiSettings
uiSettings.isCompassEnabled = true
- uiSettings.isMyLocationButtonEnabled = true
+ uiSettings.isMyLocationButtonEnabled = false
uiSettings.isScaleControlsEnabled = true
uiSettings.zoomPosition = AMapOptions.ZOOM_POSITION_RIGHT_CENTER
uiSettings.isRotateGesturesEnabled = false//不许地图随手势旋转角度
}
override fun initEvent() {
-
+ //移动到巡检起始经纬度
+ val cameraPosition = CameraPosition(LatLng(39.914199, 116.265785), 16f, 0f, 0f)
+ val cameraUpdate = CameraUpdateFactory.newCameraPosition(cameraPosition)
+ aMap.animateCamera(cameraUpdate, 1500, null)
+ //设置起点
+ addMarker(LatLng(39.914885, 116.272312), R.mipmap.start)
+ //设置终点
+ addMarker(LatLng(39.914716, 116.265097), R.mipmap.end)
+ //瞄点画线
+ val latLngPoints = ArrayList()
+ latLngPoints.add(LatLng(39.914885, 116.272312))
+ latLngPoints.add(LatLng(39.915148, 116.272312))
+ latLngPoints.add(LatLng(39.915399, 116.272302))
+ latLngPoints.add(LatLng(39.915436, 116.271787))
+ latLngPoints.add(LatLng(39.915477, 116.270886))
+ latLngPoints.add(LatLng(39.915477, 116.269968))
+ latLngPoints.add(LatLng(39.915469, 116.269544))
+ latLngPoints.add(LatLng(39.915481, 116.269196))
+ latLngPoints.add(LatLng(39.915452, 116.268472))
+ latLngPoints.add(LatLng(39.915444, 116.267722))
+ latLngPoints.add(LatLng(39.915415, 116.266755))
+ latLngPoints.add(LatLng(39.915403, 116.266165))
+ latLngPoints.add(LatLng(39.915395, 116.265703))
+ latLngPoints.add(LatLng(39.915366, 116.265119))
+ latLngPoints.add(LatLng(39.914716, 116.265097))
+ aMap.addPolyline(
+ PolylineOptions().addAll(latLngPoints).width(10.toFloat()).color(Color.RED)
+ )
}
- override fun initLayoutView(): Int = R.layout.fragment_home
+ override fun initLayoutRes(): Int = R.layout.fragment_home
override fun observeRequestState() {
@@ -36,25 +66,32 @@
}
+ private fun addMarker(point: LatLng, res: Int) {
+ val markerOption = MarkerOptions()
+ markerOption.position(point)
+ markerOption.icon(BitmapDescriptorFactory.fromResource(res))
+ aMap.addMarker(markerOption)
+ }
+
/***以下是地图生命周期管理************************************************************************/
override fun onResume() {
super.onResume()
- baseView.mapView.onResume()
+ bv.mapView.onResume()
}
override fun onPause() {
- baseView.mapView.onPause()
super.onPause()
+ bv.mapView.onPause()
}
override fun onSaveInstanceState(outState: Bundle) {
super.onSaveInstanceState(outState)
- baseView.mapView.onSaveInstanceState(outState)
+ bv.mapView.onSaveInstanceState(outState)
}
override fun onDestroy() {
- baseView.mapView.onDestroy()
super.onDestroy()
+ bv.mapView.onDestroy()
}
}
\ No newline at end of file
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index e822df6..d72c1a5 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -7,6 +7,9 @@
+
+
+
@@ -46,5 +49,8 @@
+
+
+
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/br/ktd/base/KotlinBaseFragment.kt b/app/src/main/java/com/casic/br/ktd/base/KotlinBaseFragment.kt
new file mode 100644
index 0000000..2dac61c
--- /dev/null
+++ b/app/src/main/java/com/casic/br/ktd/base/KotlinBaseFragment.kt
@@ -0,0 +1,51 @@
+package com.casic.br.ktd.base
+
+import android.os.Bundle
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import androidx.annotation.LayoutRes
+import androidx.fragment.app.Fragment
+
+abstract class KotlinBaseFragment : Fragment() {
+
+ lateinit var bv: View
+
+ override fun onCreateView(
+ inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?
+ ): View? {
+ bv = inflater.inflate(initLayoutRes(), container, false)
+ initView(savedInstanceState)
+ setupTopBarLayout()
+ return bv
+ }
+
+ override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
+ super.onViewCreated(view, savedInstanceState)
+ observeRequestState()
+ initEvent()
+ }
+
+ @LayoutRes
+ abstract fun initLayoutRes(): Int
+
+ /**
+ * 沉浸式状态栏
+ */
+ abstract fun setupTopBarLayout()
+
+ /**
+ * 初始化布局以及控件
+ */
+ abstract fun initView(savedInstanceState: Bundle?)
+
+ /**
+ * 网络请求状态监听
+ */
+ abstract fun observeRequestState()
+
+ /**
+ * 业务逻辑,按钮等事件
+ */
+ abstract fun initEvent()
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/br/ktd/fragment/AlarmPageFragment.kt b/app/src/main/java/com/casic/br/ktd/fragment/AlarmPageFragment.kt
index 6c98a3b..9418169 100644
--- a/app/src/main/java/com/casic/br/ktd/fragment/AlarmPageFragment.kt
+++ b/app/src/main/java/com/casic/br/ktd/fragment/AlarmPageFragment.kt
@@ -2,28 +2,29 @@
import android.os.Bundle
import com.casic.br.ktd.R
+import com.casic.br.ktd.base.KotlinBaseFragment
import com.casic.br.ktd.widgets.DateRangeActionSheet
-import com.pengxh.kt.lite.base.KotlinBaseFragment
import kotlinx.android.synthetic.main.fragment_alarm.view.*
class AlarmPageFragment : KotlinBaseFragment() {
- override fun initData(savedInstanceState: Bundle?) {
+
+ override fun initView(savedInstanceState: Bundle?) {
}
override fun initEvent() {
- baseView.calendarView.setOnClickListener {
+ bv.calendarView.setOnClickListener {
DateRangeActionSheet.Builder().setContext(requireContext())
.setOnActionSheetListener(object :
DateRangeActionSheet.OnDateRangeSelectedListener {
override fun onDateRangeSelected(startDate: String, endDate: String) {
- baseView.selectedDateView.text = "$startDate ~ $endDate"
+ bv.selectedDateView.text = "$startDate ~ $endDate"
}
}).build().show()
}
}
- override fun initLayoutView(): Int = R.layout.fragment_alarm
+ override fun initLayoutRes(): Int = R.layout.fragment_alarm
override fun observeRequestState() {
diff --git a/app/src/main/java/com/casic/br/ktd/fragment/HomePageFragment.kt b/app/src/main/java/com/casic/br/ktd/fragment/HomePageFragment.kt
index 9961935..f3eba5c 100644
--- a/app/src/main/java/com/casic/br/ktd/fragment/HomePageFragment.kt
+++ b/app/src/main/java/com/casic/br/ktd/fragment/HomePageFragment.kt
@@ -1,32 +1,62 @@
package com.casic.br.ktd.fragment
+import android.graphics.Color
import android.os.Bundle
import com.amap.api.maps.AMap
import com.amap.api.maps.AMapOptions
+import com.amap.api.maps.CameraUpdateFactory
+import com.amap.api.maps.model.*
import com.casic.br.ktd.R
-import com.pengxh.kt.lite.base.KotlinBaseFragment
+import com.casic.br.ktd.base.KotlinBaseFragment
import kotlinx.android.synthetic.main.fragment_home.view.*
class HomePageFragment : KotlinBaseFragment() {
private lateinit var aMap: AMap
- override fun initData(savedInstanceState: Bundle?) {
- baseView.mapView.onCreate(savedInstanceState)
- aMap = baseView.mapView.map
+ override fun initView(savedInstanceState: Bundle?) {
+ bv.mapView.onCreate(savedInstanceState)
+ aMap = bv.mapView.map
val uiSettings = aMap.uiSettings
uiSettings.isCompassEnabled = true
- uiSettings.isMyLocationButtonEnabled = true
+ uiSettings.isMyLocationButtonEnabled = false
uiSettings.isScaleControlsEnabled = true
uiSettings.zoomPosition = AMapOptions.ZOOM_POSITION_RIGHT_CENTER
uiSettings.isRotateGesturesEnabled = false//不许地图随手势旋转角度
}
override fun initEvent() {
-
+ //移动到巡检起始经纬度
+ val cameraPosition = CameraPosition(LatLng(39.914199, 116.265785), 16f, 0f, 0f)
+ val cameraUpdate = CameraUpdateFactory.newCameraPosition(cameraPosition)
+ aMap.animateCamera(cameraUpdate, 1500, null)
+ //设置起点
+ addMarker(LatLng(39.914885, 116.272312), R.mipmap.start)
+ //设置终点
+ addMarker(LatLng(39.914716, 116.265097), R.mipmap.end)
+ //瞄点画线
+ val latLngPoints = ArrayList()
+ latLngPoints.add(LatLng(39.914885, 116.272312))
+ latLngPoints.add(LatLng(39.915148, 116.272312))
+ latLngPoints.add(LatLng(39.915399, 116.272302))
+ latLngPoints.add(LatLng(39.915436, 116.271787))
+ latLngPoints.add(LatLng(39.915477, 116.270886))
+ latLngPoints.add(LatLng(39.915477, 116.269968))
+ latLngPoints.add(LatLng(39.915469, 116.269544))
+ latLngPoints.add(LatLng(39.915481, 116.269196))
+ latLngPoints.add(LatLng(39.915452, 116.268472))
+ latLngPoints.add(LatLng(39.915444, 116.267722))
+ latLngPoints.add(LatLng(39.915415, 116.266755))
+ latLngPoints.add(LatLng(39.915403, 116.266165))
+ latLngPoints.add(LatLng(39.915395, 116.265703))
+ latLngPoints.add(LatLng(39.915366, 116.265119))
+ latLngPoints.add(LatLng(39.914716, 116.265097))
+ aMap.addPolyline(
+ PolylineOptions().addAll(latLngPoints).width(10.toFloat()).color(Color.RED)
+ )
}
- override fun initLayoutView(): Int = R.layout.fragment_home
+ override fun initLayoutRes(): Int = R.layout.fragment_home
override fun observeRequestState() {
@@ -36,25 +66,32 @@
}
+ private fun addMarker(point: LatLng, res: Int) {
+ val markerOption = MarkerOptions()
+ markerOption.position(point)
+ markerOption.icon(BitmapDescriptorFactory.fromResource(res))
+ aMap.addMarker(markerOption)
+ }
+
/***以下是地图生命周期管理************************************************************************/
override fun onResume() {
super.onResume()
- baseView.mapView.onResume()
+ bv.mapView.onResume()
}
override fun onPause() {
- baseView.mapView.onPause()
super.onPause()
+ bv.mapView.onPause()
}
override fun onSaveInstanceState(outState: Bundle) {
super.onSaveInstanceState(outState)
- baseView.mapView.onSaveInstanceState(outState)
+ bv.mapView.onSaveInstanceState(outState)
}
override fun onDestroy() {
- baseView.mapView.onDestroy()
super.onDestroy()
+ bv.mapView.onDestroy()
}
}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/br/ktd/fragment/MinePageFragment.kt b/app/src/main/java/com/casic/br/ktd/fragment/MinePageFragment.kt
index 90313ac..3212794 100644
--- a/app/src/main/java/com/casic/br/ktd/fragment/MinePageFragment.kt
+++ b/app/src/main/java/com/casic/br/ktd/fragment/MinePageFragment.kt
@@ -2,10 +2,11 @@
import android.os.Bundle
import com.casic.br.ktd.R
-import com.pengxh.kt.lite.base.KotlinBaseFragment
+import com.casic.br.ktd.base.KotlinBaseFragment
class MinePageFragment : KotlinBaseFragment() {
- override fun initData(savedInstanceState: Bundle?) {
+
+ override fun initView(savedInstanceState: Bundle?) {
}
@@ -13,7 +14,7 @@
}
- override fun initLayoutView(): Int = R.layout.fragment_mine
+ override fun initLayoutRes(): Int = R.layout.fragment_mine
override fun observeRequestState() {
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index e822df6..d72c1a5 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -7,6 +7,9 @@
+
+
+
@@ -46,5 +49,8 @@
+
+
+
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/br/ktd/base/KotlinBaseFragment.kt b/app/src/main/java/com/casic/br/ktd/base/KotlinBaseFragment.kt
new file mode 100644
index 0000000..2dac61c
--- /dev/null
+++ b/app/src/main/java/com/casic/br/ktd/base/KotlinBaseFragment.kt
@@ -0,0 +1,51 @@
+package com.casic.br.ktd.base
+
+import android.os.Bundle
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import androidx.annotation.LayoutRes
+import androidx.fragment.app.Fragment
+
+abstract class KotlinBaseFragment : Fragment() {
+
+ lateinit var bv: View
+
+ override fun onCreateView(
+ inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?
+ ): View? {
+ bv = inflater.inflate(initLayoutRes(), container, false)
+ initView(savedInstanceState)
+ setupTopBarLayout()
+ return bv
+ }
+
+ override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
+ super.onViewCreated(view, savedInstanceState)
+ observeRequestState()
+ initEvent()
+ }
+
+ @LayoutRes
+ abstract fun initLayoutRes(): Int
+
+ /**
+ * 沉浸式状态栏
+ */
+ abstract fun setupTopBarLayout()
+
+ /**
+ * 初始化布局以及控件
+ */
+ abstract fun initView(savedInstanceState: Bundle?)
+
+ /**
+ * 网络请求状态监听
+ */
+ abstract fun observeRequestState()
+
+ /**
+ * 业务逻辑,按钮等事件
+ */
+ abstract fun initEvent()
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/br/ktd/fragment/AlarmPageFragment.kt b/app/src/main/java/com/casic/br/ktd/fragment/AlarmPageFragment.kt
index 6c98a3b..9418169 100644
--- a/app/src/main/java/com/casic/br/ktd/fragment/AlarmPageFragment.kt
+++ b/app/src/main/java/com/casic/br/ktd/fragment/AlarmPageFragment.kt
@@ -2,28 +2,29 @@
import android.os.Bundle
import com.casic.br.ktd.R
+import com.casic.br.ktd.base.KotlinBaseFragment
import com.casic.br.ktd.widgets.DateRangeActionSheet
-import com.pengxh.kt.lite.base.KotlinBaseFragment
import kotlinx.android.synthetic.main.fragment_alarm.view.*
class AlarmPageFragment : KotlinBaseFragment() {
- override fun initData(savedInstanceState: Bundle?) {
+
+ override fun initView(savedInstanceState: Bundle?) {
}
override fun initEvent() {
- baseView.calendarView.setOnClickListener {
+ bv.calendarView.setOnClickListener {
DateRangeActionSheet.Builder().setContext(requireContext())
.setOnActionSheetListener(object :
DateRangeActionSheet.OnDateRangeSelectedListener {
override fun onDateRangeSelected(startDate: String, endDate: String) {
- baseView.selectedDateView.text = "$startDate ~ $endDate"
+ bv.selectedDateView.text = "$startDate ~ $endDate"
}
}).build().show()
}
}
- override fun initLayoutView(): Int = R.layout.fragment_alarm
+ override fun initLayoutRes(): Int = R.layout.fragment_alarm
override fun observeRequestState() {
diff --git a/app/src/main/java/com/casic/br/ktd/fragment/HomePageFragment.kt b/app/src/main/java/com/casic/br/ktd/fragment/HomePageFragment.kt
index 9961935..f3eba5c 100644
--- a/app/src/main/java/com/casic/br/ktd/fragment/HomePageFragment.kt
+++ b/app/src/main/java/com/casic/br/ktd/fragment/HomePageFragment.kt
@@ -1,32 +1,62 @@
package com.casic.br.ktd.fragment
+import android.graphics.Color
import android.os.Bundle
import com.amap.api.maps.AMap
import com.amap.api.maps.AMapOptions
+import com.amap.api.maps.CameraUpdateFactory
+import com.amap.api.maps.model.*
import com.casic.br.ktd.R
-import com.pengxh.kt.lite.base.KotlinBaseFragment
+import com.casic.br.ktd.base.KotlinBaseFragment
import kotlinx.android.synthetic.main.fragment_home.view.*
class HomePageFragment : KotlinBaseFragment() {
private lateinit var aMap: AMap
- override fun initData(savedInstanceState: Bundle?) {
- baseView.mapView.onCreate(savedInstanceState)
- aMap = baseView.mapView.map
+ override fun initView(savedInstanceState: Bundle?) {
+ bv.mapView.onCreate(savedInstanceState)
+ aMap = bv.mapView.map
val uiSettings = aMap.uiSettings
uiSettings.isCompassEnabled = true
- uiSettings.isMyLocationButtonEnabled = true
+ uiSettings.isMyLocationButtonEnabled = false
uiSettings.isScaleControlsEnabled = true
uiSettings.zoomPosition = AMapOptions.ZOOM_POSITION_RIGHT_CENTER
uiSettings.isRotateGesturesEnabled = false//不许地图随手势旋转角度
}
override fun initEvent() {
-
+ //移动到巡检起始经纬度
+ val cameraPosition = CameraPosition(LatLng(39.914199, 116.265785), 16f, 0f, 0f)
+ val cameraUpdate = CameraUpdateFactory.newCameraPosition(cameraPosition)
+ aMap.animateCamera(cameraUpdate, 1500, null)
+ //设置起点
+ addMarker(LatLng(39.914885, 116.272312), R.mipmap.start)
+ //设置终点
+ addMarker(LatLng(39.914716, 116.265097), R.mipmap.end)
+ //瞄点画线
+ val latLngPoints = ArrayList()
+ latLngPoints.add(LatLng(39.914885, 116.272312))
+ latLngPoints.add(LatLng(39.915148, 116.272312))
+ latLngPoints.add(LatLng(39.915399, 116.272302))
+ latLngPoints.add(LatLng(39.915436, 116.271787))
+ latLngPoints.add(LatLng(39.915477, 116.270886))
+ latLngPoints.add(LatLng(39.915477, 116.269968))
+ latLngPoints.add(LatLng(39.915469, 116.269544))
+ latLngPoints.add(LatLng(39.915481, 116.269196))
+ latLngPoints.add(LatLng(39.915452, 116.268472))
+ latLngPoints.add(LatLng(39.915444, 116.267722))
+ latLngPoints.add(LatLng(39.915415, 116.266755))
+ latLngPoints.add(LatLng(39.915403, 116.266165))
+ latLngPoints.add(LatLng(39.915395, 116.265703))
+ latLngPoints.add(LatLng(39.915366, 116.265119))
+ latLngPoints.add(LatLng(39.914716, 116.265097))
+ aMap.addPolyline(
+ PolylineOptions().addAll(latLngPoints).width(10.toFloat()).color(Color.RED)
+ )
}
- override fun initLayoutView(): Int = R.layout.fragment_home
+ override fun initLayoutRes(): Int = R.layout.fragment_home
override fun observeRequestState() {
@@ -36,25 +66,32 @@
}
+ private fun addMarker(point: LatLng, res: Int) {
+ val markerOption = MarkerOptions()
+ markerOption.position(point)
+ markerOption.icon(BitmapDescriptorFactory.fromResource(res))
+ aMap.addMarker(markerOption)
+ }
+
/***以下是地图生命周期管理************************************************************************/
override fun onResume() {
super.onResume()
- baseView.mapView.onResume()
+ bv.mapView.onResume()
}
override fun onPause() {
- baseView.mapView.onPause()
super.onPause()
+ bv.mapView.onPause()
}
override fun onSaveInstanceState(outState: Bundle) {
super.onSaveInstanceState(outState)
- baseView.mapView.onSaveInstanceState(outState)
+ bv.mapView.onSaveInstanceState(outState)
}
override fun onDestroy() {
- baseView.mapView.onDestroy()
super.onDestroy()
+ bv.mapView.onDestroy()
}
}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/br/ktd/fragment/MinePageFragment.kt b/app/src/main/java/com/casic/br/ktd/fragment/MinePageFragment.kt
index 90313ac..3212794 100644
--- a/app/src/main/java/com/casic/br/ktd/fragment/MinePageFragment.kt
+++ b/app/src/main/java/com/casic/br/ktd/fragment/MinePageFragment.kt
@@ -2,10 +2,11 @@
import android.os.Bundle
import com.casic.br.ktd.R
-import com.pengxh.kt.lite.base.KotlinBaseFragment
+import com.casic.br.ktd.base.KotlinBaseFragment
class MinePageFragment : KotlinBaseFragment() {
- override fun initData(savedInstanceState: Bundle?) {
+
+ override fun initView(savedInstanceState: Bundle?) {
}
@@ -13,7 +14,7 @@
}
- override fun initLayoutView(): Int = R.layout.fragment_mine
+ override fun initLayoutRes(): Int = R.layout.fragment_mine
override fun observeRequestState() {
diff --git a/app/src/main/java/com/casic/br/ktd/fragment/TaskPageFragment.kt b/app/src/main/java/com/casic/br/ktd/fragment/TaskPageFragment.kt
index 8f6abf0..6b82a54 100644
--- a/app/src/main/java/com/casic/br/ktd/fragment/TaskPageFragment.kt
+++ b/app/src/main/java/com/casic/br/ktd/fragment/TaskPageFragment.kt
@@ -8,6 +8,7 @@
import androidx.recyclerview.widget.RecyclerView
import com.casic.br.ktd.R
import com.casic.br.ktd.adapter.TaskAdapter
+import com.casic.br.ktd.base.KotlinBaseFragment
import com.casic.br.ktd.holder.SwipeViewHolder
import com.casic.br.ktd.model.TaskListModel
import com.casic.br.ktd.view.InspectionActivity
@@ -15,7 +16,6 @@
import com.casic.br.ktd.widgets.AlertControlDialog
import com.casic.br.ktd.widgets.AlertInputDialog
import com.casic.br.ktd.widgets.DateRangeActionSheet
-import com.pengxh.kt.lite.base.KotlinBaseFragment
import com.pengxh.kt.lite.extensions.navigatePageTo
import com.pengxh.kt.lite.extensions.show
import com.pengxh.kt.lite.utils.WeakReferenceHandler
@@ -36,7 +36,7 @@
private var startTime = ""
private var endTime = ""
- override fun initData(savedInstanceState: Bundle?) {
+ override fun initView(savedInstanceState: Bundle?) {
weakReferenceHandler = WeakReferenceHandler(this)
taskViewModel = ViewModelProvider(this)[TaskViewModel::class.java]
taskViewModel.taskList.observe(this) {
@@ -45,7 +45,7 @@
when {
isRefresh -> {
taskAdapter.setRefreshData(dataRows)
- baseView.taskLayout.finishRefresh()
+ bv.taskLayout.finishRefresh()
isRefresh = false
}
isLoadMore -> {
@@ -53,7 +53,7 @@
"到底了,别拉了".show(requireContext())
}
taskAdapter.setLoadMoreData(dataRows)
- baseView.taskLayout.finishLoadMore()
+ bv.taskLayout.finishLoadMore()
isLoadMore = false
}
else -> {
@@ -76,9 +76,9 @@
when (msg.what) {
2023070501 -> {
if (dataBeans.size == 0) {
- baseView.emptyLayout.visibility = View.VISIBLE
+ bv.emptyLayout.visibility = View.VISIBLE
} else {
- baseView.emptyLayout.visibility = View.GONE
+ bv.emptyLayout.visibility = View.GONE
taskAdapter = object : TaskAdapter(
requireContext(), R.layout.item_task_rv_l, dataBeans
) {
@@ -97,8 +97,8 @@
}
}
//绑定侧滑事件
- swipeAction.attachToRecyclerView(baseView.taskRecyclerView)
- baseView.taskRecyclerView.adapter = taskAdapter
+ swipeAction.attachToRecyclerView(bv.taskRecyclerView)
+ bv.taskRecyclerView.adapter = taskAdapter
taskAdapter.setOnItemCheckedListener(object :
TaskAdapter.OnItemCheckedListener {
override fun onItemChecked(items: ArrayList) {
@@ -168,7 +168,7 @@
override fun initEvent() {
- baseView.calendarView.setOnClickListener {
+ bv.calendarView.setOnClickListener {
DateRangeActionSheet.Builder().setContext(requireContext())
.setOnActionSheetListener(object :
DateRangeActionSheet.OnDateRangeSelectedListener {
@@ -177,12 +177,12 @@
endTime = endDate
//显示
- baseView.selectedDateView.text = "$startDate ~ $endDate"
+ bv.selectedDateView.text = "$startDate ~ $endDate"
}
}).build().show()
}
- baseView.addTaskButton.setOnClickListener {
+ bv.addTaskButton.setOnClickListener {
// AlertInputDialog.Builder()
// .setContext(requireContext())
// .setTitle("新建巡检任务")
@@ -200,11 +200,11 @@
requireContext().navigatePageTo()
}
- baseView.deleteTaskButton.setOnClickListener {
+ bv.deleteTaskButton.setOnClickListener {
selectedItems.size.toString().show(requireContext())
}
- baseView.taskSettingsButton.setOnClickListener {
+ bv.taskSettingsButton.setOnClickListener {
AlertInputDialog.Builder()
.setContext(requireContext())
.setTitle("设置阈值")
@@ -221,14 +221,14 @@
}).build().show()
}
- baseView.taskLayout.setOnRefreshListener {
+ bv.taskLayout.setOnRefreshListener {
isRefresh = true
//刷新之后页码重置
pageIndex = 1
getTaskList()
}
- baseView.taskLayout.setOnLoadMoreListener {
+ bv.taskLayout.setOnLoadMoreListener {
isLoadMore = true
pageIndex++
getTaskList()
@@ -239,13 +239,13 @@
taskViewModel.getTaskList(
startTime,
endTime,
- baseView.taskNameView.text.toString(),
- baseView.taskCodeView.text.toString(),
+ bv.taskNameView.text.toString(),
+ bv.taskCodeView.text.toString(),
pageIndex
)
}
- override fun initLayoutView(): Int = R.layout.fragment_task
+ override fun initLayoutRes(): Int = R.layout.fragment_task
override fun observeRequestState() {
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index e822df6..d72c1a5 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -7,6 +7,9 @@
+
+
+
@@ -46,5 +49,8 @@
+
+
+
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/br/ktd/base/KotlinBaseFragment.kt b/app/src/main/java/com/casic/br/ktd/base/KotlinBaseFragment.kt
new file mode 100644
index 0000000..2dac61c
--- /dev/null
+++ b/app/src/main/java/com/casic/br/ktd/base/KotlinBaseFragment.kt
@@ -0,0 +1,51 @@
+package com.casic.br.ktd.base
+
+import android.os.Bundle
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import androidx.annotation.LayoutRes
+import androidx.fragment.app.Fragment
+
+abstract class KotlinBaseFragment : Fragment() {
+
+ lateinit var bv: View
+
+ override fun onCreateView(
+ inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?
+ ): View? {
+ bv = inflater.inflate(initLayoutRes(), container, false)
+ initView(savedInstanceState)
+ setupTopBarLayout()
+ return bv
+ }
+
+ override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
+ super.onViewCreated(view, savedInstanceState)
+ observeRequestState()
+ initEvent()
+ }
+
+ @LayoutRes
+ abstract fun initLayoutRes(): Int
+
+ /**
+ * 沉浸式状态栏
+ */
+ abstract fun setupTopBarLayout()
+
+ /**
+ * 初始化布局以及控件
+ */
+ abstract fun initView(savedInstanceState: Bundle?)
+
+ /**
+ * 网络请求状态监听
+ */
+ abstract fun observeRequestState()
+
+ /**
+ * 业务逻辑,按钮等事件
+ */
+ abstract fun initEvent()
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/br/ktd/fragment/AlarmPageFragment.kt b/app/src/main/java/com/casic/br/ktd/fragment/AlarmPageFragment.kt
index 6c98a3b..9418169 100644
--- a/app/src/main/java/com/casic/br/ktd/fragment/AlarmPageFragment.kt
+++ b/app/src/main/java/com/casic/br/ktd/fragment/AlarmPageFragment.kt
@@ -2,28 +2,29 @@
import android.os.Bundle
import com.casic.br.ktd.R
+import com.casic.br.ktd.base.KotlinBaseFragment
import com.casic.br.ktd.widgets.DateRangeActionSheet
-import com.pengxh.kt.lite.base.KotlinBaseFragment
import kotlinx.android.synthetic.main.fragment_alarm.view.*
class AlarmPageFragment : KotlinBaseFragment() {
- override fun initData(savedInstanceState: Bundle?) {
+
+ override fun initView(savedInstanceState: Bundle?) {
}
override fun initEvent() {
- baseView.calendarView.setOnClickListener {
+ bv.calendarView.setOnClickListener {
DateRangeActionSheet.Builder().setContext(requireContext())
.setOnActionSheetListener(object :
DateRangeActionSheet.OnDateRangeSelectedListener {
override fun onDateRangeSelected(startDate: String, endDate: String) {
- baseView.selectedDateView.text = "$startDate ~ $endDate"
+ bv.selectedDateView.text = "$startDate ~ $endDate"
}
}).build().show()
}
}
- override fun initLayoutView(): Int = R.layout.fragment_alarm
+ override fun initLayoutRes(): Int = R.layout.fragment_alarm
override fun observeRequestState() {
diff --git a/app/src/main/java/com/casic/br/ktd/fragment/HomePageFragment.kt b/app/src/main/java/com/casic/br/ktd/fragment/HomePageFragment.kt
index 9961935..f3eba5c 100644
--- a/app/src/main/java/com/casic/br/ktd/fragment/HomePageFragment.kt
+++ b/app/src/main/java/com/casic/br/ktd/fragment/HomePageFragment.kt
@@ -1,32 +1,62 @@
package com.casic.br.ktd.fragment
+import android.graphics.Color
import android.os.Bundle
import com.amap.api.maps.AMap
import com.amap.api.maps.AMapOptions
+import com.amap.api.maps.CameraUpdateFactory
+import com.amap.api.maps.model.*
import com.casic.br.ktd.R
-import com.pengxh.kt.lite.base.KotlinBaseFragment
+import com.casic.br.ktd.base.KotlinBaseFragment
import kotlinx.android.synthetic.main.fragment_home.view.*
class HomePageFragment : KotlinBaseFragment() {
private lateinit var aMap: AMap
- override fun initData(savedInstanceState: Bundle?) {
- baseView.mapView.onCreate(savedInstanceState)
- aMap = baseView.mapView.map
+ override fun initView(savedInstanceState: Bundle?) {
+ bv.mapView.onCreate(savedInstanceState)
+ aMap = bv.mapView.map
val uiSettings = aMap.uiSettings
uiSettings.isCompassEnabled = true
- uiSettings.isMyLocationButtonEnabled = true
+ uiSettings.isMyLocationButtonEnabled = false
uiSettings.isScaleControlsEnabled = true
uiSettings.zoomPosition = AMapOptions.ZOOM_POSITION_RIGHT_CENTER
uiSettings.isRotateGesturesEnabled = false//不许地图随手势旋转角度
}
override fun initEvent() {
-
+ //移动到巡检起始经纬度
+ val cameraPosition = CameraPosition(LatLng(39.914199, 116.265785), 16f, 0f, 0f)
+ val cameraUpdate = CameraUpdateFactory.newCameraPosition(cameraPosition)
+ aMap.animateCamera(cameraUpdate, 1500, null)
+ //设置起点
+ addMarker(LatLng(39.914885, 116.272312), R.mipmap.start)
+ //设置终点
+ addMarker(LatLng(39.914716, 116.265097), R.mipmap.end)
+ //瞄点画线
+ val latLngPoints = ArrayList()
+ latLngPoints.add(LatLng(39.914885, 116.272312))
+ latLngPoints.add(LatLng(39.915148, 116.272312))
+ latLngPoints.add(LatLng(39.915399, 116.272302))
+ latLngPoints.add(LatLng(39.915436, 116.271787))
+ latLngPoints.add(LatLng(39.915477, 116.270886))
+ latLngPoints.add(LatLng(39.915477, 116.269968))
+ latLngPoints.add(LatLng(39.915469, 116.269544))
+ latLngPoints.add(LatLng(39.915481, 116.269196))
+ latLngPoints.add(LatLng(39.915452, 116.268472))
+ latLngPoints.add(LatLng(39.915444, 116.267722))
+ latLngPoints.add(LatLng(39.915415, 116.266755))
+ latLngPoints.add(LatLng(39.915403, 116.266165))
+ latLngPoints.add(LatLng(39.915395, 116.265703))
+ latLngPoints.add(LatLng(39.915366, 116.265119))
+ latLngPoints.add(LatLng(39.914716, 116.265097))
+ aMap.addPolyline(
+ PolylineOptions().addAll(latLngPoints).width(10.toFloat()).color(Color.RED)
+ )
}
- override fun initLayoutView(): Int = R.layout.fragment_home
+ override fun initLayoutRes(): Int = R.layout.fragment_home
override fun observeRequestState() {
@@ -36,25 +66,32 @@
}
+ private fun addMarker(point: LatLng, res: Int) {
+ val markerOption = MarkerOptions()
+ markerOption.position(point)
+ markerOption.icon(BitmapDescriptorFactory.fromResource(res))
+ aMap.addMarker(markerOption)
+ }
+
/***以下是地图生命周期管理************************************************************************/
override fun onResume() {
super.onResume()
- baseView.mapView.onResume()
+ bv.mapView.onResume()
}
override fun onPause() {
- baseView.mapView.onPause()
super.onPause()
+ bv.mapView.onPause()
}
override fun onSaveInstanceState(outState: Bundle) {
super.onSaveInstanceState(outState)
- baseView.mapView.onSaveInstanceState(outState)
+ bv.mapView.onSaveInstanceState(outState)
}
override fun onDestroy() {
- baseView.mapView.onDestroy()
super.onDestroy()
+ bv.mapView.onDestroy()
}
}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/br/ktd/fragment/MinePageFragment.kt b/app/src/main/java/com/casic/br/ktd/fragment/MinePageFragment.kt
index 90313ac..3212794 100644
--- a/app/src/main/java/com/casic/br/ktd/fragment/MinePageFragment.kt
+++ b/app/src/main/java/com/casic/br/ktd/fragment/MinePageFragment.kt
@@ -2,10 +2,11 @@
import android.os.Bundle
import com.casic.br.ktd.R
-import com.pengxh.kt.lite.base.KotlinBaseFragment
+import com.casic.br.ktd.base.KotlinBaseFragment
class MinePageFragment : KotlinBaseFragment() {
- override fun initData(savedInstanceState: Bundle?) {
+
+ override fun initView(savedInstanceState: Bundle?) {
}
@@ -13,7 +14,7 @@
}
- override fun initLayoutView(): Int = R.layout.fragment_mine
+ override fun initLayoutRes(): Int = R.layout.fragment_mine
override fun observeRequestState() {
diff --git a/app/src/main/java/com/casic/br/ktd/fragment/TaskPageFragment.kt b/app/src/main/java/com/casic/br/ktd/fragment/TaskPageFragment.kt
index 8f6abf0..6b82a54 100644
--- a/app/src/main/java/com/casic/br/ktd/fragment/TaskPageFragment.kt
+++ b/app/src/main/java/com/casic/br/ktd/fragment/TaskPageFragment.kt
@@ -8,6 +8,7 @@
import androidx.recyclerview.widget.RecyclerView
import com.casic.br.ktd.R
import com.casic.br.ktd.adapter.TaskAdapter
+import com.casic.br.ktd.base.KotlinBaseFragment
import com.casic.br.ktd.holder.SwipeViewHolder
import com.casic.br.ktd.model.TaskListModel
import com.casic.br.ktd.view.InspectionActivity
@@ -15,7 +16,6 @@
import com.casic.br.ktd.widgets.AlertControlDialog
import com.casic.br.ktd.widgets.AlertInputDialog
import com.casic.br.ktd.widgets.DateRangeActionSheet
-import com.pengxh.kt.lite.base.KotlinBaseFragment
import com.pengxh.kt.lite.extensions.navigatePageTo
import com.pengxh.kt.lite.extensions.show
import com.pengxh.kt.lite.utils.WeakReferenceHandler
@@ -36,7 +36,7 @@
private var startTime = ""
private var endTime = ""
- override fun initData(savedInstanceState: Bundle?) {
+ override fun initView(savedInstanceState: Bundle?) {
weakReferenceHandler = WeakReferenceHandler(this)
taskViewModel = ViewModelProvider(this)[TaskViewModel::class.java]
taskViewModel.taskList.observe(this) {
@@ -45,7 +45,7 @@
when {
isRefresh -> {
taskAdapter.setRefreshData(dataRows)
- baseView.taskLayout.finishRefresh()
+ bv.taskLayout.finishRefresh()
isRefresh = false
}
isLoadMore -> {
@@ -53,7 +53,7 @@
"到底了,别拉了".show(requireContext())
}
taskAdapter.setLoadMoreData(dataRows)
- baseView.taskLayout.finishLoadMore()
+ bv.taskLayout.finishLoadMore()
isLoadMore = false
}
else -> {
@@ -76,9 +76,9 @@
when (msg.what) {
2023070501 -> {
if (dataBeans.size == 0) {
- baseView.emptyLayout.visibility = View.VISIBLE
+ bv.emptyLayout.visibility = View.VISIBLE
} else {
- baseView.emptyLayout.visibility = View.GONE
+ bv.emptyLayout.visibility = View.GONE
taskAdapter = object : TaskAdapter(
requireContext(), R.layout.item_task_rv_l, dataBeans
) {
@@ -97,8 +97,8 @@
}
}
//绑定侧滑事件
- swipeAction.attachToRecyclerView(baseView.taskRecyclerView)
- baseView.taskRecyclerView.adapter = taskAdapter
+ swipeAction.attachToRecyclerView(bv.taskRecyclerView)
+ bv.taskRecyclerView.adapter = taskAdapter
taskAdapter.setOnItemCheckedListener(object :
TaskAdapter.OnItemCheckedListener {
override fun onItemChecked(items: ArrayList) {
@@ -168,7 +168,7 @@
override fun initEvent() {
- baseView.calendarView.setOnClickListener {
+ bv.calendarView.setOnClickListener {
DateRangeActionSheet.Builder().setContext(requireContext())
.setOnActionSheetListener(object :
DateRangeActionSheet.OnDateRangeSelectedListener {
@@ -177,12 +177,12 @@
endTime = endDate
//显示
- baseView.selectedDateView.text = "$startDate ~ $endDate"
+ bv.selectedDateView.text = "$startDate ~ $endDate"
}
}).build().show()
}
- baseView.addTaskButton.setOnClickListener {
+ bv.addTaskButton.setOnClickListener {
// AlertInputDialog.Builder()
// .setContext(requireContext())
// .setTitle("新建巡检任务")
@@ -200,11 +200,11 @@
requireContext().navigatePageTo()
}
- baseView.deleteTaskButton.setOnClickListener {
+ bv.deleteTaskButton.setOnClickListener {
selectedItems.size.toString().show(requireContext())
}
- baseView.taskSettingsButton.setOnClickListener {
+ bv.taskSettingsButton.setOnClickListener {
AlertInputDialog.Builder()
.setContext(requireContext())
.setTitle("设置阈值")
@@ -221,14 +221,14 @@
}).build().show()
}
- baseView.taskLayout.setOnRefreshListener {
+ bv.taskLayout.setOnRefreshListener {
isRefresh = true
//刷新之后页码重置
pageIndex = 1
getTaskList()
}
- baseView.taskLayout.setOnLoadMoreListener {
+ bv.taskLayout.setOnLoadMoreListener {
isLoadMore = true
pageIndex++
getTaskList()
@@ -239,13 +239,13 @@
taskViewModel.getTaskList(
startTime,
endTime,
- baseView.taskNameView.text.toString(),
- baseView.taskCodeView.text.toString(),
+ bv.taskNameView.text.toString(),
+ bv.taskCodeView.text.toString(),
pageIndex
)
}
- override fun initLayoutView(): Int = R.layout.fragment_task
+ override fun initLayoutRes(): Int = R.layout.fragment_task
override fun observeRequestState() {
diff --git a/app/src/main/java/com/casic/br/ktd/netty/ISocketListener.kt b/app/src/main/java/com/casic/br/ktd/netty/ISocketListener.kt
deleted file mode 100644
index dab98e1..0000000
--- a/app/src/main/java/com/casic/br/ktd/netty/ISocketListener.kt
+++ /dev/null
@@ -1,19 +0,0 @@
-package com.casic.br.ktd.netty
-
-interface ISocketListener {
- companion object {
- const val STATUS_CONNECT_SUCCESS: Byte = 1 //连接成功
- const val STATUS_CONNECT_CLOSED: Byte = 0 //关闭连接
- const val STATUS_CONNECT_ERROR: Byte = 0 //连接失败
- }
-
- /**
- * 当接收到系统消息
- */
- fun onMessageResponse(data: ByteArray?)
-
- /**
- * 当连接状态发生变化时调用
- */
- fun onServiceStatusConnectChanged(statusCode: Byte)
-}
\ No newline at end of file
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index e822df6..d72c1a5 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -7,6 +7,9 @@
+
+
+
@@ -46,5 +49,8 @@
+
+
+
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/br/ktd/base/KotlinBaseFragment.kt b/app/src/main/java/com/casic/br/ktd/base/KotlinBaseFragment.kt
new file mode 100644
index 0000000..2dac61c
--- /dev/null
+++ b/app/src/main/java/com/casic/br/ktd/base/KotlinBaseFragment.kt
@@ -0,0 +1,51 @@
+package com.casic.br.ktd.base
+
+import android.os.Bundle
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import androidx.annotation.LayoutRes
+import androidx.fragment.app.Fragment
+
+abstract class KotlinBaseFragment : Fragment() {
+
+ lateinit var bv: View
+
+ override fun onCreateView(
+ inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?
+ ): View? {
+ bv = inflater.inflate(initLayoutRes(), container, false)
+ initView(savedInstanceState)
+ setupTopBarLayout()
+ return bv
+ }
+
+ override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
+ super.onViewCreated(view, savedInstanceState)
+ observeRequestState()
+ initEvent()
+ }
+
+ @LayoutRes
+ abstract fun initLayoutRes(): Int
+
+ /**
+ * 沉浸式状态栏
+ */
+ abstract fun setupTopBarLayout()
+
+ /**
+ * 初始化布局以及控件
+ */
+ abstract fun initView(savedInstanceState: Bundle?)
+
+ /**
+ * 网络请求状态监听
+ */
+ abstract fun observeRequestState()
+
+ /**
+ * 业务逻辑,按钮等事件
+ */
+ abstract fun initEvent()
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/br/ktd/fragment/AlarmPageFragment.kt b/app/src/main/java/com/casic/br/ktd/fragment/AlarmPageFragment.kt
index 6c98a3b..9418169 100644
--- a/app/src/main/java/com/casic/br/ktd/fragment/AlarmPageFragment.kt
+++ b/app/src/main/java/com/casic/br/ktd/fragment/AlarmPageFragment.kt
@@ -2,28 +2,29 @@
import android.os.Bundle
import com.casic.br.ktd.R
+import com.casic.br.ktd.base.KotlinBaseFragment
import com.casic.br.ktd.widgets.DateRangeActionSheet
-import com.pengxh.kt.lite.base.KotlinBaseFragment
import kotlinx.android.synthetic.main.fragment_alarm.view.*
class AlarmPageFragment : KotlinBaseFragment() {
- override fun initData(savedInstanceState: Bundle?) {
+
+ override fun initView(savedInstanceState: Bundle?) {
}
override fun initEvent() {
- baseView.calendarView.setOnClickListener {
+ bv.calendarView.setOnClickListener {
DateRangeActionSheet.Builder().setContext(requireContext())
.setOnActionSheetListener(object :
DateRangeActionSheet.OnDateRangeSelectedListener {
override fun onDateRangeSelected(startDate: String, endDate: String) {
- baseView.selectedDateView.text = "$startDate ~ $endDate"
+ bv.selectedDateView.text = "$startDate ~ $endDate"
}
}).build().show()
}
}
- override fun initLayoutView(): Int = R.layout.fragment_alarm
+ override fun initLayoutRes(): Int = R.layout.fragment_alarm
override fun observeRequestState() {
diff --git a/app/src/main/java/com/casic/br/ktd/fragment/HomePageFragment.kt b/app/src/main/java/com/casic/br/ktd/fragment/HomePageFragment.kt
index 9961935..f3eba5c 100644
--- a/app/src/main/java/com/casic/br/ktd/fragment/HomePageFragment.kt
+++ b/app/src/main/java/com/casic/br/ktd/fragment/HomePageFragment.kt
@@ -1,32 +1,62 @@
package com.casic.br.ktd.fragment
+import android.graphics.Color
import android.os.Bundle
import com.amap.api.maps.AMap
import com.amap.api.maps.AMapOptions
+import com.amap.api.maps.CameraUpdateFactory
+import com.amap.api.maps.model.*
import com.casic.br.ktd.R
-import com.pengxh.kt.lite.base.KotlinBaseFragment
+import com.casic.br.ktd.base.KotlinBaseFragment
import kotlinx.android.synthetic.main.fragment_home.view.*
class HomePageFragment : KotlinBaseFragment() {
private lateinit var aMap: AMap
- override fun initData(savedInstanceState: Bundle?) {
- baseView.mapView.onCreate(savedInstanceState)
- aMap = baseView.mapView.map
+ override fun initView(savedInstanceState: Bundle?) {
+ bv.mapView.onCreate(savedInstanceState)
+ aMap = bv.mapView.map
val uiSettings = aMap.uiSettings
uiSettings.isCompassEnabled = true
- uiSettings.isMyLocationButtonEnabled = true
+ uiSettings.isMyLocationButtonEnabled = false
uiSettings.isScaleControlsEnabled = true
uiSettings.zoomPosition = AMapOptions.ZOOM_POSITION_RIGHT_CENTER
uiSettings.isRotateGesturesEnabled = false//不许地图随手势旋转角度
}
override fun initEvent() {
-
+ //移动到巡检起始经纬度
+ val cameraPosition = CameraPosition(LatLng(39.914199, 116.265785), 16f, 0f, 0f)
+ val cameraUpdate = CameraUpdateFactory.newCameraPosition(cameraPosition)
+ aMap.animateCamera(cameraUpdate, 1500, null)
+ //设置起点
+ addMarker(LatLng(39.914885, 116.272312), R.mipmap.start)
+ //设置终点
+ addMarker(LatLng(39.914716, 116.265097), R.mipmap.end)
+ //瞄点画线
+ val latLngPoints = ArrayList()
+ latLngPoints.add(LatLng(39.914885, 116.272312))
+ latLngPoints.add(LatLng(39.915148, 116.272312))
+ latLngPoints.add(LatLng(39.915399, 116.272302))
+ latLngPoints.add(LatLng(39.915436, 116.271787))
+ latLngPoints.add(LatLng(39.915477, 116.270886))
+ latLngPoints.add(LatLng(39.915477, 116.269968))
+ latLngPoints.add(LatLng(39.915469, 116.269544))
+ latLngPoints.add(LatLng(39.915481, 116.269196))
+ latLngPoints.add(LatLng(39.915452, 116.268472))
+ latLngPoints.add(LatLng(39.915444, 116.267722))
+ latLngPoints.add(LatLng(39.915415, 116.266755))
+ latLngPoints.add(LatLng(39.915403, 116.266165))
+ latLngPoints.add(LatLng(39.915395, 116.265703))
+ latLngPoints.add(LatLng(39.915366, 116.265119))
+ latLngPoints.add(LatLng(39.914716, 116.265097))
+ aMap.addPolyline(
+ PolylineOptions().addAll(latLngPoints).width(10.toFloat()).color(Color.RED)
+ )
}
- override fun initLayoutView(): Int = R.layout.fragment_home
+ override fun initLayoutRes(): Int = R.layout.fragment_home
override fun observeRequestState() {
@@ -36,25 +66,32 @@
}
+ private fun addMarker(point: LatLng, res: Int) {
+ val markerOption = MarkerOptions()
+ markerOption.position(point)
+ markerOption.icon(BitmapDescriptorFactory.fromResource(res))
+ aMap.addMarker(markerOption)
+ }
+
/***以下是地图生命周期管理************************************************************************/
override fun onResume() {
super.onResume()
- baseView.mapView.onResume()
+ bv.mapView.onResume()
}
override fun onPause() {
- baseView.mapView.onPause()
super.onPause()
+ bv.mapView.onPause()
}
override fun onSaveInstanceState(outState: Bundle) {
super.onSaveInstanceState(outState)
- baseView.mapView.onSaveInstanceState(outState)
+ bv.mapView.onSaveInstanceState(outState)
}
override fun onDestroy() {
- baseView.mapView.onDestroy()
super.onDestroy()
+ bv.mapView.onDestroy()
}
}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/br/ktd/fragment/MinePageFragment.kt b/app/src/main/java/com/casic/br/ktd/fragment/MinePageFragment.kt
index 90313ac..3212794 100644
--- a/app/src/main/java/com/casic/br/ktd/fragment/MinePageFragment.kt
+++ b/app/src/main/java/com/casic/br/ktd/fragment/MinePageFragment.kt
@@ -2,10 +2,11 @@
import android.os.Bundle
import com.casic.br.ktd.R
-import com.pengxh.kt.lite.base.KotlinBaseFragment
+import com.casic.br.ktd.base.KotlinBaseFragment
class MinePageFragment : KotlinBaseFragment() {
- override fun initData(savedInstanceState: Bundle?) {
+
+ override fun initView(savedInstanceState: Bundle?) {
}
@@ -13,7 +14,7 @@
}
- override fun initLayoutView(): Int = R.layout.fragment_mine
+ override fun initLayoutRes(): Int = R.layout.fragment_mine
override fun observeRequestState() {
diff --git a/app/src/main/java/com/casic/br/ktd/fragment/TaskPageFragment.kt b/app/src/main/java/com/casic/br/ktd/fragment/TaskPageFragment.kt
index 8f6abf0..6b82a54 100644
--- a/app/src/main/java/com/casic/br/ktd/fragment/TaskPageFragment.kt
+++ b/app/src/main/java/com/casic/br/ktd/fragment/TaskPageFragment.kt
@@ -8,6 +8,7 @@
import androidx.recyclerview.widget.RecyclerView
import com.casic.br.ktd.R
import com.casic.br.ktd.adapter.TaskAdapter
+import com.casic.br.ktd.base.KotlinBaseFragment
import com.casic.br.ktd.holder.SwipeViewHolder
import com.casic.br.ktd.model.TaskListModel
import com.casic.br.ktd.view.InspectionActivity
@@ -15,7 +16,6 @@
import com.casic.br.ktd.widgets.AlertControlDialog
import com.casic.br.ktd.widgets.AlertInputDialog
import com.casic.br.ktd.widgets.DateRangeActionSheet
-import com.pengxh.kt.lite.base.KotlinBaseFragment
import com.pengxh.kt.lite.extensions.navigatePageTo
import com.pengxh.kt.lite.extensions.show
import com.pengxh.kt.lite.utils.WeakReferenceHandler
@@ -36,7 +36,7 @@
private var startTime = ""
private var endTime = ""
- override fun initData(savedInstanceState: Bundle?) {
+ override fun initView(savedInstanceState: Bundle?) {
weakReferenceHandler = WeakReferenceHandler(this)
taskViewModel = ViewModelProvider(this)[TaskViewModel::class.java]
taskViewModel.taskList.observe(this) {
@@ -45,7 +45,7 @@
when {
isRefresh -> {
taskAdapter.setRefreshData(dataRows)
- baseView.taskLayout.finishRefresh()
+ bv.taskLayout.finishRefresh()
isRefresh = false
}
isLoadMore -> {
@@ -53,7 +53,7 @@
"到底了,别拉了".show(requireContext())
}
taskAdapter.setLoadMoreData(dataRows)
- baseView.taskLayout.finishLoadMore()
+ bv.taskLayout.finishLoadMore()
isLoadMore = false
}
else -> {
@@ -76,9 +76,9 @@
when (msg.what) {
2023070501 -> {
if (dataBeans.size == 0) {
- baseView.emptyLayout.visibility = View.VISIBLE
+ bv.emptyLayout.visibility = View.VISIBLE
} else {
- baseView.emptyLayout.visibility = View.GONE
+ bv.emptyLayout.visibility = View.GONE
taskAdapter = object : TaskAdapter(
requireContext(), R.layout.item_task_rv_l, dataBeans
) {
@@ -97,8 +97,8 @@
}
}
//绑定侧滑事件
- swipeAction.attachToRecyclerView(baseView.taskRecyclerView)
- baseView.taskRecyclerView.adapter = taskAdapter
+ swipeAction.attachToRecyclerView(bv.taskRecyclerView)
+ bv.taskRecyclerView.adapter = taskAdapter
taskAdapter.setOnItemCheckedListener(object :
TaskAdapter.OnItemCheckedListener {
override fun onItemChecked(items: ArrayList) {
@@ -168,7 +168,7 @@
override fun initEvent() {
- baseView.calendarView.setOnClickListener {
+ bv.calendarView.setOnClickListener {
DateRangeActionSheet.Builder().setContext(requireContext())
.setOnActionSheetListener(object :
DateRangeActionSheet.OnDateRangeSelectedListener {
@@ -177,12 +177,12 @@
endTime = endDate
//显示
- baseView.selectedDateView.text = "$startDate ~ $endDate"
+ bv.selectedDateView.text = "$startDate ~ $endDate"
}
}).build().show()
}
- baseView.addTaskButton.setOnClickListener {
+ bv.addTaskButton.setOnClickListener {
// AlertInputDialog.Builder()
// .setContext(requireContext())
// .setTitle("新建巡检任务")
@@ -200,11 +200,11 @@
requireContext().navigatePageTo()
}
- baseView.deleteTaskButton.setOnClickListener {
+ bv.deleteTaskButton.setOnClickListener {
selectedItems.size.toString().show(requireContext())
}
- baseView.taskSettingsButton.setOnClickListener {
+ bv.taskSettingsButton.setOnClickListener {
AlertInputDialog.Builder()
.setContext(requireContext())
.setTitle("设置阈值")
@@ -221,14 +221,14 @@
}).build().show()
}
- baseView.taskLayout.setOnRefreshListener {
+ bv.taskLayout.setOnRefreshListener {
isRefresh = true
//刷新之后页码重置
pageIndex = 1
getTaskList()
}
- baseView.taskLayout.setOnLoadMoreListener {
+ bv.taskLayout.setOnLoadMoreListener {
isLoadMore = true
pageIndex++
getTaskList()
@@ -239,13 +239,13 @@
taskViewModel.getTaskList(
startTime,
endTime,
- baseView.taskNameView.text.toString(),
- baseView.taskCodeView.text.toString(),
+ bv.taskNameView.text.toString(),
+ bv.taskCodeView.text.toString(),
pageIndex
)
}
- override fun initLayoutView(): Int = R.layout.fragment_task
+ override fun initLayoutRes(): Int = R.layout.fragment_task
override fun observeRequestState() {
diff --git a/app/src/main/java/com/casic/br/ktd/netty/ISocketListener.kt b/app/src/main/java/com/casic/br/ktd/netty/ISocketListener.kt
deleted file mode 100644
index dab98e1..0000000
--- a/app/src/main/java/com/casic/br/ktd/netty/ISocketListener.kt
+++ /dev/null
@@ -1,19 +0,0 @@
-package com.casic.br.ktd.netty
-
-interface ISocketListener {
- companion object {
- const val STATUS_CONNECT_SUCCESS: Byte = 1 //连接成功
- const val STATUS_CONNECT_CLOSED: Byte = 0 //关闭连接
- const val STATUS_CONNECT_ERROR: Byte = 0 //连接失败
- }
-
- /**
- * 当接收到系统消息
- */
- fun onMessageResponse(data: ByteArray?)
-
- /**
- * 当连接状态发生变化时调用
- */
- fun onServiceStatusConnectChanged(statusCode: Byte)
-}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/br/ktd/netty/SocketChannelHandle.kt b/app/src/main/java/com/casic/br/ktd/netty/SocketChannelHandle.kt
deleted file mode 100644
index 42eb310..0000000
--- a/app/src/main/java/com/casic/br/ktd/netty/SocketChannelHandle.kt
+++ /dev/null
@@ -1,51 +0,0 @@
-package com.casic.br.ktd.netty
-
-import android.util.Log
-import io.netty.channel.ChannelHandlerContext
-import io.netty.channel.SimpleChannelInboundHandler
-import io.netty.handler.timeout.IdleState
-import io.netty.handler.timeout.IdleStateEvent
-import java.nio.charset.StandardCharsets
-
-class SocketChannelHandle(private val listener: ISocketListener?) :
- SimpleChannelInboundHandler() {
-
- private val kTag = "SocketChannelHandle"
-
- override fun channelActive(ctx: ChannelHandlerContext) {
- super.channelActive(ctx)
- Log.d(kTag, "channelActive ===> 连接成功")
- listener?.onServiceStatusConnectChanged(ISocketListener.STATUS_CONNECT_SUCCESS)
- }
-
- override fun channelInactive(ctx: ChannelHandlerContext) {
- super.channelInactive(ctx)
- Log.e(kTag, "channelInactive: 连接断开")
- }
-
- override fun userEventTriggered(ctx: ChannelHandlerContext, evt: Any) {
- super.userEventTriggered(ctx, evt)
- if (evt is IdleStateEvent) {
- if (evt.state() == IdleState.WRITER_IDLE) {
- //写超时,此时可以发送心跳数据给服务器
- val temp = "FF"
- ctx.writeAndFlush(temp.toByteArray(StandardCharsets.UTF_8))
- } else if (evt.state() == IdleState.READER_IDLE) {
- //读超时,此时代表没有收到心跳返回可以关闭当前连接进行重连
- ctx.close()
- }
- }
- }
-
- override fun channelRead0(ctx: ChannelHandlerContext, data: ByteArray?) {
- listener?.onMessageResponse(data)
- }
-
- override fun exceptionCaught(ctx: ChannelHandlerContext, cause: Throwable) {
- super.exceptionCaught(ctx, cause)
- Log.d(kTag, "exceptionCaught ===> $cause")
- listener?.onServiceStatusConnectChanged(ISocketListener.STATUS_CONNECT_ERROR)
- cause.printStackTrace()
- ctx.close()
- }
-}
\ No newline at end of file
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index e822df6..d72c1a5 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -7,6 +7,9 @@
+
+
+
@@ -46,5 +49,8 @@
+
+
+
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/br/ktd/base/KotlinBaseFragment.kt b/app/src/main/java/com/casic/br/ktd/base/KotlinBaseFragment.kt
new file mode 100644
index 0000000..2dac61c
--- /dev/null
+++ b/app/src/main/java/com/casic/br/ktd/base/KotlinBaseFragment.kt
@@ -0,0 +1,51 @@
+package com.casic.br.ktd.base
+
+import android.os.Bundle
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import androidx.annotation.LayoutRes
+import androidx.fragment.app.Fragment
+
+abstract class KotlinBaseFragment : Fragment() {
+
+ lateinit var bv: View
+
+ override fun onCreateView(
+ inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?
+ ): View? {
+ bv = inflater.inflate(initLayoutRes(), container, false)
+ initView(savedInstanceState)
+ setupTopBarLayout()
+ return bv
+ }
+
+ override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
+ super.onViewCreated(view, savedInstanceState)
+ observeRequestState()
+ initEvent()
+ }
+
+ @LayoutRes
+ abstract fun initLayoutRes(): Int
+
+ /**
+ * 沉浸式状态栏
+ */
+ abstract fun setupTopBarLayout()
+
+ /**
+ * 初始化布局以及控件
+ */
+ abstract fun initView(savedInstanceState: Bundle?)
+
+ /**
+ * 网络请求状态监听
+ */
+ abstract fun observeRequestState()
+
+ /**
+ * 业务逻辑,按钮等事件
+ */
+ abstract fun initEvent()
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/br/ktd/fragment/AlarmPageFragment.kt b/app/src/main/java/com/casic/br/ktd/fragment/AlarmPageFragment.kt
index 6c98a3b..9418169 100644
--- a/app/src/main/java/com/casic/br/ktd/fragment/AlarmPageFragment.kt
+++ b/app/src/main/java/com/casic/br/ktd/fragment/AlarmPageFragment.kt
@@ -2,28 +2,29 @@
import android.os.Bundle
import com.casic.br.ktd.R
+import com.casic.br.ktd.base.KotlinBaseFragment
import com.casic.br.ktd.widgets.DateRangeActionSheet
-import com.pengxh.kt.lite.base.KotlinBaseFragment
import kotlinx.android.synthetic.main.fragment_alarm.view.*
class AlarmPageFragment : KotlinBaseFragment() {
- override fun initData(savedInstanceState: Bundle?) {
+
+ override fun initView(savedInstanceState: Bundle?) {
}
override fun initEvent() {
- baseView.calendarView.setOnClickListener {
+ bv.calendarView.setOnClickListener {
DateRangeActionSheet.Builder().setContext(requireContext())
.setOnActionSheetListener(object :
DateRangeActionSheet.OnDateRangeSelectedListener {
override fun onDateRangeSelected(startDate: String, endDate: String) {
- baseView.selectedDateView.text = "$startDate ~ $endDate"
+ bv.selectedDateView.text = "$startDate ~ $endDate"
}
}).build().show()
}
}
- override fun initLayoutView(): Int = R.layout.fragment_alarm
+ override fun initLayoutRes(): Int = R.layout.fragment_alarm
override fun observeRequestState() {
diff --git a/app/src/main/java/com/casic/br/ktd/fragment/HomePageFragment.kt b/app/src/main/java/com/casic/br/ktd/fragment/HomePageFragment.kt
index 9961935..f3eba5c 100644
--- a/app/src/main/java/com/casic/br/ktd/fragment/HomePageFragment.kt
+++ b/app/src/main/java/com/casic/br/ktd/fragment/HomePageFragment.kt
@@ -1,32 +1,62 @@
package com.casic.br.ktd.fragment
+import android.graphics.Color
import android.os.Bundle
import com.amap.api.maps.AMap
import com.amap.api.maps.AMapOptions
+import com.amap.api.maps.CameraUpdateFactory
+import com.amap.api.maps.model.*
import com.casic.br.ktd.R
-import com.pengxh.kt.lite.base.KotlinBaseFragment
+import com.casic.br.ktd.base.KotlinBaseFragment
import kotlinx.android.synthetic.main.fragment_home.view.*
class HomePageFragment : KotlinBaseFragment() {
private lateinit var aMap: AMap
- override fun initData(savedInstanceState: Bundle?) {
- baseView.mapView.onCreate(savedInstanceState)
- aMap = baseView.mapView.map
+ override fun initView(savedInstanceState: Bundle?) {
+ bv.mapView.onCreate(savedInstanceState)
+ aMap = bv.mapView.map
val uiSettings = aMap.uiSettings
uiSettings.isCompassEnabled = true
- uiSettings.isMyLocationButtonEnabled = true
+ uiSettings.isMyLocationButtonEnabled = false
uiSettings.isScaleControlsEnabled = true
uiSettings.zoomPosition = AMapOptions.ZOOM_POSITION_RIGHT_CENTER
uiSettings.isRotateGesturesEnabled = false//不许地图随手势旋转角度
}
override fun initEvent() {
-
+ //移动到巡检起始经纬度
+ val cameraPosition = CameraPosition(LatLng(39.914199, 116.265785), 16f, 0f, 0f)
+ val cameraUpdate = CameraUpdateFactory.newCameraPosition(cameraPosition)
+ aMap.animateCamera(cameraUpdate, 1500, null)
+ //设置起点
+ addMarker(LatLng(39.914885, 116.272312), R.mipmap.start)
+ //设置终点
+ addMarker(LatLng(39.914716, 116.265097), R.mipmap.end)
+ //瞄点画线
+ val latLngPoints = ArrayList()
+ latLngPoints.add(LatLng(39.914885, 116.272312))
+ latLngPoints.add(LatLng(39.915148, 116.272312))
+ latLngPoints.add(LatLng(39.915399, 116.272302))
+ latLngPoints.add(LatLng(39.915436, 116.271787))
+ latLngPoints.add(LatLng(39.915477, 116.270886))
+ latLngPoints.add(LatLng(39.915477, 116.269968))
+ latLngPoints.add(LatLng(39.915469, 116.269544))
+ latLngPoints.add(LatLng(39.915481, 116.269196))
+ latLngPoints.add(LatLng(39.915452, 116.268472))
+ latLngPoints.add(LatLng(39.915444, 116.267722))
+ latLngPoints.add(LatLng(39.915415, 116.266755))
+ latLngPoints.add(LatLng(39.915403, 116.266165))
+ latLngPoints.add(LatLng(39.915395, 116.265703))
+ latLngPoints.add(LatLng(39.915366, 116.265119))
+ latLngPoints.add(LatLng(39.914716, 116.265097))
+ aMap.addPolyline(
+ PolylineOptions().addAll(latLngPoints).width(10.toFloat()).color(Color.RED)
+ )
}
- override fun initLayoutView(): Int = R.layout.fragment_home
+ override fun initLayoutRes(): Int = R.layout.fragment_home
override fun observeRequestState() {
@@ -36,25 +66,32 @@
}
+ private fun addMarker(point: LatLng, res: Int) {
+ val markerOption = MarkerOptions()
+ markerOption.position(point)
+ markerOption.icon(BitmapDescriptorFactory.fromResource(res))
+ aMap.addMarker(markerOption)
+ }
+
/***以下是地图生命周期管理************************************************************************/
override fun onResume() {
super.onResume()
- baseView.mapView.onResume()
+ bv.mapView.onResume()
}
override fun onPause() {
- baseView.mapView.onPause()
super.onPause()
+ bv.mapView.onPause()
}
override fun onSaveInstanceState(outState: Bundle) {
super.onSaveInstanceState(outState)
- baseView.mapView.onSaveInstanceState(outState)
+ bv.mapView.onSaveInstanceState(outState)
}
override fun onDestroy() {
- baseView.mapView.onDestroy()
super.onDestroy()
+ bv.mapView.onDestroy()
}
}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/br/ktd/fragment/MinePageFragment.kt b/app/src/main/java/com/casic/br/ktd/fragment/MinePageFragment.kt
index 90313ac..3212794 100644
--- a/app/src/main/java/com/casic/br/ktd/fragment/MinePageFragment.kt
+++ b/app/src/main/java/com/casic/br/ktd/fragment/MinePageFragment.kt
@@ -2,10 +2,11 @@
import android.os.Bundle
import com.casic.br.ktd.R
-import com.pengxh.kt.lite.base.KotlinBaseFragment
+import com.casic.br.ktd.base.KotlinBaseFragment
class MinePageFragment : KotlinBaseFragment() {
- override fun initData(savedInstanceState: Bundle?) {
+
+ override fun initView(savedInstanceState: Bundle?) {
}
@@ -13,7 +14,7 @@
}
- override fun initLayoutView(): Int = R.layout.fragment_mine
+ override fun initLayoutRes(): Int = R.layout.fragment_mine
override fun observeRequestState() {
diff --git a/app/src/main/java/com/casic/br/ktd/fragment/TaskPageFragment.kt b/app/src/main/java/com/casic/br/ktd/fragment/TaskPageFragment.kt
index 8f6abf0..6b82a54 100644
--- a/app/src/main/java/com/casic/br/ktd/fragment/TaskPageFragment.kt
+++ b/app/src/main/java/com/casic/br/ktd/fragment/TaskPageFragment.kt
@@ -8,6 +8,7 @@
import androidx.recyclerview.widget.RecyclerView
import com.casic.br.ktd.R
import com.casic.br.ktd.adapter.TaskAdapter
+import com.casic.br.ktd.base.KotlinBaseFragment
import com.casic.br.ktd.holder.SwipeViewHolder
import com.casic.br.ktd.model.TaskListModel
import com.casic.br.ktd.view.InspectionActivity
@@ -15,7 +16,6 @@
import com.casic.br.ktd.widgets.AlertControlDialog
import com.casic.br.ktd.widgets.AlertInputDialog
import com.casic.br.ktd.widgets.DateRangeActionSheet
-import com.pengxh.kt.lite.base.KotlinBaseFragment
import com.pengxh.kt.lite.extensions.navigatePageTo
import com.pengxh.kt.lite.extensions.show
import com.pengxh.kt.lite.utils.WeakReferenceHandler
@@ -36,7 +36,7 @@
private var startTime = ""
private var endTime = ""
- override fun initData(savedInstanceState: Bundle?) {
+ override fun initView(savedInstanceState: Bundle?) {
weakReferenceHandler = WeakReferenceHandler(this)
taskViewModel = ViewModelProvider(this)[TaskViewModel::class.java]
taskViewModel.taskList.observe(this) {
@@ -45,7 +45,7 @@
when {
isRefresh -> {
taskAdapter.setRefreshData(dataRows)
- baseView.taskLayout.finishRefresh()
+ bv.taskLayout.finishRefresh()
isRefresh = false
}
isLoadMore -> {
@@ -53,7 +53,7 @@
"到底了,别拉了".show(requireContext())
}
taskAdapter.setLoadMoreData(dataRows)
- baseView.taskLayout.finishLoadMore()
+ bv.taskLayout.finishLoadMore()
isLoadMore = false
}
else -> {
@@ -76,9 +76,9 @@
when (msg.what) {
2023070501 -> {
if (dataBeans.size == 0) {
- baseView.emptyLayout.visibility = View.VISIBLE
+ bv.emptyLayout.visibility = View.VISIBLE
} else {
- baseView.emptyLayout.visibility = View.GONE
+ bv.emptyLayout.visibility = View.GONE
taskAdapter = object : TaskAdapter(
requireContext(), R.layout.item_task_rv_l, dataBeans
) {
@@ -97,8 +97,8 @@
}
}
//绑定侧滑事件
- swipeAction.attachToRecyclerView(baseView.taskRecyclerView)
- baseView.taskRecyclerView.adapter = taskAdapter
+ swipeAction.attachToRecyclerView(bv.taskRecyclerView)
+ bv.taskRecyclerView.adapter = taskAdapter
taskAdapter.setOnItemCheckedListener(object :
TaskAdapter.OnItemCheckedListener {
override fun onItemChecked(items: ArrayList) {
@@ -168,7 +168,7 @@
override fun initEvent() {
- baseView.calendarView.setOnClickListener {
+ bv.calendarView.setOnClickListener {
DateRangeActionSheet.Builder().setContext(requireContext())
.setOnActionSheetListener(object :
DateRangeActionSheet.OnDateRangeSelectedListener {
@@ -177,12 +177,12 @@
endTime = endDate
//显示
- baseView.selectedDateView.text = "$startDate ~ $endDate"
+ bv.selectedDateView.text = "$startDate ~ $endDate"
}
}).build().show()
}
- baseView.addTaskButton.setOnClickListener {
+ bv.addTaskButton.setOnClickListener {
// AlertInputDialog.Builder()
// .setContext(requireContext())
// .setTitle("新建巡检任务")
@@ -200,11 +200,11 @@
requireContext().navigatePageTo()
}
- baseView.deleteTaskButton.setOnClickListener {
+ bv.deleteTaskButton.setOnClickListener {
selectedItems.size.toString().show(requireContext())
}
- baseView.taskSettingsButton.setOnClickListener {
+ bv.taskSettingsButton.setOnClickListener {
AlertInputDialog.Builder()
.setContext(requireContext())
.setTitle("设置阈值")
@@ -221,14 +221,14 @@
}).build().show()
}
- baseView.taskLayout.setOnRefreshListener {
+ bv.taskLayout.setOnRefreshListener {
isRefresh = true
//刷新之后页码重置
pageIndex = 1
getTaskList()
}
- baseView.taskLayout.setOnLoadMoreListener {
+ bv.taskLayout.setOnLoadMoreListener {
isLoadMore = true
pageIndex++
getTaskList()
@@ -239,13 +239,13 @@
taskViewModel.getTaskList(
startTime,
endTime,
- baseView.taskNameView.text.toString(),
- baseView.taskCodeView.text.toString(),
+ bv.taskNameView.text.toString(),
+ bv.taskCodeView.text.toString(),
pageIndex
)
}
- override fun initLayoutView(): Int = R.layout.fragment_task
+ override fun initLayoutRes(): Int = R.layout.fragment_task
override fun observeRequestState() {
diff --git a/app/src/main/java/com/casic/br/ktd/netty/ISocketListener.kt b/app/src/main/java/com/casic/br/ktd/netty/ISocketListener.kt
deleted file mode 100644
index dab98e1..0000000
--- a/app/src/main/java/com/casic/br/ktd/netty/ISocketListener.kt
+++ /dev/null
@@ -1,19 +0,0 @@
-package com.casic.br.ktd.netty
-
-interface ISocketListener {
- companion object {
- const val STATUS_CONNECT_SUCCESS: Byte = 1 //连接成功
- const val STATUS_CONNECT_CLOSED: Byte = 0 //关闭连接
- const val STATUS_CONNECT_ERROR: Byte = 0 //连接失败
- }
-
- /**
- * 当接收到系统消息
- */
- fun onMessageResponse(data: ByteArray?)
-
- /**
- * 当连接状态发生变化时调用
- */
- fun onServiceStatusConnectChanged(statusCode: Byte)
-}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/br/ktd/netty/SocketChannelHandle.kt b/app/src/main/java/com/casic/br/ktd/netty/SocketChannelHandle.kt
deleted file mode 100644
index 42eb310..0000000
--- a/app/src/main/java/com/casic/br/ktd/netty/SocketChannelHandle.kt
+++ /dev/null
@@ -1,51 +0,0 @@
-package com.casic.br.ktd.netty
-
-import android.util.Log
-import io.netty.channel.ChannelHandlerContext
-import io.netty.channel.SimpleChannelInboundHandler
-import io.netty.handler.timeout.IdleState
-import io.netty.handler.timeout.IdleStateEvent
-import java.nio.charset.StandardCharsets
-
-class SocketChannelHandle(private val listener: ISocketListener?) :
- SimpleChannelInboundHandler() {
-
- private val kTag = "SocketChannelHandle"
-
- override fun channelActive(ctx: ChannelHandlerContext) {
- super.channelActive(ctx)
- Log.d(kTag, "channelActive ===> 连接成功")
- listener?.onServiceStatusConnectChanged(ISocketListener.STATUS_CONNECT_SUCCESS)
- }
-
- override fun channelInactive(ctx: ChannelHandlerContext) {
- super.channelInactive(ctx)
- Log.e(kTag, "channelInactive: 连接断开")
- }
-
- override fun userEventTriggered(ctx: ChannelHandlerContext, evt: Any) {
- super.userEventTriggered(ctx, evt)
- if (evt is IdleStateEvent) {
- if (evt.state() == IdleState.WRITER_IDLE) {
- //写超时,此时可以发送心跳数据给服务器
- val temp = "FF"
- ctx.writeAndFlush(temp.toByteArray(StandardCharsets.UTF_8))
- } else if (evt.state() == IdleState.READER_IDLE) {
- //读超时,此时代表没有收到心跳返回可以关闭当前连接进行重连
- ctx.close()
- }
- }
- }
-
- override fun channelRead0(ctx: ChannelHandlerContext, data: ByteArray?) {
- listener?.onMessageResponse(data)
- }
-
- override fun exceptionCaught(ctx: ChannelHandlerContext, cause: Throwable) {
- super.exceptionCaught(ctx, cause)
- Log.d(kTag, "exceptionCaught ===> $cause")
- listener?.onServiceStatusConnectChanged(ISocketListener.STATUS_CONNECT_ERROR)
- cause.printStackTrace()
- ctx.close()
- }
-}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/br/ktd/netty/SocketClient.kt b/app/src/main/java/com/casic/br/ktd/netty/SocketClient.kt
deleted file mode 100644
index d05d335..0000000
--- a/app/src/main/java/com/casic/br/ktd/netty/SocketClient.kt
+++ /dev/null
@@ -1,153 +0,0 @@
-package com.casic.br.ktd.netty
-
-import android.os.SystemClock
-import android.util.Log
-import io.netty.bootstrap.Bootstrap
-import io.netty.channel.*
-import io.netty.channel.nio.NioEventLoopGroup
-import io.netty.channel.socket.SocketChannel
-import io.netty.channel.socket.nio.NioSocketChannel
-import io.netty.handler.codec.bytes.ByteArrayDecoder
-import io.netty.handler.codec.bytes.ByteArrayEncoder
-import io.netty.handler.timeout.IdleStateHandler
-
-class SocketClient {
-
- private val kTag = "SocketClient"
-
- private var host: String? = null
- private var port = 8000
- private var nioEventLoopGroup: NioEventLoopGroup? = null
- private var channel: Channel? = null
- private var listener: ISocketListener? = null
-
- //现在连接的状态
- var connectStatus = false //判断是否已连接
- private var reconnectNum = Int.MAX_VALUE //定义的重连到时候用
- private var isNeedReconnect = true //是否需要重连
- var isConnecting = false //是否正在连接
- private set
- private var reconnectIntervalTime: Long = 15000 //重连的时间
-
- //重连时间
- fun setReconnectNum(reconnectNum: Int) {
- this.reconnectNum = reconnectNum
- }
-
- fun setReconnectIntervalTime(reconnectIntervalTime: Long) {
- this.reconnectIntervalTime = reconnectIntervalTime
- }
-
- fun setSocketListener(listener: ISocketListener?) {
- this.listener = listener
- }
-
- fun connect(host: String, port: Int) {
- this.host = host
- this.port = port
- Log.d(kTag, "connect ===> 开始连接TCP服务器")
- if (isConnecting) {
- return
- }
- //起个线程
- val clientThread: Thread = object : Thread("client-Netty") {
- override fun run() {
- super.run()
- isNeedReconnect = true
- reconnectNum = Int.MAX_VALUE
- connectServer()
- }
- }
- clientThread.start()
- }
-
- private fun connectServer() {
- synchronized(this@SocketClient) {
- var channelFuture: ChannelFuture? = null //连接管理对象
- if (!connectStatus) {
- isConnecting = true
- nioEventLoopGroup = NioEventLoopGroup() //设置的连接group
- val bootstrap = Bootstrap()
- bootstrap.group(nioEventLoopGroup) //设置的一系列连接参数操作等
- .channel(NioSocketChannel::class.java)
- .option(ChannelOption.TCP_NODELAY, true) //无阻塞
- .option(ChannelOption.SO_KEEPALIVE, true) //长连接
- .option(
- ChannelOption.RCVBUF_ALLOCATOR,
- AdaptiveRecvByteBufAllocator(5000, 5000, 8000)
- ) //接收缓冲区 最小值太小时数据接收不全
- .handler(object : ChannelInitializer() {
- override fun initChannel(channel: SocketChannel) {
- val pipeline = channel.pipeline()
- //参数1:代表读套接字超时的时间,没收到数据会触发读超时回调;
- //参数2:代表写套接字超时时间,没进行写会触发写超时回调;
- //参数3:将在未执行读取或写入时触发超时回调,0代表不处理;
- //读超时尽量设置大于写超时,代表多次写超时时写心跳包,多次写了心跳数据仍然读超时代表当前连接错误,即可断开连接重新连接
- pipeline.addLast(IdleStateHandler(60, 10, 0))
- pipeline.addLast(ByteArrayDecoder())
- pipeline.addLast(ByteArrayEncoder())
- pipeline.addLast(SocketChannelHandle(listener))
- }
- })
- try {
- //连接监听
- channelFuture = bootstrap.connect(host, port)
- .addListener(object : ChannelFutureListener {
- override fun operationComplete(channelFuture: ChannelFuture) {
- if (channelFuture.isSuccess) {
- connectStatus = true
- channel = channelFuture.channel()
- } else {
- Log.e(kTag, "operationComplete: 连接失败")
- connectStatus = false
- }
- isConnecting = false
- }
- }).sync()
- // 等待连接关闭
- channelFuture.channel().closeFuture().sync()
- } catch (e: Exception) {
- e.printStackTrace()
- } finally {
- connectStatus = false
- listener?.onServiceStatusConnectChanged(ISocketListener.STATUS_CONNECT_CLOSED) //STATUS_CONNECT_CLOSED 这我自己定义的 接口标识
- if (null != channelFuture) {
- if (channelFuture.channel() != null && channelFuture.channel().isOpen) {
- channelFuture.channel().close()
- }
- }
- nioEventLoopGroup?.shutdownGracefully()
- reconnect() //重新连接
- }
- }
- }
- }
-
- //断开连接
- fun disconnect() {
- Log.d(kTag, "disconnect ===> 断开连接")
- isNeedReconnect = false
- nioEventLoopGroup?.shutdownGracefully()
- }
-
- //重新连接
- private fun reconnect() {
- if (isNeedReconnect && reconnectNum > 0 && !connectStatus) {
- reconnectNum--
- SystemClock.sleep(reconnectIntervalTime)
- if (isNeedReconnect && reconnectNum > 0 && !connectStatus) {
- Log.d(kTag, "reconnect ===> 重新连接")
- connectServer()
- }
- }
- }
-
- fun sendData(bytes: ByteArray) {
- channel?.writeAndFlush(bytes)?.addListener(ChannelFutureListener { future ->
- if (!future.isSuccess) {
- future.channel().close()
- nioEventLoopGroup!!.shutdownGracefully()
- }
- })
- }
-}
\ No newline at end of file
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index e822df6..d72c1a5 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -7,6 +7,9 @@
+
+
+
@@ -46,5 +49,8 @@
+
+
+
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/br/ktd/base/KotlinBaseFragment.kt b/app/src/main/java/com/casic/br/ktd/base/KotlinBaseFragment.kt
new file mode 100644
index 0000000..2dac61c
--- /dev/null
+++ b/app/src/main/java/com/casic/br/ktd/base/KotlinBaseFragment.kt
@@ -0,0 +1,51 @@
+package com.casic.br.ktd.base
+
+import android.os.Bundle
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import androidx.annotation.LayoutRes
+import androidx.fragment.app.Fragment
+
+abstract class KotlinBaseFragment : Fragment() {
+
+ lateinit var bv: View
+
+ override fun onCreateView(
+ inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?
+ ): View? {
+ bv = inflater.inflate(initLayoutRes(), container, false)
+ initView(savedInstanceState)
+ setupTopBarLayout()
+ return bv
+ }
+
+ override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
+ super.onViewCreated(view, savedInstanceState)
+ observeRequestState()
+ initEvent()
+ }
+
+ @LayoutRes
+ abstract fun initLayoutRes(): Int
+
+ /**
+ * 沉浸式状态栏
+ */
+ abstract fun setupTopBarLayout()
+
+ /**
+ * 初始化布局以及控件
+ */
+ abstract fun initView(savedInstanceState: Bundle?)
+
+ /**
+ * 网络请求状态监听
+ */
+ abstract fun observeRequestState()
+
+ /**
+ * 业务逻辑,按钮等事件
+ */
+ abstract fun initEvent()
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/br/ktd/fragment/AlarmPageFragment.kt b/app/src/main/java/com/casic/br/ktd/fragment/AlarmPageFragment.kt
index 6c98a3b..9418169 100644
--- a/app/src/main/java/com/casic/br/ktd/fragment/AlarmPageFragment.kt
+++ b/app/src/main/java/com/casic/br/ktd/fragment/AlarmPageFragment.kt
@@ -2,28 +2,29 @@
import android.os.Bundle
import com.casic.br.ktd.R
+import com.casic.br.ktd.base.KotlinBaseFragment
import com.casic.br.ktd.widgets.DateRangeActionSheet
-import com.pengxh.kt.lite.base.KotlinBaseFragment
import kotlinx.android.synthetic.main.fragment_alarm.view.*
class AlarmPageFragment : KotlinBaseFragment() {
- override fun initData(savedInstanceState: Bundle?) {
+
+ override fun initView(savedInstanceState: Bundle?) {
}
override fun initEvent() {
- baseView.calendarView.setOnClickListener {
+ bv.calendarView.setOnClickListener {
DateRangeActionSheet.Builder().setContext(requireContext())
.setOnActionSheetListener(object :
DateRangeActionSheet.OnDateRangeSelectedListener {
override fun onDateRangeSelected(startDate: String, endDate: String) {
- baseView.selectedDateView.text = "$startDate ~ $endDate"
+ bv.selectedDateView.text = "$startDate ~ $endDate"
}
}).build().show()
}
}
- override fun initLayoutView(): Int = R.layout.fragment_alarm
+ override fun initLayoutRes(): Int = R.layout.fragment_alarm
override fun observeRequestState() {
diff --git a/app/src/main/java/com/casic/br/ktd/fragment/HomePageFragment.kt b/app/src/main/java/com/casic/br/ktd/fragment/HomePageFragment.kt
index 9961935..f3eba5c 100644
--- a/app/src/main/java/com/casic/br/ktd/fragment/HomePageFragment.kt
+++ b/app/src/main/java/com/casic/br/ktd/fragment/HomePageFragment.kt
@@ -1,32 +1,62 @@
package com.casic.br.ktd.fragment
+import android.graphics.Color
import android.os.Bundle
import com.amap.api.maps.AMap
import com.amap.api.maps.AMapOptions
+import com.amap.api.maps.CameraUpdateFactory
+import com.amap.api.maps.model.*
import com.casic.br.ktd.R
-import com.pengxh.kt.lite.base.KotlinBaseFragment
+import com.casic.br.ktd.base.KotlinBaseFragment
import kotlinx.android.synthetic.main.fragment_home.view.*
class HomePageFragment : KotlinBaseFragment() {
private lateinit var aMap: AMap
- override fun initData(savedInstanceState: Bundle?) {
- baseView.mapView.onCreate(savedInstanceState)
- aMap = baseView.mapView.map
+ override fun initView(savedInstanceState: Bundle?) {
+ bv.mapView.onCreate(savedInstanceState)
+ aMap = bv.mapView.map
val uiSettings = aMap.uiSettings
uiSettings.isCompassEnabled = true
- uiSettings.isMyLocationButtonEnabled = true
+ uiSettings.isMyLocationButtonEnabled = false
uiSettings.isScaleControlsEnabled = true
uiSettings.zoomPosition = AMapOptions.ZOOM_POSITION_RIGHT_CENTER
uiSettings.isRotateGesturesEnabled = false//不许地图随手势旋转角度
}
override fun initEvent() {
-
+ //移动到巡检起始经纬度
+ val cameraPosition = CameraPosition(LatLng(39.914199, 116.265785), 16f, 0f, 0f)
+ val cameraUpdate = CameraUpdateFactory.newCameraPosition(cameraPosition)
+ aMap.animateCamera(cameraUpdate, 1500, null)
+ //设置起点
+ addMarker(LatLng(39.914885, 116.272312), R.mipmap.start)
+ //设置终点
+ addMarker(LatLng(39.914716, 116.265097), R.mipmap.end)
+ //瞄点画线
+ val latLngPoints = ArrayList()
+ latLngPoints.add(LatLng(39.914885, 116.272312))
+ latLngPoints.add(LatLng(39.915148, 116.272312))
+ latLngPoints.add(LatLng(39.915399, 116.272302))
+ latLngPoints.add(LatLng(39.915436, 116.271787))
+ latLngPoints.add(LatLng(39.915477, 116.270886))
+ latLngPoints.add(LatLng(39.915477, 116.269968))
+ latLngPoints.add(LatLng(39.915469, 116.269544))
+ latLngPoints.add(LatLng(39.915481, 116.269196))
+ latLngPoints.add(LatLng(39.915452, 116.268472))
+ latLngPoints.add(LatLng(39.915444, 116.267722))
+ latLngPoints.add(LatLng(39.915415, 116.266755))
+ latLngPoints.add(LatLng(39.915403, 116.266165))
+ latLngPoints.add(LatLng(39.915395, 116.265703))
+ latLngPoints.add(LatLng(39.915366, 116.265119))
+ latLngPoints.add(LatLng(39.914716, 116.265097))
+ aMap.addPolyline(
+ PolylineOptions().addAll(latLngPoints).width(10.toFloat()).color(Color.RED)
+ )
}
- override fun initLayoutView(): Int = R.layout.fragment_home
+ override fun initLayoutRes(): Int = R.layout.fragment_home
override fun observeRequestState() {
@@ -36,25 +66,32 @@
}
+ private fun addMarker(point: LatLng, res: Int) {
+ val markerOption = MarkerOptions()
+ markerOption.position(point)
+ markerOption.icon(BitmapDescriptorFactory.fromResource(res))
+ aMap.addMarker(markerOption)
+ }
+
/***以下是地图生命周期管理************************************************************************/
override fun onResume() {
super.onResume()
- baseView.mapView.onResume()
+ bv.mapView.onResume()
}
override fun onPause() {
- baseView.mapView.onPause()
super.onPause()
+ bv.mapView.onPause()
}
override fun onSaveInstanceState(outState: Bundle) {
super.onSaveInstanceState(outState)
- baseView.mapView.onSaveInstanceState(outState)
+ bv.mapView.onSaveInstanceState(outState)
}
override fun onDestroy() {
- baseView.mapView.onDestroy()
super.onDestroy()
+ bv.mapView.onDestroy()
}
}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/br/ktd/fragment/MinePageFragment.kt b/app/src/main/java/com/casic/br/ktd/fragment/MinePageFragment.kt
index 90313ac..3212794 100644
--- a/app/src/main/java/com/casic/br/ktd/fragment/MinePageFragment.kt
+++ b/app/src/main/java/com/casic/br/ktd/fragment/MinePageFragment.kt
@@ -2,10 +2,11 @@
import android.os.Bundle
import com.casic.br.ktd.R
-import com.pengxh.kt.lite.base.KotlinBaseFragment
+import com.casic.br.ktd.base.KotlinBaseFragment
class MinePageFragment : KotlinBaseFragment() {
- override fun initData(savedInstanceState: Bundle?) {
+
+ override fun initView(savedInstanceState: Bundle?) {
}
@@ -13,7 +14,7 @@
}
- override fun initLayoutView(): Int = R.layout.fragment_mine
+ override fun initLayoutRes(): Int = R.layout.fragment_mine
override fun observeRequestState() {
diff --git a/app/src/main/java/com/casic/br/ktd/fragment/TaskPageFragment.kt b/app/src/main/java/com/casic/br/ktd/fragment/TaskPageFragment.kt
index 8f6abf0..6b82a54 100644
--- a/app/src/main/java/com/casic/br/ktd/fragment/TaskPageFragment.kt
+++ b/app/src/main/java/com/casic/br/ktd/fragment/TaskPageFragment.kt
@@ -8,6 +8,7 @@
import androidx.recyclerview.widget.RecyclerView
import com.casic.br.ktd.R
import com.casic.br.ktd.adapter.TaskAdapter
+import com.casic.br.ktd.base.KotlinBaseFragment
import com.casic.br.ktd.holder.SwipeViewHolder
import com.casic.br.ktd.model.TaskListModel
import com.casic.br.ktd.view.InspectionActivity
@@ -15,7 +16,6 @@
import com.casic.br.ktd.widgets.AlertControlDialog
import com.casic.br.ktd.widgets.AlertInputDialog
import com.casic.br.ktd.widgets.DateRangeActionSheet
-import com.pengxh.kt.lite.base.KotlinBaseFragment
import com.pengxh.kt.lite.extensions.navigatePageTo
import com.pengxh.kt.lite.extensions.show
import com.pengxh.kt.lite.utils.WeakReferenceHandler
@@ -36,7 +36,7 @@
private var startTime = ""
private var endTime = ""
- override fun initData(savedInstanceState: Bundle?) {
+ override fun initView(savedInstanceState: Bundle?) {
weakReferenceHandler = WeakReferenceHandler(this)
taskViewModel = ViewModelProvider(this)[TaskViewModel::class.java]
taskViewModel.taskList.observe(this) {
@@ -45,7 +45,7 @@
when {
isRefresh -> {
taskAdapter.setRefreshData(dataRows)
- baseView.taskLayout.finishRefresh()
+ bv.taskLayout.finishRefresh()
isRefresh = false
}
isLoadMore -> {
@@ -53,7 +53,7 @@
"到底了,别拉了".show(requireContext())
}
taskAdapter.setLoadMoreData(dataRows)
- baseView.taskLayout.finishLoadMore()
+ bv.taskLayout.finishLoadMore()
isLoadMore = false
}
else -> {
@@ -76,9 +76,9 @@
when (msg.what) {
2023070501 -> {
if (dataBeans.size == 0) {
- baseView.emptyLayout.visibility = View.VISIBLE
+ bv.emptyLayout.visibility = View.VISIBLE
} else {
- baseView.emptyLayout.visibility = View.GONE
+ bv.emptyLayout.visibility = View.GONE
taskAdapter = object : TaskAdapter(
requireContext(), R.layout.item_task_rv_l, dataBeans
) {
@@ -97,8 +97,8 @@
}
}
//绑定侧滑事件
- swipeAction.attachToRecyclerView(baseView.taskRecyclerView)
- baseView.taskRecyclerView.adapter = taskAdapter
+ swipeAction.attachToRecyclerView(bv.taskRecyclerView)
+ bv.taskRecyclerView.adapter = taskAdapter
taskAdapter.setOnItemCheckedListener(object :
TaskAdapter.OnItemCheckedListener {
override fun onItemChecked(items: ArrayList) {
@@ -168,7 +168,7 @@
override fun initEvent() {
- baseView.calendarView.setOnClickListener {
+ bv.calendarView.setOnClickListener {
DateRangeActionSheet.Builder().setContext(requireContext())
.setOnActionSheetListener(object :
DateRangeActionSheet.OnDateRangeSelectedListener {
@@ -177,12 +177,12 @@
endTime = endDate
//显示
- baseView.selectedDateView.text = "$startDate ~ $endDate"
+ bv.selectedDateView.text = "$startDate ~ $endDate"
}
}).build().show()
}
- baseView.addTaskButton.setOnClickListener {
+ bv.addTaskButton.setOnClickListener {
// AlertInputDialog.Builder()
// .setContext(requireContext())
// .setTitle("新建巡检任务")
@@ -200,11 +200,11 @@
requireContext().navigatePageTo()
}
- baseView.deleteTaskButton.setOnClickListener {
+ bv.deleteTaskButton.setOnClickListener {
selectedItems.size.toString().show(requireContext())
}
- baseView.taskSettingsButton.setOnClickListener {
+ bv.taskSettingsButton.setOnClickListener {
AlertInputDialog.Builder()
.setContext(requireContext())
.setTitle("设置阈值")
@@ -221,14 +221,14 @@
}).build().show()
}
- baseView.taskLayout.setOnRefreshListener {
+ bv.taskLayout.setOnRefreshListener {
isRefresh = true
//刷新之后页码重置
pageIndex = 1
getTaskList()
}
- baseView.taskLayout.setOnLoadMoreListener {
+ bv.taskLayout.setOnLoadMoreListener {
isLoadMore = true
pageIndex++
getTaskList()
@@ -239,13 +239,13 @@
taskViewModel.getTaskList(
startTime,
endTime,
- baseView.taskNameView.text.toString(),
- baseView.taskCodeView.text.toString(),
+ bv.taskNameView.text.toString(),
+ bv.taskCodeView.text.toString(),
pageIndex
)
}
- override fun initLayoutView(): Int = R.layout.fragment_task
+ override fun initLayoutRes(): Int = R.layout.fragment_task
override fun observeRequestState() {
diff --git a/app/src/main/java/com/casic/br/ktd/netty/ISocketListener.kt b/app/src/main/java/com/casic/br/ktd/netty/ISocketListener.kt
deleted file mode 100644
index dab98e1..0000000
--- a/app/src/main/java/com/casic/br/ktd/netty/ISocketListener.kt
+++ /dev/null
@@ -1,19 +0,0 @@
-package com.casic.br.ktd.netty
-
-interface ISocketListener {
- companion object {
- const val STATUS_CONNECT_SUCCESS: Byte = 1 //连接成功
- const val STATUS_CONNECT_CLOSED: Byte = 0 //关闭连接
- const val STATUS_CONNECT_ERROR: Byte = 0 //连接失败
- }
-
- /**
- * 当接收到系统消息
- */
- fun onMessageResponse(data: ByteArray?)
-
- /**
- * 当连接状态发生变化时调用
- */
- fun onServiceStatusConnectChanged(statusCode: Byte)
-}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/br/ktd/netty/SocketChannelHandle.kt b/app/src/main/java/com/casic/br/ktd/netty/SocketChannelHandle.kt
deleted file mode 100644
index 42eb310..0000000
--- a/app/src/main/java/com/casic/br/ktd/netty/SocketChannelHandle.kt
+++ /dev/null
@@ -1,51 +0,0 @@
-package com.casic.br.ktd.netty
-
-import android.util.Log
-import io.netty.channel.ChannelHandlerContext
-import io.netty.channel.SimpleChannelInboundHandler
-import io.netty.handler.timeout.IdleState
-import io.netty.handler.timeout.IdleStateEvent
-import java.nio.charset.StandardCharsets
-
-class SocketChannelHandle(private val listener: ISocketListener?) :
- SimpleChannelInboundHandler() {
-
- private val kTag = "SocketChannelHandle"
-
- override fun channelActive(ctx: ChannelHandlerContext) {
- super.channelActive(ctx)
- Log.d(kTag, "channelActive ===> 连接成功")
- listener?.onServiceStatusConnectChanged(ISocketListener.STATUS_CONNECT_SUCCESS)
- }
-
- override fun channelInactive(ctx: ChannelHandlerContext) {
- super.channelInactive(ctx)
- Log.e(kTag, "channelInactive: 连接断开")
- }
-
- override fun userEventTriggered(ctx: ChannelHandlerContext, evt: Any) {
- super.userEventTriggered(ctx, evt)
- if (evt is IdleStateEvent) {
- if (evt.state() == IdleState.WRITER_IDLE) {
- //写超时,此时可以发送心跳数据给服务器
- val temp = "FF"
- ctx.writeAndFlush(temp.toByteArray(StandardCharsets.UTF_8))
- } else if (evt.state() == IdleState.READER_IDLE) {
- //读超时,此时代表没有收到心跳返回可以关闭当前连接进行重连
- ctx.close()
- }
- }
- }
-
- override fun channelRead0(ctx: ChannelHandlerContext, data: ByteArray?) {
- listener?.onMessageResponse(data)
- }
-
- override fun exceptionCaught(ctx: ChannelHandlerContext, cause: Throwable) {
- super.exceptionCaught(ctx, cause)
- Log.d(kTag, "exceptionCaught ===> $cause")
- listener?.onServiceStatusConnectChanged(ISocketListener.STATUS_CONNECT_ERROR)
- cause.printStackTrace()
- ctx.close()
- }
-}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/br/ktd/netty/SocketClient.kt b/app/src/main/java/com/casic/br/ktd/netty/SocketClient.kt
deleted file mode 100644
index d05d335..0000000
--- a/app/src/main/java/com/casic/br/ktd/netty/SocketClient.kt
+++ /dev/null
@@ -1,153 +0,0 @@
-package com.casic.br.ktd.netty
-
-import android.os.SystemClock
-import android.util.Log
-import io.netty.bootstrap.Bootstrap
-import io.netty.channel.*
-import io.netty.channel.nio.NioEventLoopGroup
-import io.netty.channel.socket.SocketChannel
-import io.netty.channel.socket.nio.NioSocketChannel
-import io.netty.handler.codec.bytes.ByteArrayDecoder
-import io.netty.handler.codec.bytes.ByteArrayEncoder
-import io.netty.handler.timeout.IdleStateHandler
-
-class SocketClient {
-
- private val kTag = "SocketClient"
-
- private var host: String? = null
- private var port = 8000
- private var nioEventLoopGroup: NioEventLoopGroup? = null
- private var channel: Channel? = null
- private var listener: ISocketListener? = null
-
- //现在连接的状态
- var connectStatus = false //判断是否已连接
- private var reconnectNum = Int.MAX_VALUE //定义的重连到时候用
- private var isNeedReconnect = true //是否需要重连
- var isConnecting = false //是否正在连接
- private set
- private var reconnectIntervalTime: Long = 15000 //重连的时间
-
- //重连时间
- fun setReconnectNum(reconnectNum: Int) {
- this.reconnectNum = reconnectNum
- }
-
- fun setReconnectIntervalTime(reconnectIntervalTime: Long) {
- this.reconnectIntervalTime = reconnectIntervalTime
- }
-
- fun setSocketListener(listener: ISocketListener?) {
- this.listener = listener
- }
-
- fun connect(host: String, port: Int) {
- this.host = host
- this.port = port
- Log.d(kTag, "connect ===> 开始连接TCP服务器")
- if (isConnecting) {
- return
- }
- //起个线程
- val clientThread: Thread = object : Thread("client-Netty") {
- override fun run() {
- super.run()
- isNeedReconnect = true
- reconnectNum = Int.MAX_VALUE
- connectServer()
- }
- }
- clientThread.start()
- }
-
- private fun connectServer() {
- synchronized(this@SocketClient) {
- var channelFuture: ChannelFuture? = null //连接管理对象
- if (!connectStatus) {
- isConnecting = true
- nioEventLoopGroup = NioEventLoopGroup() //设置的连接group
- val bootstrap = Bootstrap()
- bootstrap.group(nioEventLoopGroup) //设置的一系列连接参数操作等
- .channel(NioSocketChannel::class.java)
- .option(ChannelOption.TCP_NODELAY, true) //无阻塞
- .option(ChannelOption.SO_KEEPALIVE, true) //长连接
- .option(
- ChannelOption.RCVBUF_ALLOCATOR,
- AdaptiveRecvByteBufAllocator(5000, 5000, 8000)
- ) //接收缓冲区 最小值太小时数据接收不全
- .handler(object : ChannelInitializer() {
- override fun initChannel(channel: SocketChannel) {
- val pipeline = channel.pipeline()
- //参数1:代表读套接字超时的时间,没收到数据会触发读超时回调;
- //参数2:代表写套接字超时时间,没进行写会触发写超时回调;
- //参数3:将在未执行读取或写入时触发超时回调,0代表不处理;
- //读超时尽量设置大于写超时,代表多次写超时时写心跳包,多次写了心跳数据仍然读超时代表当前连接错误,即可断开连接重新连接
- pipeline.addLast(IdleStateHandler(60, 10, 0))
- pipeline.addLast(ByteArrayDecoder())
- pipeline.addLast(ByteArrayEncoder())
- pipeline.addLast(SocketChannelHandle(listener))
- }
- })
- try {
- //连接监听
- channelFuture = bootstrap.connect(host, port)
- .addListener(object : ChannelFutureListener {
- override fun operationComplete(channelFuture: ChannelFuture) {
- if (channelFuture.isSuccess) {
- connectStatus = true
- channel = channelFuture.channel()
- } else {
- Log.e(kTag, "operationComplete: 连接失败")
- connectStatus = false
- }
- isConnecting = false
- }
- }).sync()
- // 等待连接关闭
- channelFuture.channel().closeFuture().sync()
- } catch (e: Exception) {
- e.printStackTrace()
- } finally {
- connectStatus = false
- listener?.onServiceStatusConnectChanged(ISocketListener.STATUS_CONNECT_CLOSED) //STATUS_CONNECT_CLOSED 这我自己定义的 接口标识
- if (null != channelFuture) {
- if (channelFuture.channel() != null && channelFuture.channel().isOpen) {
- channelFuture.channel().close()
- }
- }
- nioEventLoopGroup?.shutdownGracefully()
- reconnect() //重新连接
- }
- }
- }
- }
-
- //断开连接
- fun disconnect() {
- Log.d(kTag, "disconnect ===> 断开连接")
- isNeedReconnect = false
- nioEventLoopGroup?.shutdownGracefully()
- }
-
- //重新连接
- private fun reconnect() {
- if (isNeedReconnect && reconnectNum > 0 && !connectStatus) {
- reconnectNum--
- SystemClock.sleep(reconnectIntervalTime)
- if (isNeedReconnect && reconnectNum > 0 && !connectStatus) {
- Log.d(kTag, "reconnect ===> 重新连接")
- connectServer()
- }
- }
- }
-
- fun sendData(bytes: ByteArray) {
- channel?.writeAndFlush(bytes)?.addListener(ChannelFutureListener { future ->
- if (!future.isSuccess) {
- future.channel().close()
- nioEventLoopGroup!!.shutdownGracefully()
- }
- })
- }
-}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/br/ktd/netty/SocketManager.kt b/app/src/main/java/com/casic/br/ktd/netty/SocketManager.kt
deleted file mode 100644
index 17daf35..0000000
--- a/app/src/main/java/com/casic/br/ktd/netty/SocketManager.kt
+++ /dev/null
@@ -1,113 +0,0 @@
-package com.casic.br.ktd.netty
-
-import android.util.Log
-import com.casic.br.ktd.base.BaseApplication
-import com.casic.br.ktd.extensions.covertAngleValue
-import com.casic.br.ktd.extensions.covertDataValue
-import com.casic.br.ktd.extensions.toUnsignedByteArray
-import com.casic.br.ktd.model.SensorDataModel
-import com.casic.br.ktd.utils.LocaleConstant
-import com.pengxh.kt.lite.extensions.toJson
-import com.pengxh.kt.lite.utils.BroadcastManager
-
-class SocketManager private constructor() : ISocketListener {
-
- private val kTag = "SocketManager"
- private var nettyClient: SocketClient = SocketClient()
-
- companion object {
- val instance: SocketManager by lazy(mode = LazyThreadSafetyMode.SYNCHRONIZED) { SocketManager() }
- }
-
- fun connectNetty(hostname: String, port: Int) {
- Thread {
- if (!nettyClient.connectStatus) {
- nettyClient.setSocketListener(this)
- nettyClient.connect(hostname, port)
- } else {
- nettyClient.disconnect()
- }
- }.start()
- }
-
- override fun onMessageResponse(data: ByteArray?) {
-// Log.d(kTag, "onMessageResponse ===> " + Arrays.toString(data))
- /**
- * 0xFF,0x01,
- * 0x01,0x37,0xE6, 甲烷浓度值(数据码1* 65536 + 数据码2 * 256 + 数据码3)
- * 0x00, 激光甲烷模块工作状态(00表示设备正常,01表示温控故障,02表示设备激光未打开)
- * 0x00,0xB2,0x35, 激光强度值(数据码5* 65536 + 数据码6 * 256 + 数据码7)
- * 0x0A,0x3D, 云台水平角度([数据码8 * 256 + 数据码9]/100,单位为°,精确到0.01)
- * 0x05,0x6F, 云台垂直角度(首先计算Tangle=[数据码10 * 256 + 数据码11]/100,单位为°,精确到0.01。若Tangle在0~90范围内,则垂直角度值=Tangle;若Tangle在-1~-90范围内,则垂直角度值=Tangle-360)
- * 0xC1
- *
- * [-1, 1, 1, 55, -26, 0, 0, -78, 53, 10, 61, 5, 111, -63]
- * 甲烷浓度值为79638,计算为79638=0x01*65536+0x37*256+0xE6[0x01为数据码1,0x37为数据码2,0xE6为数据码3];
- * 激光甲烷设备状态值为0,表示状态正常,[0x00为数据码4];
- * 激光强度值为45621,计算为45621=0x00*65536+0xB2*256+0x35[0x00为数据码5,0xB2为数据码6,0x35为数据码7];
- *
- * =========================================================================================
- * 实际数据(1800-1950左右)
- * [-86, 1, 0, 7, 71, 0, 0, 62, -92, 57, 59, -118, -111, -64]
- * */
-
- if (data == null) {
- return
- }
- val bytes = data.toUnsignedByteArray()
- if (bytes.size == 14) {
- val dataModel = SensorDataModel(0, "激光未打开", 0, 0.0, 0.0)
-
- val methaneBytes = IntArray(3)
- System.arraycopy(bytes, 2, methaneBytes, 0, 3)
- dataModel.methane = methaneBytes.covertDataValue()
-
- dataModel.methaneState = when (bytes[5]) {
- 1 -> "温控故障"
- 2 -> "激光未打开"
- else -> "正常"
- }
-
- val laserBytes = IntArray(3)
- System.arraycopy(bytes, 6, laserBytes, 0, 3)
- dataModel.laser = laserBytes.covertDataValue()
-
- /**
- * 水平角度的实际范围为从水平零点开始,顺时针方向(从上往下看),0~360°
- * 垂直角度的实际范围为从垂直零点开始,以向上为正,-90°~90°,控制精度为0.01°
- * */
- val horizontalBytes = IntArray(2)
- System.arraycopy(bytes, 9, horizontalBytes, 0, 2)
- dataModel.horizontal = horizontalBytes.covertAngleValue()
-
- val verticalBytes = IntArray(2)
- System.arraycopy(bytes, 11, verticalBytes, 0, 2)
- dataModel.vertical = verticalBytes.covertAngleValue()
-
- //{"horizontal":26.21,"laser":45621,"methane":79846,"methaneState":"正常","vertical":13.91}
- BroadcastManager.obtainInstance(BaseApplication.get()).sendBroadcast(
- LocaleConstant.ACTION_UPDATE_DATA, dataModel.toJson()
- )
- }
- }
-
- override fun onServiceStatusConnectChanged(statusCode: Byte) {
- if (statusCode == ISocketListener.STATUS_CONNECT_SUCCESS) {
- if (nettyClient.connectStatus) {
- Log.d(kTag, "连接成功")
- }
- } else {
- if (!nettyClient.connectStatus) {
- Log.e(kTag, "onServiceStatusConnectChanged:$statusCode,连接断开,正在重连")
- }
- }
- }
-
- fun sendData(data: ByteArray) {
- nettyClient.sendData(data)
- }
-
- fun close() {
- nettyClient.disconnect()
- }
-}
\ No newline at end of file
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index e822df6..d72c1a5 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -7,6 +7,9 @@
+
+
+
@@ -46,5 +49,8 @@
+
+
+
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/br/ktd/base/KotlinBaseFragment.kt b/app/src/main/java/com/casic/br/ktd/base/KotlinBaseFragment.kt
new file mode 100644
index 0000000..2dac61c
--- /dev/null
+++ b/app/src/main/java/com/casic/br/ktd/base/KotlinBaseFragment.kt
@@ -0,0 +1,51 @@
+package com.casic.br.ktd.base
+
+import android.os.Bundle
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import androidx.annotation.LayoutRes
+import androidx.fragment.app.Fragment
+
+abstract class KotlinBaseFragment : Fragment() {
+
+ lateinit var bv: View
+
+ override fun onCreateView(
+ inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?
+ ): View? {
+ bv = inflater.inflate(initLayoutRes(), container, false)
+ initView(savedInstanceState)
+ setupTopBarLayout()
+ return bv
+ }
+
+ override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
+ super.onViewCreated(view, savedInstanceState)
+ observeRequestState()
+ initEvent()
+ }
+
+ @LayoutRes
+ abstract fun initLayoutRes(): Int
+
+ /**
+ * 沉浸式状态栏
+ */
+ abstract fun setupTopBarLayout()
+
+ /**
+ * 初始化布局以及控件
+ */
+ abstract fun initView(savedInstanceState: Bundle?)
+
+ /**
+ * 网络请求状态监听
+ */
+ abstract fun observeRequestState()
+
+ /**
+ * 业务逻辑,按钮等事件
+ */
+ abstract fun initEvent()
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/br/ktd/fragment/AlarmPageFragment.kt b/app/src/main/java/com/casic/br/ktd/fragment/AlarmPageFragment.kt
index 6c98a3b..9418169 100644
--- a/app/src/main/java/com/casic/br/ktd/fragment/AlarmPageFragment.kt
+++ b/app/src/main/java/com/casic/br/ktd/fragment/AlarmPageFragment.kt
@@ -2,28 +2,29 @@
import android.os.Bundle
import com.casic.br.ktd.R
+import com.casic.br.ktd.base.KotlinBaseFragment
import com.casic.br.ktd.widgets.DateRangeActionSheet
-import com.pengxh.kt.lite.base.KotlinBaseFragment
import kotlinx.android.synthetic.main.fragment_alarm.view.*
class AlarmPageFragment : KotlinBaseFragment() {
- override fun initData(savedInstanceState: Bundle?) {
+
+ override fun initView(savedInstanceState: Bundle?) {
}
override fun initEvent() {
- baseView.calendarView.setOnClickListener {
+ bv.calendarView.setOnClickListener {
DateRangeActionSheet.Builder().setContext(requireContext())
.setOnActionSheetListener(object :
DateRangeActionSheet.OnDateRangeSelectedListener {
override fun onDateRangeSelected(startDate: String, endDate: String) {
- baseView.selectedDateView.text = "$startDate ~ $endDate"
+ bv.selectedDateView.text = "$startDate ~ $endDate"
}
}).build().show()
}
}
- override fun initLayoutView(): Int = R.layout.fragment_alarm
+ override fun initLayoutRes(): Int = R.layout.fragment_alarm
override fun observeRequestState() {
diff --git a/app/src/main/java/com/casic/br/ktd/fragment/HomePageFragment.kt b/app/src/main/java/com/casic/br/ktd/fragment/HomePageFragment.kt
index 9961935..f3eba5c 100644
--- a/app/src/main/java/com/casic/br/ktd/fragment/HomePageFragment.kt
+++ b/app/src/main/java/com/casic/br/ktd/fragment/HomePageFragment.kt
@@ -1,32 +1,62 @@
package com.casic.br.ktd.fragment
+import android.graphics.Color
import android.os.Bundle
import com.amap.api.maps.AMap
import com.amap.api.maps.AMapOptions
+import com.amap.api.maps.CameraUpdateFactory
+import com.amap.api.maps.model.*
import com.casic.br.ktd.R
-import com.pengxh.kt.lite.base.KotlinBaseFragment
+import com.casic.br.ktd.base.KotlinBaseFragment
import kotlinx.android.synthetic.main.fragment_home.view.*
class HomePageFragment : KotlinBaseFragment() {
private lateinit var aMap: AMap
- override fun initData(savedInstanceState: Bundle?) {
- baseView.mapView.onCreate(savedInstanceState)
- aMap = baseView.mapView.map
+ override fun initView(savedInstanceState: Bundle?) {
+ bv.mapView.onCreate(savedInstanceState)
+ aMap = bv.mapView.map
val uiSettings = aMap.uiSettings
uiSettings.isCompassEnabled = true
- uiSettings.isMyLocationButtonEnabled = true
+ uiSettings.isMyLocationButtonEnabled = false
uiSettings.isScaleControlsEnabled = true
uiSettings.zoomPosition = AMapOptions.ZOOM_POSITION_RIGHT_CENTER
uiSettings.isRotateGesturesEnabled = false//不许地图随手势旋转角度
}
override fun initEvent() {
-
+ //移动到巡检起始经纬度
+ val cameraPosition = CameraPosition(LatLng(39.914199, 116.265785), 16f, 0f, 0f)
+ val cameraUpdate = CameraUpdateFactory.newCameraPosition(cameraPosition)
+ aMap.animateCamera(cameraUpdate, 1500, null)
+ //设置起点
+ addMarker(LatLng(39.914885, 116.272312), R.mipmap.start)
+ //设置终点
+ addMarker(LatLng(39.914716, 116.265097), R.mipmap.end)
+ //瞄点画线
+ val latLngPoints = ArrayList()
+ latLngPoints.add(LatLng(39.914885, 116.272312))
+ latLngPoints.add(LatLng(39.915148, 116.272312))
+ latLngPoints.add(LatLng(39.915399, 116.272302))
+ latLngPoints.add(LatLng(39.915436, 116.271787))
+ latLngPoints.add(LatLng(39.915477, 116.270886))
+ latLngPoints.add(LatLng(39.915477, 116.269968))
+ latLngPoints.add(LatLng(39.915469, 116.269544))
+ latLngPoints.add(LatLng(39.915481, 116.269196))
+ latLngPoints.add(LatLng(39.915452, 116.268472))
+ latLngPoints.add(LatLng(39.915444, 116.267722))
+ latLngPoints.add(LatLng(39.915415, 116.266755))
+ latLngPoints.add(LatLng(39.915403, 116.266165))
+ latLngPoints.add(LatLng(39.915395, 116.265703))
+ latLngPoints.add(LatLng(39.915366, 116.265119))
+ latLngPoints.add(LatLng(39.914716, 116.265097))
+ aMap.addPolyline(
+ PolylineOptions().addAll(latLngPoints).width(10.toFloat()).color(Color.RED)
+ )
}
- override fun initLayoutView(): Int = R.layout.fragment_home
+ override fun initLayoutRes(): Int = R.layout.fragment_home
override fun observeRequestState() {
@@ -36,25 +66,32 @@
}
+ private fun addMarker(point: LatLng, res: Int) {
+ val markerOption = MarkerOptions()
+ markerOption.position(point)
+ markerOption.icon(BitmapDescriptorFactory.fromResource(res))
+ aMap.addMarker(markerOption)
+ }
+
/***以下是地图生命周期管理************************************************************************/
override fun onResume() {
super.onResume()
- baseView.mapView.onResume()
+ bv.mapView.onResume()
}
override fun onPause() {
- baseView.mapView.onPause()
super.onPause()
+ bv.mapView.onPause()
}
override fun onSaveInstanceState(outState: Bundle) {
super.onSaveInstanceState(outState)
- baseView.mapView.onSaveInstanceState(outState)
+ bv.mapView.onSaveInstanceState(outState)
}
override fun onDestroy() {
- baseView.mapView.onDestroy()
super.onDestroy()
+ bv.mapView.onDestroy()
}
}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/br/ktd/fragment/MinePageFragment.kt b/app/src/main/java/com/casic/br/ktd/fragment/MinePageFragment.kt
index 90313ac..3212794 100644
--- a/app/src/main/java/com/casic/br/ktd/fragment/MinePageFragment.kt
+++ b/app/src/main/java/com/casic/br/ktd/fragment/MinePageFragment.kt
@@ -2,10 +2,11 @@
import android.os.Bundle
import com.casic.br.ktd.R
-import com.pengxh.kt.lite.base.KotlinBaseFragment
+import com.casic.br.ktd.base.KotlinBaseFragment
class MinePageFragment : KotlinBaseFragment() {
- override fun initData(savedInstanceState: Bundle?) {
+
+ override fun initView(savedInstanceState: Bundle?) {
}
@@ -13,7 +14,7 @@
}
- override fun initLayoutView(): Int = R.layout.fragment_mine
+ override fun initLayoutRes(): Int = R.layout.fragment_mine
override fun observeRequestState() {
diff --git a/app/src/main/java/com/casic/br/ktd/fragment/TaskPageFragment.kt b/app/src/main/java/com/casic/br/ktd/fragment/TaskPageFragment.kt
index 8f6abf0..6b82a54 100644
--- a/app/src/main/java/com/casic/br/ktd/fragment/TaskPageFragment.kt
+++ b/app/src/main/java/com/casic/br/ktd/fragment/TaskPageFragment.kt
@@ -8,6 +8,7 @@
import androidx.recyclerview.widget.RecyclerView
import com.casic.br.ktd.R
import com.casic.br.ktd.adapter.TaskAdapter
+import com.casic.br.ktd.base.KotlinBaseFragment
import com.casic.br.ktd.holder.SwipeViewHolder
import com.casic.br.ktd.model.TaskListModel
import com.casic.br.ktd.view.InspectionActivity
@@ -15,7 +16,6 @@
import com.casic.br.ktd.widgets.AlertControlDialog
import com.casic.br.ktd.widgets.AlertInputDialog
import com.casic.br.ktd.widgets.DateRangeActionSheet
-import com.pengxh.kt.lite.base.KotlinBaseFragment
import com.pengxh.kt.lite.extensions.navigatePageTo
import com.pengxh.kt.lite.extensions.show
import com.pengxh.kt.lite.utils.WeakReferenceHandler
@@ -36,7 +36,7 @@
private var startTime = ""
private var endTime = ""
- override fun initData(savedInstanceState: Bundle?) {
+ override fun initView(savedInstanceState: Bundle?) {
weakReferenceHandler = WeakReferenceHandler(this)
taskViewModel = ViewModelProvider(this)[TaskViewModel::class.java]
taskViewModel.taskList.observe(this) {
@@ -45,7 +45,7 @@
when {
isRefresh -> {
taskAdapter.setRefreshData(dataRows)
- baseView.taskLayout.finishRefresh()
+ bv.taskLayout.finishRefresh()
isRefresh = false
}
isLoadMore -> {
@@ -53,7 +53,7 @@
"到底了,别拉了".show(requireContext())
}
taskAdapter.setLoadMoreData(dataRows)
- baseView.taskLayout.finishLoadMore()
+ bv.taskLayout.finishLoadMore()
isLoadMore = false
}
else -> {
@@ -76,9 +76,9 @@
when (msg.what) {
2023070501 -> {
if (dataBeans.size == 0) {
- baseView.emptyLayout.visibility = View.VISIBLE
+ bv.emptyLayout.visibility = View.VISIBLE
} else {
- baseView.emptyLayout.visibility = View.GONE
+ bv.emptyLayout.visibility = View.GONE
taskAdapter = object : TaskAdapter(
requireContext(), R.layout.item_task_rv_l, dataBeans
) {
@@ -97,8 +97,8 @@
}
}
//绑定侧滑事件
- swipeAction.attachToRecyclerView(baseView.taskRecyclerView)
- baseView.taskRecyclerView.adapter = taskAdapter
+ swipeAction.attachToRecyclerView(bv.taskRecyclerView)
+ bv.taskRecyclerView.adapter = taskAdapter
taskAdapter.setOnItemCheckedListener(object :
TaskAdapter.OnItemCheckedListener {
override fun onItemChecked(items: ArrayList) {
@@ -168,7 +168,7 @@
override fun initEvent() {
- baseView.calendarView.setOnClickListener {
+ bv.calendarView.setOnClickListener {
DateRangeActionSheet.Builder().setContext(requireContext())
.setOnActionSheetListener(object :
DateRangeActionSheet.OnDateRangeSelectedListener {
@@ -177,12 +177,12 @@
endTime = endDate
//显示
- baseView.selectedDateView.text = "$startDate ~ $endDate"
+ bv.selectedDateView.text = "$startDate ~ $endDate"
}
}).build().show()
}
- baseView.addTaskButton.setOnClickListener {
+ bv.addTaskButton.setOnClickListener {
// AlertInputDialog.Builder()
// .setContext(requireContext())
// .setTitle("新建巡检任务")
@@ -200,11 +200,11 @@
requireContext().navigatePageTo()
}
- baseView.deleteTaskButton.setOnClickListener {
+ bv.deleteTaskButton.setOnClickListener {
selectedItems.size.toString().show(requireContext())
}
- baseView.taskSettingsButton.setOnClickListener {
+ bv.taskSettingsButton.setOnClickListener {
AlertInputDialog.Builder()
.setContext(requireContext())
.setTitle("设置阈值")
@@ -221,14 +221,14 @@
}).build().show()
}
- baseView.taskLayout.setOnRefreshListener {
+ bv.taskLayout.setOnRefreshListener {
isRefresh = true
//刷新之后页码重置
pageIndex = 1
getTaskList()
}
- baseView.taskLayout.setOnLoadMoreListener {
+ bv.taskLayout.setOnLoadMoreListener {
isLoadMore = true
pageIndex++
getTaskList()
@@ -239,13 +239,13 @@
taskViewModel.getTaskList(
startTime,
endTime,
- baseView.taskNameView.text.toString(),
- baseView.taskCodeView.text.toString(),
+ bv.taskNameView.text.toString(),
+ bv.taskCodeView.text.toString(),
pageIndex
)
}
- override fun initLayoutView(): Int = R.layout.fragment_task
+ override fun initLayoutRes(): Int = R.layout.fragment_task
override fun observeRequestState() {
diff --git a/app/src/main/java/com/casic/br/ktd/netty/ISocketListener.kt b/app/src/main/java/com/casic/br/ktd/netty/ISocketListener.kt
deleted file mode 100644
index dab98e1..0000000
--- a/app/src/main/java/com/casic/br/ktd/netty/ISocketListener.kt
+++ /dev/null
@@ -1,19 +0,0 @@
-package com.casic.br.ktd.netty
-
-interface ISocketListener {
- companion object {
- const val STATUS_CONNECT_SUCCESS: Byte = 1 //连接成功
- const val STATUS_CONNECT_CLOSED: Byte = 0 //关闭连接
- const val STATUS_CONNECT_ERROR: Byte = 0 //连接失败
- }
-
- /**
- * 当接收到系统消息
- */
- fun onMessageResponse(data: ByteArray?)
-
- /**
- * 当连接状态发生变化时调用
- */
- fun onServiceStatusConnectChanged(statusCode: Byte)
-}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/br/ktd/netty/SocketChannelHandle.kt b/app/src/main/java/com/casic/br/ktd/netty/SocketChannelHandle.kt
deleted file mode 100644
index 42eb310..0000000
--- a/app/src/main/java/com/casic/br/ktd/netty/SocketChannelHandle.kt
+++ /dev/null
@@ -1,51 +0,0 @@
-package com.casic.br.ktd.netty
-
-import android.util.Log
-import io.netty.channel.ChannelHandlerContext
-import io.netty.channel.SimpleChannelInboundHandler
-import io.netty.handler.timeout.IdleState
-import io.netty.handler.timeout.IdleStateEvent
-import java.nio.charset.StandardCharsets
-
-class SocketChannelHandle(private val listener: ISocketListener?) :
- SimpleChannelInboundHandler() {
-
- private val kTag = "SocketChannelHandle"
-
- override fun channelActive(ctx: ChannelHandlerContext) {
- super.channelActive(ctx)
- Log.d(kTag, "channelActive ===> 连接成功")
- listener?.onServiceStatusConnectChanged(ISocketListener.STATUS_CONNECT_SUCCESS)
- }
-
- override fun channelInactive(ctx: ChannelHandlerContext) {
- super.channelInactive(ctx)
- Log.e(kTag, "channelInactive: 连接断开")
- }
-
- override fun userEventTriggered(ctx: ChannelHandlerContext, evt: Any) {
- super.userEventTriggered(ctx, evt)
- if (evt is IdleStateEvent) {
- if (evt.state() == IdleState.WRITER_IDLE) {
- //写超时,此时可以发送心跳数据给服务器
- val temp = "FF"
- ctx.writeAndFlush(temp.toByteArray(StandardCharsets.UTF_8))
- } else if (evt.state() == IdleState.READER_IDLE) {
- //读超时,此时代表没有收到心跳返回可以关闭当前连接进行重连
- ctx.close()
- }
- }
- }
-
- override fun channelRead0(ctx: ChannelHandlerContext, data: ByteArray?) {
- listener?.onMessageResponse(data)
- }
-
- override fun exceptionCaught(ctx: ChannelHandlerContext, cause: Throwable) {
- super.exceptionCaught(ctx, cause)
- Log.d(kTag, "exceptionCaught ===> $cause")
- listener?.onServiceStatusConnectChanged(ISocketListener.STATUS_CONNECT_ERROR)
- cause.printStackTrace()
- ctx.close()
- }
-}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/br/ktd/netty/SocketClient.kt b/app/src/main/java/com/casic/br/ktd/netty/SocketClient.kt
deleted file mode 100644
index d05d335..0000000
--- a/app/src/main/java/com/casic/br/ktd/netty/SocketClient.kt
+++ /dev/null
@@ -1,153 +0,0 @@
-package com.casic.br.ktd.netty
-
-import android.os.SystemClock
-import android.util.Log
-import io.netty.bootstrap.Bootstrap
-import io.netty.channel.*
-import io.netty.channel.nio.NioEventLoopGroup
-import io.netty.channel.socket.SocketChannel
-import io.netty.channel.socket.nio.NioSocketChannel
-import io.netty.handler.codec.bytes.ByteArrayDecoder
-import io.netty.handler.codec.bytes.ByteArrayEncoder
-import io.netty.handler.timeout.IdleStateHandler
-
-class SocketClient {
-
- private val kTag = "SocketClient"
-
- private var host: String? = null
- private var port = 8000
- private var nioEventLoopGroup: NioEventLoopGroup? = null
- private var channel: Channel? = null
- private var listener: ISocketListener? = null
-
- //现在连接的状态
- var connectStatus = false //判断是否已连接
- private var reconnectNum = Int.MAX_VALUE //定义的重连到时候用
- private var isNeedReconnect = true //是否需要重连
- var isConnecting = false //是否正在连接
- private set
- private var reconnectIntervalTime: Long = 15000 //重连的时间
-
- //重连时间
- fun setReconnectNum(reconnectNum: Int) {
- this.reconnectNum = reconnectNum
- }
-
- fun setReconnectIntervalTime(reconnectIntervalTime: Long) {
- this.reconnectIntervalTime = reconnectIntervalTime
- }
-
- fun setSocketListener(listener: ISocketListener?) {
- this.listener = listener
- }
-
- fun connect(host: String, port: Int) {
- this.host = host
- this.port = port
- Log.d(kTag, "connect ===> 开始连接TCP服务器")
- if (isConnecting) {
- return
- }
- //起个线程
- val clientThread: Thread = object : Thread("client-Netty") {
- override fun run() {
- super.run()
- isNeedReconnect = true
- reconnectNum = Int.MAX_VALUE
- connectServer()
- }
- }
- clientThread.start()
- }
-
- private fun connectServer() {
- synchronized(this@SocketClient) {
- var channelFuture: ChannelFuture? = null //连接管理对象
- if (!connectStatus) {
- isConnecting = true
- nioEventLoopGroup = NioEventLoopGroup() //设置的连接group
- val bootstrap = Bootstrap()
- bootstrap.group(nioEventLoopGroup) //设置的一系列连接参数操作等
- .channel(NioSocketChannel::class.java)
- .option(ChannelOption.TCP_NODELAY, true) //无阻塞
- .option(ChannelOption.SO_KEEPALIVE, true) //长连接
- .option(
- ChannelOption.RCVBUF_ALLOCATOR,
- AdaptiveRecvByteBufAllocator(5000, 5000, 8000)
- ) //接收缓冲区 最小值太小时数据接收不全
- .handler(object : ChannelInitializer() {
- override fun initChannel(channel: SocketChannel) {
- val pipeline = channel.pipeline()
- //参数1:代表读套接字超时的时间,没收到数据会触发读超时回调;
- //参数2:代表写套接字超时时间,没进行写会触发写超时回调;
- //参数3:将在未执行读取或写入时触发超时回调,0代表不处理;
- //读超时尽量设置大于写超时,代表多次写超时时写心跳包,多次写了心跳数据仍然读超时代表当前连接错误,即可断开连接重新连接
- pipeline.addLast(IdleStateHandler(60, 10, 0))
- pipeline.addLast(ByteArrayDecoder())
- pipeline.addLast(ByteArrayEncoder())
- pipeline.addLast(SocketChannelHandle(listener))
- }
- })
- try {
- //连接监听
- channelFuture = bootstrap.connect(host, port)
- .addListener(object : ChannelFutureListener {
- override fun operationComplete(channelFuture: ChannelFuture) {
- if (channelFuture.isSuccess) {
- connectStatus = true
- channel = channelFuture.channel()
- } else {
- Log.e(kTag, "operationComplete: 连接失败")
- connectStatus = false
- }
- isConnecting = false
- }
- }).sync()
- // 等待连接关闭
- channelFuture.channel().closeFuture().sync()
- } catch (e: Exception) {
- e.printStackTrace()
- } finally {
- connectStatus = false
- listener?.onServiceStatusConnectChanged(ISocketListener.STATUS_CONNECT_CLOSED) //STATUS_CONNECT_CLOSED 这我自己定义的 接口标识
- if (null != channelFuture) {
- if (channelFuture.channel() != null && channelFuture.channel().isOpen) {
- channelFuture.channel().close()
- }
- }
- nioEventLoopGroup?.shutdownGracefully()
- reconnect() //重新连接
- }
- }
- }
- }
-
- //断开连接
- fun disconnect() {
- Log.d(kTag, "disconnect ===> 断开连接")
- isNeedReconnect = false
- nioEventLoopGroup?.shutdownGracefully()
- }
-
- //重新连接
- private fun reconnect() {
- if (isNeedReconnect && reconnectNum > 0 && !connectStatus) {
- reconnectNum--
- SystemClock.sleep(reconnectIntervalTime)
- if (isNeedReconnect && reconnectNum > 0 && !connectStatus) {
- Log.d(kTag, "reconnect ===> 重新连接")
- connectServer()
- }
- }
- }
-
- fun sendData(bytes: ByteArray) {
- channel?.writeAndFlush(bytes)?.addListener(ChannelFutureListener { future ->
- if (!future.isSuccess) {
- future.channel().close()
- nioEventLoopGroup!!.shutdownGracefully()
- }
- })
- }
-}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/br/ktd/netty/SocketManager.kt b/app/src/main/java/com/casic/br/ktd/netty/SocketManager.kt
deleted file mode 100644
index 17daf35..0000000
--- a/app/src/main/java/com/casic/br/ktd/netty/SocketManager.kt
+++ /dev/null
@@ -1,113 +0,0 @@
-package com.casic.br.ktd.netty
-
-import android.util.Log
-import com.casic.br.ktd.base.BaseApplication
-import com.casic.br.ktd.extensions.covertAngleValue
-import com.casic.br.ktd.extensions.covertDataValue
-import com.casic.br.ktd.extensions.toUnsignedByteArray
-import com.casic.br.ktd.model.SensorDataModel
-import com.casic.br.ktd.utils.LocaleConstant
-import com.pengxh.kt.lite.extensions.toJson
-import com.pengxh.kt.lite.utils.BroadcastManager
-
-class SocketManager private constructor() : ISocketListener {
-
- private val kTag = "SocketManager"
- private var nettyClient: SocketClient = SocketClient()
-
- companion object {
- val instance: SocketManager by lazy(mode = LazyThreadSafetyMode.SYNCHRONIZED) { SocketManager() }
- }
-
- fun connectNetty(hostname: String, port: Int) {
- Thread {
- if (!nettyClient.connectStatus) {
- nettyClient.setSocketListener(this)
- nettyClient.connect(hostname, port)
- } else {
- nettyClient.disconnect()
- }
- }.start()
- }
-
- override fun onMessageResponse(data: ByteArray?) {
-// Log.d(kTag, "onMessageResponse ===> " + Arrays.toString(data))
- /**
- * 0xFF,0x01,
- * 0x01,0x37,0xE6, 甲烷浓度值(数据码1* 65536 + 数据码2 * 256 + 数据码3)
- * 0x00, 激光甲烷模块工作状态(00表示设备正常,01表示温控故障,02表示设备激光未打开)
- * 0x00,0xB2,0x35, 激光强度值(数据码5* 65536 + 数据码6 * 256 + 数据码7)
- * 0x0A,0x3D, 云台水平角度([数据码8 * 256 + 数据码9]/100,单位为°,精确到0.01)
- * 0x05,0x6F, 云台垂直角度(首先计算Tangle=[数据码10 * 256 + 数据码11]/100,单位为°,精确到0.01。若Tangle在0~90范围内,则垂直角度值=Tangle;若Tangle在-1~-90范围内,则垂直角度值=Tangle-360)
- * 0xC1
- *
- * [-1, 1, 1, 55, -26, 0, 0, -78, 53, 10, 61, 5, 111, -63]
- * 甲烷浓度值为79638,计算为79638=0x01*65536+0x37*256+0xE6[0x01为数据码1,0x37为数据码2,0xE6为数据码3];
- * 激光甲烷设备状态值为0,表示状态正常,[0x00为数据码4];
- * 激光强度值为45621,计算为45621=0x00*65536+0xB2*256+0x35[0x00为数据码5,0xB2为数据码6,0x35为数据码7];
- *
- * =========================================================================================
- * 实际数据(1800-1950左右)
- * [-86, 1, 0, 7, 71, 0, 0, 62, -92, 57, 59, -118, -111, -64]
- * */
-
- if (data == null) {
- return
- }
- val bytes = data.toUnsignedByteArray()
- if (bytes.size == 14) {
- val dataModel = SensorDataModel(0, "激光未打开", 0, 0.0, 0.0)
-
- val methaneBytes = IntArray(3)
- System.arraycopy(bytes, 2, methaneBytes, 0, 3)
- dataModel.methane = methaneBytes.covertDataValue()
-
- dataModel.methaneState = when (bytes[5]) {
- 1 -> "温控故障"
- 2 -> "激光未打开"
- else -> "正常"
- }
-
- val laserBytes = IntArray(3)
- System.arraycopy(bytes, 6, laserBytes, 0, 3)
- dataModel.laser = laserBytes.covertDataValue()
-
- /**
- * 水平角度的实际范围为从水平零点开始,顺时针方向(从上往下看),0~360°
- * 垂直角度的实际范围为从垂直零点开始,以向上为正,-90°~90°,控制精度为0.01°
- * */
- val horizontalBytes = IntArray(2)
- System.arraycopy(bytes, 9, horizontalBytes, 0, 2)
- dataModel.horizontal = horizontalBytes.covertAngleValue()
-
- val verticalBytes = IntArray(2)
- System.arraycopy(bytes, 11, verticalBytes, 0, 2)
- dataModel.vertical = verticalBytes.covertAngleValue()
-
- //{"horizontal":26.21,"laser":45621,"methane":79846,"methaneState":"正常","vertical":13.91}
- BroadcastManager.obtainInstance(BaseApplication.get()).sendBroadcast(
- LocaleConstant.ACTION_UPDATE_DATA, dataModel.toJson()
- )
- }
- }
-
- override fun onServiceStatusConnectChanged(statusCode: Byte) {
- if (statusCode == ISocketListener.STATUS_CONNECT_SUCCESS) {
- if (nettyClient.connectStatus) {
- Log.d(kTag, "连接成功")
- }
- } else {
- if (!nettyClient.connectStatus) {
- Log.e(kTag, "onServiceStatusConnectChanged:$statusCode,连接断开,正在重连")
- }
- }
- }
-
- fun sendData(data: ByteArray) {
- nettyClient.sendData(data)
- }
-
- fun close() {
- nettyClient.disconnect()
- }
-}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/br/ktd/netty/tcp/ISocketListener.kt b/app/src/main/java/com/casic/br/ktd/netty/tcp/ISocketListener.kt
new file mode 100644
index 0000000..13c3084
--- /dev/null
+++ b/app/src/main/java/com/casic/br/ktd/netty/tcp/ISocketListener.kt
@@ -0,0 +1,19 @@
+package com.casic.br.ktd.netty.tcp
+
+interface ISocketListener {
+ companion object {
+ const val STATUS_CONNECT_SUCCESS: Byte = 1 //连接成功
+ const val STATUS_CONNECT_CLOSED: Byte = 0 //关闭连接
+ const val STATUS_CONNECT_ERROR: Byte = 0 //连接失败
+ }
+
+ /**
+ * 当接收到系统消息
+ */
+ fun onMessageResponse(data: ByteArray?)
+
+ /**
+ * 当连接状态发生变化时调用
+ */
+ fun onServiceStatusConnectChanged(statusCode: Byte)
+}
\ No newline at end of file
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index e822df6..d72c1a5 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -7,6 +7,9 @@
+
+
+
@@ -46,5 +49,8 @@
+
+
+
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/br/ktd/base/KotlinBaseFragment.kt b/app/src/main/java/com/casic/br/ktd/base/KotlinBaseFragment.kt
new file mode 100644
index 0000000..2dac61c
--- /dev/null
+++ b/app/src/main/java/com/casic/br/ktd/base/KotlinBaseFragment.kt
@@ -0,0 +1,51 @@
+package com.casic.br.ktd.base
+
+import android.os.Bundle
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import androidx.annotation.LayoutRes
+import androidx.fragment.app.Fragment
+
+abstract class KotlinBaseFragment : Fragment() {
+
+ lateinit var bv: View
+
+ override fun onCreateView(
+ inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?
+ ): View? {
+ bv = inflater.inflate(initLayoutRes(), container, false)
+ initView(savedInstanceState)
+ setupTopBarLayout()
+ return bv
+ }
+
+ override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
+ super.onViewCreated(view, savedInstanceState)
+ observeRequestState()
+ initEvent()
+ }
+
+ @LayoutRes
+ abstract fun initLayoutRes(): Int
+
+ /**
+ * 沉浸式状态栏
+ */
+ abstract fun setupTopBarLayout()
+
+ /**
+ * 初始化布局以及控件
+ */
+ abstract fun initView(savedInstanceState: Bundle?)
+
+ /**
+ * 网络请求状态监听
+ */
+ abstract fun observeRequestState()
+
+ /**
+ * 业务逻辑,按钮等事件
+ */
+ abstract fun initEvent()
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/br/ktd/fragment/AlarmPageFragment.kt b/app/src/main/java/com/casic/br/ktd/fragment/AlarmPageFragment.kt
index 6c98a3b..9418169 100644
--- a/app/src/main/java/com/casic/br/ktd/fragment/AlarmPageFragment.kt
+++ b/app/src/main/java/com/casic/br/ktd/fragment/AlarmPageFragment.kt
@@ -2,28 +2,29 @@
import android.os.Bundle
import com.casic.br.ktd.R
+import com.casic.br.ktd.base.KotlinBaseFragment
import com.casic.br.ktd.widgets.DateRangeActionSheet
-import com.pengxh.kt.lite.base.KotlinBaseFragment
import kotlinx.android.synthetic.main.fragment_alarm.view.*
class AlarmPageFragment : KotlinBaseFragment() {
- override fun initData(savedInstanceState: Bundle?) {
+
+ override fun initView(savedInstanceState: Bundle?) {
}
override fun initEvent() {
- baseView.calendarView.setOnClickListener {
+ bv.calendarView.setOnClickListener {
DateRangeActionSheet.Builder().setContext(requireContext())
.setOnActionSheetListener(object :
DateRangeActionSheet.OnDateRangeSelectedListener {
override fun onDateRangeSelected(startDate: String, endDate: String) {
- baseView.selectedDateView.text = "$startDate ~ $endDate"
+ bv.selectedDateView.text = "$startDate ~ $endDate"
}
}).build().show()
}
}
- override fun initLayoutView(): Int = R.layout.fragment_alarm
+ override fun initLayoutRes(): Int = R.layout.fragment_alarm
override fun observeRequestState() {
diff --git a/app/src/main/java/com/casic/br/ktd/fragment/HomePageFragment.kt b/app/src/main/java/com/casic/br/ktd/fragment/HomePageFragment.kt
index 9961935..f3eba5c 100644
--- a/app/src/main/java/com/casic/br/ktd/fragment/HomePageFragment.kt
+++ b/app/src/main/java/com/casic/br/ktd/fragment/HomePageFragment.kt
@@ -1,32 +1,62 @@
package com.casic.br.ktd.fragment
+import android.graphics.Color
import android.os.Bundle
import com.amap.api.maps.AMap
import com.amap.api.maps.AMapOptions
+import com.amap.api.maps.CameraUpdateFactory
+import com.amap.api.maps.model.*
import com.casic.br.ktd.R
-import com.pengxh.kt.lite.base.KotlinBaseFragment
+import com.casic.br.ktd.base.KotlinBaseFragment
import kotlinx.android.synthetic.main.fragment_home.view.*
class HomePageFragment : KotlinBaseFragment() {
private lateinit var aMap: AMap
- override fun initData(savedInstanceState: Bundle?) {
- baseView.mapView.onCreate(savedInstanceState)
- aMap = baseView.mapView.map
+ override fun initView(savedInstanceState: Bundle?) {
+ bv.mapView.onCreate(savedInstanceState)
+ aMap = bv.mapView.map
val uiSettings = aMap.uiSettings
uiSettings.isCompassEnabled = true
- uiSettings.isMyLocationButtonEnabled = true
+ uiSettings.isMyLocationButtonEnabled = false
uiSettings.isScaleControlsEnabled = true
uiSettings.zoomPosition = AMapOptions.ZOOM_POSITION_RIGHT_CENTER
uiSettings.isRotateGesturesEnabled = false//不许地图随手势旋转角度
}
override fun initEvent() {
-
+ //移动到巡检起始经纬度
+ val cameraPosition = CameraPosition(LatLng(39.914199, 116.265785), 16f, 0f, 0f)
+ val cameraUpdate = CameraUpdateFactory.newCameraPosition(cameraPosition)
+ aMap.animateCamera(cameraUpdate, 1500, null)
+ //设置起点
+ addMarker(LatLng(39.914885, 116.272312), R.mipmap.start)
+ //设置终点
+ addMarker(LatLng(39.914716, 116.265097), R.mipmap.end)
+ //瞄点画线
+ val latLngPoints = ArrayList()
+ latLngPoints.add(LatLng(39.914885, 116.272312))
+ latLngPoints.add(LatLng(39.915148, 116.272312))
+ latLngPoints.add(LatLng(39.915399, 116.272302))
+ latLngPoints.add(LatLng(39.915436, 116.271787))
+ latLngPoints.add(LatLng(39.915477, 116.270886))
+ latLngPoints.add(LatLng(39.915477, 116.269968))
+ latLngPoints.add(LatLng(39.915469, 116.269544))
+ latLngPoints.add(LatLng(39.915481, 116.269196))
+ latLngPoints.add(LatLng(39.915452, 116.268472))
+ latLngPoints.add(LatLng(39.915444, 116.267722))
+ latLngPoints.add(LatLng(39.915415, 116.266755))
+ latLngPoints.add(LatLng(39.915403, 116.266165))
+ latLngPoints.add(LatLng(39.915395, 116.265703))
+ latLngPoints.add(LatLng(39.915366, 116.265119))
+ latLngPoints.add(LatLng(39.914716, 116.265097))
+ aMap.addPolyline(
+ PolylineOptions().addAll(latLngPoints).width(10.toFloat()).color(Color.RED)
+ )
}
- override fun initLayoutView(): Int = R.layout.fragment_home
+ override fun initLayoutRes(): Int = R.layout.fragment_home
override fun observeRequestState() {
@@ -36,25 +66,32 @@
}
+ private fun addMarker(point: LatLng, res: Int) {
+ val markerOption = MarkerOptions()
+ markerOption.position(point)
+ markerOption.icon(BitmapDescriptorFactory.fromResource(res))
+ aMap.addMarker(markerOption)
+ }
+
/***以下是地图生命周期管理************************************************************************/
override fun onResume() {
super.onResume()
- baseView.mapView.onResume()
+ bv.mapView.onResume()
}
override fun onPause() {
- baseView.mapView.onPause()
super.onPause()
+ bv.mapView.onPause()
}
override fun onSaveInstanceState(outState: Bundle) {
super.onSaveInstanceState(outState)
- baseView.mapView.onSaveInstanceState(outState)
+ bv.mapView.onSaveInstanceState(outState)
}
override fun onDestroy() {
- baseView.mapView.onDestroy()
super.onDestroy()
+ bv.mapView.onDestroy()
}
}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/br/ktd/fragment/MinePageFragment.kt b/app/src/main/java/com/casic/br/ktd/fragment/MinePageFragment.kt
index 90313ac..3212794 100644
--- a/app/src/main/java/com/casic/br/ktd/fragment/MinePageFragment.kt
+++ b/app/src/main/java/com/casic/br/ktd/fragment/MinePageFragment.kt
@@ -2,10 +2,11 @@
import android.os.Bundle
import com.casic.br.ktd.R
-import com.pengxh.kt.lite.base.KotlinBaseFragment
+import com.casic.br.ktd.base.KotlinBaseFragment
class MinePageFragment : KotlinBaseFragment() {
- override fun initData(savedInstanceState: Bundle?) {
+
+ override fun initView(savedInstanceState: Bundle?) {
}
@@ -13,7 +14,7 @@
}
- override fun initLayoutView(): Int = R.layout.fragment_mine
+ override fun initLayoutRes(): Int = R.layout.fragment_mine
override fun observeRequestState() {
diff --git a/app/src/main/java/com/casic/br/ktd/fragment/TaskPageFragment.kt b/app/src/main/java/com/casic/br/ktd/fragment/TaskPageFragment.kt
index 8f6abf0..6b82a54 100644
--- a/app/src/main/java/com/casic/br/ktd/fragment/TaskPageFragment.kt
+++ b/app/src/main/java/com/casic/br/ktd/fragment/TaskPageFragment.kt
@@ -8,6 +8,7 @@
import androidx.recyclerview.widget.RecyclerView
import com.casic.br.ktd.R
import com.casic.br.ktd.adapter.TaskAdapter
+import com.casic.br.ktd.base.KotlinBaseFragment
import com.casic.br.ktd.holder.SwipeViewHolder
import com.casic.br.ktd.model.TaskListModel
import com.casic.br.ktd.view.InspectionActivity
@@ -15,7 +16,6 @@
import com.casic.br.ktd.widgets.AlertControlDialog
import com.casic.br.ktd.widgets.AlertInputDialog
import com.casic.br.ktd.widgets.DateRangeActionSheet
-import com.pengxh.kt.lite.base.KotlinBaseFragment
import com.pengxh.kt.lite.extensions.navigatePageTo
import com.pengxh.kt.lite.extensions.show
import com.pengxh.kt.lite.utils.WeakReferenceHandler
@@ -36,7 +36,7 @@
private var startTime = ""
private var endTime = ""
- override fun initData(savedInstanceState: Bundle?) {
+ override fun initView(savedInstanceState: Bundle?) {
weakReferenceHandler = WeakReferenceHandler(this)
taskViewModel = ViewModelProvider(this)[TaskViewModel::class.java]
taskViewModel.taskList.observe(this) {
@@ -45,7 +45,7 @@
when {
isRefresh -> {
taskAdapter.setRefreshData(dataRows)
- baseView.taskLayout.finishRefresh()
+ bv.taskLayout.finishRefresh()
isRefresh = false
}
isLoadMore -> {
@@ -53,7 +53,7 @@
"到底了,别拉了".show(requireContext())
}
taskAdapter.setLoadMoreData(dataRows)
- baseView.taskLayout.finishLoadMore()
+ bv.taskLayout.finishLoadMore()
isLoadMore = false
}
else -> {
@@ -76,9 +76,9 @@
when (msg.what) {
2023070501 -> {
if (dataBeans.size == 0) {
- baseView.emptyLayout.visibility = View.VISIBLE
+ bv.emptyLayout.visibility = View.VISIBLE
} else {
- baseView.emptyLayout.visibility = View.GONE
+ bv.emptyLayout.visibility = View.GONE
taskAdapter = object : TaskAdapter(
requireContext(), R.layout.item_task_rv_l, dataBeans
) {
@@ -97,8 +97,8 @@
}
}
//绑定侧滑事件
- swipeAction.attachToRecyclerView(baseView.taskRecyclerView)
- baseView.taskRecyclerView.adapter = taskAdapter
+ swipeAction.attachToRecyclerView(bv.taskRecyclerView)
+ bv.taskRecyclerView.adapter = taskAdapter
taskAdapter.setOnItemCheckedListener(object :
TaskAdapter.OnItemCheckedListener {
override fun onItemChecked(items: ArrayList) {
@@ -168,7 +168,7 @@
override fun initEvent() {
- baseView.calendarView.setOnClickListener {
+ bv.calendarView.setOnClickListener {
DateRangeActionSheet.Builder().setContext(requireContext())
.setOnActionSheetListener(object :
DateRangeActionSheet.OnDateRangeSelectedListener {
@@ -177,12 +177,12 @@
endTime = endDate
//显示
- baseView.selectedDateView.text = "$startDate ~ $endDate"
+ bv.selectedDateView.text = "$startDate ~ $endDate"
}
}).build().show()
}
- baseView.addTaskButton.setOnClickListener {
+ bv.addTaskButton.setOnClickListener {
// AlertInputDialog.Builder()
// .setContext(requireContext())
// .setTitle("新建巡检任务")
@@ -200,11 +200,11 @@
requireContext().navigatePageTo()
}
- baseView.deleteTaskButton.setOnClickListener {
+ bv.deleteTaskButton.setOnClickListener {
selectedItems.size.toString().show(requireContext())
}
- baseView.taskSettingsButton.setOnClickListener {
+ bv.taskSettingsButton.setOnClickListener {
AlertInputDialog.Builder()
.setContext(requireContext())
.setTitle("设置阈值")
@@ -221,14 +221,14 @@
}).build().show()
}
- baseView.taskLayout.setOnRefreshListener {
+ bv.taskLayout.setOnRefreshListener {
isRefresh = true
//刷新之后页码重置
pageIndex = 1
getTaskList()
}
- baseView.taskLayout.setOnLoadMoreListener {
+ bv.taskLayout.setOnLoadMoreListener {
isLoadMore = true
pageIndex++
getTaskList()
@@ -239,13 +239,13 @@
taskViewModel.getTaskList(
startTime,
endTime,
- baseView.taskNameView.text.toString(),
- baseView.taskCodeView.text.toString(),
+ bv.taskNameView.text.toString(),
+ bv.taskCodeView.text.toString(),
pageIndex
)
}
- override fun initLayoutView(): Int = R.layout.fragment_task
+ override fun initLayoutRes(): Int = R.layout.fragment_task
override fun observeRequestState() {
diff --git a/app/src/main/java/com/casic/br/ktd/netty/ISocketListener.kt b/app/src/main/java/com/casic/br/ktd/netty/ISocketListener.kt
deleted file mode 100644
index dab98e1..0000000
--- a/app/src/main/java/com/casic/br/ktd/netty/ISocketListener.kt
+++ /dev/null
@@ -1,19 +0,0 @@
-package com.casic.br.ktd.netty
-
-interface ISocketListener {
- companion object {
- const val STATUS_CONNECT_SUCCESS: Byte = 1 //连接成功
- const val STATUS_CONNECT_CLOSED: Byte = 0 //关闭连接
- const val STATUS_CONNECT_ERROR: Byte = 0 //连接失败
- }
-
- /**
- * 当接收到系统消息
- */
- fun onMessageResponse(data: ByteArray?)
-
- /**
- * 当连接状态发生变化时调用
- */
- fun onServiceStatusConnectChanged(statusCode: Byte)
-}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/br/ktd/netty/SocketChannelHandle.kt b/app/src/main/java/com/casic/br/ktd/netty/SocketChannelHandle.kt
deleted file mode 100644
index 42eb310..0000000
--- a/app/src/main/java/com/casic/br/ktd/netty/SocketChannelHandle.kt
+++ /dev/null
@@ -1,51 +0,0 @@
-package com.casic.br.ktd.netty
-
-import android.util.Log
-import io.netty.channel.ChannelHandlerContext
-import io.netty.channel.SimpleChannelInboundHandler
-import io.netty.handler.timeout.IdleState
-import io.netty.handler.timeout.IdleStateEvent
-import java.nio.charset.StandardCharsets
-
-class SocketChannelHandle(private val listener: ISocketListener?) :
- SimpleChannelInboundHandler() {
-
- private val kTag = "SocketChannelHandle"
-
- override fun channelActive(ctx: ChannelHandlerContext) {
- super.channelActive(ctx)
- Log.d(kTag, "channelActive ===> 连接成功")
- listener?.onServiceStatusConnectChanged(ISocketListener.STATUS_CONNECT_SUCCESS)
- }
-
- override fun channelInactive(ctx: ChannelHandlerContext) {
- super.channelInactive(ctx)
- Log.e(kTag, "channelInactive: 连接断开")
- }
-
- override fun userEventTriggered(ctx: ChannelHandlerContext, evt: Any) {
- super.userEventTriggered(ctx, evt)
- if (evt is IdleStateEvent) {
- if (evt.state() == IdleState.WRITER_IDLE) {
- //写超时,此时可以发送心跳数据给服务器
- val temp = "FF"
- ctx.writeAndFlush(temp.toByteArray(StandardCharsets.UTF_8))
- } else if (evt.state() == IdleState.READER_IDLE) {
- //读超时,此时代表没有收到心跳返回可以关闭当前连接进行重连
- ctx.close()
- }
- }
- }
-
- override fun channelRead0(ctx: ChannelHandlerContext, data: ByteArray?) {
- listener?.onMessageResponse(data)
- }
-
- override fun exceptionCaught(ctx: ChannelHandlerContext, cause: Throwable) {
- super.exceptionCaught(ctx, cause)
- Log.d(kTag, "exceptionCaught ===> $cause")
- listener?.onServiceStatusConnectChanged(ISocketListener.STATUS_CONNECT_ERROR)
- cause.printStackTrace()
- ctx.close()
- }
-}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/br/ktd/netty/SocketClient.kt b/app/src/main/java/com/casic/br/ktd/netty/SocketClient.kt
deleted file mode 100644
index d05d335..0000000
--- a/app/src/main/java/com/casic/br/ktd/netty/SocketClient.kt
+++ /dev/null
@@ -1,153 +0,0 @@
-package com.casic.br.ktd.netty
-
-import android.os.SystemClock
-import android.util.Log
-import io.netty.bootstrap.Bootstrap
-import io.netty.channel.*
-import io.netty.channel.nio.NioEventLoopGroup
-import io.netty.channel.socket.SocketChannel
-import io.netty.channel.socket.nio.NioSocketChannel
-import io.netty.handler.codec.bytes.ByteArrayDecoder
-import io.netty.handler.codec.bytes.ByteArrayEncoder
-import io.netty.handler.timeout.IdleStateHandler
-
-class SocketClient {
-
- private val kTag = "SocketClient"
-
- private var host: String? = null
- private var port = 8000
- private var nioEventLoopGroup: NioEventLoopGroup? = null
- private var channel: Channel? = null
- private var listener: ISocketListener? = null
-
- //现在连接的状态
- var connectStatus = false //判断是否已连接
- private var reconnectNum = Int.MAX_VALUE //定义的重连到时候用
- private var isNeedReconnect = true //是否需要重连
- var isConnecting = false //是否正在连接
- private set
- private var reconnectIntervalTime: Long = 15000 //重连的时间
-
- //重连时间
- fun setReconnectNum(reconnectNum: Int) {
- this.reconnectNum = reconnectNum
- }
-
- fun setReconnectIntervalTime(reconnectIntervalTime: Long) {
- this.reconnectIntervalTime = reconnectIntervalTime
- }
-
- fun setSocketListener(listener: ISocketListener?) {
- this.listener = listener
- }
-
- fun connect(host: String, port: Int) {
- this.host = host
- this.port = port
- Log.d(kTag, "connect ===> 开始连接TCP服务器")
- if (isConnecting) {
- return
- }
- //起个线程
- val clientThread: Thread = object : Thread("client-Netty") {
- override fun run() {
- super.run()
- isNeedReconnect = true
- reconnectNum = Int.MAX_VALUE
- connectServer()
- }
- }
- clientThread.start()
- }
-
- private fun connectServer() {
- synchronized(this@SocketClient) {
- var channelFuture: ChannelFuture? = null //连接管理对象
- if (!connectStatus) {
- isConnecting = true
- nioEventLoopGroup = NioEventLoopGroup() //设置的连接group
- val bootstrap = Bootstrap()
- bootstrap.group(nioEventLoopGroup) //设置的一系列连接参数操作等
- .channel(NioSocketChannel::class.java)
- .option(ChannelOption.TCP_NODELAY, true) //无阻塞
- .option(ChannelOption.SO_KEEPALIVE, true) //长连接
- .option(
- ChannelOption.RCVBUF_ALLOCATOR,
- AdaptiveRecvByteBufAllocator(5000, 5000, 8000)
- ) //接收缓冲区 最小值太小时数据接收不全
- .handler(object : ChannelInitializer() {
- override fun initChannel(channel: SocketChannel) {
- val pipeline = channel.pipeline()
- //参数1:代表读套接字超时的时间,没收到数据会触发读超时回调;
- //参数2:代表写套接字超时时间,没进行写会触发写超时回调;
- //参数3:将在未执行读取或写入时触发超时回调,0代表不处理;
- //读超时尽量设置大于写超时,代表多次写超时时写心跳包,多次写了心跳数据仍然读超时代表当前连接错误,即可断开连接重新连接
- pipeline.addLast(IdleStateHandler(60, 10, 0))
- pipeline.addLast(ByteArrayDecoder())
- pipeline.addLast(ByteArrayEncoder())
- pipeline.addLast(SocketChannelHandle(listener))
- }
- })
- try {
- //连接监听
- channelFuture = bootstrap.connect(host, port)
- .addListener(object : ChannelFutureListener {
- override fun operationComplete(channelFuture: ChannelFuture) {
- if (channelFuture.isSuccess) {
- connectStatus = true
- channel = channelFuture.channel()
- } else {
- Log.e(kTag, "operationComplete: 连接失败")
- connectStatus = false
- }
- isConnecting = false
- }
- }).sync()
- // 等待连接关闭
- channelFuture.channel().closeFuture().sync()
- } catch (e: Exception) {
- e.printStackTrace()
- } finally {
- connectStatus = false
- listener?.onServiceStatusConnectChanged(ISocketListener.STATUS_CONNECT_CLOSED) //STATUS_CONNECT_CLOSED 这我自己定义的 接口标识
- if (null != channelFuture) {
- if (channelFuture.channel() != null && channelFuture.channel().isOpen) {
- channelFuture.channel().close()
- }
- }
- nioEventLoopGroup?.shutdownGracefully()
- reconnect() //重新连接
- }
- }
- }
- }
-
- //断开连接
- fun disconnect() {
- Log.d(kTag, "disconnect ===> 断开连接")
- isNeedReconnect = false
- nioEventLoopGroup?.shutdownGracefully()
- }
-
- //重新连接
- private fun reconnect() {
- if (isNeedReconnect && reconnectNum > 0 && !connectStatus) {
- reconnectNum--
- SystemClock.sleep(reconnectIntervalTime)
- if (isNeedReconnect && reconnectNum > 0 && !connectStatus) {
- Log.d(kTag, "reconnect ===> 重新连接")
- connectServer()
- }
- }
- }
-
- fun sendData(bytes: ByteArray) {
- channel?.writeAndFlush(bytes)?.addListener(ChannelFutureListener { future ->
- if (!future.isSuccess) {
- future.channel().close()
- nioEventLoopGroup!!.shutdownGracefully()
- }
- })
- }
-}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/br/ktd/netty/SocketManager.kt b/app/src/main/java/com/casic/br/ktd/netty/SocketManager.kt
deleted file mode 100644
index 17daf35..0000000
--- a/app/src/main/java/com/casic/br/ktd/netty/SocketManager.kt
+++ /dev/null
@@ -1,113 +0,0 @@
-package com.casic.br.ktd.netty
-
-import android.util.Log
-import com.casic.br.ktd.base.BaseApplication
-import com.casic.br.ktd.extensions.covertAngleValue
-import com.casic.br.ktd.extensions.covertDataValue
-import com.casic.br.ktd.extensions.toUnsignedByteArray
-import com.casic.br.ktd.model.SensorDataModel
-import com.casic.br.ktd.utils.LocaleConstant
-import com.pengxh.kt.lite.extensions.toJson
-import com.pengxh.kt.lite.utils.BroadcastManager
-
-class SocketManager private constructor() : ISocketListener {
-
- private val kTag = "SocketManager"
- private var nettyClient: SocketClient = SocketClient()
-
- companion object {
- val instance: SocketManager by lazy(mode = LazyThreadSafetyMode.SYNCHRONIZED) { SocketManager() }
- }
-
- fun connectNetty(hostname: String, port: Int) {
- Thread {
- if (!nettyClient.connectStatus) {
- nettyClient.setSocketListener(this)
- nettyClient.connect(hostname, port)
- } else {
- nettyClient.disconnect()
- }
- }.start()
- }
-
- override fun onMessageResponse(data: ByteArray?) {
-// Log.d(kTag, "onMessageResponse ===> " + Arrays.toString(data))
- /**
- * 0xFF,0x01,
- * 0x01,0x37,0xE6, 甲烷浓度值(数据码1* 65536 + 数据码2 * 256 + 数据码3)
- * 0x00, 激光甲烷模块工作状态(00表示设备正常,01表示温控故障,02表示设备激光未打开)
- * 0x00,0xB2,0x35, 激光强度值(数据码5* 65536 + 数据码6 * 256 + 数据码7)
- * 0x0A,0x3D, 云台水平角度([数据码8 * 256 + 数据码9]/100,单位为°,精确到0.01)
- * 0x05,0x6F, 云台垂直角度(首先计算Tangle=[数据码10 * 256 + 数据码11]/100,单位为°,精确到0.01。若Tangle在0~90范围内,则垂直角度值=Tangle;若Tangle在-1~-90范围内,则垂直角度值=Tangle-360)
- * 0xC1
- *
- * [-1, 1, 1, 55, -26, 0, 0, -78, 53, 10, 61, 5, 111, -63]
- * 甲烷浓度值为79638,计算为79638=0x01*65536+0x37*256+0xE6[0x01为数据码1,0x37为数据码2,0xE6为数据码3];
- * 激光甲烷设备状态值为0,表示状态正常,[0x00为数据码4];
- * 激光强度值为45621,计算为45621=0x00*65536+0xB2*256+0x35[0x00为数据码5,0xB2为数据码6,0x35为数据码7];
- *
- * =========================================================================================
- * 实际数据(1800-1950左右)
- * [-86, 1, 0, 7, 71, 0, 0, 62, -92, 57, 59, -118, -111, -64]
- * */
-
- if (data == null) {
- return
- }
- val bytes = data.toUnsignedByteArray()
- if (bytes.size == 14) {
- val dataModel = SensorDataModel(0, "激光未打开", 0, 0.0, 0.0)
-
- val methaneBytes = IntArray(3)
- System.arraycopy(bytes, 2, methaneBytes, 0, 3)
- dataModel.methane = methaneBytes.covertDataValue()
-
- dataModel.methaneState = when (bytes[5]) {
- 1 -> "温控故障"
- 2 -> "激光未打开"
- else -> "正常"
- }
-
- val laserBytes = IntArray(3)
- System.arraycopy(bytes, 6, laserBytes, 0, 3)
- dataModel.laser = laserBytes.covertDataValue()
-
- /**
- * 水平角度的实际范围为从水平零点开始,顺时针方向(从上往下看),0~360°
- * 垂直角度的实际范围为从垂直零点开始,以向上为正,-90°~90°,控制精度为0.01°
- * */
- val horizontalBytes = IntArray(2)
- System.arraycopy(bytes, 9, horizontalBytes, 0, 2)
- dataModel.horizontal = horizontalBytes.covertAngleValue()
-
- val verticalBytes = IntArray(2)
- System.arraycopy(bytes, 11, verticalBytes, 0, 2)
- dataModel.vertical = verticalBytes.covertAngleValue()
-
- //{"horizontal":26.21,"laser":45621,"methane":79846,"methaneState":"正常","vertical":13.91}
- BroadcastManager.obtainInstance(BaseApplication.get()).sendBroadcast(
- LocaleConstant.ACTION_UPDATE_DATA, dataModel.toJson()
- )
- }
- }
-
- override fun onServiceStatusConnectChanged(statusCode: Byte) {
- if (statusCode == ISocketListener.STATUS_CONNECT_SUCCESS) {
- if (nettyClient.connectStatus) {
- Log.d(kTag, "连接成功")
- }
- } else {
- if (!nettyClient.connectStatus) {
- Log.e(kTag, "onServiceStatusConnectChanged:$statusCode,连接断开,正在重连")
- }
- }
- }
-
- fun sendData(data: ByteArray) {
- nettyClient.sendData(data)
- }
-
- fun close() {
- nettyClient.disconnect()
- }
-}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/br/ktd/netty/tcp/ISocketListener.kt b/app/src/main/java/com/casic/br/ktd/netty/tcp/ISocketListener.kt
new file mode 100644
index 0000000..13c3084
--- /dev/null
+++ b/app/src/main/java/com/casic/br/ktd/netty/tcp/ISocketListener.kt
@@ -0,0 +1,19 @@
+package com.casic.br.ktd.netty.tcp
+
+interface ISocketListener {
+ companion object {
+ const val STATUS_CONNECT_SUCCESS: Byte = 1 //连接成功
+ const val STATUS_CONNECT_CLOSED: Byte = 0 //关闭连接
+ const val STATUS_CONNECT_ERROR: Byte = 0 //连接失败
+ }
+
+ /**
+ * 当接收到系统消息
+ */
+ fun onMessageResponse(data: ByteArray?)
+
+ /**
+ * 当连接状态发生变化时调用
+ */
+ fun onServiceStatusConnectChanged(statusCode: Byte)
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/br/ktd/netty/tcp/SocketChannelHandle.kt b/app/src/main/java/com/casic/br/ktd/netty/tcp/SocketChannelHandle.kt
new file mode 100644
index 0000000..8e2997f
--- /dev/null
+++ b/app/src/main/java/com/casic/br/ktd/netty/tcp/SocketChannelHandle.kt
@@ -0,0 +1,51 @@
+package com.casic.br.ktd.netty.tcp
+
+import android.util.Log
+import io.netty.channel.ChannelHandlerContext
+import io.netty.channel.SimpleChannelInboundHandler
+import io.netty.handler.timeout.IdleState
+import io.netty.handler.timeout.IdleStateEvent
+import java.nio.charset.StandardCharsets
+
+class SocketChannelHandle(private val listener: ISocketListener?) :
+ SimpleChannelInboundHandler() {
+
+ private val kTag = "SocketChannelHandle"
+
+ override fun channelActive(ctx: ChannelHandlerContext) {
+ super.channelActive(ctx)
+ Log.d(kTag, "channelActive ===> 连接成功")
+ listener?.onServiceStatusConnectChanged(ISocketListener.STATUS_CONNECT_SUCCESS)
+ }
+
+ override fun channelInactive(ctx: ChannelHandlerContext) {
+ super.channelInactive(ctx)
+ Log.e(kTag, "channelInactive: 连接断开")
+ }
+
+ override fun userEventTriggered(ctx: ChannelHandlerContext, evt: Any) {
+ super.userEventTriggered(ctx, evt)
+ if (evt is IdleStateEvent) {
+ if (evt.state() == IdleState.WRITER_IDLE) {
+ //写超时,此时可以发送心跳数据给服务器
+ val temp = "FF"
+ ctx.writeAndFlush(temp.toByteArray(StandardCharsets.UTF_8))
+ } else if (evt.state() == IdleState.READER_IDLE) {
+ //读超时,此时代表没有收到心跳返回可以关闭当前连接进行重连
+ ctx.close()
+ }
+ }
+ }
+
+ override fun channelRead0(ctx: ChannelHandlerContext, data: ByteArray?) {
+ listener?.onMessageResponse(data)
+ }
+
+ override fun exceptionCaught(ctx: ChannelHandlerContext, cause: Throwable) {
+ super.exceptionCaught(ctx, cause)
+ Log.d(kTag, "exceptionCaught ===> $cause")
+ listener?.onServiceStatusConnectChanged(ISocketListener.STATUS_CONNECT_ERROR)
+ cause.printStackTrace()
+ ctx.close()
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index e822df6..d72c1a5 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -7,6 +7,9 @@
+
+
+
@@ -46,5 +49,8 @@
+
+
+
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/br/ktd/base/KotlinBaseFragment.kt b/app/src/main/java/com/casic/br/ktd/base/KotlinBaseFragment.kt
new file mode 100644
index 0000000..2dac61c
--- /dev/null
+++ b/app/src/main/java/com/casic/br/ktd/base/KotlinBaseFragment.kt
@@ -0,0 +1,51 @@
+package com.casic.br.ktd.base
+
+import android.os.Bundle
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import androidx.annotation.LayoutRes
+import androidx.fragment.app.Fragment
+
+abstract class KotlinBaseFragment : Fragment() {
+
+ lateinit var bv: View
+
+ override fun onCreateView(
+ inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?
+ ): View? {
+ bv = inflater.inflate(initLayoutRes(), container, false)
+ initView(savedInstanceState)
+ setupTopBarLayout()
+ return bv
+ }
+
+ override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
+ super.onViewCreated(view, savedInstanceState)
+ observeRequestState()
+ initEvent()
+ }
+
+ @LayoutRes
+ abstract fun initLayoutRes(): Int
+
+ /**
+ * 沉浸式状态栏
+ */
+ abstract fun setupTopBarLayout()
+
+ /**
+ * 初始化布局以及控件
+ */
+ abstract fun initView(savedInstanceState: Bundle?)
+
+ /**
+ * 网络请求状态监听
+ */
+ abstract fun observeRequestState()
+
+ /**
+ * 业务逻辑,按钮等事件
+ */
+ abstract fun initEvent()
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/br/ktd/fragment/AlarmPageFragment.kt b/app/src/main/java/com/casic/br/ktd/fragment/AlarmPageFragment.kt
index 6c98a3b..9418169 100644
--- a/app/src/main/java/com/casic/br/ktd/fragment/AlarmPageFragment.kt
+++ b/app/src/main/java/com/casic/br/ktd/fragment/AlarmPageFragment.kt
@@ -2,28 +2,29 @@
import android.os.Bundle
import com.casic.br.ktd.R
+import com.casic.br.ktd.base.KotlinBaseFragment
import com.casic.br.ktd.widgets.DateRangeActionSheet
-import com.pengxh.kt.lite.base.KotlinBaseFragment
import kotlinx.android.synthetic.main.fragment_alarm.view.*
class AlarmPageFragment : KotlinBaseFragment() {
- override fun initData(savedInstanceState: Bundle?) {
+
+ override fun initView(savedInstanceState: Bundle?) {
}
override fun initEvent() {
- baseView.calendarView.setOnClickListener {
+ bv.calendarView.setOnClickListener {
DateRangeActionSheet.Builder().setContext(requireContext())
.setOnActionSheetListener(object :
DateRangeActionSheet.OnDateRangeSelectedListener {
override fun onDateRangeSelected(startDate: String, endDate: String) {
- baseView.selectedDateView.text = "$startDate ~ $endDate"
+ bv.selectedDateView.text = "$startDate ~ $endDate"
}
}).build().show()
}
}
- override fun initLayoutView(): Int = R.layout.fragment_alarm
+ override fun initLayoutRes(): Int = R.layout.fragment_alarm
override fun observeRequestState() {
diff --git a/app/src/main/java/com/casic/br/ktd/fragment/HomePageFragment.kt b/app/src/main/java/com/casic/br/ktd/fragment/HomePageFragment.kt
index 9961935..f3eba5c 100644
--- a/app/src/main/java/com/casic/br/ktd/fragment/HomePageFragment.kt
+++ b/app/src/main/java/com/casic/br/ktd/fragment/HomePageFragment.kt
@@ -1,32 +1,62 @@
package com.casic.br.ktd.fragment
+import android.graphics.Color
import android.os.Bundle
import com.amap.api.maps.AMap
import com.amap.api.maps.AMapOptions
+import com.amap.api.maps.CameraUpdateFactory
+import com.amap.api.maps.model.*
import com.casic.br.ktd.R
-import com.pengxh.kt.lite.base.KotlinBaseFragment
+import com.casic.br.ktd.base.KotlinBaseFragment
import kotlinx.android.synthetic.main.fragment_home.view.*
class HomePageFragment : KotlinBaseFragment() {
private lateinit var aMap: AMap
- override fun initData(savedInstanceState: Bundle?) {
- baseView.mapView.onCreate(savedInstanceState)
- aMap = baseView.mapView.map
+ override fun initView(savedInstanceState: Bundle?) {
+ bv.mapView.onCreate(savedInstanceState)
+ aMap = bv.mapView.map
val uiSettings = aMap.uiSettings
uiSettings.isCompassEnabled = true
- uiSettings.isMyLocationButtonEnabled = true
+ uiSettings.isMyLocationButtonEnabled = false
uiSettings.isScaleControlsEnabled = true
uiSettings.zoomPosition = AMapOptions.ZOOM_POSITION_RIGHT_CENTER
uiSettings.isRotateGesturesEnabled = false//不许地图随手势旋转角度
}
override fun initEvent() {
-
+ //移动到巡检起始经纬度
+ val cameraPosition = CameraPosition(LatLng(39.914199, 116.265785), 16f, 0f, 0f)
+ val cameraUpdate = CameraUpdateFactory.newCameraPosition(cameraPosition)
+ aMap.animateCamera(cameraUpdate, 1500, null)
+ //设置起点
+ addMarker(LatLng(39.914885, 116.272312), R.mipmap.start)
+ //设置终点
+ addMarker(LatLng(39.914716, 116.265097), R.mipmap.end)
+ //瞄点画线
+ val latLngPoints = ArrayList()
+ latLngPoints.add(LatLng(39.914885, 116.272312))
+ latLngPoints.add(LatLng(39.915148, 116.272312))
+ latLngPoints.add(LatLng(39.915399, 116.272302))
+ latLngPoints.add(LatLng(39.915436, 116.271787))
+ latLngPoints.add(LatLng(39.915477, 116.270886))
+ latLngPoints.add(LatLng(39.915477, 116.269968))
+ latLngPoints.add(LatLng(39.915469, 116.269544))
+ latLngPoints.add(LatLng(39.915481, 116.269196))
+ latLngPoints.add(LatLng(39.915452, 116.268472))
+ latLngPoints.add(LatLng(39.915444, 116.267722))
+ latLngPoints.add(LatLng(39.915415, 116.266755))
+ latLngPoints.add(LatLng(39.915403, 116.266165))
+ latLngPoints.add(LatLng(39.915395, 116.265703))
+ latLngPoints.add(LatLng(39.915366, 116.265119))
+ latLngPoints.add(LatLng(39.914716, 116.265097))
+ aMap.addPolyline(
+ PolylineOptions().addAll(latLngPoints).width(10.toFloat()).color(Color.RED)
+ )
}
- override fun initLayoutView(): Int = R.layout.fragment_home
+ override fun initLayoutRes(): Int = R.layout.fragment_home
override fun observeRequestState() {
@@ -36,25 +66,32 @@
}
+ private fun addMarker(point: LatLng, res: Int) {
+ val markerOption = MarkerOptions()
+ markerOption.position(point)
+ markerOption.icon(BitmapDescriptorFactory.fromResource(res))
+ aMap.addMarker(markerOption)
+ }
+
/***以下是地图生命周期管理************************************************************************/
override fun onResume() {
super.onResume()
- baseView.mapView.onResume()
+ bv.mapView.onResume()
}
override fun onPause() {
- baseView.mapView.onPause()
super.onPause()
+ bv.mapView.onPause()
}
override fun onSaveInstanceState(outState: Bundle) {
super.onSaveInstanceState(outState)
- baseView.mapView.onSaveInstanceState(outState)
+ bv.mapView.onSaveInstanceState(outState)
}
override fun onDestroy() {
- baseView.mapView.onDestroy()
super.onDestroy()
+ bv.mapView.onDestroy()
}
}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/br/ktd/fragment/MinePageFragment.kt b/app/src/main/java/com/casic/br/ktd/fragment/MinePageFragment.kt
index 90313ac..3212794 100644
--- a/app/src/main/java/com/casic/br/ktd/fragment/MinePageFragment.kt
+++ b/app/src/main/java/com/casic/br/ktd/fragment/MinePageFragment.kt
@@ -2,10 +2,11 @@
import android.os.Bundle
import com.casic.br.ktd.R
-import com.pengxh.kt.lite.base.KotlinBaseFragment
+import com.casic.br.ktd.base.KotlinBaseFragment
class MinePageFragment : KotlinBaseFragment() {
- override fun initData(savedInstanceState: Bundle?) {
+
+ override fun initView(savedInstanceState: Bundle?) {
}
@@ -13,7 +14,7 @@
}
- override fun initLayoutView(): Int = R.layout.fragment_mine
+ override fun initLayoutRes(): Int = R.layout.fragment_mine
override fun observeRequestState() {
diff --git a/app/src/main/java/com/casic/br/ktd/fragment/TaskPageFragment.kt b/app/src/main/java/com/casic/br/ktd/fragment/TaskPageFragment.kt
index 8f6abf0..6b82a54 100644
--- a/app/src/main/java/com/casic/br/ktd/fragment/TaskPageFragment.kt
+++ b/app/src/main/java/com/casic/br/ktd/fragment/TaskPageFragment.kt
@@ -8,6 +8,7 @@
import androidx.recyclerview.widget.RecyclerView
import com.casic.br.ktd.R
import com.casic.br.ktd.adapter.TaskAdapter
+import com.casic.br.ktd.base.KotlinBaseFragment
import com.casic.br.ktd.holder.SwipeViewHolder
import com.casic.br.ktd.model.TaskListModel
import com.casic.br.ktd.view.InspectionActivity
@@ -15,7 +16,6 @@
import com.casic.br.ktd.widgets.AlertControlDialog
import com.casic.br.ktd.widgets.AlertInputDialog
import com.casic.br.ktd.widgets.DateRangeActionSheet
-import com.pengxh.kt.lite.base.KotlinBaseFragment
import com.pengxh.kt.lite.extensions.navigatePageTo
import com.pengxh.kt.lite.extensions.show
import com.pengxh.kt.lite.utils.WeakReferenceHandler
@@ -36,7 +36,7 @@
private var startTime = ""
private var endTime = ""
- override fun initData(savedInstanceState: Bundle?) {
+ override fun initView(savedInstanceState: Bundle?) {
weakReferenceHandler = WeakReferenceHandler(this)
taskViewModel = ViewModelProvider(this)[TaskViewModel::class.java]
taskViewModel.taskList.observe(this) {
@@ -45,7 +45,7 @@
when {
isRefresh -> {
taskAdapter.setRefreshData(dataRows)
- baseView.taskLayout.finishRefresh()
+ bv.taskLayout.finishRefresh()
isRefresh = false
}
isLoadMore -> {
@@ -53,7 +53,7 @@
"到底了,别拉了".show(requireContext())
}
taskAdapter.setLoadMoreData(dataRows)
- baseView.taskLayout.finishLoadMore()
+ bv.taskLayout.finishLoadMore()
isLoadMore = false
}
else -> {
@@ -76,9 +76,9 @@
when (msg.what) {
2023070501 -> {
if (dataBeans.size == 0) {
- baseView.emptyLayout.visibility = View.VISIBLE
+ bv.emptyLayout.visibility = View.VISIBLE
} else {
- baseView.emptyLayout.visibility = View.GONE
+ bv.emptyLayout.visibility = View.GONE
taskAdapter = object : TaskAdapter(
requireContext(), R.layout.item_task_rv_l, dataBeans
) {
@@ -97,8 +97,8 @@
}
}
//绑定侧滑事件
- swipeAction.attachToRecyclerView(baseView.taskRecyclerView)
- baseView.taskRecyclerView.adapter = taskAdapter
+ swipeAction.attachToRecyclerView(bv.taskRecyclerView)
+ bv.taskRecyclerView.adapter = taskAdapter
taskAdapter.setOnItemCheckedListener(object :
TaskAdapter.OnItemCheckedListener {
override fun onItemChecked(items: ArrayList) {
@@ -168,7 +168,7 @@
override fun initEvent() {
- baseView.calendarView.setOnClickListener {
+ bv.calendarView.setOnClickListener {
DateRangeActionSheet.Builder().setContext(requireContext())
.setOnActionSheetListener(object :
DateRangeActionSheet.OnDateRangeSelectedListener {
@@ -177,12 +177,12 @@
endTime = endDate
//显示
- baseView.selectedDateView.text = "$startDate ~ $endDate"
+ bv.selectedDateView.text = "$startDate ~ $endDate"
}
}).build().show()
}
- baseView.addTaskButton.setOnClickListener {
+ bv.addTaskButton.setOnClickListener {
// AlertInputDialog.Builder()
// .setContext(requireContext())
// .setTitle("新建巡检任务")
@@ -200,11 +200,11 @@
requireContext().navigatePageTo()
}
- baseView.deleteTaskButton.setOnClickListener {
+ bv.deleteTaskButton.setOnClickListener {
selectedItems.size.toString().show(requireContext())
}
- baseView.taskSettingsButton.setOnClickListener {
+ bv.taskSettingsButton.setOnClickListener {
AlertInputDialog.Builder()
.setContext(requireContext())
.setTitle("设置阈值")
@@ -221,14 +221,14 @@
}).build().show()
}
- baseView.taskLayout.setOnRefreshListener {
+ bv.taskLayout.setOnRefreshListener {
isRefresh = true
//刷新之后页码重置
pageIndex = 1
getTaskList()
}
- baseView.taskLayout.setOnLoadMoreListener {
+ bv.taskLayout.setOnLoadMoreListener {
isLoadMore = true
pageIndex++
getTaskList()
@@ -239,13 +239,13 @@
taskViewModel.getTaskList(
startTime,
endTime,
- baseView.taskNameView.text.toString(),
- baseView.taskCodeView.text.toString(),
+ bv.taskNameView.text.toString(),
+ bv.taskCodeView.text.toString(),
pageIndex
)
}
- override fun initLayoutView(): Int = R.layout.fragment_task
+ override fun initLayoutRes(): Int = R.layout.fragment_task
override fun observeRequestState() {
diff --git a/app/src/main/java/com/casic/br/ktd/netty/ISocketListener.kt b/app/src/main/java/com/casic/br/ktd/netty/ISocketListener.kt
deleted file mode 100644
index dab98e1..0000000
--- a/app/src/main/java/com/casic/br/ktd/netty/ISocketListener.kt
+++ /dev/null
@@ -1,19 +0,0 @@
-package com.casic.br.ktd.netty
-
-interface ISocketListener {
- companion object {
- const val STATUS_CONNECT_SUCCESS: Byte = 1 //连接成功
- const val STATUS_CONNECT_CLOSED: Byte = 0 //关闭连接
- const val STATUS_CONNECT_ERROR: Byte = 0 //连接失败
- }
-
- /**
- * 当接收到系统消息
- */
- fun onMessageResponse(data: ByteArray?)
-
- /**
- * 当连接状态发生变化时调用
- */
- fun onServiceStatusConnectChanged(statusCode: Byte)
-}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/br/ktd/netty/SocketChannelHandle.kt b/app/src/main/java/com/casic/br/ktd/netty/SocketChannelHandle.kt
deleted file mode 100644
index 42eb310..0000000
--- a/app/src/main/java/com/casic/br/ktd/netty/SocketChannelHandle.kt
+++ /dev/null
@@ -1,51 +0,0 @@
-package com.casic.br.ktd.netty
-
-import android.util.Log
-import io.netty.channel.ChannelHandlerContext
-import io.netty.channel.SimpleChannelInboundHandler
-import io.netty.handler.timeout.IdleState
-import io.netty.handler.timeout.IdleStateEvent
-import java.nio.charset.StandardCharsets
-
-class SocketChannelHandle(private val listener: ISocketListener?) :
- SimpleChannelInboundHandler() {
-
- private val kTag = "SocketChannelHandle"
-
- override fun channelActive(ctx: ChannelHandlerContext) {
- super.channelActive(ctx)
- Log.d(kTag, "channelActive ===> 连接成功")
- listener?.onServiceStatusConnectChanged(ISocketListener.STATUS_CONNECT_SUCCESS)
- }
-
- override fun channelInactive(ctx: ChannelHandlerContext) {
- super.channelInactive(ctx)
- Log.e(kTag, "channelInactive: 连接断开")
- }
-
- override fun userEventTriggered(ctx: ChannelHandlerContext, evt: Any) {
- super.userEventTriggered(ctx, evt)
- if (evt is IdleStateEvent) {
- if (evt.state() == IdleState.WRITER_IDLE) {
- //写超时,此时可以发送心跳数据给服务器
- val temp = "FF"
- ctx.writeAndFlush(temp.toByteArray(StandardCharsets.UTF_8))
- } else if (evt.state() == IdleState.READER_IDLE) {
- //读超时,此时代表没有收到心跳返回可以关闭当前连接进行重连
- ctx.close()
- }
- }
- }
-
- override fun channelRead0(ctx: ChannelHandlerContext, data: ByteArray?) {
- listener?.onMessageResponse(data)
- }
-
- override fun exceptionCaught(ctx: ChannelHandlerContext, cause: Throwable) {
- super.exceptionCaught(ctx, cause)
- Log.d(kTag, "exceptionCaught ===> $cause")
- listener?.onServiceStatusConnectChanged(ISocketListener.STATUS_CONNECT_ERROR)
- cause.printStackTrace()
- ctx.close()
- }
-}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/br/ktd/netty/SocketClient.kt b/app/src/main/java/com/casic/br/ktd/netty/SocketClient.kt
deleted file mode 100644
index d05d335..0000000
--- a/app/src/main/java/com/casic/br/ktd/netty/SocketClient.kt
+++ /dev/null
@@ -1,153 +0,0 @@
-package com.casic.br.ktd.netty
-
-import android.os.SystemClock
-import android.util.Log
-import io.netty.bootstrap.Bootstrap
-import io.netty.channel.*
-import io.netty.channel.nio.NioEventLoopGroup
-import io.netty.channel.socket.SocketChannel
-import io.netty.channel.socket.nio.NioSocketChannel
-import io.netty.handler.codec.bytes.ByteArrayDecoder
-import io.netty.handler.codec.bytes.ByteArrayEncoder
-import io.netty.handler.timeout.IdleStateHandler
-
-class SocketClient {
-
- private val kTag = "SocketClient"
-
- private var host: String? = null
- private var port = 8000
- private var nioEventLoopGroup: NioEventLoopGroup? = null
- private var channel: Channel? = null
- private var listener: ISocketListener? = null
-
- //现在连接的状态
- var connectStatus = false //判断是否已连接
- private var reconnectNum = Int.MAX_VALUE //定义的重连到时候用
- private var isNeedReconnect = true //是否需要重连
- var isConnecting = false //是否正在连接
- private set
- private var reconnectIntervalTime: Long = 15000 //重连的时间
-
- //重连时间
- fun setReconnectNum(reconnectNum: Int) {
- this.reconnectNum = reconnectNum
- }
-
- fun setReconnectIntervalTime(reconnectIntervalTime: Long) {
- this.reconnectIntervalTime = reconnectIntervalTime
- }
-
- fun setSocketListener(listener: ISocketListener?) {
- this.listener = listener
- }
-
- fun connect(host: String, port: Int) {
- this.host = host
- this.port = port
- Log.d(kTag, "connect ===> 开始连接TCP服务器")
- if (isConnecting) {
- return
- }
- //起个线程
- val clientThread: Thread = object : Thread("client-Netty") {
- override fun run() {
- super.run()
- isNeedReconnect = true
- reconnectNum = Int.MAX_VALUE
- connectServer()
- }
- }
- clientThread.start()
- }
-
- private fun connectServer() {
- synchronized(this@SocketClient) {
- var channelFuture: ChannelFuture? = null //连接管理对象
- if (!connectStatus) {
- isConnecting = true
- nioEventLoopGroup = NioEventLoopGroup() //设置的连接group
- val bootstrap = Bootstrap()
- bootstrap.group(nioEventLoopGroup) //设置的一系列连接参数操作等
- .channel(NioSocketChannel::class.java)
- .option(ChannelOption.TCP_NODELAY, true) //无阻塞
- .option(ChannelOption.SO_KEEPALIVE, true) //长连接
- .option(
- ChannelOption.RCVBUF_ALLOCATOR,
- AdaptiveRecvByteBufAllocator(5000, 5000, 8000)
- ) //接收缓冲区 最小值太小时数据接收不全
- .handler(object : ChannelInitializer() {
- override fun initChannel(channel: SocketChannel) {
- val pipeline = channel.pipeline()
- //参数1:代表读套接字超时的时间,没收到数据会触发读超时回调;
- //参数2:代表写套接字超时时间,没进行写会触发写超时回调;
- //参数3:将在未执行读取或写入时触发超时回调,0代表不处理;
- //读超时尽量设置大于写超时,代表多次写超时时写心跳包,多次写了心跳数据仍然读超时代表当前连接错误,即可断开连接重新连接
- pipeline.addLast(IdleStateHandler(60, 10, 0))
- pipeline.addLast(ByteArrayDecoder())
- pipeline.addLast(ByteArrayEncoder())
- pipeline.addLast(SocketChannelHandle(listener))
- }
- })
- try {
- //连接监听
- channelFuture = bootstrap.connect(host, port)
- .addListener(object : ChannelFutureListener {
- override fun operationComplete(channelFuture: ChannelFuture) {
- if (channelFuture.isSuccess) {
- connectStatus = true
- channel = channelFuture.channel()
- } else {
- Log.e(kTag, "operationComplete: 连接失败")
- connectStatus = false
- }
- isConnecting = false
- }
- }).sync()
- // 等待连接关闭
- channelFuture.channel().closeFuture().sync()
- } catch (e: Exception) {
- e.printStackTrace()
- } finally {
- connectStatus = false
- listener?.onServiceStatusConnectChanged(ISocketListener.STATUS_CONNECT_CLOSED) //STATUS_CONNECT_CLOSED 这我自己定义的 接口标识
- if (null != channelFuture) {
- if (channelFuture.channel() != null && channelFuture.channel().isOpen) {
- channelFuture.channel().close()
- }
- }
- nioEventLoopGroup?.shutdownGracefully()
- reconnect() //重新连接
- }
- }
- }
- }
-
- //断开连接
- fun disconnect() {
- Log.d(kTag, "disconnect ===> 断开连接")
- isNeedReconnect = false
- nioEventLoopGroup?.shutdownGracefully()
- }
-
- //重新连接
- private fun reconnect() {
- if (isNeedReconnect && reconnectNum > 0 && !connectStatus) {
- reconnectNum--
- SystemClock.sleep(reconnectIntervalTime)
- if (isNeedReconnect && reconnectNum > 0 && !connectStatus) {
- Log.d(kTag, "reconnect ===> 重新连接")
- connectServer()
- }
- }
- }
-
- fun sendData(bytes: ByteArray) {
- channel?.writeAndFlush(bytes)?.addListener(ChannelFutureListener { future ->
- if (!future.isSuccess) {
- future.channel().close()
- nioEventLoopGroup!!.shutdownGracefully()
- }
- })
- }
-}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/br/ktd/netty/SocketManager.kt b/app/src/main/java/com/casic/br/ktd/netty/SocketManager.kt
deleted file mode 100644
index 17daf35..0000000
--- a/app/src/main/java/com/casic/br/ktd/netty/SocketManager.kt
+++ /dev/null
@@ -1,113 +0,0 @@
-package com.casic.br.ktd.netty
-
-import android.util.Log
-import com.casic.br.ktd.base.BaseApplication
-import com.casic.br.ktd.extensions.covertAngleValue
-import com.casic.br.ktd.extensions.covertDataValue
-import com.casic.br.ktd.extensions.toUnsignedByteArray
-import com.casic.br.ktd.model.SensorDataModel
-import com.casic.br.ktd.utils.LocaleConstant
-import com.pengxh.kt.lite.extensions.toJson
-import com.pengxh.kt.lite.utils.BroadcastManager
-
-class SocketManager private constructor() : ISocketListener {
-
- private val kTag = "SocketManager"
- private var nettyClient: SocketClient = SocketClient()
-
- companion object {
- val instance: SocketManager by lazy(mode = LazyThreadSafetyMode.SYNCHRONIZED) { SocketManager() }
- }
-
- fun connectNetty(hostname: String, port: Int) {
- Thread {
- if (!nettyClient.connectStatus) {
- nettyClient.setSocketListener(this)
- nettyClient.connect(hostname, port)
- } else {
- nettyClient.disconnect()
- }
- }.start()
- }
-
- override fun onMessageResponse(data: ByteArray?) {
-// Log.d(kTag, "onMessageResponse ===> " + Arrays.toString(data))
- /**
- * 0xFF,0x01,
- * 0x01,0x37,0xE6, 甲烷浓度值(数据码1* 65536 + 数据码2 * 256 + 数据码3)
- * 0x00, 激光甲烷模块工作状态(00表示设备正常,01表示温控故障,02表示设备激光未打开)
- * 0x00,0xB2,0x35, 激光强度值(数据码5* 65536 + 数据码6 * 256 + 数据码7)
- * 0x0A,0x3D, 云台水平角度([数据码8 * 256 + 数据码9]/100,单位为°,精确到0.01)
- * 0x05,0x6F, 云台垂直角度(首先计算Tangle=[数据码10 * 256 + 数据码11]/100,单位为°,精确到0.01。若Tangle在0~90范围内,则垂直角度值=Tangle;若Tangle在-1~-90范围内,则垂直角度值=Tangle-360)
- * 0xC1
- *
- * [-1, 1, 1, 55, -26, 0, 0, -78, 53, 10, 61, 5, 111, -63]
- * 甲烷浓度值为79638,计算为79638=0x01*65536+0x37*256+0xE6[0x01为数据码1,0x37为数据码2,0xE6为数据码3];
- * 激光甲烷设备状态值为0,表示状态正常,[0x00为数据码4];
- * 激光强度值为45621,计算为45621=0x00*65536+0xB2*256+0x35[0x00为数据码5,0xB2为数据码6,0x35为数据码7];
- *
- * =========================================================================================
- * 实际数据(1800-1950左右)
- * [-86, 1, 0, 7, 71, 0, 0, 62, -92, 57, 59, -118, -111, -64]
- * */
-
- if (data == null) {
- return
- }
- val bytes = data.toUnsignedByteArray()
- if (bytes.size == 14) {
- val dataModel = SensorDataModel(0, "激光未打开", 0, 0.0, 0.0)
-
- val methaneBytes = IntArray(3)
- System.arraycopy(bytes, 2, methaneBytes, 0, 3)
- dataModel.methane = methaneBytes.covertDataValue()
-
- dataModel.methaneState = when (bytes[5]) {
- 1 -> "温控故障"
- 2 -> "激光未打开"
- else -> "正常"
- }
-
- val laserBytes = IntArray(3)
- System.arraycopy(bytes, 6, laserBytes, 0, 3)
- dataModel.laser = laserBytes.covertDataValue()
-
- /**
- * 水平角度的实际范围为从水平零点开始,顺时针方向(从上往下看),0~360°
- * 垂直角度的实际范围为从垂直零点开始,以向上为正,-90°~90°,控制精度为0.01°
- * */
- val horizontalBytes = IntArray(2)
- System.arraycopy(bytes, 9, horizontalBytes, 0, 2)
- dataModel.horizontal = horizontalBytes.covertAngleValue()
-
- val verticalBytes = IntArray(2)
- System.arraycopy(bytes, 11, verticalBytes, 0, 2)
- dataModel.vertical = verticalBytes.covertAngleValue()
-
- //{"horizontal":26.21,"laser":45621,"methane":79846,"methaneState":"正常","vertical":13.91}
- BroadcastManager.obtainInstance(BaseApplication.get()).sendBroadcast(
- LocaleConstant.ACTION_UPDATE_DATA, dataModel.toJson()
- )
- }
- }
-
- override fun onServiceStatusConnectChanged(statusCode: Byte) {
- if (statusCode == ISocketListener.STATUS_CONNECT_SUCCESS) {
- if (nettyClient.connectStatus) {
- Log.d(kTag, "连接成功")
- }
- } else {
- if (!nettyClient.connectStatus) {
- Log.e(kTag, "onServiceStatusConnectChanged:$statusCode,连接断开,正在重连")
- }
- }
- }
-
- fun sendData(data: ByteArray) {
- nettyClient.sendData(data)
- }
-
- fun close() {
- nettyClient.disconnect()
- }
-}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/br/ktd/netty/tcp/ISocketListener.kt b/app/src/main/java/com/casic/br/ktd/netty/tcp/ISocketListener.kt
new file mode 100644
index 0000000..13c3084
--- /dev/null
+++ b/app/src/main/java/com/casic/br/ktd/netty/tcp/ISocketListener.kt
@@ -0,0 +1,19 @@
+package com.casic.br.ktd.netty.tcp
+
+interface ISocketListener {
+ companion object {
+ const val STATUS_CONNECT_SUCCESS: Byte = 1 //连接成功
+ const val STATUS_CONNECT_CLOSED: Byte = 0 //关闭连接
+ const val STATUS_CONNECT_ERROR: Byte = 0 //连接失败
+ }
+
+ /**
+ * 当接收到系统消息
+ */
+ fun onMessageResponse(data: ByteArray?)
+
+ /**
+ * 当连接状态发生变化时调用
+ */
+ fun onServiceStatusConnectChanged(statusCode: Byte)
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/br/ktd/netty/tcp/SocketChannelHandle.kt b/app/src/main/java/com/casic/br/ktd/netty/tcp/SocketChannelHandle.kt
new file mode 100644
index 0000000..8e2997f
--- /dev/null
+++ b/app/src/main/java/com/casic/br/ktd/netty/tcp/SocketChannelHandle.kt
@@ -0,0 +1,51 @@
+package com.casic.br.ktd.netty.tcp
+
+import android.util.Log
+import io.netty.channel.ChannelHandlerContext
+import io.netty.channel.SimpleChannelInboundHandler
+import io.netty.handler.timeout.IdleState
+import io.netty.handler.timeout.IdleStateEvent
+import java.nio.charset.StandardCharsets
+
+class SocketChannelHandle(private val listener: ISocketListener?) :
+ SimpleChannelInboundHandler() {
+
+ private val kTag = "SocketChannelHandle"
+
+ override fun channelActive(ctx: ChannelHandlerContext) {
+ super.channelActive(ctx)
+ Log.d(kTag, "channelActive ===> 连接成功")
+ listener?.onServiceStatusConnectChanged(ISocketListener.STATUS_CONNECT_SUCCESS)
+ }
+
+ override fun channelInactive(ctx: ChannelHandlerContext) {
+ super.channelInactive(ctx)
+ Log.e(kTag, "channelInactive: 连接断开")
+ }
+
+ override fun userEventTriggered(ctx: ChannelHandlerContext, evt: Any) {
+ super.userEventTriggered(ctx, evt)
+ if (evt is IdleStateEvent) {
+ if (evt.state() == IdleState.WRITER_IDLE) {
+ //写超时,此时可以发送心跳数据给服务器
+ val temp = "FF"
+ ctx.writeAndFlush(temp.toByteArray(StandardCharsets.UTF_8))
+ } else if (evt.state() == IdleState.READER_IDLE) {
+ //读超时,此时代表没有收到心跳返回可以关闭当前连接进行重连
+ ctx.close()
+ }
+ }
+ }
+
+ override fun channelRead0(ctx: ChannelHandlerContext, data: ByteArray?) {
+ listener?.onMessageResponse(data)
+ }
+
+ override fun exceptionCaught(ctx: ChannelHandlerContext, cause: Throwable) {
+ super.exceptionCaught(ctx, cause)
+ Log.d(kTag, "exceptionCaught ===> $cause")
+ listener?.onServiceStatusConnectChanged(ISocketListener.STATUS_CONNECT_ERROR)
+ cause.printStackTrace()
+ ctx.close()
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/br/ktd/netty/tcp/SocketClient.kt b/app/src/main/java/com/casic/br/ktd/netty/tcp/SocketClient.kt
new file mode 100644
index 0000000..34960a0
--- /dev/null
+++ b/app/src/main/java/com/casic/br/ktd/netty/tcp/SocketClient.kt
@@ -0,0 +1,153 @@
+package com.casic.br.ktd.netty.tcp
+
+import android.os.SystemClock
+import android.util.Log
+import io.netty.bootstrap.Bootstrap
+import io.netty.channel.*
+import io.netty.channel.nio.NioEventLoopGroup
+import io.netty.channel.socket.SocketChannel
+import io.netty.channel.socket.nio.NioSocketChannel
+import io.netty.handler.codec.bytes.ByteArrayDecoder
+import io.netty.handler.codec.bytes.ByteArrayEncoder
+import io.netty.handler.timeout.IdleStateHandler
+
+class SocketClient {
+
+ private val kTag = "SocketClient"
+
+ private var host: String? = null
+ private var port = 8000
+ private var nioEventLoopGroup: NioEventLoopGroup? = null
+ private var channel: Channel? = null
+ private var listener: ISocketListener? = null
+
+ //现在连接的状态
+ var connectStatus = false //判断是否已连接
+ private var reconnectNum = Int.MAX_VALUE //定义的重连到时候用
+ private var isNeedReconnect = true //是否需要重连
+ var isConnecting = false //是否正在连接
+ private set
+ private var reconnectIntervalTime: Long = 15000 //重连的时间
+
+ //重连时间
+ fun setReconnectNum(reconnectNum: Int) {
+ this.reconnectNum = reconnectNum
+ }
+
+ fun setReconnectIntervalTime(reconnectIntervalTime: Long) {
+ this.reconnectIntervalTime = reconnectIntervalTime
+ }
+
+ fun setSocketListener(listener: ISocketListener?) {
+ this.listener = listener
+ }
+
+ fun connect(host: String, port: Int) {
+ this.host = host
+ this.port = port
+ Log.d(kTag, "connect ===> 开始连接TCP服务器")
+ if (isConnecting) {
+ return
+ }
+ //起个线程
+ val clientThread: Thread = object : Thread("client-Netty") {
+ override fun run() {
+ super.run()
+ isNeedReconnect = true
+ reconnectNum = Int.MAX_VALUE
+ connectServer()
+ }
+ }
+ clientThread.start()
+ }
+
+ private fun connectServer() {
+ synchronized(this@SocketClient) {
+ var channelFuture: ChannelFuture? = null //连接管理对象
+ if (!connectStatus) {
+ isConnecting = true
+ nioEventLoopGroup = NioEventLoopGroup() //设置的连接group
+ val bootstrap = Bootstrap()
+ bootstrap.group(nioEventLoopGroup) //设置的一系列连接参数操作等
+ .channel(NioSocketChannel::class.java)
+ .option(ChannelOption.TCP_NODELAY, true) //无阻塞
+ .option(ChannelOption.SO_KEEPALIVE, true) //长连接
+ .option(
+ ChannelOption.RCVBUF_ALLOCATOR,
+ AdaptiveRecvByteBufAllocator(5000, 5000, 8000)
+ ) //接收缓冲区 最小值太小时数据接收不全
+ .handler(object : ChannelInitializer() {
+ override fun initChannel(channel: SocketChannel) {
+ val pipeline = channel.pipeline()
+ //参数1:代表读套接字超时的时间,没收到数据会触发读超时回调;
+ //参数2:代表写套接字超时时间,没进行写会触发写超时回调;
+ //参数3:将在未执行读取或写入时触发超时回调,0代表不处理;
+ //读超时尽量设置大于写超时,代表多次写超时时写心跳包,多次写了心跳数据仍然读超时代表当前连接错误,即可断开连接重新连接
+ pipeline.addLast(IdleStateHandler(60, 10, 0))
+ pipeline.addLast(ByteArrayDecoder())
+ pipeline.addLast(ByteArrayEncoder())
+ pipeline.addLast(SocketChannelHandle(listener))
+ }
+ })
+ try {
+ //连接监听
+ channelFuture = bootstrap.connect(host, port)
+ .addListener(object : ChannelFutureListener {
+ override fun operationComplete(channelFuture: ChannelFuture) {
+ if (channelFuture.isSuccess) {
+ connectStatus = true
+ channel = channelFuture.channel()
+ } else {
+ Log.e(kTag, "operationComplete: 连接失败")
+ connectStatus = false
+ }
+ isConnecting = false
+ }
+ }).sync()
+ // 等待连接关闭
+ channelFuture.channel().closeFuture().sync()
+ } catch (e: Exception) {
+ e.printStackTrace()
+ } finally {
+ connectStatus = false
+ listener?.onServiceStatusConnectChanged(ISocketListener.STATUS_CONNECT_CLOSED) //STATUS_CONNECT_CLOSED 这我自己定义的 接口标识
+ if (null != channelFuture) {
+ if (channelFuture.channel() != null && channelFuture.channel().isOpen) {
+ channelFuture.channel().close()
+ }
+ }
+ nioEventLoopGroup?.shutdownGracefully()
+ reconnect() //重新连接
+ }
+ }
+ }
+ }
+
+ //断开连接
+ fun disconnect() {
+ Log.d(kTag, "disconnect ===> 断开连接")
+ isNeedReconnect = false
+ nioEventLoopGroup?.shutdownGracefully()
+ }
+
+ //重新连接
+ private fun reconnect() {
+ if (isNeedReconnect && reconnectNum > 0 && !connectStatus) {
+ reconnectNum--
+ SystemClock.sleep(reconnectIntervalTime)
+ if (isNeedReconnect && reconnectNum > 0 && !connectStatus) {
+ Log.d(kTag, "reconnect ===> 重新连接")
+ connectServer()
+ }
+ }
+ }
+
+ fun sendData(bytes: ByteArray) {
+ channel?.writeAndFlush(bytes)?.addListener(ChannelFutureListener { future ->
+ if (!future.isSuccess) {
+ future.channel().close()
+ nioEventLoopGroup!!.shutdownGracefully()
+ }
+ })
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index e822df6..d72c1a5 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -7,6 +7,9 @@
+
+
+
@@ -46,5 +49,8 @@
+
+
+
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/br/ktd/base/KotlinBaseFragment.kt b/app/src/main/java/com/casic/br/ktd/base/KotlinBaseFragment.kt
new file mode 100644
index 0000000..2dac61c
--- /dev/null
+++ b/app/src/main/java/com/casic/br/ktd/base/KotlinBaseFragment.kt
@@ -0,0 +1,51 @@
+package com.casic.br.ktd.base
+
+import android.os.Bundle
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import androidx.annotation.LayoutRes
+import androidx.fragment.app.Fragment
+
+abstract class KotlinBaseFragment : Fragment() {
+
+ lateinit var bv: View
+
+ override fun onCreateView(
+ inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?
+ ): View? {
+ bv = inflater.inflate(initLayoutRes(), container, false)
+ initView(savedInstanceState)
+ setupTopBarLayout()
+ return bv
+ }
+
+ override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
+ super.onViewCreated(view, savedInstanceState)
+ observeRequestState()
+ initEvent()
+ }
+
+ @LayoutRes
+ abstract fun initLayoutRes(): Int
+
+ /**
+ * 沉浸式状态栏
+ */
+ abstract fun setupTopBarLayout()
+
+ /**
+ * 初始化布局以及控件
+ */
+ abstract fun initView(savedInstanceState: Bundle?)
+
+ /**
+ * 网络请求状态监听
+ */
+ abstract fun observeRequestState()
+
+ /**
+ * 业务逻辑,按钮等事件
+ */
+ abstract fun initEvent()
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/br/ktd/fragment/AlarmPageFragment.kt b/app/src/main/java/com/casic/br/ktd/fragment/AlarmPageFragment.kt
index 6c98a3b..9418169 100644
--- a/app/src/main/java/com/casic/br/ktd/fragment/AlarmPageFragment.kt
+++ b/app/src/main/java/com/casic/br/ktd/fragment/AlarmPageFragment.kt
@@ -2,28 +2,29 @@
import android.os.Bundle
import com.casic.br.ktd.R
+import com.casic.br.ktd.base.KotlinBaseFragment
import com.casic.br.ktd.widgets.DateRangeActionSheet
-import com.pengxh.kt.lite.base.KotlinBaseFragment
import kotlinx.android.synthetic.main.fragment_alarm.view.*
class AlarmPageFragment : KotlinBaseFragment() {
- override fun initData(savedInstanceState: Bundle?) {
+
+ override fun initView(savedInstanceState: Bundle?) {
}
override fun initEvent() {
- baseView.calendarView.setOnClickListener {
+ bv.calendarView.setOnClickListener {
DateRangeActionSheet.Builder().setContext(requireContext())
.setOnActionSheetListener(object :
DateRangeActionSheet.OnDateRangeSelectedListener {
override fun onDateRangeSelected(startDate: String, endDate: String) {
- baseView.selectedDateView.text = "$startDate ~ $endDate"
+ bv.selectedDateView.text = "$startDate ~ $endDate"
}
}).build().show()
}
}
- override fun initLayoutView(): Int = R.layout.fragment_alarm
+ override fun initLayoutRes(): Int = R.layout.fragment_alarm
override fun observeRequestState() {
diff --git a/app/src/main/java/com/casic/br/ktd/fragment/HomePageFragment.kt b/app/src/main/java/com/casic/br/ktd/fragment/HomePageFragment.kt
index 9961935..f3eba5c 100644
--- a/app/src/main/java/com/casic/br/ktd/fragment/HomePageFragment.kt
+++ b/app/src/main/java/com/casic/br/ktd/fragment/HomePageFragment.kt
@@ -1,32 +1,62 @@
package com.casic.br.ktd.fragment
+import android.graphics.Color
import android.os.Bundle
import com.amap.api.maps.AMap
import com.amap.api.maps.AMapOptions
+import com.amap.api.maps.CameraUpdateFactory
+import com.amap.api.maps.model.*
import com.casic.br.ktd.R
-import com.pengxh.kt.lite.base.KotlinBaseFragment
+import com.casic.br.ktd.base.KotlinBaseFragment
import kotlinx.android.synthetic.main.fragment_home.view.*
class HomePageFragment : KotlinBaseFragment() {
private lateinit var aMap: AMap
- override fun initData(savedInstanceState: Bundle?) {
- baseView.mapView.onCreate(savedInstanceState)
- aMap = baseView.mapView.map
+ override fun initView(savedInstanceState: Bundle?) {
+ bv.mapView.onCreate(savedInstanceState)
+ aMap = bv.mapView.map
val uiSettings = aMap.uiSettings
uiSettings.isCompassEnabled = true
- uiSettings.isMyLocationButtonEnabled = true
+ uiSettings.isMyLocationButtonEnabled = false
uiSettings.isScaleControlsEnabled = true
uiSettings.zoomPosition = AMapOptions.ZOOM_POSITION_RIGHT_CENTER
uiSettings.isRotateGesturesEnabled = false//不许地图随手势旋转角度
}
override fun initEvent() {
-
+ //移动到巡检起始经纬度
+ val cameraPosition = CameraPosition(LatLng(39.914199, 116.265785), 16f, 0f, 0f)
+ val cameraUpdate = CameraUpdateFactory.newCameraPosition(cameraPosition)
+ aMap.animateCamera(cameraUpdate, 1500, null)
+ //设置起点
+ addMarker(LatLng(39.914885, 116.272312), R.mipmap.start)
+ //设置终点
+ addMarker(LatLng(39.914716, 116.265097), R.mipmap.end)
+ //瞄点画线
+ val latLngPoints = ArrayList()
+ latLngPoints.add(LatLng(39.914885, 116.272312))
+ latLngPoints.add(LatLng(39.915148, 116.272312))
+ latLngPoints.add(LatLng(39.915399, 116.272302))
+ latLngPoints.add(LatLng(39.915436, 116.271787))
+ latLngPoints.add(LatLng(39.915477, 116.270886))
+ latLngPoints.add(LatLng(39.915477, 116.269968))
+ latLngPoints.add(LatLng(39.915469, 116.269544))
+ latLngPoints.add(LatLng(39.915481, 116.269196))
+ latLngPoints.add(LatLng(39.915452, 116.268472))
+ latLngPoints.add(LatLng(39.915444, 116.267722))
+ latLngPoints.add(LatLng(39.915415, 116.266755))
+ latLngPoints.add(LatLng(39.915403, 116.266165))
+ latLngPoints.add(LatLng(39.915395, 116.265703))
+ latLngPoints.add(LatLng(39.915366, 116.265119))
+ latLngPoints.add(LatLng(39.914716, 116.265097))
+ aMap.addPolyline(
+ PolylineOptions().addAll(latLngPoints).width(10.toFloat()).color(Color.RED)
+ )
}
- override fun initLayoutView(): Int = R.layout.fragment_home
+ override fun initLayoutRes(): Int = R.layout.fragment_home
override fun observeRequestState() {
@@ -36,25 +66,32 @@
}
+ private fun addMarker(point: LatLng, res: Int) {
+ val markerOption = MarkerOptions()
+ markerOption.position(point)
+ markerOption.icon(BitmapDescriptorFactory.fromResource(res))
+ aMap.addMarker(markerOption)
+ }
+
/***以下是地图生命周期管理************************************************************************/
override fun onResume() {
super.onResume()
- baseView.mapView.onResume()
+ bv.mapView.onResume()
}
override fun onPause() {
- baseView.mapView.onPause()
super.onPause()
+ bv.mapView.onPause()
}
override fun onSaveInstanceState(outState: Bundle) {
super.onSaveInstanceState(outState)
- baseView.mapView.onSaveInstanceState(outState)
+ bv.mapView.onSaveInstanceState(outState)
}
override fun onDestroy() {
- baseView.mapView.onDestroy()
super.onDestroy()
+ bv.mapView.onDestroy()
}
}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/br/ktd/fragment/MinePageFragment.kt b/app/src/main/java/com/casic/br/ktd/fragment/MinePageFragment.kt
index 90313ac..3212794 100644
--- a/app/src/main/java/com/casic/br/ktd/fragment/MinePageFragment.kt
+++ b/app/src/main/java/com/casic/br/ktd/fragment/MinePageFragment.kt
@@ -2,10 +2,11 @@
import android.os.Bundle
import com.casic.br.ktd.R
-import com.pengxh.kt.lite.base.KotlinBaseFragment
+import com.casic.br.ktd.base.KotlinBaseFragment
class MinePageFragment : KotlinBaseFragment() {
- override fun initData(savedInstanceState: Bundle?) {
+
+ override fun initView(savedInstanceState: Bundle?) {
}
@@ -13,7 +14,7 @@
}
- override fun initLayoutView(): Int = R.layout.fragment_mine
+ override fun initLayoutRes(): Int = R.layout.fragment_mine
override fun observeRequestState() {
diff --git a/app/src/main/java/com/casic/br/ktd/fragment/TaskPageFragment.kt b/app/src/main/java/com/casic/br/ktd/fragment/TaskPageFragment.kt
index 8f6abf0..6b82a54 100644
--- a/app/src/main/java/com/casic/br/ktd/fragment/TaskPageFragment.kt
+++ b/app/src/main/java/com/casic/br/ktd/fragment/TaskPageFragment.kt
@@ -8,6 +8,7 @@
import androidx.recyclerview.widget.RecyclerView
import com.casic.br.ktd.R
import com.casic.br.ktd.adapter.TaskAdapter
+import com.casic.br.ktd.base.KotlinBaseFragment
import com.casic.br.ktd.holder.SwipeViewHolder
import com.casic.br.ktd.model.TaskListModel
import com.casic.br.ktd.view.InspectionActivity
@@ -15,7 +16,6 @@
import com.casic.br.ktd.widgets.AlertControlDialog
import com.casic.br.ktd.widgets.AlertInputDialog
import com.casic.br.ktd.widgets.DateRangeActionSheet
-import com.pengxh.kt.lite.base.KotlinBaseFragment
import com.pengxh.kt.lite.extensions.navigatePageTo
import com.pengxh.kt.lite.extensions.show
import com.pengxh.kt.lite.utils.WeakReferenceHandler
@@ -36,7 +36,7 @@
private var startTime = ""
private var endTime = ""
- override fun initData(savedInstanceState: Bundle?) {
+ override fun initView(savedInstanceState: Bundle?) {
weakReferenceHandler = WeakReferenceHandler(this)
taskViewModel = ViewModelProvider(this)[TaskViewModel::class.java]
taskViewModel.taskList.observe(this) {
@@ -45,7 +45,7 @@
when {
isRefresh -> {
taskAdapter.setRefreshData(dataRows)
- baseView.taskLayout.finishRefresh()
+ bv.taskLayout.finishRefresh()
isRefresh = false
}
isLoadMore -> {
@@ -53,7 +53,7 @@
"到底了,别拉了".show(requireContext())
}
taskAdapter.setLoadMoreData(dataRows)
- baseView.taskLayout.finishLoadMore()
+ bv.taskLayout.finishLoadMore()
isLoadMore = false
}
else -> {
@@ -76,9 +76,9 @@
when (msg.what) {
2023070501 -> {
if (dataBeans.size == 0) {
- baseView.emptyLayout.visibility = View.VISIBLE
+ bv.emptyLayout.visibility = View.VISIBLE
} else {
- baseView.emptyLayout.visibility = View.GONE
+ bv.emptyLayout.visibility = View.GONE
taskAdapter = object : TaskAdapter(
requireContext(), R.layout.item_task_rv_l, dataBeans
) {
@@ -97,8 +97,8 @@
}
}
//绑定侧滑事件
- swipeAction.attachToRecyclerView(baseView.taskRecyclerView)
- baseView.taskRecyclerView.adapter = taskAdapter
+ swipeAction.attachToRecyclerView(bv.taskRecyclerView)
+ bv.taskRecyclerView.adapter = taskAdapter
taskAdapter.setOnItemCheckedListener(object :
TaskAdapter.OnItemCheckedListener {
override fun onItemChecked(items: ArrayList) {
@@ -168,7 +168,7 @@
override fun initEvent() {
- baseView.calendarView.setOnClickListener {
+ bv.calendarView.setOnClickListener {
DateRangeActionSheet.Builder().setContext(requireContext())
.setOnActionSheetListener(object :
DateRangeActionSheet.OnDateRangeSelectedListener {
@@ -177,12 +177,12 @@
endTime = endDate
//显示
- baseView.selectedDateView.text = "$startDate ~ $endDate"
+ bv.selectedDateView.text = "$startDate ~ $endDate"
}
}).build().show()
}
- baseView.addTaskButton.setOnClickListener {
+ bv.addTaskButton.setOnClickListener {
// AlertInputDialog.Builder()
// .setContext(requireContext())
// .setTitle("新建巡检任务")
@@ -200,11 +200,11 @@
requireContext().navigatePageTo()
}
- baseView.deleteTaskButton.setOnClickListener {
+ bv.deleteTaskButton.setOnClickListener {
selectedItems.size.toString().show(requireContext())
}
- baseView.taskSettingsButton.setOnClickListener {
+ bv.taskSettingsButton.setOnClickListener {
AlertInputDialog.Builder()
.setContext(requireContext())
.setTitle("设置阈值")
@@ -221,14 +221,14 @@
}).build().show()
}
- baseView.taskLayout.setOnRefreshListener {
+ bv.taskLayout.setOnRefreshListener {
isRefresh = true
//刷新之后页码重置
pageIndex = 1
getTaskList()
}
- baseView.taskLayout.setOnLoadMoreListener {
+ bv.taskLayout.setOnLoadMoreListener {
isLoadMore = true
pageIndex++
getTaskList()
@@ -239,13 +239,13 @@
taskViewModel.getTaskList(
startTime,
endTime,
- baseView.taskNameView.text.toString(),
- baseView.taskCodeView.text.toString(),
+ bv.taskNameView.text.toString(),
+ bv.taskCodeView.text.toString(),
pageIndex
)
}
- override fun initLayoutView(): Int = R.layout.fragment_task
+ override fun initLayoutRes(): Int = R.layout.fragment_task
override fun observeRequestState() {
diff --git a/app/src/main/java/com/casic/br/ktd/netty/ISocketListener.kt b/app/src/main/java/com/casic/br/ktd/netty/ISocketListener.kt
deleted file mode 100644
index dab98e1..0000000
--- a/app/src/main/java/com/casic/br/ktd/netty/ISocketListener.kt
+++ /dev/null
@@ -1,19 +0,0 @@
-package com.casic.br.ktd.netty
-
-interface ISocketListener {
- companion object {
- const val STATUS_CONNECT_SUCCESS: Byte = 1 //连接成功
- const val STATUS_CONNECT_CLOSED: Byte = 0 //关闭连接
- const val STATUS_CONNECT_ERROR: Byte = 0 //连接失败
- }
-
- /**
- * 当接收到系统消息
- */
- fun onMessageResponse(data: ByteArray?)
-
- /**
- * 当连接状态发生变化时调用
- */
- fun onServiceStatusConnectChanged(statusCode: Byte)
-}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/br/ktd/netty/SocketChannelHandle.kt b/app/src/main/java/com/casic/br/ktd/netty/SocketChannelHandle.kt
deleted file mode 100644
index 42eb310..0000000
--- a/app/src/main/java/com/casic/br/ktd/netty/SocketChannelHandle.kt
+++ /dev/null
@@ -1,51 +0,0 @@
-package com.casic.br.ktd.netty
-
-import android.util.Log
-import io.netty.channel.ChannelHandlerContext
-import io.netty.channel.SimpleChannelInboundHandler
-import io.netty.handler.timeout.IdleState
-import io.netty.handler.timeout.IdleStateEvent
-import java.nio.charset.StandardCharsets
-
-class SocketChannelHandle(private val listener: ISocketListener?) :
- SimpleChannelInboundHandler() {
-
- private val kTag = "SocketChannelHandle"
-
- override fun channelActive(ctx: ChannelHandlerContext) {
- super.channelActive(ctx)
- Log.d(kTag, "channelActive ===> 连接成功")
- listener?.onServiceStatusConnectChanged(ISocketListener.STATUS_CONNECT_SUCCESS)
- }
-
- override fun channelInactive(ctx: ChannelHandlerContext) {
- super.channelInactive(ctx)
- Log.e(kTag, "channelInactive: 连接断开")
- }
-
- override fun userEventTriggered(ctx: ChannelHandlerContext, evt: Any) {
- super.userEventTriggered(ctx, evt)
- if (evt is IdleStateEvent) {
- if (evt.state() == IdleState.WRITER_IDLE) {
- //写超时,此时可以发送心跳数据给服务器
- val temp = "FF"
- ctx.writeAndFlush(temp.toByteArray(StandardCharsets.UTF_8))
- } else if (evt.state() == IdleState.READER_IDLE) {
- //读超时,此时代表没有收到心跳返回可以关闭当前连接进行重连
- ctx.close()
- }
- }
- }
-
- override fun channelRead0(ctx: ChannelHandlerContext, data: ByteArray?) {
- listener?.onMessageResponse(data)
- }
-
- override fun exceptionCaught(ctx: ChannelHandlerContext, cause: Throwable) {
- super.exceptionCaught(ctx, cause)
- Log.d(kTag, "exceptionCaught ===> $cause")
- listener?.onServiceStatusConnectChanged(ISocketListener.STATUS_CONNECT_ERROR)
- cause.printStackTrace()
- ctx.close()
- }
-}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/br/ktd/netty/SocketClient.kt b/app/src/main/java/com/casic/br/ktd/netty/SocketClient.kt
deleted file mode 100644
index d05d335..0000000
--- a/app/src/main/java/com/casic/br/ktd/netty/SocketClient.kt
+++ /dev/null
@@ -1,153 +0,0 @@
-package com.casic.br.ktd.netty
-
-import android.os.SystemClock
-import android.util.Log
-import io.netty.bootstrap.Bootstrap
-import io.netty.channel.*
-import io.netty.channel.nio.NioEventLoopGroup
-import io.netty.channel.socket.SocketChannel
-import io.netty.channel.socket.nio.NioSocketChannel
-import io.netty.handler.codec.bytes.ByteArrayDecoder
-import io.netty.handler.codec.bytes.ByteArrayEncoder
-import io.netty.handler.timeout.IdleStateHandler
-
-class SocketClient {
-
- private val kTag = "SocketClient"
-
- private var host: String? = null
- private var port = 8000
- private var nioEventLoopGroup: NioEventLoopGroup? = null
- private var channel: Channel? = null
- private var listener: ISocketListener? = null
-
- //现在连接的状态
- var connectStatus = false //判断是否已连接
- private var reconnectNum = Int.MAX_VALUE //定义的重连到时候用
- private var isNeedReconnect = true //是否需要重连
- var isConnecting = false //是否正在连接
- private set
- private var reconnectIntervalTime: Long = 15000 //重连的时间
-
- //重连时间
- fun setReconnectNum(reconnectNum: Int) {
- this.reconnectNum = reconnectNum
- }
-
- fun setReconnectIntervalTime(reconnectIntervalTime: Long) {
- this.reconnectIntervalTime = reconnectIntervalTime
- }
-
- fun setSocketListener(listener: ISocketListener?) {
- this.listener = listener
- }
-
- fun connect(host: String, port: Int) {
- this.host = host
- this.port = port
- Log.d(kTag, "connect ===> 开始连接TCP服务器")
- if (isConnecting) {
- return
- }
- //起个线程
- val clientThread: Thread = object : Thread("client-Netty") {
- override fun run() {
- super.run()
- isNeedReconnect = true
- reconnectNum = Int.MAX_VALUE
- connectServer()
- }
- }
- clientThread.start()
- }
-
- private fun connectServer() {
- synchronized(this@SocketClient) {
- var channelFuture: ChannelFuture? = null //连接管理对象
- if (!connectStatus) {
- isConnecting = true
- nioEventLoopGroup = NioEventLoopGroup() //设置的连接group
- val bootstrap = Bootstrap()
- bootstrap.group(nioEventLoopGroup) //设置的一系列连接参数操作等
- .channel(NioSocketChannel::class.java)
- .option(ChannelOption.TCP_NODELAY, true) //无阻塞
- .option(ChannelOption.SO_KEEPALIVE, true) //长连接
- .option(
- ChannelOption.RCVBUF_ALLOCATOR,
- AdaptiveRecvByteBufAllocator(5000, 5000, 8000)
- ) //接收缓冲区 最小值太小时数据接收不全
- .handler(object : ChannelInitializer() {
- override fun initChannel(channel: SocketChannel) {
- val pipeline = channel.pipeline()
- //参数1:代表读套接字超时的时间,没收到数据会触发读超时回调;
- //参数2:代表写套接字超时时间,没进行写会触发写超时回调;
- //参数3:将在未执行读取或写入时触发超时回调,0代表不处理;
- //读超时尽量设置大于写超时,代表多次写超时时写心跳包,多次写了心跳数据仍然读超时代表当前连接错误,即可断开连接重新连接
- pipeline.addLast(IdleStateHandler(60, 10, 0))
- pipeline.addLast(ByteArrayDecoder())
- pipeline.addLast(ByteArrayEncoder())
- pipeline.addLast(SocketChannelHandle(listener))
- }
- })
- try {
- //连接监听
- channelFuture = bootstrap.connect(host, port)
- .addListener(object : ChannelFutureListener {
- override fun operationComplete(channelFuture: ChannelFuture) {
- if (channelFuture.isSuccess) {
- connectStatus = true
- channel = channelFuture.channel()
- } else {
- Log.e(kTag, "operationComplete: 连接失败")
- connectStatus = false
- }
- isConnecting = false
- }
- }).sync()
- // 等待连接关闭
- channelFuture.channel().closeFuture().sync()
- } catch (e: Exception) {
- e.printStackTrace()
- } finally {
- connectStatus = false
- listener?.onServiceStatusConnectChanged(ISocketListener.STATUS_CONNECT_CLOSED) //STATUS_CONNECT_CLOSED 这我自己定义的 接口标识
- if (null != channelFuture) {
- if (channelFuture.channel() != null && channelFuture.channel().isOpen) {
- channelFuture.channel().close()
- }
- }
- nioEventLoopGroup?.shutdownGracefully()
- reconnect() //重新连接
- }
- }
- }
- }
-
- //断开连接
- fun disconnect() {
- Log.d(kTag, "disconnect ===> 断开连接")
- isNeedReconnect = false
- nioEventLoopGroup?.shutdownGracefully()
- }
-
- //重新连接
- private fun reconnect() {
- if (isNeedReconnect && reconnectNum > 0 && !connectStatus) {
- reconnectNum--
- SystemClock.sleep(reconnectIntervalTime)
- if (isNeedReconnect && reconnectNum > 0 && !connectStatus) {
- Log.d(kTag, "reconnect ===> 重新连接")
- connectServer()
- }
- }
- }
-
- fun sendData(bytes: ByteArray) {
- channel?.writeAndFlush(bytes)?.addListener(ChannelFutureListener { future ->
- if (!future.isSuccess) {
- future.channel().close()
- nioEventLoopGroup!!.shutdownGracefully()
- }
- })
- }
-}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/br/ktd/netty/SocketManager.kt b/app/src/main/java/com/casic/br/ktd/netty/SocketManager.kt
deleted file mode 100644
index 17daf35..0000000
--- a/app/src/main/java/com/casic/br/ktd/netty/SocketManager.kt
+++ /dev/null
@@ -1,113 +0,0 @@
-package com.casic.br.ktd.netty
-
-import android.util.Log
-import com.casic.br.ktd.base.BaseApplication
-import com.casic.br.ktd.extensions.covertAngleValue
-import com.casic.br.ktd.extensions.covertDataValue
-import com.casic.br.ktd.extensions.toUnsignedByteArray
-import com.casic.br.ktd.model.SensorDataModel
-import com.casic.br.ktd.utils.LocaleConstant
-import com.pengxh.kt.lite.extensions.toJson
-import com.pengxh.kt.lite.utils.BroadcastManager
-
-class SocketManager private constructor() : ISocketListener {
-
- private val kTag = "SocketManager"
- private var nettyClient: SocketClient = SocketClient()
-
- companion object {
- val instance: SocketManager by lazy(mode = LazyThreadSafetyMode.SYNCHRONIZED) { SocketManager() }
- }
-
- fun connectNetty(hostname: String, port: Int) {
- Thread {
- if (!nettyClient.connectStatus) {
- nettyClient.setSocketListener(this)
- nettyClient.connect(hostname, port)
- } else {
- nettyClient.disconnect()
- }
- }.start()
- }
-
- override fun onMessageResponse(data: ByteArray?) {
-// Log.d(kTag, "onMessageResponse ===> " + Arrays.toString(data))
- /**
- * 0xFF,0x01,
- * 0x01,0x37,0xE6, 甲烷浓度值(数据码1* 65536 + 数据码2 * 256 + 数据码3)
- * 0x00, 激光甲烷模块工作状态(00表示设备正常,01表示温控故障,02表示设备激光未打开)
- * 0x00,0xB2,0x35, 激光强度值(数据码5* 65536 + 数据码6 * 256 + 数据码7)
- * 0x0A,0x3D, 云台水平角度([数据码8 * 256 + 数据码9]/100,单位为°,精确到0.01)
- * 0x05,0x6F, 云台垂直角度(首先计算Tangle=[数据码10 * 256 + 数据码11]/100,单位为°,精确到0.01。若Tangle在0~90范围内,则垂直角度值=Tangle;若Tangle在-1~-90范围内,则垂直角度值=Tangle-360)
- * 0xC1
- *
- * [-1, 1, 1, 55, -26, 0, 0, -78, 53, 10, 61, 5, 111, -63]
- * 甲烷浓度值为79638,计算为79638=0x01*65536+0x37*256+0xE6[0x01为数据码1,0x37为数据码2,0xE6为数据码3];
- * 激光甲烷设备状态值为0,表示状态正常,[0x00为数据码4];
- * 激光强度值为45621,计算为45621=0x00*65536+0xB2*256+0x35[0x00为数据码5,0xB2为数据码6,0x35为数据码7];
- *
- * =========================================================================================
- * 实际数据(1800-1950左右)
- * [-86, 1, 0, 7, 71, 0, 0, 62, -92, 57, 59, -118, -111, -64]
- * */
-
- if (data == null) {
- return
- }
- val bytes = data.toUnsignedByteArray()
- if (bytes.size == 14) {
- val dataModel = SensorDataModel(0, "激光未打开", 0, 0.0, 0.0)
-
- val methaneBytes = IntArray(3)
- System.arraycopy(bytes, 2, methaneBytes, 0, 3)
- dataModel.methane = methaneBytes.covertDataValue()
-
- dataModel.methaneState = when (bytes[5]) {
- 1 -> "温控故障"
- 2 -> "激光未打开"
- else -> "正常"
- }
-
- val laserBytes = IntArray(3)
- System.arraycopy(bytes, 6, laserBytes, 0, 3)
- dataModel.laser = laserBytes.covertDataValue()
-
- /**
- * 水平角度的实际范围为从水平零点开始,顺时针方向(从上往下看),0~360°
- * 垂直角度的实际范围为从垂直零点开始,以向上为正,-90°~90°,控制精度为0.01°
- * */
- val horizontalBytes = IntArray(2)
- System.arraycopy(bytes, 9, horizontalBytes, 0, 2)
- dataModel.horizontal = horizontalBytes.covertAngleValue()
-
- val verticalBytes = IntArray(2)
- System.arraycopy(bytes, 11, verticalBytes, 0, 2)
- dataModel.vertical = verticalBytes.covertAngleValue()
-
- //{"horizontal":26.21,"laser":45621,"methane":79846,"methaneState":"正常","vertical":13.91}
- BroadcastManager.obtainInstance(BaseApplication.get()).sendBroadcast(
- LocaleConstant.ACTION_UPDATE_DATA, dataModel.toJson()
- )
- }
- }
-
- override fun onServiceStatusConnectChanged(statusCode: Byte) {
- if (statusCode == ISocketListener.STATUS_CONNECT_SUCCESS) {
- if (nettyClient.connectStatus) {
- Log.d(kTag, "连接成功")
- }
- } else {
- if (!nettyClient.connectStatus) {
- Log.e(kTag, "onServiceStatusConnectChanged:$statusCode,连接断开,正在重连")
- }
- }
- }
-
- fun sendData(data: ByteArray) {
- nettyClient.sendData(data)
- }
-
- fun close() {
- nettyClient.disconnect()
- }
-}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/br/ktd/netty/tcp/ISocketListener.kt b/app/src/main/java/com/casic/br/ktd/netty/tcp/ISocketListener.kt
new file mode 100644
index 0000000..13c3084
--- /dev/null
+++ b/app/src/main/java/com/casic/br/ktd/netty/tcp/ISocketListener.kt
@@ -0,0 +1,19 @@
+package com.casic.br.ktd.netty.tcp
+
+interface ISocketListener {
+ companion object {
+ const val STATUS_CONNECT_SUCCESS: Byte = 1 //连接成功
+ const val STATUS_CONNECT_CLOSED: Byte = 0 //关闭连接
+ const val STATUS_CONNECT_ERROR: Byte = 0 //连接失败
+ }
+
+ /**
+ * 当接收到系统消息
+ */
+ fun onMessageResponse(data: ByteArray?)
+
+ /**
+ * 当连接状态发生变化时调用
+ */
+ fun onServiceStatusConnectChanged(statusCode: Byte)
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/br/ktd/netty/tcp/SocketChannelHandle.kt b/app/src/main/java/com/casic/br/ktd/netty/tcp/SocketChannelHandle.kt
new file mode 100644
index 0000000..8e2997f
--- /dev/null
+++ b/app/src/main/java/com/casic/br/ktd/netty/tcp/SocketChannelHandle.kt
@@ -0,0 +1,51 @@
+package com.casic.br.ktd.netty.tcp
+
+import android.util.Log
+import io.netty.channel.ChannelHandlerContext
+import io.netty.channel.SimpleChannelInboundHandler
+import io.netty.handler.timeout.IdleState
+import io.netty.handler.timeout.IdleStateEvent
+import java.nio.charset.StandardCharsets
+
+class SocketChannelHandle(private val listener: ISocketListener?) :
+ SimpleChannelInboundHandler() {
+
+ private val kTag = "SocketChannelHandle"
+
+ override fun channelActive(ctx: ChannelHandlerContext) {
+ super.channelActive(ctx)
+ Log.d(kTag, "channelActive ===> 连接成功")
+ listener?.onServiceStatusConnectChanged(ISocketListener.STATUS_CONNECT_SUCCESS)
+ }
+
+ override fun channelInactive(ctx: ChannelHandlerContext) {
+ super.channelInactive(ctx)
+ Log.e(kTag, "channelInactive: 连接断开")
+ }
+
+ override fun userEventTriggered(ctx: ChannelHandlerContext, evt: Any) {
+ super.userEventTriggered(ctx, evt)
+ if (evt is IdleStateEvent) {
+ if (evt.state() == IdleState.WRITER_IDLE) {
+ //写超时,此时可以发送心跳数据给服务器
+ val temp = "FF"
+ ctx.writeAndFlush(temp.toByteArray(StandardCharsets.UTF_8))
+ } else if (evt.state() == IdleState.READER_IDLE) {
+ //读超时,此时代表没有收到心跳返回可以关闭当前连接进行重连
+ ctx.close()
+ }
+ }
+ }
+
+ override fun channelRead0(ctx: ChannelHandlerContext, data: ByteArray?) {
+ listener?.onMessageResponse(data)
+ }
+
+ override fun exceptionCaught(ctx: ChannelHandlerContext, cause: Throwable) {
+ super.exceptionCaught(ctx, cause)
+ Log.d(kTag, "exceptionCaught ===> $cause")
+ listener?.onServiceStatusConnectChanged(ISocketListener.STATUS_CONNECT_ERROR)
+ cause.printStackTrace()
+ ctx.close()
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/br/ktd/netty/tcp/SocketClient.kt b/app/src/main/java/com/casic/br/ktd/netty/tcp/SocketClient.kt
new file mode 100644
index 0000000..34960a0
--- /dev/null
+++ b/app/src/main/java/com/casic/br/ktd/netty/tcp/SocketClient.kt
@@ -0,0 +1,153 @@
+package com.casic.br.ktd.netty.tcp
+
+import android.os.SystemClock
+import android.util.Log
+import io.netty.bootstrap.Bootstrap
+import io.netty.channel.*
+import io.netty.channel.nio.NioEventLoopGroup
+import io.netty.channel.socket.SocketChannel
+import io.netty.channel.socket.nio.NioSocketChannel
+import io.netty.handler.codec.bytes.ByteArrayDecoder
+import io.netty.handler.codec.bytes.ByteArrayEncoder
+import io.netty.handler.timeout.IdleStateHandler
+
+class SocketClient {
+
+ private val kTag = "SocketClient"
+
+ private var host: String? = null
+ private var port = 8000
+ private var nioEventLoopGroup: NioEventLoopGroup? = null
+ private var channel: Channel? = null
+ private var listener: ISocketListener? = null
+
+ //现在连接的状态
+ var connectStatus = false //判断是否已连接
+ private var reconnectNum = Int.MAX_VALUE //定义的重连到时候用
+ private var isNeedReconnect = true //是否需要重连
+ var isConnecting = false //是否正在连接
+ private set
+ private var reconnectIntervalTime: Long = 15000 //重连的时间
+
+ //重连时间
+ fun setReconnectNum(reconnectNum: Int) {
+ this.reconnectNum = reconnectNum
+ }
+
+ fun setReconnectIntervalTime(reconnectIntervalTime: Long) {
+ this.reconnectIntervalTime = reconnectIntervalTime
+ }
+
+ fun setSocketListener(listener: ISocketListener?) {
+ this.listener = listener
+ }
+
+ fun connect(host: String, port: Int) {
+ this.host = host
+ this.port = port
+ Log.d(kTag, "connect ===> 开始连接TCP服务器")
+ if (isConnecting) {
+ return
+ }
+ //起个线程
+ val clientThread: Thread = object : Thread("client-Netty") {
+ override fun run() {
+ super.run()
+ isNeedReconnect = true
+ reconnectNum = Int.MAX_VALUE
+ connectServer()
+ }
+ }
+ clientThread.start()
+ }
+
+ private fun connectServer() {
+ synchronized(this@SocketClient) {
+ var channelFuture: ChannelFuture? = null //连接管理对象
+ if (!connectStatus) {
+ isConnecting = true
+ nioEventLoopGroup = NioEventLoopGroup() //设置的连接group
+ val bootstrap = Bootstrap()
+ bootstrap.group(nioEventLoopGroup) //设置的一系列连接参数操作等
+ .channel(NioSocketChannel::class.java)
+ .option(ChannelOption.TCP_NODELAY, true) //无阻塞
+ .option(ChannelOption.SO_KEEPALIVE, true) //长连接
+ .option(
+ ChannelOption.RCVBUF_ALLOCATOR,
+ AdaptiveRecvByteBufAllocator(5000, 5000, 8000)
+ ) //接收缓冲区 最小值太小时数据接收不全
+ .handler(object : ChannelInitializer() {
+ override fun initChannel(channel: SocketChannel) {
+ val pipeline = channel.pipeline()
+ //参数1:代表读套接字超时的时间,没收到数据会触发读超时回调;
+ //参数2:代表写套接字超时时间,没进行写会触发写超时回调;
+ //参数3:将在未执行读取或写入时触发超时回调,0代表不处理;
+ //读超时尽量设置大于写超时,代表多次写超时时写心跳包,多次写了心跳数据仍然读超时代表当前连接错误,即可断开连接重新连接
+ pipeline.addLast(IdleStateHandler(60, 10, 0))
+ pipeline.addLast(ByteArrayDecoder())
+ pipeline.addLast(ByteArrayEncoder())
+ pipeline.addLast(SocketChannelHandle(listener))
+ }
+ })
+ try {
+ //连接监听
+ channelFuture = bootstrap.connect(host, port)
+ .addListener(object : ChannelFutureListener {
+ override fun operationComplete(channelFuture: ChannelFuture) {
+ if (channelFuture.isSuccess) {
+ connectStatus = true
+ channel = channelFuture.channel()
+ } else {
+ Log.e(kTag, "operationComplete: 连接失败")
+ connectStatus = false
+ }
+ isConnecting = false
+ }
+ }).sync()
+ // 等待连接关闭
+ channelFuture.channel().closeFuture().sync()
+ } catch (e: Exception) {
+ e.printStackTrace()
+ } finally {
+ connectStatus = false
+ listener?.onServiceStatusConnectChanged(ISocketListener.STATUS_CONNECT_CLOSED) //STATUS_CONNECT_CLOSED 这我自己定义的 接口标识
+ if (null != channelFuture) {
+ if (channelFuture.channel() != null && channelFuture.channel().isOpen) {
+ channelFuture.channel().close()
+ }
+ }
+ nioEventLoopGroup?.shutdownGracefully()
+ reconnect() //重新连接
+ }
+ }
+ }
+ }
+
+ //断开连接
+ fun disconnect() {
+ Log.d(kTag, "disconnect ===> 断开连接")
+ isNeedReconnect = false
+ nioEventLoopGroup?.shutdownGracefully()
+ }
+
+ //重新连接
+ private fun reconnect() {
+ if (isNeedReconnect && reconnectNum > 0 && !connectStatus) {
+ reconnectNum--
+ SystemClock.sleep(reconnectIntervalTime)
+ if (isNeedReconnect && reconnectNum > 0 && !connectStatus) {
+ Log.d(kTag, "reconnect ===> 重新连接")
+ connectServer()
+ }
+ }
+ }
+
+ fun sendData(bytes: ByteArray) {
+ channel?.writeAndFlush(bytes)?.addListener(ChannelFutureListener { future ->
+ if (!future.isSuccess) {
+ future.channel().close()
+ nioEventLoopGroup!!.shutdownGracefully()
+ }
+ })
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/br/ktd/netty/tcp/SocketManager.kt b/app/src/main/java/com/casic/br/ktd/netty/tcp/SocketManager.kt
new file mode 100644
index 0000000..35980b9
--- /dev/null
+++ b/app/src/main/java/com/casic/br/ktd/netty/tcp/SocketManager.kt
@@ -0,0 +1,113 @@
+package com.casic.br.ktd.netty.tcp
+
+import android.util.Log
+import com.casic.br.ktd.base.BaseApplication
+import com.casic.br.ktd.extensions.covertAngleValue
+import com.casic.br.ktd.extensions.covertDataValue
+import com.casic.br.ktd.extensions.toUnsignedByteArray
+import com.casic.br.ktd.model.SensorDataModel
+import com.casic.br.ktd.utils.LocaleConstant
+import com.pengxh.kt.lite.extensions.toJson
+import com.pengxh.kt.lite.utils.BroadcastManager
+
+class SocketManager private constructor() : ISocketListener {
+
+ private val kTag = "SocketManager"
+ private var nettyClient: SocketClient = SocketClient()
+
+ companion object {
+ val instance: SocketManager by lazy(mode = LazyThreadSafetyMode.SYNCHRONIZED) { SocketManager() }
+ }
+
+ fun connectNetty(hostname: String, port: Int) {
+ Thread {
+ if (!nettyClient.connectStatus) {
+ nettyClient.setSocketListener(this)
+ nettyClient.connect(hostname, port)
+ } else {
+ nettyClient.disconnect()
+ }
+ }.start()
+ }
+
+ override fun onMessageResponse(data: ByteArray?) {
+// Log.d(kTag, "onMessageResponse ===> " + Arrays.toString(data))
+ /**
+ * 0xFF,0x01,
+ * 0x01,0x37,0xE6, 甲烷浓度值(数据码1* 65536 + 数据码2 * 256 + 数据码3)
+ * 0x00, 激光甲烷模块工作状态(00表示设备正常,01表示温控故障,02表示设备激光未打开)
+ * 0x00,0xB2,0x35, 激光强度值(数据码5* 65536 + 数据码6 * 256 + 数据码7)
+ * 0x0A,0x3D, 云台水平角度([数据码8 * 256 + 数据码9]/100,单位为°,精确到0.01)
+ * 0x05,0x6F, 云台垂直角度(首先计算Tangle=[数据码10 * 256 + 数据码11]/100,单位为°,精确到0.01。若Tangle在0~90范围内,则垂直角度值=Tangle;若Tangle在-1~-90范围内,则垂直角度值=Tangle-360)
+ * 0xC1
+ *
+ * [-1, 1, 1, 55, -26, 0, 0, -78, 53, 10, 61, 5, 111, -63]
+ * 甲烷浓度值为79638,计算为79638=0x01*65536+0x37*256+0xE6[0x01为数据码1,0x37为数据码2,0xE6为数据码3];
+ * 激光甲烷设备状态值为0,表示状态正常,[0x00为数据码4];
+ * 激光强度值为45621,计算为45621=0x00*65536+0xB2*256+0x35[0x00为数据码5,0xB2为数据码6,0x35为数据码7];
+ *
+ * =========================================================================================
+ * 实际数据(1800-1950左右)
+ * [-86, 1, 0, 7, 71, 0, 0, 62, -92, 57, 59, -118, -111, -64]
+ * */
+
+ if (data == null) {
+ return
+ }
+ val bytes = data.toUnsignedByteArray()
+ if (bytes.size == 14) {
+ val dataModel = SensorDataModel(0, "激光未打开", 0, 0.0, 0.0)
+
+ val methaneBytes = IntArray(3)
+ System.arraycopy(bytes, 2, methaneBytes, 0, 3)
+ dataModel.methane = methaneBytes.covertDataValue()
+
+ dataModel.methaneState = when (bytes[5]) {
+ 1 -> "温控故障"
+ 2 -> "激光未打开"
+ else -> "正常"
+ }
+
+ val laserBytes = IntArray(3)
+ System.arraycopy(bytes, 6, laserBytes, 0, 3)
+ dataModel.laser = laserBytes.covertDataValue()
+
+ /**
+ * 水平角度的实际范围为从水平零点开始,顺时针方向(从上往下看),0~360°
+ * 垂直角度的实际范围为从垂直零点开始,以向上为正,-90°~90°,控制精度为0.01°
+ * */
+ val horizontalBytes = IntArray(2)
+ System.arraycopy(bytes, 9, horizontalBytes, 0, 2)
+ dataModel.horizontal = horizontalBytes.covertAngleValue()
+
+ val verticalBytes = IntArray(2)
+ System.arraycopy(bytes, 11, verticalBytes, 0, 2)
+ dataModel.vertical = verticalBytes.covertAngleValue()
+
+ //{"horizontal":26.21,"laser":45621,"methane":79846,"methaneState":"正常","vertical":13.91}
+ BroadcastManager.obtainInstance(BaseApplication.get()).sendBroadcast(
+ LocaleConstant.ACTION_UPDATE_DATA, dataModel.toJson()
+ )
+ }
+ }
+
+ override fun onServiceStatusConnectChanged(statusCode: Byte) {
+ if (statusCode == ISocketListener.STATUS_CONNECT_SUCCESS) {
+ if (nettyClient.connectStatus) {
+ Log.d(kTag, "连接成功")
+ }
+ } else {
+ if (!nettyClient.connectStatus) {
+ Log.e(kTag, "onServiceStatusConnectChanged:$statusCode,连接断开,正在重连")
+ }
+ }
+ }
+
+ fun sendData(data: ByteArray) {
+ nettyClient.sendData(data)
+ }
+
+ fun close() {
+ nettyClient.disconnect()
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index e822df6..d72c1a5 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -7,6 +7,9 @@
+
+
+
@@ -46,5 +49,8 @@
+
+
+
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/br/ktd/base/KotlinBaseFragment.kt b/app/src/main/java/com/casic/br/ktd/base/KotlinBaseFragment.kt
new file mode 100644
index 0000000..2dac61c
--- /dev/null
+++ b/app/src/main/java/com/casic/br/ktd/base/KotlinBaseFragment.kt
@@ -0,0 +1,51 @@
+package com.casic.br.ktd.base
+
+import android.os.Bundle
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import androidx.annotation.LayoutRes
+import androidx.fragment.app.Fragment
+
+abstract class KotlinBaseFragment : Fragment() {
+
+ lateinit var bv: View
+
+ override fun onCreateView(
+ inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?
+ ): View? {
+ bv = inflater.inflate(initLayoutRes(), container, false)
+ initView(savedInstanceState)
+ setupTopBarLayout()
+ return bv
+ }
+
+ override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
+ super.onViewCreated(view, savedInstanceState)
+ observeRequestState()
+ initEvent()
+ }
+
+ @LayoutRes
+ abstract fun initLayoutRes(): Int
+
+ /**
+ * 沉浸式状态栏
+ */
+ abstract fun setupTopBarLayout()
+
+ /**
+ * 初始化布局以及控件
+ */
+ abstract fun initView(savedInstanceState: Bundle?)
+
+ /**
+ * 网络请求状态监听
+ */
+ abstract fun observeRequestState()
+
+ /**
+ * 业务逻辑,按钮等事件
+ */
+ abstract fun initEvent()
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/br/ktd/fragment/AlarmPageFragment.kt b/app/src/main/java/com/casic/br/ktd/fragment/AlarmPageFragment.kt
index 6c98a3b..9418169 100644
--- a/app/src/main/java/com/casic/br/ktd/fragment/AlarmPageFragment.kt
+++ b/app/src/main/java/com/casic/br/ktd/fragment/AlarmPageFragment.kt
@@ -2,28 +2,29 @@
import android.os.Bundle
import com.casic.br.ktd.R
+import com.casic.br.ktd.base.KotlinBaseFragment
import com.casic.br.ktd.widgets.DateRangeActionSheet
-import com.pengxh.kt.lite.base.KotlinBaseFragment
import kotlinx.android.synthetic.main.fragment_alarm.view.*
class AlarmPageFragment : KotlinBaseFragment() {
- override fun initData(savedInstanceState: Bundle?) {
+
+ override fun initView(savedInstanceState: Bundle?) {
}
override fun initEvent() {
- baseView.calendarView.setOnClickListener {
+ bv.calendarView.setOnClickListener {
DateRangeActionSheet.Builder().setContext(requireContext())
.setOnActionSheetListener(object :
DateRangeActionSheet.OnDateRangeSelectedListener {
override fun onDateRangeSelected(startDate: String, endDate: String) {
- baseView.selectedDateView.text = "$startDate ~ $endDate"
+ bv.selectedDateView.text = "$startDate ~ $endDate"
}
}).build().show()
}
}
- override fun initLayoutView(): Int = R.layout.fragment_alarm
+ override fun initLayoutRes(): Int = R.layout.fragment_alarm
override fun observeRequestState() {
diff --git a/app/src/main/java/com/casic/br/ktd/fragment/HomePageFragment.kt b/app/src/main/java/com/casic/br/ktd/fragment/HomePageFragment.kt
index 9961935..f3eba5c 100644
--- a/app/src/main/java/com/casic/br/ktd/fragment/HomePageFragment.kt
+++ b/app/src/main/java/com/casic/br/ktd/fragment/HomePageFragment.kt
@@ -1,32 +1,62 @@
package com.casic.br.ktd.fragment
+import android.graphics.Color
import android.os.Bundle
import com.amap.api.maps.AMap
import com.amap.api.maps.AMapOptions
+import com.amap.api.maps.CameraUpdateFactory
+import com.amap.api.maps.model.*
import com.casic.br.ktd.R
-import com.pengxh.kt.lite.base.KotlinBaseFragment
+import com.casic.br.ktd.base.KotlinBaseFragment
import kotlinx.android.synthetic.main.fragment_home.view.*
class HomePageFragment : KotlinBaseFragment() {
private lateinit var aMap: AMap
- override fun initData(savedInstanceState: Bundle?) {
- baseView.mapView.onCreate(savedInstanceState)
- aMap = baseView.mapView.map
+ override fun initView(savedInstanceState: Bundle?) {
+ bv.mapView.onCreate(savedInstanceState)
+ aMap = bv.mapView.map
val uiSettings = aMap.uiSettings
uiSettings.isCompassEnabled = true
- uiSettings.isMyLocationButtonEnabled = true
+ uiSettings.isMyLocationButtonEnabled = false
uiSettings.isScaleControlsEnabled = true
uiSettings.zoomPosition = AMapOptions.ZOOM_POSITION_RIGHT_CENTER
uiSettings.isRotateGesturesEnabled = false//不许地图随手势旋转角度
}
override fun initEvent() {
-
+ //移动到巡检起始经纬度
+ val cameraPosition = CameraPosition(LatLng(39.914199, 116.265785), 16f, 0f, 0f)
+ val cameraUpdate = CameraUpdateFactory.newCameraPosition(cameraPosition)
+ aMap.animateCamera(cameraUpdate, 1500, null)
+ //设置起点
+ addMarker(LatLng(39.914885, 116.272312), R.mipmap.start)
+ //设置终点
+ addMarker(LatLng(39.914716, 116.265097), R.mipmap.end)
+ //瞄点画线
+ val latLngPoints = ArrayList()
+ latLngPoints.add(LatLng(39.914885, 116.272312))
+ latLngPoints.add(LatLng(39.915148, 116.272312))
+ latLngPoints.add(LatLng(39.915399, 116.272302))
+ latLngPoints.add(LatLng(39.915436, 116.271787))
+ latLngPoints.add(LatLng(39.915477, 116.270886))
+ latLngPoints.add(LatLng(39.915477, 116.269968))
+ latLngPoints.add(LatLng(39.915469, 116.269544))
+ latLngPoints.add(LatLng(39.915481, 116.269196))
+ latLngPoints.add(LatLng(39.915452, 116.268472))
+ latLngPoints.add(LatLng(39.915444, 116.267722))
+ latLngPoints.add(LatLng(39.915415, 116.266755))
+ latLngPoints.add(LatLng(39.915403, 116.266165))
+ latLngPoints.add(LatLng(39.915395, 116.265703))
+ latLngPoints.add(LatLng(39.915366, 116.265119))
+ latLngPoints.add(LatLng(39.914716, 116.265097))
+ aMap.addPolyline(
+ PolylineOptions().addAll(latLngPoints).width(10.toFloat()).color(Color.RED)
+ )
}
- override fun initLayoutView(): Int = R.layout.fragment_home
+ override fun initLayoutRes(): Int = R.layout.fragment_home
override fun observeRequestState() {
@@ -36,25 +66,32 @@
}
+ private fun addMarker(point: LatLng, res: Int) {
+ val markerOption = MarkerOptions()
+ markerOption.position(point)
+ markerOption.icon(BitmapDescriptorFactory.fromResource(res))
+ aMap.addMarker(markerOption)
+ }
+
/***以下是地图生命周期管理************************************************************************/
override fun onResume() {
super.onResume()
- baseView.mapView.onResume()
+ bv.mapView.onResume()
}
override fun onPause() {
- baseView.mapView.onPause()
super.onPause()
+ bv.mapView.onPause()
}
override fun onSaveInstanceState(outState: Bundle) {
super.onSaveInstanceState(outState)
- baseView.mapView.onSaveInstanceState(outState)
+ bv.mapView.onSaveInstanceState(outState)
}
override fun onDestroy() {
- baseView.mapView.onDestroy()
super.onDestroy()
+ bv.mapView.onDestroy()
}
}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/br/ktd/fragment/MinePageFragment.kt b/app/src/main/java/com/casic/br/ktd/fragment/MinePageFragment.kt
index 90313ac..3212794 100644
--- a/app/src/main/java/com/casic/br/ktd/fragment/MinePageFragment.kt
+++ b/app/src/main/java/com/casic/br/ktd/fragment/MinePageFragment.kt
@@ -2,10 +2,11 @@
import android.os.Bundle
import com.casic.br.ktd.R
-import com.pengxh.kt.lite.base.KotlinBaseFragment
+import com.casic.br.ktd.base.KotlinBaseFragment
class MinePageFragment : KotlinBaseFragment() {
- override fun initData(savedInstanceState: Bundle?) {
+
+ override fun initView(savedInstanceState: Bundle?) {
}
@@ -13,7 +14,7 @@
}
- override fun initLayoutView(): Int = R.layout.fragment_mine
+ override fun initLayoutRes(): Int = R.layout.fragment_mine
override fun observeRequestState() {
diff --git a/app/src/main/java/com/casic/br/ktd/fragment/TaskPageFragment.kt b/app/src/main/java/com/casic/br/ktd/fragment/TaskPageFragment.kt
index 8f6abf0..6b82a54 100644
--- a/app/src/main/java/com/casic/br/ktd/fragment/TaskPageFragment.kt
+++ b/app/src/main/java/com/casic/br/ktd/fragment/TaskPageFragment.kt
@@ -8,6 +8,7 @@
import androidx.recyclerview.widget.RecyclerView
import com.casic.br.ktd.R
import com.casic.br.ktd.adapter.TaskAdapter
+import com.casic.br.ktd.base.KotlinBaseFragment
import com.casic.br.ktd.holder.SwipeViewHolder
import com.casic.br.ktd.model.TaskListModel
import com.casic.br.ktd.view.InspectionActivity
@@ -15,7 +16,6 @@
import com.casic.br.ktd.widgets.AlertControlDialog
import com.casic.br.ktd.widgets.AlertInputDialog
import com.casic.br.ktd.widgets.DateRangeActionSheet
-import com.pengxh.kt.lite.base.KotlinBaseFragment
import com.pengxh.kt.lite.extensions.navigatePageTo
import com.pengxh.kt.lite.extensions.show
import com.pengxh.kt.lite.utils.WeakReferenceHandler
@@ -36,7 +36,7 @@
private var startTime = ""
private var endTime = ""
- override fun initData(savedInstanceState: Bundle?) {
+ override fun initView(savedInstanceState: Bundle?) {
weakReferenceHandler = WeakReferenceHandler(this)
taskViewModel = ViewModelProvider(this)[TaskViewModel::class.java]
taskViewModel.taskList.observe(this) {
@@ -45,7 +45,7 @@
when {
isRefresh -> {
taskAdapter.setRefreshData(dataRows)
- baseView.taskLayout.finishRefresh()
+ bv.taskLayout.finishRefresh()
isRefresh = false
}
isLoadMore -> {
@@ -53,7 +53,7 @@
"到底了,别拉了".show(requireContext())
}
taskAdapter.setLoadMoreData(dataRows)
- baseView.taskLayout.finishLoadMore()
+ bv.taskLayout.finishLoadMore()
isLoadMore = false
}
else -> {
@@ -76,9 +76,9 @@
when (msg.what) {
2023070501 -> {
if (dataBeans.size == 0) {
- baseView.emptyLayout.visibility = View.VISIBLE
+ bv.emptyLayout.visibility = View.VISIBLE
} else {
- baseView.emptyLayout.visibility = View.GONE
+ bv.emptyLayout.visibility = View.GONE
taskAdapter = object : TaskAdapter(
requireContext(), R.layout.item_task_rv_l, dataBeans
) {
@@ -97,8 +97,8 @@
}
}
//绑定侧滑事件
- swipeAction.attachToRecyclerView(baseView.taskRecyclerView)
- baseView.taskRecyclerView.adapter = taskAdapter
+ swipeAction.attachToRecyclerView(bv.taskRecyclerView)
+ bv.taskRecyclerView.adapter = taskAdapter
taskAdapter.setOnItemCheckedListener(object :
TaskAdapter.OnItemCheckedListener {
override fun onItemChecked(items: ArrayList) {
@@ -168,7 +168,7 @@
override fun initEvent() {
- baseView.calendarView.setOnClickListener {
+ bv.calendarView.setOnClickListener {
DateRangeActionSheet.Builder().setContext(requireContext())
.setOnActionSheetListener(object :
DateRangeActionSheet.OnDateRangeSelectedListener {
@@ -177,12 +177,12 @@
endTime = endDate
//显示
- baseView.selectedDateView.text = "$startDate ~ $endDate"
+ bv.selectedDateView.text = "$startDate ~ $endDate"
}
}).build().show()
}
- baseView.addTaskButton.setOnClickListener {
+ bv.addTaskButton.setOnClickListener {
// AlertInputDialog.Builder()
// .setContext(requireContext())
// .setTitle("新建巡检任务")
@@ -200,11 +200,11 @@
requireContext().navigatePageTo()
}
- baseView.deleteTaskButton.setOnClickListener {
+ bv.deleteTaskButton.setOnClickListener {
selectedItems.size.toString().show(requireContext())
}
- baseView.taskSettingsButton.setOnClickListener {
+ bv.taskSettingsButton.setOnClickListener {
AlertInputDialog.Builder()
.setContext(requireContext())
.setTitle("设置阈值")
@@ -221,14 +221,14 @@
}).build().show()
}
- baseView.taskLayout.setOnRefreshListener {
+ bv.taskLayout.setOnRefreshListener {
isRefresh = true
//刷新之后页码重置
pageIndex = 1
getTaskList()
}
- baseView.taskLayout.setOnLoadMoreListener {
+ bv.taskLayout.setOnLoadMoreListener {
isLoadMore = true
pageIndex++
getTaskList()
@@ -239,13 +239,13 @@
taskViewModel.getTaskList(
startTime,
endTime,
- baseView.taskNameView.text.toString(),
- baseView.taskCodeView.text.toString(),
+ bv.taskNameView.text.toString(),
+ bv.taskCodeView.text.toString(),
pageIndex
)
}
- override fun initLayoutView(): Int = R.layout.fragment_task
+ override fun initLayoutRes(): Int = R.layout.fragment_task
override fun observeRequestState() {
diff --git a/app/src/main/java/com/casic/br/ktd/netty/ISocketListener.kt b/app/src/main/java/com/casic/br/ktd/netty/ISocketListener.kt
deleted file mode 100644
index dab98e1..0000000
--- a/app/src/main/java/com/casic/br/ktd/netty/ISocketListener.kt
+++ /dev/null
@@ -1,19 +0,0 @@
-package com.casic.br.ktd.netty
-
-interface ISocketListener {
- companion object {
- const val STATUS_CONNECT_SUCCESS: Byte = 1 //连接成功
- const val STATUS_CONNECT_CLOSED: Byte = 0 //关闭连接
- const val STATUS_CONNECT_ERROR: Byte = 0 //连接失败
- }
-
- /**
- * 当接收到系统消息
- */
- fun onMessageResponse(data: ByteArray?)
-
- /**
- * 当连接状态发生变化时调用
- */
- fun onServiceStatusConnectChanged(statusCode: Byte)
-}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/br/ktd/netty/SocketChannelHandle.kt b/app/src/main/java/com/casic/br/ktd/netty/SocketChannelHandle.kt
deleted file mode 100644
index 42eb310..0000000
--- a/app/src/main/java/com/casic/br/ktd/netty/SocketChannelHandle.kt
+++ /dev/null
@@ -1,51 +0,0 @@
-package com.casic.br.ktd.netty
-
-import android.util.Log
-import io.netty.channel.ChannelHandlerContext
-import io.netty.channel.SimpleChannelInboundHandler
-import io.netty.handler.timeout.IdleState
-import io.netty.handler.timeout.IdleStateEvent
-import java.nio.charset.StandardCharsets
-
-class SocketChannelHandle(private val listener: ISocketListener?) :
- SimpleChannelInboundHandler() {
-
- private val kTag = "SocketChannelHandle"
-
- override fun channelActive(ctx: ChannelHandlerContext) {
- super.channelActive(ctx)
- Log.d(kTag, "channelActive ===> 连接成功")
- listener?.onServiceStatusConnectChanged(ISocketListener.STATUS_CONNECT_SUCCESS)
- }
-
- override fun channelInactive(ctx: ChannelHandlerContext) {
- super.channelInactive(ctx)
- Log.e(kTag, "channelInactive: 连接断开")
- }
-
- override fun userEventTriggered(ctx: ChannelHandlerContext, evt: Any) {
- super.userEventTriggered(ctx, evt)
- if (evt is IdleStateEvent) {
- if (evt.state() == IdleState.WRITER_IDLE) {
- //写超时,此时可以发送心跳数据给服务器
- val temp = "FF"
- ctx.writeAndFlush(temp.toByteArray(StandardCharsets.UTF_8))
- } else if (evt.state() == IdleState.READER_IDLE) {
- //读超时,此时代表没有收到心跳返回可以关闭当前连接进行重连
- ctx.close()
- }
- }
- }
-
- override fun channelRead0(ctx: ChannelHandlerContext, data: ByteArray?) {
- listener?.onMessageResponse(data)
- }
-
- override fun exceptionCaught(ctx: ChannelHandlerContext, cause: Throwable) {
- super.exceptionCaught(ctx, cause)
- Log.d(kTag, "exceptionCaught ===> $cause")
- listener?.onServiceStatusConnectChanged(ISocketListener.STATUS_CONNECT_ERROR)
- cause.printStackTrace()
- ctx.close()
- }
-}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/br/ktd/netty/SocketClient.kt b/app/src/main/java/com/casic/br/ktd/netty/SocketClient.kt
deleted file mode 100644
index d05d335..0000000
--- a/app/src/main/java/com/casic/br/ktd/netty/SocketClient.kt
+++ /dev/null
@@ -1,153 +0,0 @@
-package com.casic.br.ktd.netty
-
-import android.os.SystemClock
-import android.util.Log
-import io.netty.bootstrap.Bootstrap
-import io.netty.channel.*
-import io.netty.channel.nio.NioEventLoopGroup
-import io.netty.channel.socket.SocketChannel
-import io.netty.channel.socket.nio.NioSocketChannel
-import io.netty.handler.codec.bytes.ByteArrayDecoder
-import io.netty.handler.codec.bytes.ByteArrayEncoder
-import io.netty.handler.timeout.IdleStateHandler
-
-class SocketClient {
-
- private val kTag = "SocketClient"
-
- private var host: String? = null
- private var port = 8000
- private var nioEventLoopGroup: NioEventLoopGroup? = null
- private var channel: Channel? = null
- private var listener: ISocketListener? = null
-
- //现在连接的状态
- var connectStatus = false //判断是否已连接
- private var reconnectNum = Int.MAX_VALUE //定义的重连到时候用
- private var isNeedReconnect = true //是否需要重连
- var isConnecting = false //是否正在连接
- private set
- private var reconnectIntervalTime: Long = 15000 //重连的时间
-
- //重连时间
- fun setReconnectNum(reconnectNum: Int) {
- this.reconnectNum = reconnectNum
- }
-
- fun setReconnectIntervalTime(reconnectIntervalTime: Long) {
- this.reconnectIntervalTime = reconnectIntervalTime
- }
-
- fun setSocketListener(listener: ISocketListener?) {
- this.listener = listener
- }
-
- fun connect(host: String, port: Int) {
- this.host = host
- this.port = port
- Log.d(kTag, "connect ===> 开始连接TCP服务器")
- if (isConnecting) {
- return
- }
- //起个线程
- val clientThread: Thread = object : Thread("client-Netty") {
- override fun run() {
- super.run()
- isNeedReconnect = true
- reconnectNum = Int.MAX_VALUE
- connectServer()
- }
- }
- clientThread.start()
- }
-
- private fun connectServer() {
- synchronized(this@SocketClient) {
- var channelFuture: ChannelFuture? = null //连接管理对象
- if (!connectStatus) {
- isConnecting = true
- nioEventLoopGroup = NioEventLoopGroup() //设置的连接group
- val bootstrap = Bootstrap()
- bootstrap.group(nioEventLoopGroup) //设置的一系列连接参数操作等
- .channel(NioSocketChannel::class.java)
- .option(ChannelOption.TCP_NODELAY, true) //无阻塞
- .option(ChannelOption.SO_KEEPALIVE, true) //长连接
- .option(
- ChannelOption.RCVBUF_ALLOCATOR,
- AdaptiveRecvByteBufAllocator(5000, 5000, 8000)
- ) //接收缓冲区 最小值太小时数据接收不全
- .handler(object : ChannelInitializer() {
- override fun initChannel(channel: SocketChannel) {
- val pipeline = channel.pipeline()
- //参数1:代表读套接字超时的时间,没收到数据会触发读超时回调;
- //参数2:代表写套接字超时时间,没进行写会触发写超时回调;
- //参数3:将在未执行读取或写入时触发超时回调,0代表不处理;
- //读超时尽量设置大于写超时,代表多次写超时时写心跳包,多次写了心跳数据仍然读超时代表当前连接错误,即可断开连接重新连接
- pipeline.addLast(IdleStateHandler(60, 10, 0))
- pipeline.addLast(ByteArrayDecoder())
- pipeline.addLast(ByteArrayEncoder())
- pipeline.addLast(SocketChannelHandle(listener))
- }
- })
- try {
- //连接监听
- channelFuture = bootstrap.connect(host, port)
- .addListener(object : ChannelFutureListener {
- override fun operationComplete(channelFuture: ChannelFuture) {
- if (channelFuture.isSuccess) {
- connectStatus = true
- channel = channelFuture.channel()
- } else {
- Log.e(kTag, "operationComplete: 连接失败")
- connectStatus = false
- }
- isConnecting = false
- }
- }).sync()
- // 等待连接关闭
- channelFuture.channel().closeFuture().sync()
- } catch (e: Exception) {
- e.printStackTrace()
- } finally {
- connectStatus = false
- listener?.onServiceStatusConnectChanged(ISocketListener.STATUS_CONNECT_CLOSED) //STATUS_CONNECT_CLOSED 这我自己定义的 接口标识
- if (null != channelFuture) {
- if (channelFuture.channel() != null && channelFuture.channel().isOpen) {
- channelFuture.channel().close()
- }
- }
- nioEventLoopGroup?.shutdownGracefully()
- reconnect() //重新连接
- }
- }
- }
- }
-
- //断开连接
- fun disconnect() {
- Log.d(kTag, "disconnect ===> 断开连接")
- isNeedReconnect = false
- nioEventLoopGroup?.shutdownGracefully()
- }
-
- //重新连接
- private fun reconnect() {
- if (isNeedReconnect && reconnectNum > 0 && !connectStatus) {
- reconnectNum--
- SystemClock.sleep(reconnectIntervalTime)
- if (isNeedReconnect && reconnectNum > 0 && !connectStatus) {
- Log.d(kTag, "reconnect ===> 重新连接")
- connectServer()
- }
- }
- }
-
- fun sendData(bytes: ByteArray) {
- channel?.writeAndFlush(bytes)?.addListener(ChannelFutureListener { future ->
- if (!future.isSuccess) {
- future.channel().close()
- nioEventLoopGroup!!.shutdownGracefully()
- }
- })
- }
-}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/br/ktd/netty/SocketManager.kt b/app/src/main/java/com/casic/br/ktd/netty/SocketManager.kt
deleted file mode 100644
index 17daf35..0000000
--- a/app/src/main/java/com/casic/br/ktd/netty/SocketManager.kt
+++ /dev/null
@@ -1,113 +0,0 @@
-package com.casic.br.ktd.netty
-
-import android.util.Log
-import com.casic.br.ktd.base.BaseApplication
-import com.casic.br.ktd.extensions.covertAngleValue
-import com.casic.br.ktd.extensions.covertDataValue
-import com.casic.br.ktd.extensions.toUnsignedByteArray
-import com.casic.br.ktd.model.SensorDataModel
-import com.casic.br.ktd.utils.LocaleConstant
-import com.pengxh.kt.lite.extensions.toJson
-import com.pengxh.kt.lite.utils.BroadcastManager
-
-class SocketManager private constructor() : ISocketListener {
-
- private val kTag = "SocketManager"
- private var nettyClient: SocketClient = SocketClient()
-
- companion object {
- val instance: SocketManager by lazy(mode = LazyThreadSafetyMode.SYNCHRONIZED) { SocketManager() }
- }
-
- fun connectNetty(hostname: String, port: Int) {
- Thread {
- if (!nettyClient.connectStatus) {
- nettyClient.setSocketListener(this)
- nettyClient.connect(hostname, port)
- } else {
- nettyClient.disconnect()
- }
- }.start()
- }
-
- override fun onMessageResponse(data: ByteArray?) {
-// Log.d(kTag, "onMessageResponse ===> " + Arrays.toString(data))
- /**
- * 0xFF,0x01,
- * 0x01,0x37,0xE6, 甲烷浓度值(数据码1* 65536 + 数据码2 * 256 + 数据码3)
- * 0x00, 激光甲烷模块工作状态(00表示设备正常,01表示温控故障,02表示设备激光未打开)
- * 0x00,0xB2,0x35, 激光强度值(数据码5* 65536 + 数据码6 * 256 + 数据码7)
- * 0x0A,0x3D, 云台水平角度([数据码8 * 256 + 数据码9]/100,单位为°,精确到0.01)
- * 0x05,0x6F, 云台垂直角度(首先计算Tangle=[数据码10 * 256 + 数据码11]/100,单位为°,精确到0.01。若Tangle在0~90范围内,则垂直角度值=Tangle;若Tangle在-1~-90范围内,则垂直角度值=Tangle-360)
- * 0xC1
- *
- * [-1, 1, 1, 55, -26, 0, 0, -78, 53, 10, 61, 5, 111, -63]
- * 甲烷浓度值为79638,计算为79638=0x01*65536+0x37*256+0xE6[0x01为数据码1,0x37为数据码2,0xE6为数据码3];
- * 激光甲烷设备状态值为0,表示状态正常,[0x00为数据码4];
- * 激光强度值为45621,计算为45621=0x00*65536+0xB2*256+0x35[0x00为数据码5,0xB2为数据码6,0x35为数据码7];
- *
- * =========================================================================================
- * 实际数据(1800-1950左右)
- * [-86, 1, 0, 7, 71, 0, 0, 62, -92, 57, 59, -118, -111, -64]
- * */
-
- if (data == null) {
- return
- }
- val bytes = data.toUnsignedByteArray()
- if (bytes.size == 14) {
- val dataModel = SensorDataModel(0, "激光未打开", 0, 0.0, 0.0)
-
- val methaneBytes = IntArray(3)
- System.arraycopy(bytes, 2, methaneBytes, 0, 3)
- dataModel.methane = methaneBytes.covertDataValue()
-
- dataModel.methaneState = when (bytes[5]) {
- 1 -> "温控故障"
- 2 -> "激光未打开"
- else -> "正常"
- }
-
- val laserBytes = IntArray(3)
- System.arraycopy(bytes, 6, laserBytes, 0, 3)
- dataModel.laser = laserBytes.covertDataValue()
-
- /**
- * 水平角度的实际范围为从水平零点开始,顺时针方向(从上往下看),0~360°
- * 垂直角度的实际范围为从垂直零点开始,以向上为正,-90°~90°,控制精度为0.01°
- * */
- val horizontalBytes = IntArray(2)
- System.arraycopy(bytes, 9, horizontalBytes, 0, 2)
- dataModel.horizontal = horizontalBytes.covertAngleValue()
-
- val verticalBytes = IntArray(2)
- System.arraycopy(bytes, 11, verticalBytes, 0, 2)
- dataModel.vertical = verticalBytes.covertAngleValue()
-
- //{"horizontal":26.21,"laser":45621,"methane":79846,"methaneState":"正常","vertical":13.91}
- BroadcastManager.obtainInstance(BaseApplication.get()).sendBroadcast(
- LocaleConstant.ACTION_UPDATE_DATA, dataModel.toJson()
- )
- }
- }
-
- override fun onServiceStatusConnectChanged(statusCode: Byte) {
- if (statusCode == ISocketListener.STATUS_CONNECT_SUCCESS) {
- if (nettyClient.connectStatus) {
- Log.d(kTag, "连接成功")
- }
- } else {
- if (!nettyClient.connectStatus) {
- Log.e(kTag, "onServiceStatusConnectChanged:$statusCode,连接断开,正在重连")
- }
- }
- }
-
- fun sendData(data: ByteArray) {
- nettyClient.sendData(data)
- }
-
- fun close() {
- nettyClient.disconnect()
- }
-}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/br/ktd/netty/tcp/ISocketListener.kt b/app/src/main/java/com/casic/br/ktd/netty/tcp/ISocketListener.kt
new file mode 100644
index 0000000..13c3084
--- /dev/null
+++ b/app/src/main/java/com/casic/br/ktd/netty/tcp/ISocketListener.kt
@@ -0,0 +1,19 @@
+package com.casic.br.ktd.netty.tcp
+
+interface ISocketListener {
+ companion object {
+ const val STATUS_CONNECT_SUCCESS: Byte = 1 //连接成功
+ const val STATUS_CONNECT_CLOSED: Byte = 0 //关闭连接
+ const val STATUS_CONNECT_ERROR: Byte = 0 //连接失败
+ }
+
+ /**
+ * 当接收到系统消息
+ */
+ fun onMessageResponse(data: ByteArray?)
+
+ /**
+ * 当连接状态发生变化时调用
+ */
+ fun onServiceStatusConnectChanged(statusCode: Byte)
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/br/ktd/netty/tcp/SocketChannelHandle.kt b/app/src/main/java/com/casic/br/ktd/netty/tcp/SocketChannelHandle.kt
new file mode 100644
index 0000000..8e2997f
--- /dev/null
+++ b/app/src/main/java/com/casic/br/ktd/netty/tcp/SocketChannelHandle.kt
@@ -0,0 +1,51 @@
+package com.casic.br.ktd.netty.tcp
+
+import android.util.Log
+import io.netty.channel.ChannelHandlerContext
+import io.netty.channel.SimpleChannelInboundHandler
+import io.netty.handler.timeout.IdleState
+import io.netty.handler.timeout.IdleStateEvent
+import java.nio.charset.StandardCharsets
+
+class SocketChannelHandle(private val listener: ISocketListener?) :
+ SimpleChannelInboundHandler() {
+
+ private val kTag = "SocketChannelHandle"
+
+ override fun channelActive(ctx: ChannelHandlerContext) {
+ super.channelActive(ctx)
+ Log.d(kTag, "channelActive ===> 连接成功")
+ listener?.onServiceStatusConnectChanged(ISocketListener.STATUS_CONNECT_SUCCESS)
+ }
+
+ override fun channelInactive(ctx: ChannelHandlerContext) {
+ super.channelInactive(ctx)
+ Log.e(kTag, "channelInactive: 连接断开")
+ }
+
+ override fun userEventTriggered(ctx: ChannelHandlerContext, evt: Any) {
+ super.userEventTriggered(ctx, evt)
+ if (evt is IdleStateEvent) {
+ if (evt.state() == IdleState.WRITER_IDLE) {
+ //写超时,此时可以发送心跳数据给服务器
+ val temp = "FF"
+ ctx.writeAndFlush(temp.toByteArray(StandardCharsets.UTF_8))
+ } else if (evt.state() == IdleState.READER_IDLE) {
+ //读超时,此时代表没有收到心跳返回可以关闭当前连接进行重连
+ ctx.close()
+ }
+ }
+ }
+
+ override fun channelRead0(ctx: ChannelHandlerContext, data: ByteArray?) {
+ listener?.onMessageResponse(data)
+ }
+
+ override fun exceptionCaught(ctx: ChannelHandlerContext, cause: Throwable) {
+ super.exceptionCaught(ctx, cause)
+ Log.d(kTag, "exceptionCaught ===> $cause")
+ listener?.onServiceStatusConnectChanged(ISocketListener.STATUS_CONNECT_ERROR)
+ cause.printStackTrace()
+ ctx.close()
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/br/ktd/netty/tcp/SocketClient.kt b/app/src/main/java/com/casic/br/ktd/netty/tcp/SocketClient.kt
new file mode 100644
index 0000000..34960a0
--- /dev/null
+++ b/app/src/main/java/com/casic/br/ktd/netty/tcp/SocketClient.kt
@@ -0,0 +1,153 @@
+package com.casic.br.ktd.netty.tcp
+
+import android.os.SystemClock
+import android.util.Log
+import io.netty.bootstrap.Bootstrap
+import io.netty.channel.*
+import io.netty.channel.nio.NioEventLoopGroup
+import io.netty.channel.socket.SocketChannel
+import io.netty.channel.socket.nio.NioSocketChannel
+import io.netty.handler.codec.bytes.ByteArrayDecoder
+import io.netty.handler.codec.bytes.ByteArrayEncoder
+import io.netty.handler.timeout.IdleStateHandler
+
+class SocketClient {
+
+ private val kTag = "SocketClient"
+
+ private var host: String? = null
+ private var port = 8000
+ private var nioEventLoopGroup: NioEventLoopGroup? = null
+ private var channel: Channel? = null
+ private var listener: ISocketListener? = null
+
+ //现在连接的状态
+ var connectStatus = false //判断是否已连接
+ private var reconnectNum = Int.MAX_VALUE //定义的重连到时候用
+ private var isNeedReconnect = true //是否需要重连
+ var isConnecting = false //是否正在连接
+ private set
+ private var reconnectIntervalTime: Long = 15000 //重连的时间
+
+ //重连时间
+ fun setReconnectNum(reconnectNum: Int) {
+ this.reconnectNum = reconnectNum
+ }
+
+ fun setReconnectIntervalTime(reconnectIntervalTime: Long) {
+ this.reconnectIntervalTime = reconnectIntervalTime
+ }
+
+ fun setSocketListener(listener: ISocketListener?) {
+ this.listener = listener
+ }
+
+ fun connect(host: String, port: Int) {
+ this.host = host
+ this.port = port
+ Log.d(kTag, "connect ===> 开始连接TCP服务器")
+ if (isConnecting) {
+ return
+ }
+ //起个线程
+ val clientThread: Thread = object : Thread("client-Netty") {
+ override fun run() {
+ super.run()
+ isNeedReconnect = true
+ reconnectNum = Int.MAX_VALUE
+ connectServer()
+ }
+ }
+ clientThread.start()
+ }
+
+ private fun connectServer() {
+ synchronized(this@SocketClient) {
+ var channelFuture: ChannelFuture? = null //连接管理对象
+ if (!connectStatus) {
+ isConnecting = true
+ nioEventLoopGroup = NioEventLoopGroup() //设置的连接group
+ val bootstrap = Bootstrap()
+ bootstrap.group(nioEventLoopGroup) //设置的一系列连接参数操作等
+ .channel(NioSocketChannel::class.java)
+ .option(ChannelOption.TCP_NODELAY, true) //无阻塞
+ .option(ChannelOption.SO_KEEPALIVE, true) //长连接
+ .option(
+ ChannelOption.RCVBUF_ALLOCATOR,
+ AdaptiveRecvByteBufAllocator(5000, 5000, 8000)
+ ) //接收缓冲区 最小值太小时数据接收不全
+ .handler(object : ChannelInitializer() {
+ override fun initChannel(channel: SocketChannel) {
+ val pipeline = channel.pipeline()
+ //参数1:代表读套接字超时的时间,没收到数据会触发读超时回调;
+ //参数2:代表写套接字超时时间,没进行写会触发写超时回调;
+ //参数3:将在未执行读取或写入时触发超时回调,0代表不处理;
+ //读超时尽量设置大于写超时,代表多次写超时时写心跳包,多次写了心跳数据仍然读超时代表当前连接错误,即可断开连接重新连接
+ pipeline.addLast(IdleStateHandler(60, 10, 0))
+ pipeline.addLast(ByteArrayDecoder())
+ pipeline.addLast(ByteArrayEncoder())
+ pipeline.addLast(SocketChannelHandle(listener))
+ }
+ })
+ try {
+ //连接监听
+ channelFuture = bootstrap.connect(host, port)
+ .addListener(object : ChannelFutureListener {
+ override fun operationComplete(channelFuture: ChannelFuture) {
+ if (channelFuture.isSuccess) {
+ connectStatus = true
+ channel = channelFuture.channel()
+ } else {
+ Log.e(kTag, "operationComplete: 连接失败")
+ connectStatus = false
+ }
+ isConnecting = false
+ }
+ }).sync()
+ // 等待连接关闭
+ channelFuture.channel().closeFuture().sync()
+ } catch (e: Exception) {
+ e.printStackTrace()
+ } finally {
+ connectStatus = false
+ listener?.onServiceStatusConnectChanged(ISocketListener.STATUS_CONNECT_CLOSED) //STATUS_CONNECT_CLOSED 这我自己定义的 接口标识
+ if (null != channelFuture) {
+ if (channelFuture.channel() != null && channelFuture.channel().isOpen) {
+ channelFuture.channel().close()
+ }
+ }
+ nioEventLoopGroup?.shutdownGracefully()
+ reconnect() //重新连接
+ }
+ }
+ }
+ }
+
+ //断开连接
+ fun disconnect() {
+ Log.d(kTag, "disconnect ===> 断开连接")
+ isNeedReconnect = false
+ nioEventLoopGroup?.shutdownGracefully()
+ }
+
+ //重新连接
+ private fun reconnect() {
+ if (isNeedReconnect && reconnectNum > 0 && !connectStatus) {
+ reconnectNum--
+ SystemClock.sleep(reconnectIntervalTime)
+ if (isNeedReconnect && reconnectNum > 0 && !connectStatus) {
+ Log.d(kTag, "reconnect ===> 重新连接")
+ connectServer()
+ }
+ }
+ }
+
+ fun sendData(bytes: ByteArray) {
+ channel?.writeAndFlush(bytes)?.addListener(ChannelFutureListener { future ->
+ if (!future.isSuccess) {
+ future.channel().close()
+ nioEventLoopGroup!!.shutdownGracefully()
+ }
+ })
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/br/ktd/netty/tcp/SocketManager.kt b/app/src/main/java/com/casic/br/ktd/netty/tcp/SocketManager.kt
new file mode 100644
index 0000000..35980b9
--- /dev/null
+++ b/app/src/main/java/com/casic/br/ktd/netty/tcp/SocketManager.kt
@@ -0,0 +1,113 @@
+package com.casic.br.ktd.netty.tcp
+
+import android.util.Log
+import com.casic.br.ktd.base.BaseApplication
+import com.casic.br.ktd.extensions.covertAngleValue
+import com.casic.br.ktd.extensions.covertDataValue
+import com.casic.br.ktd.extensions.toUnsignedByteArray
+import com.casic.br.ktd.model.SensorDataModel
+import com.casic.br.ktd.utils.LocaleConstant
+import com.pengxh.kt.lite.extensions.toJson
+import com.pengxh.kt.lite.utils.BroadcastManager
+
+class SocketManager private constructor() : ISocketListener {
+
+ private val kTag = "SocketManager"
+ private var nettyClient: SocketClient = SocketClient()
+
+ companion object {
+ val instance: SocketManager by lazy(mode = LazyThreadSafetyMode.SYNCHRONIZED) { SocketManager() }
+ }
+
+ fun connectNetty(hostname: String, port: Int) {
+ Thread {
+ if (!nettyClient.connectStatus) {
+ nettyClient.setSocketListener(this)
+ nettyClient.connect(hostname, port)
+ } else {
+ nettyClient.disconnect()
+ }
+ }.start()
+ }
+
+ override fun onMessageResponse(data: ByteArray?) {
+// Log.d(kTag, "onMessageResponse ===> " + Arrays.toString(data))
+ /**
+ * 0xFF,0x01,
+ * 0x01,0x37,0xE6, 甲烷浓度值(数据码1* 65536 + 数据码2 * 256 + 数据码3)
+ * 0x00, 激光甲烷模块工作状态(00表示设备正常,01表示温控故障,02表示设备激光未打开)
+ * 0x00,0xB2,0x35, 激光强度值(数据码5* 65536 + 数据码6 * 256 + 数据码7)
+ * 0x0A,0x3D, 云台水平角度([数据码8 * 256 + 数据码9]/100,单位为°,精确到0.01)
+ * 0x05,0x6F, 云台垂直角度(首先计算Tangle=[数据码10 * 256 + 数据码11]/100,单位为°,精确到0.01。若Tangle在0~90范围内,则垂直角度值=Tangle;若Tangle在-1~-90范围内,则垂直角度值=Tangle-360)
+ * 0xC1
+ *
+ * [-1, 1, 1, 55, -26, 0, 0, -78, 53, 10, 61, 5, 111, -63]
+ * 甲烷浓度值为79638,计算为79638=0x01*65536+0x37*256+0xE6[0x01为数据码1,0x37为数据码2,0xE6为数据码3];
+ * 激光甲烷设备状态值为0,表示状态正常,[0x00为数据码4];
+ * 激光强度值为45621,计算为45621=0x00*65536+0xB2*256+0x35[0x00为数据码5,0xB2为数据码6,0x35为数据码7];
+ *
+ * =========================================================================================
+ * 实际数据(1800-1950左右)
+ * [-86, 1, 0, 7, 71, 0, 0, 62, -92, 57, 59, -118, -111, -64]
+ * */
+
+ if (data == null) {
+ return
+ }
+ val bytes = data.toUnsignedByteArray()
+ if (bytes.size == 14) {
+ val dataModel = SensorDataModel(0, "激光未打开", 0, 0.0, 0.0)
+
+ val methaneBytes = IntArray(3)
+ System.arraycopy(bytes, 2, methaneBytes, 0, 3)
+ dataModel.methane = methaneBytes.covertDataValue()
+
+ dataModel.methaneState = when (bytes[5]) {
+ 1 -> "温控故障"
+ 2 -> "激光未打开"
+ else -> "正常"
+ }
+
+ val laserBytes = IntArray(3)
+ System.arraycopy(bytes, 6, laserBytes, 0, 3)
+ dataModel.laser = laserBytes.covertDataValue()
+
+ /**
+ * 水平角度的实际范围为从水平零点开始,顺时针方向(从上往下看),0~360°
+ * 垂直角度的实际范围为从垂直零点开始,以向上为正,-90°~90°,控制精度为0.01°
+ * */
+ val horizontalBytes = IntArray(2)
+ System.arraycopy(bytes, 9, horizontalBytes, 0, 2)
+ dataModel.horizontal = horizontalBytes.covertAngleValue()
+
+ val verticalBytes = IntArray(2)
+ System.arraycopy(bytes, 11, verticalBytes, 0, 2)
+ dataModel.vertical = verticalBytes.covertAngleValue()
+
+ //{"horizontal":26.21,"laser":45621,"methane":79846,"methaneState":"正常","vertical":13.91}
+ BroadcastManager.obtainInstance(BaseApplication.get()).sendBroadcast(
+ LocaleConstant.ACTION_UPDATE_DATA, dataModel.toJson()
+ )
+ }
+ }
+
+ override fun onServiceStatusConnectChanged(statusCode: Byte) {
+ if (statusCode == ISocketListener.STATUS_CONNECT_SUCCESS) {
+ if (nettyClient.connectStatus) {
+ Log.d(kTag, "连接成功")
+ }
+ } else {
+ if (!nettyClient.connectStatus) {
+ Log.e(kTag, "onServiceStatusConnectChanged:$statusCode,连接断开,正在重连")
+ }
+ }
+ }
+
+ fun sendData(data: ByteArray) {
+ nettyClient.sendData(data)
+ }
+
+ fun close() {
+ nettyClient.disconnect()
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/br/ktd/netty/udp/UdpChannelInboundHandler.kt b/app/src/main/java/com/casic/br/ktd/netty/udp/UdpChannelInboundHandler.kt
new file mode 100644
index 0000000..4d6f97c
--- /dev/null
+++ b/app/src/main/java/com/casic/br/ktd/netty/udp/UdpChannelInboundHandler.kt
@@ -0,0 +1,36 @@
+package com.casic.br.ktd.netty.udp
+
+import io.netty.channel.ChannelHandlerContext
+import io.netty.channel.SimpleChannelInboundHandler
+import io.netty.channel.socket.DatagramPacket
+import io.netty.util.CharsetUtil
+
+
+abstract class UdpChannelInboundHandler : SimpleChannelInboundHandler() {
+
+ private var handlerContext: ChannelHandlerContext? = null
+
+ override fun channelActive(ctx: ChannelHandlerContext?) {
+ super.channelActive(ctx)
+ handlerContext = ctx
+ }
+
+ override fun channelInactive(ctx: ChannelHandlerContext?) {
+ super.channelInactive(ctx)
+ handlerContext?.close()
+ }
+
+ fun sendDatagramPacket(obj: Any) {
+ handlerContext?.writeAndFlush(obj)
+ }
+
+ fun releasePort() {
+ handlerContext?.close()
+ }
+
+ override fun channelRead0(ctx: ChannelHandlerContext, datagramPacket: DatagramPacket) {
+ receivedMessage(datagramPacket.content().toString(CharsetUtil.UTF_8))
+ }
+
+ abstract fun receivedMessage(data: String)
+}
\ No newline at end of file
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index e822df6..d72c1a5 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -7,6 +7,9 @@
+
+
+
@@ -46,5 +49,8 @@
+
+
+
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/br/ktd/base/KotlinBaseFragment.kt b/app/src/main/java/com/casic/br/ktd/base/KotlinBaseFragment.kt
new file mode 100644
index 0000000..2dac61c
--- /dev/null
+++ b/app/src/main/java/com/casic/br/ktd/base/KotlinBaseFragment.kt
@@ -0,0 +1,51 @@
+package com.casic.br.ktd.base
+
+import android.os.Bundle
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import androidx.annotation.LayoutRes
+import androidx.fragment.app.Fragment
+
+abstract class KotlinBaseFragment : Fragment() {
+
+ lateinit var bv: View
+
+ override fun onCreateView(
+ inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?
+ ): View? {
+ bv = inflater.inflate(initLayoutRes(), container, false)
+ initView(savedInstanceState)
+ setupTopBarLayout()
+ return bv
+ }
+
+ override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
+ super.onViewCreated(view, savedInstanceState)
+ observeRequestState()
+ initEvent()
+ }
+
+ @LayoutRes
+ abstract fun initLayoutRes(): Int
+
+ /**
+ * 沉浸式状态栏
+ */
+ abstract fun setupTopBarLayout()
+
+ /**
+ * 初始化布局以及控件
+ */
+ abstract fun initView(savedInstanceState: Bundle?)
+
+ /**
+ * 网络请求状态监听
+ */
+ abstract fun observeRequestState()
+
+ /**
+ * 业务逻辑,按钮等事件
+ */
+ abstract fun initEvent()
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/br/ktd/fragment/AlarmPageFragment.kt b/app/src/main/java/com/casic/br/ktd/fragment/AlarmPageFragment.kt
index 6c98a3b..9418169 100644
--- a/app/src/main/java/com/casic/br/ktd/fragment/AlarmPageFragment.kt
+++ b/app/src/main/java/com/casic/br/ktd/fragment/AlarmPageFragment.kt
@@ -2,28 +2,29 @@
import android.os.Bundle
import com.casic.br.ktd.R
+import com.casic.br.ktd.base.KotlinBaseFragment
import com.casic.br.ktd.widgets.DateRangeActionSheet
-import com.pengxh.kt.lite.base.KotlinBaseFragment
import kotlinx.android.synthetic.main.fragment_alarm.view.*
class AlarmPageFragment : KotlinBaseFragment() {
- override fun initData(savedInstanceState: Bundle?) {
+
+ override fun initView(savedInstanceState: Bundle?) {
}
override fun initEvent() {
- baseView.calendarView.setOnClickListener {
+ bv.calendarView.setOnClickListener {
DateRangeActionSheet.Builder().setContext(requireContext())
.setOnActionSheetListener(object :
DateRangeActionSheet.OnDateRangeSelectedListener {
override fun onDateRangeSelected(startDate: String, endDate: String) {
- baseView.selectedDateView.text = "$startDate ~ $endDate"
+ bv.selectedDateView.text = "$startDate ~ $endDate"
}
}).build().show()
}
}
- override fun initLayoutView(): Int = R.layout.fragment_alarm
+ override fun initLayoutRes(): Int = R.layout.fragment_alarm
override fun observeRequestState() {
diff --git a/app/src/main/java/com/casic/br/ktd/fragment/HomePageFragment.kt b/app/src/main/java/com/casic/br/ktd/fragment/HomePageFragment.kt
index 9961935..f3eba5c 100644
--- a/app/src/main/java/com/casic/br/ktd/fragment/HomePageFragment.kt
+++ b/app/src/main/java/com/casic/br/ktd/fragment/HomePageFragment.kt
@@ -1,32 +1,62 @@
package com.casic.br.ktd.fragment
+import android.graphics.Color
import android.os.Bundle
import com.amap.api.maps.AMap
import com.amap.api.maps.AMapOptions
+import com.amap.api.maps.CameraUpdateFactory
+import com.amap.api.maps.model.*
import com.casic.br.ktd.R
-import com.pengxh.kt.lite.base.KotlinBaseFragment
+import com.casic.br.ktd.base.KotlinBaseFragment
import kotlinx.android.synthetic.main.fragment_home.view.*
class HomePageFragment : KotlinBaseFragment() {
private lateinit var aMap: AMap
- override fun initData(savedInstanceState: Bundle?) {
- baseView.mapView.onCreate(savedInstanceState)
- aMap = baseView.mapView.map
+ override fun initView(savedInstanceState: Bundle?) {
+ bv.mapView.onCreate(savedInstanceState)
+ aMap = bv.mapView.map
val uiSettings = aMap.uiSettings
uiSettings.isCompassEnabled = true
- uiSettings.isMyLocationButtonEnabled = true
+ uiSettings.isMyLocationButtonEnabled = false
uiSettings.isScaleControlsEnabled = true
uiSettings.zoomPosition = AMapOptions.ZOOM_POSITION_RIGHT_CENTER
uiSettings.isRotateGesturesEnabled = false//不许地图随手势旋转角度
}
override fun initEvent() {
-
+ //移动到巡检起始经纬度
+ val cameraPosition = CameraPosition(LatLng(39.914199, 116.265785), 16f, 0f, 0f)
+ val cameraUpdate = CameraUpdateFactory.newCameraPosition(cameraPosition)
+ aMap.animateCamera(cameraUpdate, 1500, null)
+ //设置起点
+ addMarker(LatLng(39.914885, 116.272312), R.mipmap.start)
+ //设置终点
+ addMarker(LatLng(39.914716, 116.265097), R.mipmap.end)
+ //瞄点画线
+ val latLngPoints = ArrayList()
+ latLngPoints.add(LatLng(39.914885, 116.272312))
+ latLngPoints.add(LatLng(39.915148, 116.272312))
+ latLngPoints.add(LatLng(39.915399, 116.272302))
+ latLngPoints.add(LatLng(39.915436, 116.271787))
+ latLngPoints.add(LatLng(39.915477, 116.270886))
+ latLngPoints.add(LatLng(39.915477, 116.269968))
+ latLngPoints.add(LatLng(39.915469, 116.269544))
+ latLngPoints.add(LatLng(39.915481, 116.269196))
+ latLngPoints.add(LatLng(39.915452, 116.268472))
+ latLngPoints.add(LatLng(39.915444, 116.267722))
+ latLngPoints.add(LatLng(39.915415, 116.266755))
+ latLngPoints.add(LatLng(39.915403, 116.266165))
+ latLngPoints.add(LatLng(39.915395, 116.265703))
+ latLngPoints.add(LatLng(39.915366, 116.265119))
+ latLngPoints.add(LatLng(39.914716, 116.265097))
+ aMap.addPolyline(
+ PolylineOptions().addAll(latLngPoints).width(10.toFloat()).color(Color.RED)
+ )
}
- override fun initLayoutView(): Int = R.layout.fragment_home
+ override fun initLayoutRes(): Int = R.layout.fragment_home
override fun observeRequestState() {
@@ -36,25 +66,32 @@
}
+ private fun addMarker(point: LatLng, res: Int) {
+ val markerOption = MarkerOptions()
+ markerOption.position(point)
+ markerOption.icon(BitmapDescriptorFactory.fromResource(res))
+ aMap.addMarker(markerOption)
+ }
+
/***以下是地图生命周期管理************************************************************************/
override fun onResume() {
super.onResume()
- baseView.mapView.onResume()
+ bv.mapView.onResume()
}
override fun onPause() {
- baseView.mapView.onPause()
super.onPause()
+ bv.mapView.onPause()
}
override fun onSaveInstanceState(outState: Bundle) {
super.onSaveInstanceState(outState)
- baseView.mapView.onSaveInstanceState(outState)
+ bv.mapView.onSaveInstanceState(outState)
}
override fun onDestroy() {
- baseView.mapView.onDestroy()
super.onDestroy()
+ bv.mapView.onDestroy()
}
}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/br/ktd/fragment/MinePageFragment.kt b/app/src/main/java/com/casic/br/ktd/fragment/MinePageFragment.kt
index 90313ac..3212794 100644
--- a/app/src/main/java/com/casic/br/ktd/fragment/MinePageFragment.kt
+++ b/app/src/main/java/com/casic/br/ktd/fragment/MinePageFragment.kt
@@ -2,10 +2,11 @@
import android.os.Bundle
import com.casic.br.ktd.R
-import com.pengxh.kt.lite.base.KotlinBaseFragment
+import com.casic.br.ktd.base.KotlinBaseFragment
class MinePageFragment : KotlinBaseFragment() {
- override fun initData(savedInstanceState: Bundle?) {
+
+ override fun initView(savedInstanceState: Bundle?) {
}
@@ -13,7 +14,7 @@
}
- override fun initLayoutView(): Int = R.layout.fragment_mine
+ override fun initLayoutRes(): Int = R.layout.fragment_mine
override fun observeRequestState() {
diff --git a/app/src/main/java/com/casic/br/ktd/fragment/TaskPageFragment.kt b/app/src/main/java/com/casic/br/ktd/fragment/TaskPageFragment.kt
index 8f6abf0..6b82a54 100644
--- a/app/src/main/java/com/casic/br/ktd/fragment/TaskPageFragment.kt
+++ b/app/src/main/java/com/casic/br/ktd/fragment/TaskPageFragment.kt
@@ -8,6 +8,7 @@
import androidx.recyclerview.widget.RecyclerView
import com.casic.br.ktd.R
import com.casic.br.ktd.adapter.TaskAdapter
+import com.casic.br.ktd.base.KotlinBaseFragment
import com.casic.br.ktd.holder.SwipeViewHolder
import com.casic.br.ktd.model.TaskListModel
import com.casic.br.ktd.view.InspectionActivity
@@ -15,7 +16,6 @@
import com.casic.br.ktd.widgets.AlertControlDialog
import com.casic.br.ktd.widgets.AlertInputDialog
import com.casic.br.ktd.widgets.DateRangeActionSheet
-import com.pengxh.kt.lite.base.KotlinBaseFragment
import com.pengxh.kt.lite.extensions.navigatePageTo
import com.pengxh.kt.lite.extensions.show
import com.pengxh.kt.lite.utils.WeakReferenceHandler
@@ -36,7 +36,7 @@
private var startTime = ""
private var endTime = ""
- override fun initData(savedInstanceState: Bundle?) {
+ override fun initView(savedInstanceState: Bundle?) {
weakReferenceHandler = WeakReferenceHandler(this)
taskViewModel = ViewModelProvider(this)[TaskViewModel::class.java]
taskViewModel.taskList.observe(this) {
@@ -45,7 +45,7 @@
when {
isRefresh -> {
taskAdapter.setRefreshData(dataRows)
- baseView.taskLayout.finishRefresh()
+ bv.taskLayout.finishRefresh()
isRefresh = false
}
isLoadMore -> {
@@ -53,7 +53,7 @@
"到底了,别拉了".show(requireContext())
}
taskAdapter.setLoadMoreData(dataRows)
- baseView.taskLayout.finishLoadMore()
+ bv.taskLayout.finishLoadMore()
isLoadMore = false
}
else -> {
@@ -76,9 +76,9 @@
when (msg.what) {
2023070501 -> {
if (dataBeans.size == 0) {
- baseView.emptyLayout.visibility = View.VISIBLE
+ bv.emptyLayout.visibility = View.VISIBLE
} else {
- baseView.emptyLayout.visibility = View.GONE
+ bv.emptyLayout.visibility = View.GONE
taskAdapter = object : TaskAdapter(
requireContext(), R.layout.item_task_rv_l, dataBeans
) {
@@ -97,8 +97,8 @@
}
}
//绑定侧滑事件
- swipeAction.attachToRecyclerView(baseView.taskRecyclerView)
- baseView.taskRecyclerView.adapter = taskAdapter
+ swipeAction.attachToRecyclerView(bv.taskRecyclerView)
+ bv.taskRecyclerView.adapter = taskAdapter
taskAdapter.setOnItemCheckedListener(object :
TaskAdapter.OnItemCheckedListener {
override fun onItemChecked(items: ArrayList) {
@@ -168,7 +168,7 @@
override fun initEvent() {
- baseView.calendarView.setOnClickListener {
+ bv.calendarView.setOnClickListener {
DateRangeActionSheet.Builder().setContext(requireContext())
.setOnActionSheetListener(object :
DateRangeActionSheet.OnDateRangeSelectedListener {
@@ -177,12 +177,12 @@
endTime = endDate
//显示
- baseView.selectedDateView.text = "$startDate ~ $endDate"
+ bv.selectedDateView.text = "$startDate ~ $endDate"
}
}).build().show()
}
- baseView.addTaskButton.setOnClickListener {
+ bv.addTaskButton.setOnClickListener {
// AlertInputDialog.Builder()
// .setContext(requireContext())
// .setTitle("新建巡检任务")
@@ -200,11 +200,11 @@
requireContext().navigatePageTo()
}
- baseView.deleteTaskButton.setOnClickListener {
+ bv.deleteTaskButton.setOnClickListener {
selectedItems.size.toString().show(requireContext())
}
- baseView.taskSettingsButton.setOnClickListener {
+ bv.taskSettingsButton.setOnClickListener {
AlertInputDialog.Builder()
.setContext(requireContext())
.setTitle("设置阈值")
@@ -221,14 +221,14 @@
}).build().show()
}
- baseView.taskLayout.setOnRefreshListener {
+ bv.taskLayout.setOnRefreshListener {
isRefresh = true
//刷新之后页码重置
pageIndex = 1
getTaskList()
}
- baseView.taskLayout.setOnLoadMoreListener {
+ bv.taskLayout.setOnLoadMoreListener {
isLoadMore = true
pageIndex++
getTaskList()
@@ -239,13 +239,13 @@
taskViewModel.getTaskList(
startTime,
endTime,
- baseView.taskNameView.text.toString(),
- baseView.taskCodeView.text.toString(),
+ bv.taskNameView.text.toString(),
+ bv.taskCodeView.text.toString(),
pageIndex
)
}
- override fun initLayoutView(): Int = R.layout.fragment_task
+ override fun initLayoutRes(): Int = R.layout.fragment_task
override fun observeRequestState() {
diff --git a/app/src/main/java/com/casic/br/ktd/netty/ISocketListener.kt b/app/src/main/java/com/casic/br/ktd/netty/ISocketListener.kt
deleted file mode 100644
index dab98e1..0000000
--- a/app/src/main/java/com/casic/br/ktd/netty/ISocketListener.kt
+++ /dev/null
@@ -1,19 +0,0 @@
-package com.casic.br.ktd.netty
-
-interface ISocketListener {
- companion object {
- const val STATUS_CONNECT_SUCCESS: Byte = 1 //连接成功
- const val STATUS_CONNECT_CLOSED: Byte = 0 //关闭连接
- const val STATUS_CONNECT_ERROR: Byte = 0 //连接失败
- }
-
- /**
- * 当接收到系统消息
- */
- fun onMessageResponse(data: ByteArray?)
-
- /**
- * 当连接状态发生变化时调用
- */
- fun onServiceStatusConnectChanged(statusCode: Byte)
-}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/br/ktd/netty/SocketChannelHandle.kt b/app/src/main/java/com/casic/br/ktd/netty/SocketChannelHandle.kt
deleted file mode 100644
index 42eb310..0000000
--- a/app/src/main/java/com/casic/br/ktd/netty/SocketChannelHandle.kt
+++ /dev/null
@@ -1,51 +0,0 @@
-package com.casic.br.ktd.netty
-
-import android.util.Log
-import io.netty.channel.ChannelHandlerContext
-import io.netty.channel.SimpleChannelInboundHandler
-import io.netty.handler.timeout.IdleState
-import io.netty.handler.timeout.IdleStateEvent
-import java.nio.charset.StandardCharsets
-
-class SocketChannelHandle(private val listener: ISocketListener?) :
- SimpleChannelInboundHandler() {
-
- private val kTag = "SocketChannelHandle"
-
- override fun channelActive(ctx: ChannelHandlerContext) {
- super.channelActive(ctx)
- Log.d(kTag, "channelActive ===> 连接成功")
- listener?.onServiceStatusConnectChanged(ISocketListener.STATUS_CONNECT_SUCCESS)
- }
-
- override fun channelInactive(ctx: ChannelHandlerContext) {
- super.channelInactive(ctx)
- Log.e(kTag, "channelInactive: 连接断开")
- }
-
- override fun userEventTriggered(ctx: ChannelHandlerContext, evt: Any) {
- super.userEventTriggered(ctx, evt)
- if (evt is IdleStateEvent) {
- if (evt.state() == IdleState.WRITER_IDLE) {
- //写超时,此时可以发送心跳数据给服务器
- val temp = "FF"
- ctx.writeAndFlush(temp.toByteArray(StandardCharsets.UTF_8))
- } else if (evt.state() == IdleState.READER_IDLE) {
- //读超时,此时代表没有收到心跳返回可以关闭当前连接进行重连
- ctx.close()
- }
- }
- }
-
- override fun channelRead0(ctx: ChannelHandlerContext, data: ByteArray?) {
- listener?.onMessageResponse(data)
- }
-
- override fun exceptionCaught(ctx: ChannelHandlerContext, cause: Throwable) {
- super.exceptionCaught(ctx, cause)
- Log.d(kTag, "exceptionCaught ===> $cause")
- listener?.onServiceStatusConnectChanged(ISocketListener.STATUS_CONNECT_ERROR)
- cause.printStackTrace()
- ctx.close()
- }
-}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/br/ktd/netty/SocketClient.kt b/app/src/main/java/com/casic/br/ktd/netty/SocketClient.kt
deleted file mode 100644
index d05d335..0000000
--- a/app/src/main/java/com/casic/br/ktd/netty/SocketClient.kt
+++ /dev/null
@@ -1,153 +0,0 @@
-package com.casic.br.ktd.netty
-
-import android.os.SystemClock
-import android.util.Log
-import io.netty.bootstrap.Bootstrap
-import io.netty.channel.*
-import io.netty.channel.nio.NioEventLoopGroup
-import io.netty.channel.socket.SocketChannel
-import io.netty.channel.socket.nio.NioSocketChannel
-import io.netty.handler.codec.bytes.ByteArrayDecoder
-import io.netty.handler.codec.bytes.ByteArrayEncoder
-import io.netty.handler.timeout.IdleStateHandler
-
-class SocketClient {
-
- private val kTag = "SocketClient"
-
- private var host: String? = null
- private var port = 8000
- private var nioEventLoopGroup: NioEventLoopGroup? = null
- private var channel: Channel? = null
- private var listener: ISocketListener? = null
-
- //现在连接的状态
- var connectStatus = false //判断是否已连接
- private var reconnectNum = Int.MAX_VALUE //定义的重连到时候用
- private var isNeedReconnect = true //是否需要重连
- var isConnecting = false //是否正在连接
- private set
- private var reconnectIntervalTime: Long = 15000 //重连的时间
-
- //重连时间
- fun setReconnectNum(reconnectNum: Int) {
- this.reconnectNum = reconnectNum
- }
-
- fun setReconnectIntervalTime(reconnectIntervalTime: Long) {
- this.reconnectIntervalTime = reconnectIntervalTime
- }
-
- fun setSocketListener(listener: ISocketListener?) {
- this.listener = listener
- }
-
- fun connect(host: String, port: Int) {
- this.host = host
- this.port = port
- Log.d(kTag, "connect ===> 开始连接TCP服务器")
- if (isConnecting) {
- return
- }
- //起个线程
- val clientThread: Thread = object : Thread("client-Netty") {
- override fun run() {
- super.run()
- isNeedReconnect = true
- reconnectNum = Int.MAX_VALUE
- connectServer()
- }
- }
- clientThread.start()
- }
-
- private fun connectServer() {
- synchronized(this@SocketClient) {
- var channelFuture: ChannelFuture? = null //连接管理对象
- if (!connectStatus) {
- isConnecting = true
- nioEventLoopGroup = NioEventLoopGroup() //设置的连接group
- val bootstrap = Bootstrap()
- bootstrap.group(nioEventLoopGroup) //设置的一系列连接参数操作等
- .channel(NioSocketChannel::class.java)
- .option(ChannelOption.TCP_NODELAY, true) //无阻塞
- .option(ChannelOption.SO_KEEPALIVE, true) //长连接
- .option(
- ChannelOption.RCVBUF_ALLOCATOR,
- AdaptiveRecvByteBufAllocator(5000, 5000, 8000)
- ) //接收缓冲区 最小值太小时数据接收不全
- .handler(object : ChannelInitializer() {
- override fun initChannel(channel: SocketChannel) {
- val pipeline = channel.pipeline()
- //参数1:代表读套接字超时的时间,没收到数据会触发读超时回调;
- //参数2:代表写套接字超时时间,没进行写会触发写超时回调;
- //参数3:将在未执行读取或写入时触发超时回调,0代表不处理;
- //读超时尽量设置大于写超时,代表多次写超时时写心跳包,多次写了心跳数据仍然读超时代表当前连接错误,即可断开连接重新连接
- pipeline.addLast(IdleStateHandler(60, 10, 0))
- pipeline.addLast(ByteArrayDecoder())
- pipeline.addLast(ByteArrayEncoder())
- pipeline.addLast(SocketChannelHandle(listener))
- }
- })
- try {
- //连接监听
- channelFuture = bootstrap.connect(host, port)
- .addListener(object : ChannelFutureListener {
- override fun operationComplete(channelFuture: ChannelFuture) {
- if (channelFuture.isSuccess) {
- connectStatus = true
- channel = channelFuture.channel()
- } else {
- Log.e(kTag, "operationComplete: 连接失败")
- connectStatus = false
- }
- isConnecting = false
- }
- }).sync()
- // 等待连接关闭
- channelFuture.channel().closeFuture().sync()
- } catch (e: Exception) {
- e.printStackTrace()
- } finally {
- connectStatus = false
- listener?.onServiceStatusConnectChanged(ISocketListener.STATUS_CONNECT_CLOSED) //STATUS_CONNECT_CLOSED 这我自己定义的 接口标识
- if (null != channelFuture) {
- if (channelFuture.channel() != null && channelFuture.channel().isOpen) {
- channelFuture.channel().close()
- }
- }
- nioEventLoopGroup?.shutdownGracefully()
- reconnect() //重新连接
- }
- }
- }
- }
-
- //断开连接
- fun disconnect() {
- Log.d(kTag, "disconnect ===> 断开连接")
- isNeedReconnect = false
- nioEventLoopGroup?.shutdownGracefully()
- }
-
- //重新连接
- private fun reconnect() {
- if (isNeedReconnect && reconnectNum > 0 && !connectStatus) {
- reconnectNum--
- SystemClock.sleep(reconnectIntervalTime)
- if (isNeedReconnect && reconnectNum > 0 && !connectStatus) {
- Log.d(kTag, "reconnect ===> 重新连接")
- connectServer()
- }
- }
- }
-
- fun sendData(bytes: ByteArray) {
- channel?.writeAndFlush(bytes)?.addListener(ChannelFutureListener { future ->
- if (!future.isSuccess) {
- future.channel().close()
- nioEventLoopGroup!!.shutdownGracefully()
- }
- })
- }
-}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/br/ktd/netty/SocketManager.kt b/app/src/main/java/com/casic/br/ktd/netty/SocketManager.kt
deleted file mode 100644
index 17daf35..0000000
--- a/app/src/main/java/com/casic/br/ktd/netty/SocketManager.kt
+++ /dev/null
@@ -1,113 +0,0 @@
-package com.casic.br.ktd.netty
-
-import android.util.Log
-import com.casic.br.ktd.base.BaseApplication
-import com.casic.br.ktd.extensions.covertAngleValue
-import com.casic.br.ktd.extensions.covertDataValue
-import com.casic.br.ktd.extensions.toUnsignedByteArray
-import com.casic.br.ktd.model.SensorDataModel
-import com.casic.br.ktd.utils.LocaleConstant
-import com.pengxh.kt.lite.extensions.toJson
-import com.pengxh.kt.lite.utils.BroadcastManager
-
-class SocketManager private constructor() : ISocketListener {
-
- private val kTag = "SocketManager"
- private var nettyClient: SocketClient = SocketClient()
-
- companion object {
- val instance: SocketManager by lazy(mode = LazyThreadSafetyMode.SYNCHRONIZED) { SocketManager() }
- }
-
- fun connectNetty(hostname: String, port: Int) {
- Thread {
- if (!nettyClient.connectStatus) {
- nettyClient.setSocketListener(this)
- nettyClient.connect(hostname, port)
- } else {
- nettyClient.disconnect()
- }
- }.start()
- }
-
- override fun onMessageResponse(data: ByteArray?) {
-// Log.d(kTag, "onMessageResponse ===> " + Arrays.toString(data))
- /**
- * 0xFF,0x01,
- * 0x01,0x37,0xE6, 甲烷浓度值(数据码1* 65536 + 数据码2 * 256 + 数据码3)
- * 0x00, 激光甲烷模块工作状态(00表示设备正常,01表示温控故障,02表示设备激光未打开)
- * 0x00,0xB2,0x35, 激光强度值(数据码5* 65536 + 数据码6 * 256 + 数据码7)
- * 0x0A,0x3D, 云台水平角度([数据码8 * 256 + 数据码9]/100,单位为°,精确到0.01)
- * 0x05,0x6F, 云台垂直角度(首先计算Tangle=[数据码10 * 256 + 数据码11]/100,单位为°,精确到0.01。若Tangle在0~90范围内,则垂直角度值=Tangle;若Tangle在-1~-90范围内,则垂直角度值=Tangle-360)
- * 0xC1
- *
- * [-1, 1, 1, 55, -26, 0, 0, -78, 53, 10, 61, 5, 111, -63]
- * 甲烷浓度值为79638,计算为79638=0x01*65536+0x37*256+0xE6[0x01为数据码1,0x37为数据码2,0xE6为数据码3];
- * 激光甲烷设备状态值为0,表示状态正常,[0x00为数据码4];
- * 激光强度值为45621,计算为45621=0x00*65536+0xB2*256+0x35[0x00为数据码5,0xB2为数据码6,0x35为数据码7];
- *
- * =========================================================================================
- * 实际数据(1800-1950左右)
- * [-86, 1, 0, 7, 71, 0, 0, 62, -92, 57, 59, -118, -111, -64]
- * */
-
- if (data == null) {
- return
- }
- val bytes = data.toUnsignedByteArray()
- if (bytes.size == 14) {
- val dataModel = SensorDataModel(0, "激光未打开", 0, 0.0, 0.0)
-
- val methaneBytes = IntArray(3)
- System.arraycopy(bytes, 2, methaneBytes, 0, 3)
- dataModel.methane = methaneBytes.covertDataValue()
-
- dataModel.methaneState = when (bytes[5]) {
- 1 -> "温控故障"
- 2 -> "激光未打开"
- else -> "正常"
- }
-
- val laserBytes = IntArray(3)
- System.arraycopy(bytes, 6, laserBytes, 0, 3)
- dataModel.laser = laserBytes.covertDataValue()
-
- /**
- * 水平角度的实际范围为从水平零点开始,顺时针方向(从上往下看),0~360°
- * 垂直角度的实际范围为从垂直零点开始,以向上为正,-90°~90°,控制精度为0.01°
- * */
- val horizontalBytes = IntArray(2)
- System.arraycopy(bytes, 9, horizontalBytes, 0, 2)
- dataModel.horizontal = horizontalBytes.covertAngleValue()
-
- val verticalBytes = IntArray(2)
- System.arraycopy(bytes, 11, verticalBytes, 0, 2)
- dataModel.vertical = verticalBytes.covertAngleValue()
-
- //{"horizontal":26.21,"laser":45621,"methane":79846,"methaneState":"正常","vertical":13.91}
- BroadcastManager.obtainInstance(BaseApplication.get()).sendBroadcast(
- LocaleConstant.ACTION_UPDATE_DATA, dataModel.toJson()
- )
- }
- }
-
- override fun onServiceStatusConnectChanged(statusCode: Byte) {
- if (statusCode == ISocketListener.STATUS_CONNECT_SUCCESS) {
- if (nettyClient.connectStatus) {
- Log.d(kTag, "连接成功")
- }
- } else {
- if (!nettyClient.connectStatus) {
- Log.e(kTag, "onServiceStatusConnectChanged:$statusCode,连接断开,正在重连")
- }
- }
- }
-
- fun sendData(data: ByteArray) {
- nettyClient.sendData(data)
- }
-
- fun close() {
- nettyClient.disconnect()
- }
-}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/br/ktd/netty/tcp/ISocketListener.kt b/app/src/main/java/com/casic/br/ktd/netty/tcp/ISocketListener.kt
new file mode 100644
index 0000000..13c3084
--- /dev/null
+++ b/app/src/main/java/com/casic/br/ktd/netty/tcp/ISocketListener.kt
@@ -0,0 +1,19 @@
+package com.casic.br.ktd.netty.tcp
+
+interface ISocketListener {
+ companion object {
+ const val STATUS_CONNECT_SUCCESS: Byte = 1 //连接成功
+ const val STATUS_CONNECT_CLOSED: Byte = 0 //关闭连接
+ const val STATUS_CONNECT_ERROR: Byte = 0 //连接失败
+ }
+
+ /**
+ * 当接收到系统消息
+ */
+ fun onMessageResponse(data: ByteArray?)
+
+ /**
+ * 当连接状态发生变化时调用
+ */
+ fun onServiceStatusConnectChanged(statusCode: Byte)
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/br/ktd/netty/tcp/SocketChannelHandle.kt b/app/src/main/java/com/casic/br/ktd/netty/tcp/SocketChannelHandle.kt
new file mode 100644
index 0000000..8e2997f
--- /dev/null
+++ b/app/src/main/java/com/casic/br/ktd/netty/tcp/SocketChannelHandle.kt
@@ -0,0 +1,51 @@
+package com.casic.br.ktd.netty.tcp
+
+import android.util.Log
+import io.netty.channel.ChannelHandlerContext
+import io.netty.channel.SimpleChannelInboundHandler
+import io.netty.handler.timeout.IdleState
+import io.netty.handler.timeout.IdleStateEvent
+import java.nio.charset.StandardCharsets
+
+class SocketChannelHandle(private val listener: ISocketListener?) :
+ SimpleChannelInboundHandler() {
+
+ private val kTag = "SocketChannelHandle"
+
+ override fun channelActive(ctx: ChannelHandlerContext) {
+ super.channelActive(ctx)
+ Log.d(kTag, "channelActive ===> 连接成功")
+ listener?.onServiceStatusConnectChanged(ISocketListener.STATUS_CONNECT_SUCCESS)
+ }
+
+ override fun channelInactive(ctx: ChannelHandlerContext) {
+ super.channelInactive(ctx)
+ Log.e(kTag, "channelInactive: 连接断开")
+ }
+
+ override fun userEventTriggered(ctx: ChannelHandlerContext, evt: Any) {
+ super.userEventTriggered(ctx, evt)
+ if (evt is IdleStateEvent) {
+ if (evt.state() == IdleState.WRITER_IDLE) {
+ //写超时,此时可以发送心跳数据给服务器
+ val temp = "FF"
+ ctx.writeAndFlush(temp.toByteArray(StandardCharsets.UTF_8))
+ } else if (evt.state() == IdleState.READER_IDLE) {
+ //读超时,此时代表没有收到心跳返回可以关闭当前连接进行重连
+ ctx.close()
+ }
+ }
+ }
+
+ override fun channelRead0(ctx: ChannelHandlerContext, data: ByteArray?) {
+ listener?.onMessageResponse(data)
+ }
+
+ override fun exceptionCaught(ctx: ChannelHandlerContext, cause: Throwable) {
+ super.exceptionCaught(ctx, cause)
+ Log.d(kTag, "exceptionCaught ===> $cause")
+ listener?.onServiceStatusConnectChanged(ISocketListener.STATUS_CONNECT_ERROR)
+ cause.printStackTrace()
+ ctx.close()
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/br/ktd/netty/tcp/SocketClient.kt b/app/src/main/java/com/casic/br/ktd/netty/tcp/SocketClient.kt
new file mode 100644
index 0000000..34960a0
--- /dev/null
+++ b/app/src/main/java/com/casic/br/ktd/netty/tcp/SocketClient.kt
@@ -0,0 +1,153 @@
+package com.casic.br.ktd.netty.tcp
+
+import android.os.SystemClock
+import android.util.Log
+import io.netty.bootstrap.Bootstrap
+import io.netty.channel.*
+import io.netty.channel.nio.NioEventLoopGroup
+import io.netty.channel.socket.SocketChannel
+import io.netty.channel.socket.nio.NioSocketChannel
+import io.netty.handler.codec.bytes.ByteArrayDecoder
+import io.netty.handler.codec.bytes.ByteArrayEncoder
+import io.netty.handler.timeout.IdleStateHandler
+
+class SocketClient {
+
+ private val kTag = "SocketClient"
+
+ private var host: String? = null
+ private var port = 8000
+ private var nioEventLoopGroup: NioEventLoopGroup? = null
+ private var channel: Channel? = null
+ private var listener: ISocketListener? = null
+
+ //现在连接的状态
+ var connectStatus = false //判断是否已连接
+ private var reconnectNum = Int.MAX_VALUE //定义的重连到时候用
+ private var isNeedReconnect = true //是否需要重连
+ var isConnecting = false //是否正在连接
+ private set
+ private var reconnectIntervalTime: Long = 15000 //重连的时间
+
+ //重连时间
+ fun setReconnectNum(reconnectNum: Int) {
+ this.reconnectNum = reconnectNum
+ }
+
+ fun setReconnectIntervalTime(reconnectIntervalTime: Long) {
+ this.reconnectIntervalTime = reconnectIntervalTime
+ }
+
+ fun setSocketListener(listener: ISocketListener?) {
+ this.listener = listener
+ }
+
+ fun connect(host: String, port: Int) {
+ this.host = host
+ this.port = port
+ Log.d(kTag, "connect ===> 开始连接TCP服务器")
+ if (isConnecting) {
+ return
+ }
+ //起个线程
+ val clientThread: Thread = object : Thread("client-Netty") {
+ override fun run() {
+ super.run()
+ isNeedReconnect = true
+ reconnectNum = Int.MAX_VALUE
+ connectServer()
+ }
+ }
+ clientThread.start()
+ }
+
+ private fun connectServer() {
+ synchronized(this@SocketClient) {
+ var channelFuture: ChannelFuture? = null //连接管理对象
+ if (!connectStatus) {
+ isConnecting = true
+ nioEventLoopGroup = NioEventLoopGroup() //设置的连接group
+ val bootstrap = Bootstrap()
+ bootstrap.group(nioEventLoopGroup) //设置的一系列连接参数操作等
+ .channel(NioSocketChannel::class.java)
+ .option(ChannelOption.TCP_NODELAY, true) //无阻塞
+ .option(ChannelOption.SO_KEEPALIVE, true) //长连接
+ .option(
+ ChannelOption.RCVBUF_ALLOCATOR,
+ AdaptiveRecvByteBufAllocator(5000, 5000, 8000)
+ ) //接收缓冲区 最小值太小时数据接收不全
+ .handler(object : ChannelInitializer() {
+ override fun initChannel(channel: SocketChannel) {
+ val pipeline = channel.pipeline()
+ //参数1:代表读套接字超时的时间,没收到数据会触发读超时回调;
+ //参数2:代表写套接字超时时间,没进行写会触发写超时回调;
+ //参数3:将在未执行读取或写入时触发超时回调,0代表不处理;
+ //读超时尽量设置大于写超时,代表多次写超时时写心跳包,多次写了心跳数据仍然读超时代表当前连接错误,即可断开连接重新连接
+ pipeline.addLast(IdleStateHandler(60, 10, 0))
+ pipeline.addLast(ByteArrayDecoder())
+ pipeline.addLast(ByteArrayEncoder())
+ pipeline.addLast(SocketChannelHandle(listener))
+ }
+ })
+ try {
+ //连接监听
+ channelFuture = bootstrap.connect(host, port)
+ .addListener(object : ChannelFutureListener {
+ override fun operationComplete(channelFuture: ChannelFuture) {
+ if (channelFuture.isSuccess) {
+ connectStatus = true
+ channel = channelFuture.channel()
+ } else {
+ Log.e(kTag, "operationComplete: 连接失败")
+ connectStatus = false
+ }
+ isConnecting = false
+ }
+ }).sync()
+ // 等待连接关闭
+ channelFuture.channel().closeFuture().sync()
+ } catch (e: Exception) {
+ e.printStackTrace()
+ } finally {
+ connectStatus = false
+ listener?.onServiceStatusConnectChanged(ISocketListener.STATUS_CONNECT_CLOSED) //STATUS_CONNECT_CLOSED 这我自己定义的 接口标识
+ if (null != channelFuture) {
+ if (channelFuture.channel() != null && channelFuture.channel().isOpen) {
+ channelFuture.channel().close()
+ }
+ }
+ nioEventLoopGroup?.shutdownGracefully()
+ reconnect() //重新连接
+ }
+ }
+ }
+ }
+
+ //断开连接
+ fun disconnect() {
+ Log.d(kTag, "disconnect ===> 断开连接")
+ isNeedReconnect = false
+ nioEventLoopGroup?.shutdownGracefully()
+ }
+
+ //重新连接
+ private fun reconnect() {
+ if (isNeedReconnect && reconnectNum > 0 && !connectStatus) {
+ reconnectNum--
+ SystemClock.sleep(reconnectIntervalTime)
+ if (isNeedReconnect && reconnectNum > 0 && !connectStatus) {
+ Log.d(kTag, "reconnect ===> 重新连接")
+ connectServer()
+ }
+ }
+ }
+
+ fun sendData(bytes: ByteArray) {
+ channel?.writeAndFlush(bytes)?.addListener(ChannelFutureListener { future ->
+ if (!future.isSuccess) {
+ future.channel().close()
+ nioEventLoopGroup!!.shutdownGracefully()
+ }
+ })
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/br/ktd/netty/tcp/SocketManager.kt b/app/src/main/java/com/casic/br/ktd/netty/tcp/SocketManager.kt
new file mode 100644
index 0000000..35980b9
--- /dev/null
+++ b/app/src/main/java/com/casic/br/ktd/netty/tcp/SocketManager.kt
@@ -0,0 +1,113 @@
+package com.casic.br.ktd.netty.tcp
+
+import android.util.Log
+import com.casic.br.ktd.base.BaseApplication
+import com.casic.br.ktd.extensions.covertAngleValue
+import com.casic.br.ktd.extensions.covertDataValue
+import com.casic.br.ktd.extensions.toUnsignedByteArray
+import com.casic.br.ktd.model.SensorDataModel
+import com.casic.br.ktd.utils.LocaleConstant
+import com.pengxh.kt.lite.extensions.toJson
+import com.pengxh.kt.lite.utils.BroadcastManager
+
+class SocketManager private constructor() : ISocketListener {
+
+ private val kTag = "SocketManager"
+ private var nettyClient: SocketClient = SocketClient()
+
+ companion object {
+ val instance: SocketManager by lazy(mode = LazyThreadSafetyMode.SYNCHRONIZED) { SocketManager() }
+ }
+
+ fun connectNetty(hostname: String, port: Int) {
+ Thread {
+ if (!nettyClient.connectStatus) {
+ nettyClient.setSocketListener(this)
+ nettyClient.connect(hostname, port)
+ } else {
+ nettyClient.disconnect()
+ }
+ }.start()
+ }
+
+ override fun onMessageResponse(data: ByteArray?) {
+// Log.d(kTag, "onMessageResponse ===> " + Arrays.toString(data))
+ /**
+ * 0xFF,0x01,
+ * 0x01,0x37,0xE6, 甲烷浓度值(数据码1* 65536 + 数据码2 * 256 + 数据码3)
+ * 0x00, 激光甲烷模块工作状态(00表示设备正常,01表示温控故障,02表示设备激光未打开)
+ * 0x00,0xB2,0x35, 激光强度值(数据码5* 65536 + 数据码6 * 256 + 数据码7)
+ * 0x0A,0x3D, 云台水平角度([数据码8 * 256 + 数据码9]/100,单位为°,精确到0.01)
+ * 0x05,0x6F, 云台垂直角度(首先计算Tangle=[数据码10 * 256 + 数据码11]/100,单位为°,精确到0.01。若Tangle在0~90范围内,则垂直角度值=Tangle;若Tangle在-1~-90范围内,则垂直角度值=Tangle-360)
+ * 0xC1
+ *
+ * [-1, 1, 1, 55, -26, 0, 0, -78, 53, 10, 61, 5, 111, -63]
+ * 甲烷浓度值为79638,计算为79638=0x01*65536+0x37*256+0xE6[0x01为数据码1,0x37为数据码2,0xE6为数据码3];
+ * 激光甲烷设备状态值为0,表示状态正常,[0x00为数据码4];
+ * 激光强度值为45621,计算为45621=0x00*65536+0xB2*256+0x35[0x00为数据码5,0xB2为数据码6,0x35为数据码7];
+ *
+ * =========================================================================================
+ * 实际数据(1800-1950左右)
+ * [-86, 1, 0, 7, 71, 0, 0, 62, -92, 57, 59, -118, -111, -64]
+ * */
+
+ if (data == null) {
+ return
+ }
+ val bytes = data.toUnsignedByteArray()
+ if (bytes.size == 14) {
+ val dataModel = SensorDataModel(0, "激光未打开", 0, 0.0, 0.0)
+
+ val methaneBytes = IntArray(3)
+ System.arraycopy(bytes, 2, methaneBytes, 0, 3)
+ dataModel.methane = methaneBytes.covertDataValue()
+
+ dataModel.methaneState = when (bytes[5]) {
+ 1 -> "温控故障"
+ 2 -> "激光未打开"
+ else -> "正常"
+ }
+
+ val laserBytes = IntArray(3)
+ System.arraycopy(bytes, 6, laserBytes, 0, 3)
+ dataModel.laser = laserBytes.covertDataValue()
+
+ /**
+ * 水平角度的实际范围为从水平零点开始,顺时针方向(从上往下看),0~360°
+ * 垂直角度的实际范围为从垂直零点开始,以向上为正,-90°~90°,控制精度为0.01°
+ * */
+ val horizontalBytes = IntArray(2)
+ System.arraycopy(bytes, 9, horizontalBytes, 0, 2)
+ dataModel.horizontal = horizontalBytes.covertAngleValue()
+
+ val verticalBytes = IntArray(2)
+ System.arraycopy(bytes, 11, verticalBytes, 0, 2)
+ dataModel.vertical = verticalBytes.covertAngleValue()
+
+ //{"horizontal":26.21,"laser":45621,"methane":79846,"methaneState":"正常","vertical":13.91}
+ BroadcastManager.obtainInstance(BaseApplication.get()).sendBroadcast(
+ LocaleConstant.ACTION_UPDATE_DATA, dataModel.toJson()
+ )
+ }
+ }
+
+ override fun onServiceStatusConnectChanged(statusCode: Byte) {
+ if (statusCode == ISocketListener.STATUS_CONNECT_SUCCESS) {
+ if (nettyClient.connectStatus) {
+ Log.d(kTag, "连接成功")
+ }
+ } else {
+ if (!nettyClient.connectStatus) {
+ Log.e(kTag, "onServiceStatusConnectChanged:$statusCode,连接断开,正在重连")
+ }
+ }
+ }
+
+ fun sendData(data: ByteArray) {
+ nettyClient.sendData(data)
+ }
+
+ fun close() {
+ nettyClient.disconnect()
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/br/ktd/netty/udp/UdpChannelInboundHandler.kt b/app/src/main/java/com/casic/br/ktd/netty/udp/UdpChannelInboundHandler.kt
new file mode 100644
index 0000000..4d6f97c
--- /dev/null
+++ b/app/src/main/java/com/casic/br/ktd/netty/udp/UdpChannelInboundHandler.kt
@@ -0,0 +1,36 @@
+package com.casic.br.ktd.netty.udp
+
+import io.netty.channel.ChannelHandlerContext
+import io.netty.channel.SimpleChannelInboundHandler
+import io.netty.channel.socket.DatagramPacket
+import io.netty.util.CharsetUtil
+
+
+abstract class UdpChannelInboundHandler : SimpleChannelInboundHandler() {
+
+ private var handlerContext: ChannelHandlerContext? = null
+
+ override fun channelActive(ctx: ChannelHandlerContext?) {
+ super.channelActive(ctx)
+ handlerContext = ctx
+ }
+
+ override fun channelInactive(ctx: ChannelHandlerContext?) {
+ super.channelInactive(ctx)
+ handlerContext?.close()
+ }
+
+ fun sendDatagramPacket(obj: Any) {
+ handlerContext?.writeAndFlush(obj)
+ }
+
+ fun releasePort() {
+ handlerContext?.close()
+ }
+
+ override fun channelRead0(ctx: ChannelHandlerContext, datagramPacket: DatagramPacket) {
+ receivedMessage(datagramPacket.content().toString(CharsetUtil.UTF_8))
+ }
+
+ abstract fun receivedMessage(data: String)
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/br/ktd/netty/udp/UdpChannelInitializer.kt b/app/src/main/java/com/casic/br/ktd/netty/udp/UdpChannelInitializer.kt
new file mode 100644
index 0000000..416c5a1
--- /dev/null
+++ b/app/src/main/java/com/casic/br/ktd/netty/udp/UdpChannelInitializer.kt
@@ -0,0 +1,17 @@
+package com.casic.br.ktd.netty.udp
+
+import io.netty.channel.ChannelInitializer
+import io.netty.channel.socket.DatagramChannel
+import io.netty.handler.timeout.IdleStateHandler
+
+
+open class UdpChannelInitializer(private val handler: UdpChannelInboundHandler) :
+ ChannelInitializer() {
+
+ override fun initChannel(datagramChannel: DatagramChannel) {
+ val pipeline = datagramChannel.pipeline()
+ pipeline.addLast(
+ IdleStateHandler(12, 15, 0)
+ ).addLast(handler)
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index e822df6..d72c1a5 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -7,6 +7,9 @@
+
+
+
@@ -46,5 +49,8 @@
+
+
+
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/br/ktd/base/KotlinBaseFragment.kt b/app/src/main/java/com/casic/br/ktd/base/KotlinBaseFragment.kt
new file mode 100644
index 0000000..2dac61c
--- /dev/null
+++ b/app/src/main/java/com/casic/br/ktd/base/KotlinBaseFragment.kt
@@ -0,0 +1,51 @@
+package com.casic.br.ktd.base
+
+import android.os.Bundle
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import androidx.annotation.LayoutRes
+import androidx.fragment.app.Fragment
+
+abstract class KotlinBaseFragment : Fragment() {
+
+ lateinit var bv: View
+
+ override fun onCreateView(
+ inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?
+ ): View? {
+ bv = inflater.inflate(initLayoutRes(), container, false)
+ initView(savedInstanceState)
+ setupTopBarLayout()
+ return bv
+ }
+
+ override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
+ super.onViewCreated(view, savedInstanceState)
+ observeRequestState()
+ initEvent()
+ }
+
+ @LayoutRes
+ abstract fun initLayoutRes(): Int
+
+ /**
+ * 沉浸式状态栏
+ */
+ abstract fun setupTopBarLayout()
+
+ /**
+ * 初始化布局以及控件
+ */
+ abstract fun initView(savedInstanceState: Bundle?)
+
+ /**
+ * 网络请求状态监听
+ */
+ abstract fun observeRequestState()
+
+ /**
+ * 业务逻辑,按钮等事件
+ */
+ abstract fun initEvent()
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/br/ktd/fragment/AlarmPageFragment.kt b/app/src/main/java/com/casic/br/ktd/fragment/AlarmPageFragment.kt
index 6c98a3b..9418169 100644
--- a/app/src/main/java/com/casic/br/ktd/fragment/AlarmPageFragment.kt
+++ b/app/src/main/java/com/casic/br/ktd/fragment/AlarmPageFragment.kt
@@ -2,28 +2,29 @@
import android.os.Bundle
import com.casic.br.ktd.R
+import com.casic.br.ktd.base.KotlinBaseFragment
import com.casic.br.ktd.widgets.DateRangeActionSheet
-import com.pengxh.kt.lite.base.KotlinBaseFragment
import kotlinx.android.synthetic.main.fragment_alarm.view.*
class AlarmPageFragment : KotlinBaseFragment() {
- override fun initData(savedInstanceState: Bundle?) {
+
+ override fun initView(savedInstanceState: Bundle?) {
}
override fun initEvent() {
- baseView.calendarView.setOnClickListener {
+ bv.calendarView.setOnClickListener {
DateRangeActionSheet.Builder().setContext(requireContext())
.setOnActionSheetListener(object :
DateRangeActionSheet.OnDateRangeSelectedListener {
override fun onDateRangeSelected(startDate: String, endDate: String) {
- baseView.selectedDateView.text = "$startDate ~ $endDate"
+ bv.selectedDateView.text = "$startDate ~ $endDate"
}
}).build().show()
}
}
- override fun initLayoutView(): Int = R.layout.fragment_alarm
+ override fun initLayoutRes(): Int = R.layout.fragment_alarm
override fun observeRequestState() {
diff --git a/app/src/main/java/com/casic/br/ktd/fragment/HomePageFragment.kt b/app/src/main/java/com/casic/br/ktd/fragment/HomePageFragment.kt
index 9961935..f3eba5c 100644
--- a/app/src/main/java/com/casic/br/ktd/fragment/HomePageFragment.kt
+++ b/app/src/main/java/com/casic/br/ktd/fragment/HomePageFragment.kt
@@ -1,32 +1,62 @@
package com.casic.br.ktd.fragment
+import android.graphics.Color
import android.os.Bundle
import com.amap.api.maps.AMap
import com.amap.api.maps.AMapOptions
+import com.amap.api.maps.CameraUpdateFactory
+import com.amap.api.maps.model.*
import com.casic.br.ktd.R
-import com.pengxh.kt.lite.base.KotlinBaseFragment
+import com.casic.br.ktd.base.KotlinBaseFragment
import kotlinx.android.synthetic.main.fragment_home.view.*
class HomePageFragment : KotlinBaseFragment() {
private lateinit var aMap: AMap
- override fun initData(savedInstanceState: Bundle?) {
- baseView.mapView.onCreate(savedInstanceState)
- aMap = baseView.mapView.map
+ override fun initView(savedInstanceState: Bundle?) {
+ bv.mapView.onCreate(savedInstanceState)
+ aMap = bv.mapView.map
val uiSettings = aMap.uiSettings
uiSettings.isCompassEnabled = true
- uiSettings.isMyLocationButtonEnabled = true
+ uiSettings.isMyLocationButtonEnabled = false
uiSettings.isScaleControlsEnabled = true
uiSettings.zoomPosition = AMapOptions.ZOOM_POSITION_RIGHT_CENTER
uiSettings.isRotateGesturesEnabled = false//不许地图随手势旋转角度
}
override fun initEvent() {
-
+ //移动到巡检起始经纬度
+ val cameraPosition = CameraPosition(LatLng(39.914199, 116.265785), 16f, 0f, 0f)
+ val cameraUpdate = CameraUpdateFactory.newCameraPosition(cameraPosition)
+ aMap.animateCamera(cameraUpdate, 1500, null)
+ //设置起点
+ addMarker(LatLng(39.914885, 116.272312), R.mipmap.start)
+ //设置终点
+ addMarker(LatLng(39.914716, 116.265097), R.mipmap.end)
+ //瞄点画线
+ val latLngPoints = ArrayList()
+ latLngPoints.add(LatLng(39.914885, 116.272312))
+ latLngPoints.add(LatLng(39.915148, 116.272312))
+ latLngPoints.add(LatLng(39.915399, 116.272302))
+ latLngPoints.add(LatLng(39.915436, 116.271787))
+ latLngPoints.add(LatLng(39.915477, 116.270886))
+ latLngPoints.add(LatLng(39.915477, 116.269968))
+ latLngPoints.add(LatLng(39.915469, 116.269544))
+ latLngPoints.add(LatLng(39.915481, 116.269196))
+ latLngPoints.add(LatLng(39.915452, 116.268472))
+ latLngPoints.add(LatLng(39.915444, 116.267722))
+ latLngPoints.add(LatLng(39.915415, 116.266755))
+ latLngPoints.add(LatLng(39.915403, 116.266165))
+ latLngPoints.add(LatLng(39.915395, 116.265703))
+ latLngPoints.add(LatLng(39.915366, 116.265119))
+ latLngPoints.add(LatLng(39.914716, 116.265097))
+ aMap.addPolyline(
+ PolylineOptions().addAll(latLngPoints).width(10.toFloat()).color(Color.RED)
+ )
}
- override fun initLayoutView(): Int = R.layout.fragment_home
+ override fun initLayoutRes(): Int = R.layout.fragment_home
override fun observeRequestState() {
@@ -36,25 +66,32 @@
}
+ private fun addMarker(point: LatLng, res: Int) {
+ val markerOption = MarkerOptions()
+ markerOption.position(point)
+ markerOption.icon(BitmapDescriptorFactory.fromResource(res))
+ aMap.addMarker(markerOption)
+ }
+
/***以下是地图生命周期管理************************************************************************/
override fun onResume() {
super.onResume()
- baseView.mapView.onResume()
+ bv.mapView.onResume()
}
override fun onPause() {
- baseView.mapView.onPause()
super.onPause()
+ bv.mapView.onPause()
}
override fun onSaveInstanceState(outState: Bundle) {
super.onSaveInstanceState(outState)
- baseView.mapView.onSaveInstanceState(outState)
+ bv.mapView.onSaveInstanceState(outState)
}
override fun onDestroy() {
- baseView.mapView.onDestroy()
super.onDestroy()
+ bv.mapView.onDestroy()
}
}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/br/ktd/fragment/MinePageFragment.kt b/app/src/main/java/com/casic/br/ktd/fragment/MinePageFragment.kt
index 90313ac..3212794 100644
--- a/app/src/main/java/com/casic/br/ktd/fragment/MinePageFragment.kt
+++ b/app/src/main/java/com/casic/br/ktd/fragment/MinePageFragment.kt
@@ -2,10 +2,11 @@
import android.os.Bundle
import com.casic.br.ktd.R
-import com.pengxh.kt.lite.base.KotlinBaseFragment
+import com.casic.br.ktd.base.KotlinBaseFragment
class MinePageFragment : KotlinBaseFragment() {
- override fun initData(savedInstanceState: Bundle?) {
+
+ override fun initView(savedInstanceState: Bundle?) {
}
@@ -13,7 +14,7 @@
}
- override fun initLayoutView(): Int = R.layout.fragment_mine
+ override fun initLayoutRes(): Int = R.layout.fragment_mine
override fun observeRequestState() {
diff --git a/app/src/main/java/com/casic/br/ktd/fragment/TaskPageFragment.kt b/app/src/main/java/com/casic/br/ktd/fragment/TaskPageFragment.kt
index 8f6abf0..6b82a54 100644
--- a/app/src/main/java/com/casic/br/ktd/fragment/TaskPageFragment.kt
+++ b/app/src/main/java/com/casic/br/ktd/fragment/TaskPageFragment.kt
@@ -8,6 +8,7 @@
import androidx.recyclerview.widget.RecyclerView
import com.casic.br.ktd.R
import com.casic.br.ktd.adapter.TaskAdapter
+import com.casic.br.ktd.base.KotlinBaseFragment
import com.casic.br.ktd.holder.SwipeViewHolder
import com.casic.br.ktd.model.TaskListModel
import com.casic.br.ktd.view.InspectionActivity
@@ -15,7 +16,6 @@
import com.casic.br.ktd.widgets.AlertControlDialog
import com.casic.br.ktd.widgets.AlertInputDialog
import com.casic.br.ktd.widgets.DateRangeActionSheet
-import com.pengxh.kt.lite.base.KotlinBaseFragment
import com.pengxh.kt.lite.extensions.navigatePageTo
import com.pengxh.kt.lite.extensions.show
import com.pengxh.kt.lite.utils.WeakReferenceHandler
@@ -36,7 +36,7 @@
private var startTime = ""
private var endTime = ""
- override fun initData(savedInstanceState: Bundle?) {
+ override fun initView(savedInstanceState: Bundle?) {
weakReferenceHandler = WeakReferenceHandler(this)
taskViewModel = ViewModelProvider(this)[TaskViewModel::class.java]
taskViewModel.taskList.observe(this) {
@@ -45,7 +45,7 @@
when {
isRefresh -> {
taskAdapter.setRefreshData(dataRows)
- baseView.taskLayout.finishRefresh()
+ bv.taskLayout.finishRefresh()
isRefresh = false
}
isLoadMore -> {
@@ -53,7 +53,7 @@
"到底了,别拉了".show(requireContext())
}
taskAdapter.setLoadMoreData(dataRows)
- baseView.taskLayout.finishLoadMore()
+ bv.taskLayout.finishLoadMore()
isLoadMore = false
}
else -> {
@@ -76,9 +76,9 @@
when (msg.what) {
2023070501 -> {
if (dataBeans.size == 0) {
- baseView.emptyLayout.visibility = View.VISIBLE
+ bv.emptyLayout.visibility = View.VISIBLE
} else {
- baseView.emptyLayout.visibility = View.GONE
+ bv.emptyLayout.visibility = View.GONE
taskAdapter = object : TaskAdapter(
requireContext(), R.layout.item_task_rv_l, dataBeans
) {
@@ -97,8 +97,8 @@
}
}
//绑定侧滑事件
- swipeAction.attachToRecyclerView(baseView.taskRecyclerView)
- baseView.taskRecyclerView.adapter = taskAdapter
+ swipeAction.attachToRecyclerView(bv.taskRecyclerView)
+ bv.taskRecyclerView.adapter = taskAdapter
taskAdapter.setOnItemCheckedListener(object :
TaskAdapter.OnItemCheckedListener {
override fun onItemChecked(items: ArrayList) {
@@ -168,7 +168,7 @@
override fun initEvent() {
- baseView.calendarView.setOnClickListener {
+ bv.calendarView.setOnClickListener {
DateRangeActionSheet.Builder().setContext(requireContext())
.setOnActionSheetListener(object :
DateRangeActionSheet.OnDateRangeSelectedListener {
@@ -177,12 +177,12 @@
endTime = endDate
//显示
- baseView.selectedDateView.text = "$startDate ~ $endDate"
+ bv.selectedDateView.text = "$startDate ~ $endDate"
}
}).build().show()
}
- baseView.addTaskButton.setOnClickListener {
+ bv.addTaskButton.setOnClickListener {
// AlertInputDialog.Builder()
// .setContext(requireContext())
// .setTitle("新建巡检任务")
@@ -200,11 +200,11 @@
requireContext().navigatePageTo()
}
- baseView.deleteTaskButton.setOnClickListener {
+ bv.deleteTaskButton.setOnClickListener {
selectedItems.size.toString().show(requireContext())
}
- baseView.taskSettingsButton.setOnClickListener {
+ bv.taskSettingsButton.setOnClickListener {
AlertInputDialog.Builder()
.setContext(requireContext())
.setTitle("设置阈值")
@@ -221,14 +221,14 @@
}).build().show()
}
- baseView.taskLayout.setOnRefreshListener {
+ bv.taskLayout.setOnRefreshListener {
isRefresh = true
//刷新之后页码重置
pageIndex = 1
getTaskList()
}
- baseView.taskLayout.setOnLoadMoreListener {
+ bv.taskLayout.setOnLoadMoreListener {
isLoadMore = true
pageIndex++
getTaskList()
@@ -239,13 +239,13 @@
taskViewModel.getTaskList(
startTime,
endTime,
- baseView.taskNameView.text.toString(),
- baseView.taskCodeView.text.toString(),
+ bv.taskNameView.text.toString(),
+ bv.taskCodeView.text.toString(),
pageIndex
)
}
- override fun initLayoutView(): Int = R.layout.fragment_task
+ override fun initLayoutRes(): Int = R.layout.fragment_task
override fun observeRequestState() {
diff --git a/app/src/main/java/com/casic/br/ktd/netty/ISocketListener.kt b/app/src/main/java/com/casic/br/ktd/netty/ISocketListener.kt
deleted file mode 100644
index dab98e1..0000000
--- a/app/src/main/java/com/casic/br/ktd/netty/ISocketListener.kt
+++ /dev/null
@@ -1,19 +0,0 @@
-package com.casic.br.ktd.netty
-
-interface ISocketListener {
- companion object {
- const val STATUS_CONNECT_SUCCESS: Byte = 1 //连接成功
- const val STATUS_CONNECT_CLOSED: Byte = 0 //关闭连接
- const val STATUS_CONNECT_ERROR: Byte = 0 //连接失败
- }
-
- /**
- * 当接收到系统消息
- */
- fun onMessageResponse(data: ByteArray?)
-
- /**
- * 当连接状态发生变化时调用
- */
- fun onServiceStatusConnectChanged(statusCode: Byte)
-}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/br/ktd/netty/SocketChannelHandle.kt b/app/src/main/java/com/casic/br/ktd/netty/SocketChannelHandle.kt
deleted file mode 100644
index 42eb310..0000000
--- a/app/src/main/java/com/casic/br/ktd/netty/SocketChannelHandle.kt
+++ /dev/null
@@ -1,51 +0,0 @@
-package com.casic.br.ktd.netty
-
-import android.util.Log
-import io.netty.channel.ChannelHandlerContext
-import io.netty.channel.SimpleChannelInboundHandler
-import io.netty.handler.timeout.IdleState
-import io.netty.handler.timeout.IdleStateEvent
-import java.nio.charset.StandardCharsets
-
-class SocketChannelHandle(private val listener: ISocketListener?) :
- SimpleChannelInboundHandler() {
-
- private val kTag = "SocketChannelHandle"
-
- override fun channelActive(ctx: ChannelHandlerContext) {
- super.channelActive(ctx)
- Log.d(kTag, "channelActive ===> 连接成功")
- listener?.onServiceStatusConnectChanged(ISocketListener.STATUS_CONNECT_SUCCESS)
- }
-
- override fun channelInactive(ctx: ChannelHandlerContext) {
- super.channelInactive(ctx)
- Log.e(kTag, "channelInactive: 连接断开")
- }
-
- override fun userEventTriggered(ctx: ChannelHandlerContext, evt: Any) {
- super.userEventTriggered(ctx, evt)
- if (evt is IdleStateEvent) {
- if (evt.state() == IdleState.WRITER_IDLE) {
- //写超时,此时可以发送心跳数据给服务器
- val temp = "FF"
- ctx.writeAndFlush(temp.toByteArray(StandardCharsets.UTF_8))
- } else if (evt.state() == IdleState.READER_IDLE) {
- //读超时,此时代表没有收到心跳返回可以关闭当前连接进行重连
- ctx.close()
- }
- }
- }
-
- override fun channelRead0(ctx: ChannelHandlerContext, data: ByteArray?) {
- listener?.onMessageResponse(data)
- }
-
- override fun exceptionCaught(ctx: ChannelHandlerContext, cause: Throwable) {
- super.exceptionCaught(ctx, cause)
- Log.d(kTag, "exceptionCaught ===> $cause")
- listener?.onServiceStatusConnectChanged(ISocketListener.STATUS_CONNECT_ERROR)
- cause.printStackTrace()
- ctx.close()
- }
-}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/br/ktd/netty/SocketClient.kt b/app/src/main/java/com/casic/br/ktd/netty/SocketClient.kt
deleted file mode 100644
index d05d335..0000000
--- a/app/src/main/java/com/casic/br/ktd/netty/SocketClient.kt
+++ /dev/null
@@ -1,153 +0,0 @@
-package com.casic.br.ktd.netty
-
-import android.os.SystemClock
-import android.util.Log
-import io.netty.bootstrap.Bootstrap
-import io.netty.channel.*
-import io.netty.channel.nio.NioEventLoopGroup
-import io.netty.channel.socket.SocketChannel
-import io.netty.channel.socket.nio.NioSocketChannel
-import io.netty.handler.codec.bytes.ByteArrayDecoder
-import io.netty.handler.codec.bytes.ByteArrayEncoder
-import io.netty.handler.timeout.IdleStateHandler
-
-class SocketClient {
-
- private val kTag = "SocketClient"
-
- private var host: String? = null
- private var port = 8000
- private var nioEventLoopGroup: NioEventLoopGroup? = null
- private var channel: Channel? = null
- private var listener: ISocketListener? = null
-
- //现在连接的状态
- var connectStatus = false //判断是否已连接
- private var reconnectNum = Int.MAX_VALUE //定义的重连到时候用
- private var isNeedReconnect = true //是否需要重连
- var isConnecting = false //是否正在连接
- private set
- private var reconnectIntervalTime: Long = 15000 //重连的时间
-
- //重连时间
- fun setReconnectNum(reconnectNum: Int) {
- this.reconnectNum = reconnectNum
- }
-
- fun setReconnectIntervalTime(reconnectIntervalTime: Long) {
- this.reconnectIntervalTime = reconnectIntervalTime
- }
-
- fun setSocketListener(listener: ISocketListener?) {
- this.listener = listener
- }
-
- fun connect(host: String, port: Int) {
- this.host = host
- this.port = port
- Log.d(kTag, "connect ===> 开始连接TCP服务器")
- if (isConnecting) {
- return
- }
- //起个线程
- val clientThread: Thread = object : Thread("client-Netty") {
- override fun run() {
- super.run()
- isNeedReconnect = true
- reconnectNum = Int.MAX_VALUE
- connectServer()
- }
- }
- clientThread.start()
- }
-
- private fun connectServer() {
- synchronized(this@SocketClient) {
- var channelFuture: ChannelFuture? = null //连接管理对象
- if (!connectStatus) {
- isConnecting = true
- nioEventLoopGroup = NioEventLoopGroup() //设置的连接group
- val bootstrap = Bootstrap()
- bootstrap.group(nioEventLoopGroup) //设置的一系列连接参数操作等
- .channel(NioSocketChannel::class.java)
- .option(ChannelOption.TCP_NODELAY, true) //无阻塞
- .option(ChannelOption.SO_KEEPALIVE, true) //长连接
- .option(
- ChannelOption.RCVBUF_ALLOCATOR,
- AdaptiveRecvByteBufAllocator(5000, 5000, 8000)
- ) //接收缓冲区 最小值太小时数据接收不全
- .handler(object : ChannelInitializer() {
- override fun initChannel(channel: SocketChannel) {
- val pipeline = channel.pipeline()
- //参数1:代表读套接字超时的时间,没收到数据会触发读超时回调;
- //参数2:代表写套接字超时时间,没进行写会触发写超时回调;
- //参数3:将在未执行读取或写入时触发超时回调,0代表不处理;
- //读超时尽量设置大于写超时,代表多次写超时时写心跳包,多次写了心跳数据仍然读超时代表当前连接错误,即可断开连接重新连接
- pipeline.addLast(IdleStateHandler(60, 10, 0))
- pipeline.addLast(ByteArrayDecoder())
- pipeline.addLast(ByteArrayEncoder())
- pipeline.addLast(SocketChannelHandle(listener))
- }
- })
- try {
- //连接监听
- channelFuture = bootstrap.connect(host, port)
- .addListener(object : ChannelFutureListener {
- override fun operationComplete(channelFuture: ChannelFuture) {
- if (channelFuture.isSuccess) {
- connectStatus = true
- channel = channelFuture.channel()
- } else {
- Log.e(kTag, "operationComplete: 连接失败")
- connectStatus = false
- }
- isConnecting = false
- }
- }).sync()
- // 等待连接关闭
- channelFuture.channel().closeFuture().sync()
- } catch (e: Exception) {
- e.printStackTrace()
- } finally {
- connectStatus = false
- listener?.onServiceStatusConnectChanged(ISocketListener.STATUS_CONNECT_CLOSED) //STATUS_CONNECT_CLOSED 这我自己定义的 接口标识
- if (null != channelFuture) {
- if (channelFuture.channel() != null && channelFuture.channel().isOpen) {
- channelFuture.channel().close()
- }
- }
- nioEventLoopGroup?.shutdownGracefully()
- reconnect() //重新连接
- }
- }
- }
- }
-
- //断开连接
- fun disconnect() {
- Log.d(kTag, "disconnect ===> 断开连接")
- isNeedReconnect = false
- nioEventLoopGroup?.shutdownGracefully()
- }
-
- //重新连接
- private fun reconnect() {
- if (isNeedReconnect && reconnectNum > 0 && !connectStatus) {
- reconnectNum--
- SystemClock.sleep(reconnectIntervalTime)
- if (isNeedReconnect && reconnectNum > 0 && !connectStatus) {
- Log.d(kTag, "reconnect ===> 重新连接")
- connectServer()
- }
- }
- }
-
- fun sendData(bytes: ByteArray) {
- channel?.writeAndFlush(bytes)?.addListener(ChannelFutureListener { future ->
- if (!future.isSuccess) {
- future.channel().close()
- nioEventLoopGroup!!.shutdownGracefully()
- }
- })
- }
-}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/br/ktd/netty/SocketManager.kt b/app/src/main/java/com/casic/br/ktd/netty/SocketManager.kt
deleted file mode 100644
index 17daf35..0000000
--- a/app/src/main/java/com/casic/br/ktd/netty/SocketManager.kt
+++ /dev/null
@@ -1,113 +0,0 @@
-package com.casic.br.ktd.netty
-
-import android.util.Log
-import com.casic.br.ktd.base.BaseApplication
-import com.casic.br.ktd.extensions.covertAngleValue
-import com.casic.br.ktd.extensions.covertDataValue
-import com.casic.br.ktd.extensions.toUnsignedByteArray
-import com.casic.br.ktd.model.SensorDataModel
-import com.casic.br.ktd.utils.LocaleConstant
-import com.pengxh.kt.lite.extensions.toJson
-import com.pengxh.kt.lite.utils.BroadcastManager
-
-class SocketManager private constructor() : ISocketListener {
-
- private val kTag = "SocketManager"
- private var nettyClient: SocketClient = SocketClient()
-
- companion object {
- val instance: SocketManager by lazy(mode = LazyThreadSafetyMode.SYNCHRONIZED) { SocketManager() }
- }
-
- fun connectNetty(hostname: String, port: Int) {
- Thread {
- if (!nettyClient.connectStatus) {
- nettyClient.setSocketListener(this)
- nettyClient.connect(hostname, port)
- } else {
- nettyClient.disconnect()
- }
- }.start()
- }
-
- override fun onMessageResponse(data: ByteArray?) {
-// Log.d(kTag, "onMessageResponse ===> " + Arrays.toString(data))
- /**
- * 0xFF,0x01,
- * 0x01,0x37,0xE6, 甲烷浓度值(数据码1* 65536 + 数据码2 * 256 + 数据码3)
- * 0x00, 激光甲烷模块工作状态(00表示设备正常,01表示温控故障,02表示设备激光未打开)
- * 0x00,0xB2,0x35, 激光强度值(数据码5* 65536 + 数据码6 * 256 + 数据码7)
- * 0x0A,0x3D, 云台水平角度([数据码8 * 256 + 数据码9]/100,单位为°,精确到0.01)
- * 0x05,0x6F, 云台垂直角度(首先计算Tangle=[数据码10 * 256 + 数据码11]/100,单位为°,精确到0.01。若Tangle在0~90范围内,则垂直角度值=Tangle;若Tangle在-1~-90范围内,则垂直角度值=Tangle-360)
- * 0xC1
- *
- * [-1, 1, 1, 55, -26, 0, 0, -78, 53, 10, 61, 5, 111, -63]
- * 甲烷浓度值为79638,计算为79638=0x01*65536+0x37*256+0xE6[0x01为数据码1,0x37为数据码2,0xE6为数据码3];
- * 激光甲烷设备状态值为0,表示状态正常,[0x00为数据码4];
- * 激光强度值为45621,计算为45621=0x00*65536+0xB2*256+0x35[0x00为数据码5,0xB2为数据码6,0x35为数据码7];
- *
- * =========================================================================================
- * 实际数据(1800-1950左右)
- * [-86, 1, 0, 7, 71, 0, 0, 62, -92, 57, 59, -118, -111, -64]
- * */
-
- if (data == null) {
- return
- }
- val bytes = data.toUnsignedByteArray()
- if (bytes.size == 14) {
- val dataModel = SensorDataModel(0, "激光未打开", 0, 0.0, 0.0)
-
- val methaneBytes = IntArray(3)
- System.arraycopy(bytes, 2, methaneBytes, 0, 3)
- dataModel.methane = methaneBytes.covertDataValue()
-
- dataModel.methaneState = when (bytes[5]) {
- 1 -> "温控故障"
- 2 -> "激光未打开"
- else -> "正常"
- }
-
- val laserBytes = IntArray(3)
- System.arraycopy(bytes, 6, laserBytes, 0, 3)
- dataModel.laser = laserBytes.covertDataValue()
-
- /**
- * 水平角度的实际范围为从水平零点开始,顺时针方向(从上往下看),0~360°
- * 垂直角度的实际范围为从垂直零点开始,以向上为正,-90°~90°,控制精度为0.01°
- * */
- val horizontalBytes = IntArray(2)
- System.arraycopy(bytes, 9, horizontalBytes, 0, 2)
- dataModel.horizontal = horizontalBytes.covertAngleValue()
-
- val verticalBytes = IntArray(2)
- System.arraycopy(bytes, 11, verticalBytes, 0, 2)
- dataModel.vertical = verticalBytes.covertAngleValue()
-
- //{"horizontal":26.21,"laser":45621,"methane":79846,"methaneState":"正常","vertical":13.91}
- BroadcastManager.obtainInstance(BaseApplication.get()).sendBroadcast(
- LocaleConstant.ACTION_UPDATE_DATA, dataModel.toJson()
- )
- }
- }
-
- override fun onServiceStatusConnectChanged(statusCode: Byte) {
- if (statusCode == ISocketListener.STATUS_CONNECT_SUCCESS) {
- if (nettyClient.connectStatus) {
- Log.d(kTag, "连接成功")
- }
- } else {
- if (!nettyClient.connectStatus) {
- Log.e(kTag, "onServiceStatusConnectChanged:$statusCode,连接断开,正在重连")
- }
- }
- }
-
- fun sendData(data: ByteArray) {
- nettyClient.sendData(data)
- }
-
- fun close() {
- nettyClient.disconnect()
- }
-}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/br/ktd/netty/tcp/ISocketListener.kt b/app/src/main/java/com/casic/br/ktd/netty/tcp/ISocketListener.kt
new file mode 100644
index 0000000..13c3084
--- /dev/null
+++ b/app/src/main/java/com/casic/br/ktd/netty/tcp/ISocketListener.kt
@@ -0,0 +1,19 @@
+package com.casic.br.ktd.netty.tcp
+
+interface ISocketListener {
+ companion object {
+ const val STATUS_CONNECT_SUCCESS: Byte = 1 //连接成功
+ const val STATUS_CONNECT_CLOSED: Byte = 0 //关闭连接
+ const val STATUS_CONNECT_ERROR: Byte = 0 //连接失败
+ }
+
+ /**
+ * 当接收到系统消息
+ */
+ fun onMessageResponse(data: ByteArray?)
+
+ /**
+ * 当连接状态发生变化时调用
+ */
+ fun onServiceStatusConnectChanged(statusCode: Byte)
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/br/ktd/netty/tcp/SocketChannelHandle.kt b/app/src/main/java/com/casic/br/ktd/netty/tcp/SocketChannelHandle.kt
new file mode 100644
index 0000000..8e2997f
--- /dev/null
+++ b/app/src/main/java/com/casic/br/ktd/netty/tcp/SocketChannelHandle.kt
@@ -0,0 +1,51 @@
+package com.casic.br.ktd.netty.tcp
+
+import android.util.Log
+import io.netty.channel.ChannelHandlerContext
+import io.netty.channel.SimpleChannelInboundHandler
+import io.netty.handler.timeout.IdleState
+import io.netty.handler.timeout.IdleStateEvent
+import java.nio.charset.StandardCharsets
+
+class SocketChannelHandle(private val listener: ISocketListener?) :
+ SimpleChannelInboundHandler() {
+
+ private val kTag = "SocketChannelHandle"
+
+ override fun channelActive(ctx: ChannelHandlerContext) {
+ super.channelActive(ctx)
+ Log.d(kTag, "channelActive ===> 连接成功")
+ listener?.onServiceStatusConnectChanged(ISocketListener.STATUS_CONNECT_SUCCESS)
+ }
+
+ override fun channelInactive(ctx: ChannelHandlerContext) {
+ super.channelInactive(ctx)
+ Log.e(kTag, "channelInactive: 连接断开")
+ }
+
+ override fun userEventTriggered(ctx: ChannelHandlerContext, evt: Any) {
+ super.userEventTriggered(ctx, evt)
+ if (evt is IdleStateEvent) {
+ if (evt.state() == IdleState.WRITER_IDLE) {
+ //写超时,此时可以发送心跳数据给服务器
+ val temp = "FF"
+ ctx.writeAndFlush(temp.toByteArray(StandardCharsets.UTF_8))
+ } else if (evt.state() == IdleState.READER_IDLE) {
+ //读超时,此时代表没有收到心跳返回可以关闭当前连接进行重连
+ ctx.close()
+ }
+ }
+ }
+
+ override fun channelRead0(ctx: ChannelHandlerContext, data: ByteArray?) {
+ listener?.onMessageResponse(data)
+ }
+
+ override fun exceptionCaught(ctx: ChannelHandlerContext, cause: Throwable) {
+ super.exceptionCaught(ctx, cause)
+ Log.d(kTag, "exceptionCaught ===> $cause")
+ listener?.onServiceStatusConnectChanged(ISocketListener.STATUS_CONNECT_ERROR)
+ cause.printStackTrace()
+ ctx.close()
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/br/ktd/netty/tcp/SocketClient.kt b/app/src/main/java/com/casic/br/ktd/netty/tcp/SocketClient.kt
new file mode 100644
index 0000000..34960a0
--- /dev/null
+++ b/app/src/main/java/com/casic/br/ktd/netty/tcp/SocketClient.kt
@@ -0,0 +1,153 @@
+package com.casic.br.ktd.netty.tcp
+
+import android.os.SystemClock
+import android.util.Log
+import io.netty.bootstrap.Bootstrap
+import io.netty.channel.*
+import io.netty.channel.nio.NioEventLoopGroup
+import io.netty.channel.socket.SocketChannel
+import io.netty.channel.socket.nio.NioSocketChannel
+import io.netty.handler.codec.bytes.ByteArrayDecoder
+import io.netty.handler.codec.bytes.ByteArrayEncoder
+import io.netty.handler.timeout.IdleStateHandler
+
+class SocketClient {
+
+ private val kTag = "SocketClient"
+
+ private var host: String? = null
+ private var port = 8000
+ private var nioEventLoopGroup: NioEventLoopGroup? = null
+ private var channel: Channel? = null
+ private var listener: ISocketListener? = null
+
+ //现在连接的状态
+ var connectStatus = false //判断是否已连接
+ private var reconnectNum = Int.MAX_VALUE //定义的重连到时候用
+ private var isNeedReconnect = true //是否需要重连
+ var isConnecting = false //是否正在连接
+ private set
+ private var reconnectIntervalTime: Long = 15000 //重连的时间
+
+ //重连时间
+ fun setReconnectNum(reconnectNum: Int) {
+ this.reconnectNum = reconnectNum
+ }
+
+ fun setReconnectIntervalTime(reconnectIntervalTime: Long) {
+ this.reconnectIntervalTime = reconnectIntervalTime
+ }
+
+ fun setSocketListener(listener: ISocketListener?) {
+ this.listener = listener
+ }
+
+ fun connect(host: String, port: Int) {
+ this.host = host
+ this.port = port
+ Log.d(kTag, "connect ===> 开始连接TCP服务器")
+ if (isConnecting) {
+ return
+ }
+ //起个线程
+ val clientThread: Thread = object : Thread("client-Netty") {
+ override fun run() {
+ super.run()
+ isNeedReconnect = true
+ reconnectNum = Int.MAX_VALUE
+ connectServer()
+ }
+ }
+ clientThread.start()
+ }
+
+ private fun connectServer() {
+ synchronized(this@SocketClient) {
+ var channelFuture: ChannelFuture? = null //连接管理对象
+ if (!connectStatus) {
+ isConnecting = true
+ nioEventLoopGroup = NioEventLoopGroup() //设置的连接group
+ val bootstrap = Bootstrap()
+ bootstrap.group(nioEventLoopGroup) //设置的一系列连接参数操作等
+ .channel(NioSocketChannel::class.java)
+ .option(ChannelOption.TCP_NODELAY, true) //无阻塞
+ .option(ChannelOption.SO_KEEPALIVE, true) //长连接
+ .option(
+ ChannelOption.RCVBUF_ALLOCATOR,
+ AdaptiveRecvByteBufAllocator(5000, 5000, 8000)
+ ) //接收缓冲区 最小值太小时数据接收不全
+ .handler(object : ChannelInitializer() {
+ override fun initChannel(channel: SocketChannel) {
+ val pipeline = channel.pipeline()
+ //参数1:代表读套接字超时的时间,没收到数据会触发读超时回调;
+ //参数2:代表写套接字超时时间,没进行写会触发写超时回调;
+ //参数3:将在未执行读取或写入时触发超时回调,0代表不处理;
+ //读超时尽量设置大于写超时,代表多次写超时时写心跳包,多次写了心跳数据仍然读超时代表当前连接错误,即可断开连接重新连接
+ pipeline.addLast(IdleStateHandler(60, 10, 0))
+ pipeline.addLast(ByteArrayDecoder())
+ pipeline.addLast(ByteArrayEncoder())
+ pipeline.addLast(SocketChannelHandle(listener))
+ }
+ })
+ try {
+ //连接监听
+ channelFuture = bootstrap.connect(host, port)
+ .addListener(object : ChannelFutureListener {
+ override fun operationComplete(channelFuture: ChannelFuture) {
+ if (channelFuture.isSuccess) {
+ connectStatus = true
+ channel = channelFuture.channel()
+ } else {
+ Log.e(kTag, "operationComplete: 连接失败")
+ connectStatus = false
+ }
+ isConnecting = false
+ }
+ }).sync()
+ // 等待连接关闭
+ channelFuture.channel().closeFuture().sync()
+ } catch (e: Exception) {
+ e.printStackTrace()
+ } finally {
+ connectStatus = false
+ listener?.onServiceStatusConnectChanged(ISocketListener.STATUS_CONNECT_CLOSED) //STATUS_CONNECT_CLOSED 这我自己定义的 接口标识
+ if (null != channelFuture) {
+ if (channelFuture.channel() != null && channelFuture.channel().isOpen) {
+ channelFuture.channel().close()
+ }
+ }
+ nioEventLoopGroup?.shutdownGracefully()
+ reconnect() //重新连接
+ }
+ }
+ }
+ }
+
+ //断开连接
+ fun disconnect() {
+ Log.d(kTag, "disconnect ===> 断开连接")
+ isNeedReconnect = false
+ nioEventLoopGroup?.shutdownGracefully()
+ }
+
+ //重新连接
+ private fun reconnect() {
+ if (isNeedReconnect && reconnectNum > 0 && !connectStatus) {
+ reconnectNum--
+ SystemClock.sleep(reconnectIntervalTime)
+ if (isNeedReconnect && reconnectNum > 0 && !connectStatus) {
+ Log.d(kTag, "reconnect ===> 重新连接")
+ connectServer()
+ }
+ }
+ }
+
+ fun sendData(bytes: ByteArray) {
+ channel?.writeAndFlush(bytes)?.addListener(ChannelFutureListener { future ->
+ if (!future.isSuccess) {
+ future.channel().close()
+ nioEventLoopGroup!!.shutdownGracefully()
+ }
+ })
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/br/ktd/netty/tcp/SocketManager.kt b/app/src/main/java/com/casic/br/ktd/netty/tcp/SocketManager.kt
new file mode 100644
index 0000000..35980b9
--- /dev/null
+++ b/app/src/main/java/com/casic/br/ktd/netty/tcp/SocketManager.kt
@@ -0,0 +1,113 @@
+package com.casic.br.ktd.netty.tcp
+
+import android.util.Log
+import com.casic.br.ktd.base.BaseApplication
+import com.casic.br.ktd.extensions.covertAngleValue
+import com.casic.br.ktd.extensions.covertDataValue
+import com.casic.br.ktd.extensions.toUnsignedByteArray
+import com.casic.br.ktd.model.SensorDataModel
+import com.casic.br.ktd.utils.LocaleConstant
+import com.pengxh.kt.lite.extensions.toJson
+import com.pengxh.kt.lite.utils.BroadcastManager
+
+class SocketManager private constructor() : ISocketListener {
+
+ private val kTag = "SocketManager"
+ private var nettyClient: SocketClient = SocketClient()
+
+ companion object {
+ val instance: SocketManager by lazy(mode = LazyThreadSafetyMode.SYNCHRONIZED) { SocketManager() }
+ }
+
+ fun connectNetty(hostname: String, port: Int) {
+ Thread {
+ if (!nettyClient.connectStatus) {
+ nettyClient.setSocketListener(this)
+ nettyClient.connect(hostname, port)
+ } else {
+ nettyClient.disconnect()
+ }
+ }.start()
+ }
+
+ override fun onMessageResponse(data: ByteArray?) {
+// Log.d(kTag, "onMessageResponse ===> " + Arrays.toString(data))
+ /**
+ * 0xFF,0x01,
+ * 0x01,0x37,0xE6, 甲烷浓度值(数据码1* 65536 + 数据码2 * 256 + 数据码3)
+ * 0x00, 激光甲烷模块工作状态(00表示设备正常,01表示温控故障,02表示设备激光未打开)
+ * 0x00,0xB2,0x35, 激光强度值(数据码5* 65536 + 数据码6 * 256 + 数据码7)
+ * 0x0A,0x3D, 云台水平角度([数据码8 * 256 + 数据码9]/100,单位为°,精确到0.01)
+ * 0x05,0x6F, 云台垂直角度(首先计算Tangle=[数据码10 * 256 + 数据码11]/100,单位为°,精确到0.01。若Tangle在0~90范围内,则垂直角度值=Tangle;若Tangle在-1~-90范围内,则垂直角度值=Tangle-360)
+ * 0xC1
+ *
+ * [-1, 1, 1, 55, -26, 0, 0, -78, 53, 10, 61, 5, 111, -63]
+ * 甲烷浓度值为79638,计算为79638=0x01*65536+0x37*256+0xE6[0x01为数据码1,0x37为数据码2,0xE6为数据码3];
+ * 激光甲烷设备状态值为0,表示状态正常,[0x00为数据码4];
+ * 激光强度值为45621,计算为45621=0x00*65536+0xB2*256+0x35[0x00为数据码5,0xB2为数据码6,0x35为数据码7];
+ *
+ * =========================================================================================
+ * 实际数据(1800-1950左右)
+ * [-86, 1, 0, 7, 71, 0, 0, 62, -92, 57, 59, -118, -111, -64]
+ * */
+
+ if (data == null) {
+ return
+ }
+ val bytes = data.toUnsignedByteArray()
+ if (bytes.size == 14) {
+ val dataModel = SensorDataModel(0, "激光未打开", 0, 0.0, 0.0)
+
+ val methaneBytes = IntArray(3)
+ System.arraycopy(bytes, 2, methaneBytes, 0, 3)
+ dataModel.methane = methaneBytes.covertDataValue()
+
+ dataModel.methaneState = when (bytes[5]) {
+ 1 -> "温控故障"
+ 2 -> "激光未打开"
+ else -> "正常"
+ }
+
+ val laserBytes = IntArray(3)
+ System.arraycopy(bytes, 6, laserBytes, 0, 3)
+ dataModel.laser = laserBytes.covertDataValue()
+
+ /**
+ * 水平角度的实际范围为从水平零点开始,顺时针方向(从上往下看),0~360°
+ * 垂直角度的实际范围为从垂直零点开始,以向上为正,-90°~90°,控制精度为0.01°
+ * */
+ val horizontalBytes = IntArray(2)
+ System.arraycopy(bytes, 9, horizontalBytes, 0, 2)
+ dataModel.horizontal = horizontalBytes.covertAngleValue()
+
+ val verticalBytes = IntArray(2)
+ System.arraycopy(bytes, 11, verticalBytes, 0, 2)
+ dataModel.vertical = verticalBytes.covertAngleValue()
+
+ //{"horizontal":26.21,"laser":45621,"methane":79846,"methaneState":"正常","vertical":13.91}
+ BroadcastManager.obtainInstance(BaseApplication.get()).sendBroadcast(
+ LocaleConstant.ACTION_UPDATE_DATA, dataModel.toJson()
+ )
+ }
+ }
+
+ override fun onServiceStatusConnectChanged(statusCode: Byte) {
+ if (statusCode == ISocketListener.STATUS_CONNECT_SUCCESS) {
+ if (nettyClient.connectStatus) {
+ Log.d(kTag, "连接成功")
+ }
+ } else {
+ if (!nettyClient.connectStatus) {
+ Log.e(kTag, "onServiceStatusConnectChanged:$statusCode,连接断开,正在重连")
+ }
+ }
+ }
+
+ fun sendData(data: ByteArray) {
+ nettyClient.sendData(data)
+ }
+
+ fun close() {
+ nettyClient.disconnect()
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/br/ktd/netty/udp/UdpChannelInboundHandler.kt b/app/src/main/java/com/casic/br/ktd/netty/udp/UdpChannelInboundHandler.kt
new file mode 100644
index 0000000..4d6f97c
--- /dev/null
+++ b/app/src/main/java/com/casic/br/ktd/netty/udp/UdpChannelInboundHandler.kt
@@ -0,0 +1,36 @@
+package com.casic.br.ktd.netty.udp
+
+import io.netty.channel.ChannelHandlerContext
+import io.netty.channel.SimpleChannelInboundHandler
+import io.netty.channel.socket.DatagramPacket
+import io.netty.util.CharsetUtil
+
+
+abstract class UdpChannelInboundHandler : SimpleChannelInboundHandler() {
+
+ private var handlerContext: ChannelHandlerContext? = null
+
+ override fun channelActive(ctx: ChannelHandlerContext?) {
+ super.channelActive(ctx)
+ handlerContext = ctx
+ }
+
+ override fun channelInactive(ctx: ChannelHandlerContext?) {
+ super.channelInactive(ctx)
+ handlerContext?.close()
+ }
+
+ fun sendDatagramPacket(obj: Any) {
+ handlerContext?.writeAndFlush(obj)
+ }
+
+ fun releasePort() {
+ handlerContext?.close()
+ }
+
+ override fun channelRead0(ctx: ChannelHandlerContext, datagramPacket: DatagramPacket) {
+ receivedMessage(datagramPacket.content().toString(CharsetUtil.UTF_8))
+ }
+
+ abstract fun receivedMessage(data: String)
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/br/ktd/netty/udp/UdpChannelInitializer.kt b/app/src/main/java/com/casic/br/ktd/netty/udp/UdpChannelInitializer.kt
new file mode 100644
index 0000000..416c5a1
--- /dev/null
+++ b/app/src/main/java/com/casic/br/ktd/netty/udp/UdpChannelInitializer.kt
@@ -0,0 +1,17 @@
+package com.casic.br.ktd.netty.udp
+
+import io.netty.channel.ChannelInitializer
+import io.netty.channel.socket.DatagramChannel
+import io.netty.handler.timeout.IdleStateHandler
+
+
+open class UdpChannelInitializer(private val handler: UdpChannelInboundHandler) :
+ ChannelInitializer() {
+
+ override fun initChannel(datagramChannel: DatagramChannel) {
+ val pipeline = datagramChannel.pipeline()
+ pipeline.addLast(
+ IdleStateHandler(12, 15, 0)
+ ).addLast(handler)
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/br/ktd/netty/udp/UdpClient.kt b/app/src/main/java/com/casic/br/ktd/netty/udp/UdpClient.kt
new file mode 100644
index 0000000..3893afa
--- /dev/null
+++ b/app/src/main/java/com/casic/br/ktd/netty/udp/UdpClient.kt
@@ -0,0 +1,103 @@
+package com.casic.br.ktd.netty.udp
+
+import com.casic.br.ktd.utils.LocaleConstant
+import com.pengxh.kt.lite.utils.SaveKeyValues
+import io.netty.bootstrap.Bootstrap
+import io.netty.buffer.ByteBuf
+import io.netty.buffer.Unpooled
+import io.netty.channel.ChannelOption
+import io.netty.channel.nio.NioEventLoopGroup
+import io.netty.channel.socket.DatagramPacket
+import io.netty.channel.socket.nio.NioDatagramChannel
+import io.netty.util.CharsetUtil
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.launch
+import kotlinx.coroutines.withContext
+import java.net.InetSocketAddress
+import java.util.concurrent.ExecutorService
+import java.util.concurrent.Executors
+
+
+class UdpClient : UdpChannelInboundHandler(), Runnable {
+
+ private val bootStrap by lazy { Bootstrap() }
+ private val eventLoopGroup by lazy { NioEventLoopGroup() }
+ private val udpChannelInitializer by lazy { UdpChannelInitializer(this) }
+ private var executorService: ExecutorService
+
+ init {
+ bootStrap.group(eventLoopGroup)
+ bootStrap.channel(NioDatagramChannel::class.java)
+ .option(ChannelOption.SO_RCVBUF, 1024)
+ .option(ChannelOption.SO_SNDBUF, 1024)
+ bootStrap.handler(udpChannelInitializer)
+
+ executorService = Executors.newSingleThreadExecutor()
+ executorService.execute(this)
+ }
+
+ override fun run() {
+ try {
+ val channelFuture = bootStrap.bind(LocaleConstant.LOCATION_UDP_PORT).sync()
+ channelFuture.channel().closeFuture().sync()
+ } catch (e: InterruptedException) {
+ e.printStackTrace()
+ } finally {
+ eventLoopGroup.shutdownGracefully()
+ }
+ }
+
+ fun send(value: String) {
+ CoroutineScope(Dispatchers.Main).launch {
+ withContext(Dispatchers.IO) {
+ val host = SaveKeyValues.getValue(
+ LocaleConstant.LOCATION_UDP_SERVER, "192.168.149.213"
+ ).toString()
+ val datagramPacket = DatagramPacket(
+ Unpooled.copiedBuffer(value, CharsetUtil.UTF_8),
+ InetSocketAddress(host, LocaleConstant.LOCATION_UDP_PORT)
+ )
+ sendDatagramPacket(datagramPacket)
+ }
+ }
+ }
+
+ fun send(value: ByteArray) {
+ CoroutineScope(Dispatchers.Main).launch {
+ withContext(Dispatchers.IO) {
+ val host = SaveKeyValues.getValue(
+ LocaleConstant.LOCATION_UDP_SERVER, "192.168.149.213"
+ ).toString()
+ val datagramPacket = DatagramPacket(
+ Unpooled.copiedBuffer(value),
+ InetSocketAddress(host, LocaleConstant.LOCATION_UDP_PORT)
+ )
+ sendDatagramPacket(datagramPacket)
+ }
+ }
+ }
+
+ fun send(value: ByteBuf) {
+ CoroutineScope(Dispatchers.Main).launch {
+ withContext(Dispatchers.IO) {
+ val host = SaveKeyValues.getValue(
+ LocaleConstant.LOCATION_UDP_SERVER, "192.168.149.213"
+ ).toString()
+ val datagramPacket = DatagramPacket(
+ Unpooled.copiedBuffer(value),
+ InetSocketAddress(host, LocaleConstant.LOCATION_UDP_PORT)
+ )
+ sendDatagramPacket(datagramPacket)
+ }
+ }
+ }
+
+ fun release() {
+ releasePort()
+ }
+
+ override fun receivedMessage(data: String) {
+
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index e822df6..d72c1a5 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -7,6 +7,9 @@
+
+
+
@@ -46,5 +49,8 @@
+
+
+
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/br/ktd/base/KotlinBaseFragment.kt b/app/src/main/java/com/casic/br/ktd/base/KotlinBaseFragment.kt
new file mode 100644
index 0000000..2dac61c
--- /dev/null
+++ b/app/src/main/java/com/casic/br/ktd/base/KotlinBaseFragment.kt
@@ -0,0 +1,51 @@
+package com.casic.br.ktd.base
+
+import android.os.Bundle
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import androidx.annotation.LayoutRes
+import androidx.fragment.app.Fragment
+
+abstract class KotlinBaseFragment : Fragment() {
+
+ lateinit var bv: View
+
+ override fun onCreateView(
+ inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?
+ ): View? {
+ bv = inflater.inflate(initLayoutRes(), container, false)
+ initView(savedInstanceState)
+ setupTopBarLayout()
+ return bv
+ }
+
+ override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
+ super.onViewCreated(view, savedInstanceState)
+ observeRequestState()
+ initEvent()
+ }
+
+ @LayoutRes
+ abstract fun initLayoutRes(): Int
+
+ /**
+ * 沉浸式状态栏
+ */
+ abstract fun setupTopBarLayout()
+
+ /**
+ * 初始化布局以及控件
+ */
+ abstract fun initView(savedInstanceState: Bundle?)
+
+ /**
+ * 网络请求状态监听
+ */
+ abstract fun observeRequestState()
+
+ /**
+ * 业务逻辑,按钮等事件
+ */
+ abstract fun initEvent()
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/br/ktd/fragment/AlarmPageFragment.kt b/app/src/main/java/com/casic/br/ktd/fragment/AlarmPageFragment.kt
index 6c98a3b..9418169 100644
--- a/app/src/main/java/com/casic/br/ktd/fragment/AlarmPageFragment.kt
+++ b/app/src/main/java/com/casic/br/ktd/fragment/AlarmPageFragment.kt
@@ -2,28 +2,29 @@
import android.os.Bundle
import com.casic.br.ktd.R
+import com.casic.br.ktd.base.KotlinBaseFragment
import com.casic.br.ktd.widgets.DateRangeActionSheet
-import com.pengxh.kt.lite.base.KotlinBaseFragment
import kotlinx.android.synthetic.main.fragment_alarm.view.*
class AlarmPageFragment : KotlinBaseFragment() {
- override fun initData(savedInstanceState: Bundle?) {
+
+ override fun initView(savedInstanceState: Bundle?) {
}
override fun initEvent() {
- baseView.calendarView.setOnClickListener {
+ bv.calendarView.setOnClickListener {
DateRangeActionSheet.Builder().setContext(requireContext())
.setOnActionSheetListener(object :
DateRangeActionSheet.OnDateRangeSelectedListener {
override fun onDateRangeSelected(startDate: String, endDate: String) {
- baseView.selectedDateView.text = "$startDate ~ $endDate"
+ bv.selectedDateView.text = "$startDate ~ $endDate"
}
}).build().show()
}
}
- override fun initLayoutView(): Int = R.layout.fragment_alarm
+ override fun initLayoutRes(): Int = R.layout.fragment_alarm
override fun observeRequestState() {
diff --git a/app/src/main/java/com/casic/br/ktd/fragment/HomePageFragment.kt b/app/src/main/java/com/casic/br/ktd/fragment/HomePageFragment.kt
index 9961935..f3eba5c 100644
--- a/app/src/main/java/com/casic/br/ktd/fragment/HomePageFragment.kt
+++ b/app/src/main/java/com/casic/br/ktd/fragment/HomePageFragment.kt
@@ -1,32 +1,62 @@
package com.casic.br.ktd.fragment
+import android.graphics.Color
import android.os.Bundle
import com.amap.api.maps.AMap
import com.amap.api.maps.AMapOptions
+import com.amap.api.maps.CameraUpdateFactory
+import com.amap.api.maps.model.*
import com.casic.br.ktd.R
-import com.pengxh.kt.lite.base.KotlinBaseFragment
+import com.casic.br.ktd.base.KotlinBaseFragment
import kotlinx.android.synthetic.main.fragment_home.view.*
class HomePageFragment : KotlinBaseFragment() {
private lateinit var aMap: AMap
- override fun initData(savedInstanceState: Bundle?) {
- baseView.mapView.onCreate(savedInstanceState)
- aMap = baseView.mapView.map
+ override fun initView(savedInstanceState: Bundle?) {
+ bv.mapView.onCreate(savedInstanceState)
+ aMap = bv.mapView.map
val uiSettings = aMap.uiSettings
uiSettings.isCompassEnabled = true
- uiSettings.isMyLocationButtonEnabled = true
+ uiSettings.isMyLocationButtonEnabled = false
uiSettings.isScaleControlsEnabled = true
uiSettings.zoomPosition = AMapOptions.ZOOM_POSITION_RIGHT_CENTER
uiSettings.isRotateGesturesEnabled = false//不许地图随手势旋转角度
}
override fun initEvent() {
-
+ //移动到巡检起始经纬度
+ val cameraPosition = CameraPosition(LatLng(39.914199, 116.265785), 16f, 0f, 0f)
+ val cameraUpdate = CameraUpdateFactory.newCameraPosition(cameraPosition)
+ aMap.animateCamera(cameraUpdate, 1500, null)
+ //设置起点
+ addMarker(LatLng(39.914885, 116.272312), R.mipmap.start)
+ //设置终点
+ addMarker(LatLng(39.914716, 116.265097), R.mipmap.end)
+ //瞄点画线
+ val latLngPoints = ArrayList()
+ latLngPoints.add(LatLng(39.914885, 116.272312))
+ latLngPoints.add(LatLng(39.915148, 116.272312))
+ latLngPoints.add(LatLng(39.915399, 116.272302))
+ latLngPoints.add(LatLng(39.915436, 116.271787))
+ latLngPoints.add(LatLng(39.915477, 116.270886))
+ latLngPoints.add(LatLng(39.915477, 116.269968))
+ latLngPoints.add(LatLng(39.915469, 116.269544))
+ latLngPoints.add(LatLng(39.915481, 116.269196))
+ latLngPoints.add(LatLng(39.915452, 116.268472))
+ latLngPoints.add(LatLng(39.915444, 116.267722))
+ latLngPoints.add(LatLng(39.915415, 116.266755))
+ latLngPoints.add(LatLng(39.915403, 116.266165))
+ latLngPoints.add(LatLng(39.915395, 116.265703))
+ latLngPoints.add(LatLng(39.915366, 116.265119))
+ latLngPoints.add(LatLng(39.914716, 116.265097))
+ aMap.addPolyline(
+ PolylineOptions().addAll(latLngPoints).width(10.toFloat()).color(Color.RED)
+ )
}
- override fun initLayoutView(): Int = R.layout.fragment_home
+ override fun initLayoutRes(): Int = R.layout.fragment_home
override fun observeRequestState() {
@@ -36,25 +66,32 @@
}
+ private fun addMarker(point: LatLng, res: Int) {
+ val markerOption = MarkerOptions()
+ markerOption.position(point)
+ markerOption.icon(BitmapDescriptorFactory.fromResource(res))
+ aMap.addMarker(markerOption)
+ }
+
/***以下是地图生命周期管理************************************************************************/
override fun onResume() {
super.onResume()
- baseView.mapView.onResume()
+ bv.mapView.onResume()
}
override fun onPause() {
- baseView.mapView.onPause()
super.onPause()
+ bv.mapView.onPause()
}
override fun onSaveInstanceState(outState: Bundle) {
super.onSaveInstanceState(outState)
- baseView.mapView.onSaveInstanceState(outState)
+ bv.mapView.onSaveInstanceState(outState)
}
override fun onDestroy() {
- baseView.mapView.onDestroy()
super.onDestroy()
+ bv.mapView.onDestroy()
}
}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/br/ktd/fragment/MinePageFragment.kt b/app/src/main/java/com/casic/br/ktd/fragment/MinePageFragment.kt
index 90313ac..3212794 100644
--- a/app/src/main/java/com/casic/br/ktd/fragment/MinePageFragment.kt
+++ b/app/src/main/java/com/casic/br/ktd/fragment/MinePageFragment.kt
@@ -2,10 +2,11 @@
import android.os.Bundle
import com.casic.br.ktd.R
-import com.pengxh.kt.lite.base.KotlinBaseFragment
+import com.casic.br.ktd.base.KotlinBaseFragment
class MinePageFragment : KotlinBaseFragment() {
- override fun initData(savedInstanceState: Bundle?) {
+
+ override fun initView(savedInstanceState: Bundle?) {
}
@@ -13,7 +14,7 @@
}
- override fun initLayoutView(): Int = R.layout.fragment_mine
+ override fun initLayoutRes(): Int = R.layout.fragment_mine
override fun observeRequestState() {
diff --git a/app/src/main/java/com/casic/br/ktd/fragment/TaskPageFragment.kt b/app/src/main/java/com/casic/br/ktd/fragment/TaskPageFragment.kt
index 8f6abf0..6b82a54 100644
--- a/app/src/main/java/com/casic/br/ktd/fragment/TaskPageFragment.kt
+++ b/app/src/main/java/com/casic/br/ktd/fragment/TaskPageFragment.kt
@@ -8,6 +8,7 @@
import androidx.recyclerview.widget.RecyclerView
import com.casic.br.ktd.R
import com.casic.br.ktd.adapter.TaskAdapter
+import com.casic.br.ktd.base.KotlinBaseFragment
import com.casic.br.ktd.holder.SwipeViewHolder
import com.casic.br.ktd.model.TaskListModel
import com.casic.br.ktd.view.InspectionActivity
@@ -15,7 +16,6 @@
import com.casic.br.ktd.widgets.AlertControlDialog
import com.casic.br.ktd.widgets.AlertInputDialog
import com.casic.br.ktd.widgets.DateRangeActionSheet
-import com.pengxh.kt.lite.base.KotlinBaseFragment
import com.pengxh.kt.lite.extensions.navigatePageTo
import com.pengxh.kt.lite.extensions.show
import com.pengxh.kt.lite.utils.WeakReferenceHandler
@@ -36,7 +36,7 @@
private var startTime = ""
private var endTime = ""
- override fun initData(savedInstanceState: Bundle?) {
+ override fun initView(savedInstanceState: Bundle?) {
weakReferenceHandler = WeakReferenceHandler(this)
taskViewModel = ViewModelProvider(this)[TaskViewModel::class.java]
taskViewModel.taskList.observe(this) {
@@ -45,7 +45,7 @@
when {
isRefresh -> {
taskAdapter.setRefreshData(dataRows)
- baseView.taskLayout.finishRefresh()
+ bv.taskLayout.finishRefresh()
isRefresh = false
}
isLoadMore -> {
@@ -53,7 +53,7 @@
"到底了,别拉了".show(requireContext())
}
taskAdapter.setLoadMoreData(dataRows)
- baseView.taskLayout.finishLoadMore()
+ bv.taskLayout.finishLoadMore()
isLoadMore = false
}
else -> {
@@ -76,9 +76,9 @@
when (msg.what) {
2023070501 -> {
if (dataBeans.size == 0) {
- baseView.emptyLayout.visibility = View.VISIBLE
+ bv.emptyLayout.visibility = View.VISIBLE
} else {
- baseView.emptyLayout.visibility = View.GONE
+ bv.emptyLayout.visibility = View.GONE
taskAdapter = object : TaskAdapter(
requireContext(), R.layout.item_task_rv_l, dataBeans
) {
@@ -97,8 +97,8 @@
}
}
//绑定侧滑事件
- swipeAction.attachToRecyclerView(baseView.taskRecyclerView)
- baseView.taskRecyclerView.adapter = taskAdapter
+ swipeAction.attachToRecyclerView(bv.taskRecyclerView)
+ bv.taskRecyclerView.adapter = taskAdapter
taskAdapter.setOnItemCheckedListener(object :
TaskAdapter.OnItemCheckedListener {
override fun onItemChecked(items: ArrayList) {
@@ -168,7 +168,7 @@
override fun initEvent() {
- baseView.calendarView.setOnClickListener {
+ bv.calendarView.setOnClickListener {
DateRangeActionSheet.Builder().setContext(requireContext())
.setOnActionSheetListener(object :
DateRangeActionSheet.OnDateRangeSelectedListener {
@@ -177,12 +177,12 @@
endTime = endDate
//显示
- baseView.selectedDateView.text = "$startDate ~ $endDate"
+ bv.selectedDateView.text = "$startDate ~ $endDate"
}
}).build().show()
}
- baseView.addTaskButton.setOnClickListener {
+ bv.addTaskButton.setOnClickListener {
// AlertInputDialog.Builder()
// .setContext(requireContext())
// .setTitle("新建巡检任务")
@@ -200,11 +200,11 @@
requireContext().navigatePageTo()
}
- baseView.deleteTaskButton.setOnClickListener {
+ bv.deleteTaskButton.setOnClickListener {
selectedItems.size.toString().show(requireContext())
}
- baseView.taskSettingsButton.setOnClickListener {
+ bv.taskSettingsButton.setOnClickListener {
AlertInputDialog.Builder()
.setContext(requireContext())
.setTitle("设置阈值")
@@ -221,14 +221,14 @@
}).build().show()
}
- baseView.taskLayout.setOnRefreshListener {
+ bv.taskLayout.setOnRefreshListener {
isRefresh = true
//刷新之后页码重置
pageIndex = 1
getTaskList()
}
- baseView.taskLayout.setOnLoadMoreListener {
+ bv.taskLayout.setOnLoadMoreListener {
isLoadMore = true
pageIndex++
getTaskList()
@@ -239,13 +239,13 @@
taskViewModel.getTaskList(
startTime,
endTime,
- baseView.taskNameView.text.toString(),
- baseView.taskCodeView.text.toString(),
+ bv.taskNameView.text.toString(),
+ bv.taskCodeView.text.toString(),
pageIndex
)
}
- override fun initLayoutView(): Int = R.layout.fragment_task
+ override fun initLayoutRes(): Int = R.layout.fragment_task
override fun observeRequestState() {
diff --git a/app/src/main/java/com/casic/br/ktd/netty/ISocketListener.kt b/app/src/main/java/com/casic/br/ktd/netty/ISocketListener.kt
deleted file mode 100644
index dab98e1..0000000
--- a/app/src/main/java/com/casic/br/ktd/netty/ISocketListener.kt
+++ /dev/null
@@ -1,19 +0,0 @@
-package com.casic.br.ktd.netty
-
-interface ISocketListener {
- companion object {
- const val STATUS_CONNECT_SUCCESS: Byte = 1 //连接成功
- const val STATUS_CONNECT_CLOSED: Byte = 0 //关闭连接
- const val STATUS_CONNECT_ERROR: Byte = 0 //连接失败
- }
-
- /**
- * 当接收到系统消息
- */
- fun onMessageResponse(data: ByteArray?)
-
- /**
- * 当连接状态发生变化时调用
- */
- fun onServiceStatusConnectChanged(statusCode: Byte)
-}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/br/ktd/netty/SocketChannelHandle.kt b/app/src/main/java/com/casic/br/ktd/netty/SocketChannelHandle.kt
deleted file mode 100644
index 42eb310..0000000
--- a/app/src/main/java/com/casic/br/ktd/netty/SocketChannelHandle.kt
+++ /dev/null
@@ -1,51 +0,0 @@
-package com.casic.br.ktd.netty
-
-import android.util.Log
-import io.netty.channel.ChannelHandlerContext
-import io.netty.channel.SimpleChannelInboundHandler
-import io.netty.handler.timeout.IdleState
-import io.netty.handler.timeout.IdleStateEvent
-import java.nio.charset.StandardCharsets
-
-class SocketChannelHandle(private val listener: ISocketListener?) :
- SimpleChannelInboundHandler() {
-
- private val kTag = "SocketChannelHandle"
-
- override fun channelActive(ctx: ChannelHandlerContext) {
- super.channelActive(ctx)
- Log.d(kTag, "channelActive ===> 连接成功")
- listener?.onServiceStatusConnectChanged(ISocketListener.STATUS_CONNECT_SUCCESS)
- }
-
- override fun channelInactive(ctx: ChannelHandlerContext) {
- super.channelInactive(ctx)
- Log.e(kTag, "channelInactive: 连接断开")
- }
-
- override fun userEventTriggered(ctx: ChannelHandlerContext, evt: Any) {
- super.userEventTriggered(ctx, evt)
- if (evt is IdleStateEvent) {
- if (evt.state() == IdleState.WRITER_IDLE) {
- //写超时,此时可以发送心跳数据给服务器
- val temp = "FF"
- ctx.writeAndFlush(temp.toByteArray(StandardCharsets.UTF_8))
- } else if (evt.state() == IdleState.READER_IDLE) {
- //读超时,此时代表没有收到心跳返回可以关闭当前连接进行重连
- ctx.close()
- }
- }
- }
-
- override fun channelRead0(ctx: ChannelHandlerContext, data: ByteArray?) {
- listener?.onMessageResponse(data)
- }
-
- override fun exceptionCaught(ctx: ChannelHandlerContext, cause: Throwable) {
- super.exceptionCaught(ctx, cause)
- Log.d(kTag, "exceptionCaught ===> $cause")
- listener?.onServiceStatusConnectChanged(ISocketListener.STATUS_CONNECT_ERROR)
- cause.printStackTrace()
- ctx.close()
- }
-}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/br/ktd/netty/SocketClient.kt b/app/src/main/java/com/casic/br/ktd/netty/SocketClient.kt
deleted file mode 100644
index d05d335..0000000
--- a/app/src/main/java/com/casic/br/ktd/netty/SocketClient.kt
+++ /dev/null
@@ -1,153 +0,0 @@
-package com.casic.br.ktd.netty
-
-import android.os.SystemClock
-import android.util.Log
-import io.netty.bootstrap.Bootstrap
-import io.netty.channel.*
-import io.netty.channel.nio.NioEventLoopGroup
-import io.netty.channel.socket.SocketChannel
-import io.netty.channel.socket.nio.NioSocketChannel
-import io.netty.handler.codec.bytes.ByteArrayDecoder
-import io.netty.handler.codec.bytes.ByteArrayEncoder
-import io.netty.handler.timeout.IdleStateHandler
-
-class SocketClient {
-
- private val kTag = "SocketClient"
-
- private var host: String? = null
- private var port = 8000
- private var nioEventLoopGroup: NioEventLoopGroup? = null
- private var channel: Channel? = null
- private var listener: ISocketListener? = null
-
- //现在连接的状态
- var connectStatus = false //判断是否已连接
- private var reconnectNum = Int.MAX_VALUE //定义的重连到时候用
- private var isNeedReconnect = true //是否需要重连
- var isConnecting = false //是否正在连接
- private set
- private var reconnectIntervalTime: Long = 15000 //重连的时间
-
- //重连时间
- fun setReconnectNum(reconnectNum: Int) {
- this.reconnectNum = reconnectNum
- }
-
- fun setReconnectIntervalTime(reconnectIntervalTime: Long) {
- this.reconnectIntervalTime = reconnectIntervalTime
- }
-
- fun setSocketListener(listener: ISocketListener?) {
- this.listener = listener
- }
-
- fun connect(host: String, port: Int) {
- this.host = host
- this.port = port
- Log.d(kTag, "connect ===> 开始连接TCP服务器")
- if (isConnecting) {
- return
- }
- //起个线程
- val clientThread: Thread = object : Thread("client-Netty") {
- override fun run() {
- super.run()
- isNeedReconnect = true
- reconnectNum = Int.MAX_VALUE
- connectServer()
- }
- }
- clientThread.start()
- }
-
- private fun connectServer() {
- synchronized(this@SocketClient) {
- var channelFuture: ChannelFuture? = null //连接管理对象
- if (!connectStatus) {
- isConnecting = true
- nioEventLoopGroup = NioEventLoopGroup() //设置的连接group
- val bootstrap = Bootstrap()
- bootstrap.group(nioEventLoopGroup) //设置的一系列连接参数操作等
- .channel(NioSocketChannel::class.java)
- .option(ChannelOption.TCP_NODELAY, true) //无阻塞
- .option(ChannelOption.SO_KEEPALIVE, true) //长连接
- .option(
- ChannelOption.RCVBUF_ALLOCATOR,
- AdaptiveRecvByteBufAllocator(5000, 5000, 8000)
- ) //接收缓冲区 最小值太小时数据接收不全
- .handler(object : ChannelInitializer() {
- override fun initChannel(channel: SocketChannel) {
- val pipeline = channel.pipeline()
- //参数1:代表读套接字超时的时间,没收到数据会触发读超时回调;
- //参数2:代表写套接字超时时间,没进行写会触发写超时回调;
- //参数3:将在未执行读取或写入时触发超时回调,0代表不处理;
- //读超时尽量设置大于写超时,代表多次写超时时写心跳包,多次写了心跳数据仍然读超时代表当前连接错误,即可断开连接重新连接
- pipeline.addLast(IdleStateHandler(60, 10, 0))
- pipeline.addLast(ByteArrayDecoder())
- pipeline.addLast(ByteArrayEncoder())
- pipeline.addLast(SocketChannelHandle(listener))
- }
- })
- try {
- //连接监听
- channelFuture = bootstrap.connect(host, port)
- .addListener(object : ChannelFutureListener {
- override fun operationComplete(channelFuture: ChannelFuture) {
- if (channelFuture.isSuccess) {
- connectStatus = true
- channel = channelFuture.channel()
- } else {
- Log.e(kTag, "operationComplete: 连接失败")
- connectStatus = false
- }
- isConnecting = false
- }
- }).sync()
- // 等待连接关闭
- channelFuture.channel().closeFuture().sync()
- } catch (e: Exception) {
- e.printStackTrace()
- } finally {
- connectStatus = false
- listener?.onServiceStatusConnectChanged(ISocketListener.STATUS_CONNECT_CLOSED) //STATUS_CONNECT_CLOSED 这我自己定义的 接口标识
- if (null != channelFuture) {
- if (channelFuture.channel() != null && channelFuture.channel().isOpen) {
- channelFuture.channel().close()
- }
- }
- nioEventLoopGroup?.shutdownGracefully()
- reconnect() //重新连接
- }
- }
- }
- }
-
- //断开连接
- fun disconnect() {
- Log.d(kTag, "disconnect ===> 断开连接")
- isNeedReconnect = false
- nioEventLoopGroup?.shutdownGracefully()
- }
-
- //重新连接
- private fun reconnect() {
- if (isNeedReconnect && reconnectNum > 0 && !connectStatus) {
- reconnectNum--
- SystemClock.sleep(reconnectIntervalTime)
- if (isNeedReconnect && reconnectNum > 0 && !connectStatus) {
- Log.d(kTag, "reconnect ===> 重新连接")
- connectServer()
- }
- }
- }
-
- fun sendData(bytes: ByteArray) {
- channel?.writeAndFlush(bytes)?.addListener(ChannelFutureListener { future ->
- if (!future.isSuccess) {
- future.channel().close()
- nioEventLoopGroup!!.shutdownGracefully()
- }
- })
- }
-}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/br/ktd/netty/SocketManager.kt b/app/src/main/java/com/casic/br/ktd/netty/SocketManager.kt
deleted file mode 100644
index 17daf35..0000000
--- a/app/src/main/java/com/casic/br/ktd/netty/SocketManager.kt
+++ /dev/null
@@ -1,113 +0,0 @@
-package com.casic.br.ktd.netty
-
-import android.util.Log
-import com.casic.br.ktd.base.BaseApplication
-import com.casic.br.ktd.extensions.covertAngleValue
-import com.casic.br.ktd.extensions.covertDataValue
-import com.casic.br.ktd.extensions.toUnsignedByteArray
-import com.casic.br.ktd.model.SensorDataModel
-import com.casic.br.ktd.utils.LocaleConstant
-import com.pengxh.kt.lite.extensions.toJson
-import com.pengxh.kt.lite.utils.BroadcastManager
-
-class SocketManager private constructor() : ISocketListener {
-
- private val kTag = "SocketManager"
- private var nettyClient: SocketClient = SocketClient()
-
- companion object {
- val instance: SocketManager by lazy(mode = LazyThreadSafetyMode.SYNCHRONIZED) { SocketManager() }
- }
-
- fun connectNetty(hostname: String, port: Int) {
- Thread {
- if (!nettyClient.connectStatus) {
- nettyClient.setSocketListener(this)
- nettyClient.connect(hostname, port)
- } else {
- nettyClient.disconnect()
- }
- }.start()
- }
-
- override fun onMessageResponse(data: ByteArray?) {
-// Log.d(kTag, "onMessageResponse ===> " + Arrays.toString(data))
- /**
- * 0xFF,0x01,
- * 0x01,0x37,0xE6, 甲烷浓度值(数据码1* 65536 + 数据码2 * 256 + 数据码3)
- * 0x00, 激光甲烷模块工作状态(00表示设备正常,01表示温控故障,02表示设备激光未打开)
- * 0x00,0xB2,0x35, 激光强度值(数据码5* 65536 + 数据码6 * 256 + 数据码7)
- * 0x0A,0x3D, 云台水平角度([数据码8 * 256 + 数据码9]/100,单位为°,精确到0.01)
- * 0x05,0x6F, 云台垂直角度(首先计算Tangle=[数据码10 * 256 + 数据码11]/100,单位为°,精确到0.01。若Tangle在0~90范围内,则垂直角度值=Tangle;若Tangle在-1~-90范围内,则垂直角度值=Tangle-360)
- * 0xC1
- *
- * [-1, 1, 1, 55, -26, 0, 0, -78, 53, 10, 61, 5, 111, -63]
- * 甲烷浓度值为79638,计算为79638=0x01*65536+0x37*256+0xE6[0x01为数据码1,0x37为数据码2,0xE6为数据码3];
- * 激光甲烷设备状态值为0,表示状态正常,[0x00为数据码4];
- * 激光强度值为45621,计算为45621=0x00*65536+0xB2*256+0x35[0x00为数据码5,0xB2为数据码6,0x35为数据码7];
- *
- * =========================================================================================
- * 实际数据(1800-1950左右)
- * [-86, 1, 0, 7, 71, 0, 0, 62, -92, 57, 59, -118, -111, -64]
- * */
-
- if (data == null) {
- return
- }
- val bytes = data.toUnsignedByteArray()
- if (bytes.size == 14) {
- val dataModel = SensorDataModel(0, "激光未打开", 0, 0.0, 0.0)
-
- val methaneBytes = IntArray(3)
- System.arraycopy(bytes, 2, methaneBytes, 0, 3)
- dataModel.methane = methaneBytes.covertDataValue()
-
- dataModel.methaneState = when (bytes[5]) {
- 1 -> "温控故障"
- 2 -> "激光未打开"
- else -> "正常"
- }
-
- val laserBytes = IntArray(3)
- System.arraycopy(bytes, 6, laserBytes, 0, 3)
- dataModel.laser = laserBytes.covertDataValue()
-
- /**
- * 水平角度的实际范围为从水平零点开始,顺时针方向(从上往下看),0~360°
- * 垂直角度的实际范围为从垂直零点开始,以向上为正,-90°~90°,控制精度为0.01°
- * */
- val horizontalBytes = IntArray(2)
- System.arraycopy(bytes, 9, horizontalBytes, 0, 2)
- dataModel.horizontal = horizontalBytes.covertAngleValue()
-
- val verticalBytes = IntArray(2)
- System.arraycopy(bytes, 11, verticalBytes, 0, 2)
- dataModel.vertical = verticalBytes.covertAngleValue()
-
- //{"horizontal":26.21,"laser":45621,"methane":79846,"methaneState":"正常","vertical":13.91}
- BroadcastManager.obtainInstance(BaseApplication.get()).sendBroadcast(
- LocaleConstant.ACTION_UPDATE_DATA, dataModel.toJson()
- )
- }
- }
-
- override fun onServiceStatusConnectChanged(statusCode: Byte) {
- if (statusCode == ISocketListener.STATUS_CONNECT_SUCCESS) {
- if (nettyClient.connectStatus) {
- Log.d(kTag, "连接成功")
- }
- } else {
- if (!nettyClient.connectStatus) {
- Log.e(kTag, "onServiceStatusConnectChanged:$statusCode,连接断开,正在重连")
- }
- }
- }
-
- fun sendData(data: ByteArray) {
- nettyClient.sendData(data)
- }
-
- fun close() {
- nettyClient.disconnect()
- }
-}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/br/ktd/netty/tcp/ISocketListener.kt b/app/src/main/java/com/casic/br/ktd/netty/tcp/ISocketListener.kt
new file mode 100644
index 0000000..13c3084
--- /dev/null
+++ b/app/src/main/java/com/casic/br/ktd/netty/tcp/ISocketListener.kt
@@ -0,0 +1,19 @@
+package com.casic.br.ktd.netty.tcp
+
+interface ISocketListener {
+ companion object {
+ const val STATUS_CONNECT_SUCCESS: Byte = 1 //连接成功
+ const val STATUS_CONNECT_CLOSED: Byte = 0 //关闭连接
+ const val STATUS_CONNECT_ERROR: Byte = 0 //连接失败
+ }
+
+ /**
+ * 当接收到系统消息
+ */
+ fun onMessageResponse(data: ByteArray?)
+
+ /**
+ * 当连接状态发生变化时调用
+ */
+ fun onServiceStatusConnectChanged(statusCode: Byte)
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/br/ktd/netty/tcp/SocketChannelHandle.kt b/app/src/main/java/com/casic/br/ktd/netty/tcp/SocketChannelHandle.kt
new file mode 100644
index 0000000..8e2997f
--- /dev/null
+++ b/app/src/main/java/com/casic/br/ktd/netty/tcp/SocketChannelHandle.kt
@@ -0,0 +1,51 @@
+package com.casic.br.ktd.netty.tcp
+
+import android.util.Log
+import io.netty.channel.ChannelHandlerContext
+import io.netty.channel.SimpleChannelInboundHandler
+import io.netty.handler.timeout.IdleState
+import io.netty.handler.timeout.IdleStateEvent
+import java.nio.charset.StandardCharsets
+
+class SocketChannelHandle(private val listener: ISocketListener?) :
+ SimpleChannelInboundHandler() {
+
+ private val kTag = "SocketChannelHandle"
+
+ override fun channelActive(ctx: ChannelHandlerContext) {
+ super.channelActive(ctx)
+ Log.d(kTag, "channelActive ===> 连接成功")
+ listener?.onServiceStatusConnectChanged(ISocketListener.STATUS_CONNECT_SUCCESS)
+ }
+
+ override fun channelInactive(ctx: ChannelHandlerContext) {
+ super.channelInactive(ctx)
+ Log.e(kTag, "channelInactive: 连接断开")
+ }
+
+ override fun userEventTriggered(ctx: ChannelHandlerContext, evt: Any) {
+ super.userEventTriggered(ctx, evt)
+ if (evt is IdleStateEvent) {
+ if (evt.state() == IdleState.WRITER_IDLE) {
+ //写超时,此时可以发送心跳数据给服务器
+ val temp = "FF"
+ ctx.writeAndFlush(temp.toByteArray(StandardCharsets.UTF_8))
+ } else if (evt.state() == IdleState.READER_IDLE) {
+ //读超时,此时代表没有收到心跳返回可以关闭当前连接进行重连
+ ctx.close()
+ }
+ }
+ }
+
+ override fun channelRead0(ctx: ChannelHandlerContext, data: ByteArray?) {
+ listener?.onMessageResponse(data)
+ }
+
+ override fun exceptionCaught(ctx: ChannelHandlerContext, cause: Throwable) {
+ super.exceptionCaught(ctx, cause)
+ Log.d(kTag, "exceptionCaught ===> $cause")
+ listener?.onServiceStatusConnectChanged(ISocketListener.STATUS_CONNECT_ERROR)
+ cause.printStackTrace()
+ ctx.close()
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/br/ktd/netty/tcp/SocketClient.kt b/app/src/main/java/com/casic/br/ktd/netty/tcp/SocketClient.kt
new file mode 100644
index 0000000..34960a0
--- /dev/null
+++ b/app/src/main/java/com/casic/br/ktd/netty/tcp/SocketClient.kt
@@ -0,0 +1,153 @@
+package com.casic.br.ktd.netty.tcp
+
+import android.os.SystemClock
+import android.util.Log
+import io.netty.bootstrap.Bootstrap
+import io.netty.channel.*
+import io.netty.channel.nio.NioEventLoopGroup
+import io.netty.channel.socket.SocketChannel
+import io.netty.channel.socket.nio.NioSocketChannel
+import io.netty.handler.codec.bytes.ByteArrayDecoder
+import io.netty.handler.codec.bytes.ByteArrayEncoder
+import io.netty.handler.timeout.IdleStateHandler
+
+class SocketClient {
+
+ private val kTag = "SocketClient"
+
+ private var host: String? = null
+ private var port = 8000
+ private var nioEventLoopGroup: NioEventLoopGroup? = null
+ private var channel: Channel? = null
+ private var listener: ISocketListener? = null
+
+ //现在连接的状态
+ var connectStatus = false //判断是否已连接
+ private var reconnectNum = Int.MAX_VALUE //定义的重连到时候用
+ private var isNeedReconnect = true //是否需要重连
+ var isConnecting = false //是否正在连接
+ private set
+ private var reconnectIntervalTime: Long = 15000 //重连的时间
+
+ //重连时间
+ fun setReconnectNum(reconnectNum: Int) {
+ this.reconnectNum = reconnectNum
+ }
+
+ fun setReconnectIntervalTime(reconnectIntervalTime: Long) {
+ this.reconnectIntervalTime = reconnectIntervalTime
+ }
+
+ fun setSocketListener(listener: ISocketListener?) {
+ this.listener = listener
+ }
+
+ fun connect(host: String, port: Int) {
+ this.host = host
+ this.port = port
+ Log.d(kTag, "connect ===> 开始连接TCP服务器")
+ if (isConnecting) {
+ return
+ }
+ //起个线程
+ val clientThread: Thread = object : Thread("client-Netty") {
+ override fun run() {
+ super.run()
+ isNeedReconnect = true
+ reconnectNum = Int.MAX_VALUE
+ connectServer()
+ }
+ }
+ clientThread.start()
+ }
+
+ private fun connectServer() {
+ synchronized(this@SocketClient) {
+ var channelFuture: ChannelFuture? = null //连接管理对象
+ if (!connectStatus) {
+ isConnecting = true
+ nioEventLoopGroup = NioEventLoopGroup() //设置的连接group
+ val bootstrap = Bootstrap()
+ bootstrap.group(nioEventLoopGroup) //设置的一系列连接参数操作等
+ .channel(NioSocketChannel::class.java)
+ .option(ChannelOption.TCP_NODELAY, true) //无阻塞
+ .option(ChannelOption.SO_KEEPALIVE, true) //长连接
+ .option(
+ ChannelOption.RCVBUF_ALLOCATOR,
+ AdaptiveRecvByteBufAllocator(5000, 5000, 8000)
+ ) //接收缓冲区 最小值太小时数据接收不全
+ .handler(object : ChannelInitializer() {
+ override fun initChannel(channel: SocketChannel) {
+ val pipeline = channel.pipeline()
+ //参数1:代表读套接字超时的时间,没收到数据会触发读超时回调;
+ //参数2:代表写套接字超时时间,没进行写会触发写超时回调;
+ //参数3:将在未执行读取或写入时触发超时回调,0代表不处理;
+ //读超时尽量设置大于写超时,代表多次写超时时写心跳包,多次写了心跳数据仍然读超时代表当前连接错误,即可断开连接重新连接
+ pipeline.addLast(IdleStateHandler(60, 10, 0))
+ pipeline.addLast(ByteArrayDecoder())
+ pipeline.addLast(ByteArrayEncoder())
+ pipeline.addLast(SocketChannelHandle(listener))
+ }
+ })
+ try {
+ //连接监听
+ channelFuture = bootstrap.connect(host, port)
+ .addListener(object : ChannelFutureListener {
+ override fun operationComplete(channelFuture: ChannelFuture) {
+ if (channelFuture.isSuccess) {
+ connectStatus = true
+ channel = channelFuture.channel()
+ } else {
+ Log.e(kTag, "operationComplete: 连接失败")
+ connectStatus = false
+ }
+ isConnecting = false
+ }
+ }).sync()
+ // 等待连接关闭
+ channelFuture.channel().closeFuture().sync()
+ } catch (e: Exception) {
+ e.printStackTrace()
+ } finally {
+ connectStatus = false
+ listener?.onServiceStatusConnectChanged(ISocketListener.STATUS_CONNECT_CLOSED) //STATUS_CONNECT_CLOSED 这我自己定义的 接口标识
+ if (null != channelFuture) {
+ if (channelFuture.channel() != null && channelFuture.channel().isOpen) {
+ channelFuture.channel().close()
+ }
+ }
+ nioEventLoopGroup?.shutdownGracefully()
+ reconnect() //重新连接
+ }
+ }
+ }
+ }
+
+ //断开连接
+ fun disconnect() {
+ Log.d(kTag, "disconnect ===> 断开连接")
+ isNeedReconnect = false
+ nioEventLoopGroup?.shutdownGracefully()
+ }
+
+ //重新连接
+ private fun reconnect() {
+ if (isNeedReconnect && reconnectNum > 0 && !connectStatus) {
+ reconnectNum--
+ SystemClock.sleep(reconnectIntervalTime)
+ if (isNeedReconnect && reconnectNum > 0 && !connectStatus) {
+ Log.d(kTag, "reconnect ===> 重新连接")
+ connectServer()
+ }
+ }
+ }
+
+ fun sendData(bytes: ByteArray) {
+ channel?.writeAndFlush(bytes)?.addListener(ChannelFutureListener { future ->
+ if (!future.isSuccess) {
+ future.channel().close()
+ nioEventLoopGroup!!.shutdownGracefully()
+ }
+ })
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/br/ktd/netty/tcp/SocketManager.kt b/app/src/main/java/com/casic/br/ktd/netty/tcp/SocketManager.kt
new file mode 100644
index 0000000..35980b9
--- /dev/null
+++ b/app/src/main/java/com/casic/br/ktd/netty/tcp/SocketManager.kt
@@ -0,0 +1,113 @@
+package com.casic.br.ktd.netty.tcp
+
+import android.util.Log
+import com.casic.br.ktd.base.BaseApplication
+import com.casic.br.ktd.extensions.covertAngleValue
+import com.casic.br.ktd.extensions.covertDataValue
+import com.casic.br.ktd.extensions.toUnsignedByteArray
+import com.casic.br.ktd.model.SensorDataModel
+import com.casic.br.ktd.utils.LocaleConstant
+import com.pengxh.kt.lite.extensions.toJson
+import com.pengxh.kt.lite.utils.BroadcastManager
+
+class SocketManager private constructor() : ISocketListener {
+
+ private val kTag = "SocketManager"
+ private var nettyClient: SocketClient = SocketClient()
+
+ companion object {
+ val instance: SocketManager by lazy(mode = LazyThreadSafetyMode.SYNCHRONIZED) { SocketManager() }
+ }
+
+ fun connectNetty(hostname: String, port: Int) {
+ Thread {
+ if (!nettyClient.connectStatus) {
+ nettyClient.setSocketListener(this)
+ nettyClient.connect(hostname, port)
+ } else {
+ nettyClient.disconnect()
+ }
+ }.start()
+ }
+
+ override fun onMessageResponse(data: ByteArray?) {
+// Log.d(kTag, "onMessageResponse ===> " + Arrays.toString(data))
+ /**
+ * 0xFF,0x01,
+ * 0x01,0x37,0xE6, 甲烷浓度值(数据码1* 65536 + 数据码2 * 256 + 数据码3)
+ * 0x00, 激光甲烷模块工作状态(00表示设备正常,01表示温控故障,02表示设备激光未打开)
+ * 0x00,0xB2,0x35, 激光强度值(数据码5* 65536 + 数据码6 * 256 + 数据码7)
+ * 0x0A,0x3D, 云台水平角度([数据码8 * 256 + 数据码9]/100,单位为°,精确到0.01)
+ * 0x05,0x6F, 云台垂直角度(首先计算Tangle=[数据码10 * 256 + 数据码11]/100,单位为°,精确到0.01。若Tangle在0~90范围内,则垂直角度值=Tangle;若Tangle在-1~-90范围内,则垂直角度值=Tangle-360)
+ * 0xC1
+ *
+ * [-1, 1, 1, 55, -26, 0, 0, -78, 53, 10, 61, 5, 111, -63]
+ * 甲烷浓度值为79638,计算为79638=0x01*65536+0x37*256+0xE6[0x01为数据码1,0x37为数据码2,0xE6为数据码3];
+ * 激光甲烷设备状态值为0,表示状态正常,[0x00为数据码4];
+ * 激光强度值为45621,计算为45621=0x00*65536+0xB2*256+0x35[0x00为数据码5,0xB2为数据码6,0x35为数据码7];
+ *
+ * =========================================================================================
+ * 实际数据(1800-1950左右)
+ * [-86, 1, 0, 7, 71, 0, 0, 62, -92, 57, 59, -118, -111, -64]
+ * */
+
+ if (data == null) {
+ return
+ }
+ val bytes = data.toUnsignedByteArray()
+ if (bytes.size == 14) {
+ val dataModel = SensorDataModel(0, "激光未打开", 0, 0.0, 0.0)
+
+ val methaneBytes = IntArray(3)
+ System.arraycopy(bytes, 2, methaneBytes, 0, 3)
+ dataModel.methane = methaneBytes.covertDataValue()
+
+ dataModel.methaneState = when (bytes[5]) {
+ 1 -> "温控故障"
+ 2 -> "激光未打开"
+ else -> "正常"
+ }
+
+ val laserBytes = IntArray(3)
+ System.arraycopy(bytes, 6, laserBytes, 0, 3)
+ dataModel.laser = laserBytes.covertDataValue()
+
+ /**
+ * 水平角度的实际范围为从水平零点开始,顺时针方向(从上往下看),0~360°
+ * 垂直角度的实际范围为从垂直零点开始,以向上为正,-90°~90°,控制精度为0.01°
+ * */
+ val horizontalBytes = IntArray(2)
+ System.arraycopy(bytes, 9, horizontalBytes, 0, 2)
+ dataModel.horizontal = horizontalBytes.covertAngleValue()
+
+ val verticalBytes = IntArray(2)
+ System.arraycopy(bytes, 11, verticalBytes, 0, 2)
+ dataModel.vertical = verticalBytes.covertAngleValue()
+
+ //{"horizontal":26.21,"laser":45621,"methane":79846,"methaneState":"正常","vertical":13.91}
+ BroadcastManager.obtainInstance(BaseApplication.get()).sendBroadcast(
+ LocaleConstant.ACTION_UPDATE_DATA, dataModel.toJson()
+ )
+ }
+ }
+
+ override fun onServiceStatusConnectChanged(statusCode: Byte) {
+ if (statusCode == ISocketListener.STATUS_CONNECT_SUCCESS) {
+ if (nettyClient.connectStatus) {
+ Log.d(kTag, "连接成功")
+ }
+ } else {
+ if (!nettyClient.connectStatus) {
+ Log.e(kTag, "onServiceStatusConnectChanged:$statusCode,连接断开,正在重连")
+ }
+ }
+ }
+
+ fun sendData(data: ByteArray) {
+ nettyClient.sendData(data)
+ }
+
+ fun close() {
+ nettyClient.disconnect()
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/br/ktd/netty/udp/UdpChannelInboundHandler.kt b/app/src/main/java/com/casic/br/ktd/netty/udp/UdpChannelInboundHandler.kt
new file mode 100644
index 0000000..4d6f97c
--- /dev/null
+++ b/app/src/main/java/com/casic/br/ktd/netty/udp/UdpChannelInboundHandler.kt
@@ -0,0 +1,36 @@
+package com.casic.br.ktd.netty.udp
+
+import io.netty.channel.ChannelHandlerContext
+import io.netty.channel.SimpleChannelInboundHandler
+import io.netty.channel.socket.DatagramPacket
+import io.netty.util.CharsetUtil
+
+
+abstract class UdpChannelInboundHandler : SimpleChannelInboundHandler() {
+
+ private var handlerContext: ChannelHandlerContext? = null
+
+ override fun channelActive(ctx: ChannelHandlerContext?) {
+ super.channelActive(ctx)
+ handlerContext = ctx
+ }
+
+ override fun channelInactive(ctx: ChannelHandlerContext?) {
+ super.channelInactive(ctx)
+ handlerContext?.close()
+ }
+
+ fun sendDatagramPacket(obj: Any) {
+ handlerContext?.writeAndFlush(obj)
+ }
+
+ fun releasePort() {
+ handlerContext?.close()
+ }
+
+ override fun channelRead0(ctx: ChannelHandlerContext, datagramPacket: DatagramPacket) {
+ receivedMessage(datagramPacket.content().toString(CharsetUtil.UTF_8))
+ }
+
+ abstract fun receivedMessage(data: String)
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/br/ktd/netty/udp/UdpChannelInitializer.kt b/app/src/main/java/com/casic/br/ktd/netty/udp/UdpChannelInitializer.kt
new file mode 100644
index 0000000..416c5a1
--- /dev/null
+++ b/app/src/main/java/com/casic/br/ktd/netty/udp/UdpChannelInitializer.kt
@@ -0,0 +1,17 @@
+package com.casic.br.ktd.netty.udp
+
+import io.netty.channel.ChannelInitializer
+import io.netty.channel.socket.DatagramChannel
+import io.netty.handler.timeout.IdleStateHandler
+
+
+open class UdpChannelInitializer(private val handler: UdpChannelInboundHandler) :
+ ChannelInitializer() {
+
+ override fun initChannel(datagramChannel: DatagramChannel) {
+ val pipeline = datagramChannel.pipeline()
+ pipeline.addLast(
+ IdleStateHandler(12, 15, 0)
+ ).addLast(handler)
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/br/ktd/netty/udp/UdpClient.kt b/app/src/main/java/com/casic/br/ktd/netty/udp/UdpClient.kt
new file mode 100644
index 0000000..3893afa
--- /dev/null
+++ b/app/src/main/java/com/casic/br/ktd/netty/udp/UdpClient.kt
@@ -0,0 +1,103 @@
+package com.casic.br.ktd.netty.udp
+
+import com.casic.br.ktd.utils.LocaleConstant
+import com.pengxh.kt.lite.utils.SaveKeyValues
+import io.netty.bootstrap.Bootstrap
+import io.netty.buffer.ByteBuf
+import io.netty.buffer.Unpooled
+import io.netty.channel.ChannelOption
+import io.netty.channel.nio.NioEventLoopGroup
+import io.netty.channel.socket.DatagramPacket
+import io.netty.channel.socket.nio.NioDatagramChannel
+import io.netty.util.CharsetUtil
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.launch
+import kotlinx.coroutines.withContext
+import java.net.InetSocketAddress
+import java.util.concurrent.ExecutorService
+import java.util.concurrent.Executors
+
+
+class UdpClient : UdpChannelInboundHandler(), Runnable {
+
+ private val bootStrap by lazy { Bootstrap() }
+ private val eventLoopGroup by lazy { NioEventLoopGroup() }
+ private val udpChannelInitializer by lazy { UdpChannelInitializer(this) }
+ private var executorService: ExecutorService
+
+ init {
+ bootStrap.group(eventLoopGroup)
+ bootStrap.channel(NioDatagramChannel::class.java)
+ .option(ChannelOption.SO_RCVBUF, 1024)
+ .option(ChannelOption.SO_SNDBUF, 1024)
+ bootStrap.handler(udpChannelInitializer)
+
+ executorService = Executors.newSingleThreadExecutor()
+ executorService.execute(this)
+ }
+
+ override fun run() {
+ try {
+ val channelFuture = bootStrap.bind(LocaleConstant.LOCATION_UDP_PORT).sync()
+ channelFuture.channel().closeFuture().sync()
+ } catch (e: InterruptedException) {
+ e.printStackTrace()
+ } finally {
+ eventLoopGroup.shutdownGracefully()
+ }
+ }
+
+ fun send(value: String) {
+ CoroutineScope(Dispatchers.Main).launch {
+ withContext(Dispatchers.IO) {
+ val host = SaveKeyValues.getValue(
+ LocaleConstant.LOCATION_UDP_SERVER, "192.168.149.213"
+ ).toString()
+ val datagramPacket = DatagramPacket(
+ Unpooled.copiedBuffer(value, CharsetUtil.UTF_8),
+ InetSocketAddress(host, LocaleConstant.LOCATION_UDP_PORT)
+ )
+ sendDatagramPacket(datagramPacket)
+ }
+ }
+ }
+
+ fun send(value: ByteArray) {
+ CoroutineScope(Dispatchers.Main).launch {
+ withContext(Dispatchers.IO) {
+ val host = SaveKeyValues.getValue(
+ LocaleConstant.LOCATION_UDP_SERVER, "192.168.149.213"
+ ).toString()
+ val datagramPacket = DatagramPacket(
+ Unpooled.copiedBuffer(value),
+ InetSocketAddress(host, LocaleConstant.LOCATION_UDP_PORT)
+ )
+ sendDatagramPacket(datagramPacket)
+ }
+ }
+ }
+
+ fun send(value: ByteBuf) {
+ CoroutineScope(Dispatchers.Main).launch {
+ withContext(Dispatchers.IO) {
+ val host = SaveKeyValues.getValue(
+ LocaleConstant.LOCATION_UDP_SERVER, "192.168.149.213"
+ ).toString()
+ val datagramPacket = DatagramPacket(
+ Unpooled.copiedBuffer(value),
+ InetSocketAddress(host, LocaleConstant.LOCATION_UDP_PORT)
+ )
+ sendDatagramPacket(datagramPacket)
+ }
+ }
+ }
+
+ fun release() {
+ releasePort()
+ }
+
+ override fun receivedMessage(data: String) {
+
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/br/ktd/utils/LocaleConstant.kt b/app/src/main/java/com/casic/br/ktd/utils/LocaleConstant.kt
index 0dd119e..4c675df 100644
--- a/app/src/main/java/com/casic/br/ktd/utils/LocaleConstant.kt
+++ b/app/src/main/java/com/casic/br/ktd/utils/LocaleConstant.kt
@@ -50,6 +50,10 @@
const val DEV_NET_IP = "192.168.1.21"
const val DEV_NET_PORT = "8000"
+ //位置信息UDP端口
+ const val LOCATION_UDP_SERVER = "udpServer"
+ const val LOCATION_UDP_PORT = 7777
+
//BroadcastReceiver Action
const val ACTION_UPDATE_DATA = "update"
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index e822df6..d72c1a5 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -7,6 +7,9 @@
+
+
+
@@ -46,5 +49,8 @@
+
+
+
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/br/ktd/base/KotlinBaseFragment.kt b/app/src/main/java/com/casic/br/ktd/base/KotlinBaseFragment.kt
new file mode 100644
index 0000000..2dac61c
--- /dev/null
+++ b/app/src/main/java/com/casic/br/ktd/base/KotlinBaseFragment.kt
@@ -0,0 +1,51 @@
+package com.casic.br.ktd.base
+
+import android.os.Bundle
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import androidx.annotation.LayoutRes
+import androidx.fragment.app.Fragment
+
+abstract class KotlinBaseFragment : Fragment() {
+
+ lateinit var bv: View
+
+ override fun onCreateView(
+ inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?
+ ): View? {
+ bv = inflater.inflate(initLayoutRes(), container, false)
+ initView(savedInstanceState)
+ setupTopBarLayout()
+ return bv
+ }
+
+ override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
+ super.onViewCreated(view, savedInstanceState)
+ observeRequestState()
+ initEvent()
+ }
+
+ @LayoutRes
+ abstract fun initLayoutRes(): Int
+
+ /**
+ * 沉浸式状态栏
+ */
+ abstract fun setupTopBarLayout()
+
+ /**
+ * 初始化布局以及控件
+ */
+ abstract fun initView(savedInstanceState: Bundle?)
+
+ /**
+ * 网络请求状态监听
+ */
+ abstract fun observeRequestState()
+
+ /**
+ * 业务逻辑,按钮等事件
+ */
+ abstract fun initEvent()
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/br/ktd/fragment/AlarmPageFragment.kt b/app/src/main/java/com/casic/br/ktd/fragment/AlarmPageFragment.kt
index 6c98a3b..9418169 100644
--- a/app/src/main/java/com/casic/br/ktd/fragment/AlarmPageFragment.kt
+++ b/app/src/main/java/com/casic/br/ktd/fragment/AlarmPageFragment.kt
@@ -2,28 +2,29 @@
import android.os.Bundle
import com.casic.br.ktd.R
+import com.casic.br.ktd.base.KotlinBaseFragment
import com.casic.br.ktd.widgets.DateRangeActionSheet
-import com.pengxh.kt.lite.base.KotlinBaseFragment
import kotlinx.android.synthetic.main.fragment_alarm.view.*
class AlarmPageFragment : KotlinBaseFragment() {
- override fun initData(savedInstanceState: Bundle?) {
+
+ override fun initView(savedInstanceState: Bundle?) {
}
override fun initEvent() {
- baseView.calendarView.setOnClickListener {
+ bv.calendarView.setOnClickListener {
DateRangeActionSheet.Builder().setContext(requireContext())
.setOnActionSheetListener(object :
DateRangeActionSheet.OnDateRangeSelectedListener {
override fun onDateRangeSelected(startDate: String, endDate: String) {
- baseView.selectedDateView.text = "$startDate ~ $endDate"
+ bv.selectedDateView.text = "$startDate ~ $endDate"
}
}).build().show()
}
}
- override fun initLayoutView(): Int = R.layout.fragment_alarm
+ override fun initLayoutRes(): Int = R.layout.fragment_alarm
override fun observeRequestState() {
diff --git a/app/src/main/java/com/casic/br/ktd/fragment/HomePageFragment.kt b/app/src/main/java/com/casic/br/ktd/fragment/HomePageFragment.kt
index 9961935..f3eba5c 100644
--- a/app/src/main/java/com/casic/br/ktd/fragment/HomePageFragment.kt
+++ b/app/src/main/java/com/casic/br/ktd/fragment/HomePageFragment.kt
@@ -1,32 +1,62 @@
package com.casic.br.ktd.fragment
+import android.graphics.Color
import android.os.Bundle
import com.amap.api.maps.AMap
import com.amap.api.maps.AMapOptions
+import com.amap.api.maps.CameraUpdateFactory
+import com.amap.api.maps.model.*
import com.casic.br.ktd.R
-import com.pengxh.kt.lite.base.KotlinBaseFragment
+import com.casic.br.ktd.base.KotlinBaseFragment
import kotlinx.android.synthetic.main.fragment_home.view.*
class HomePageFragment : KotlinBaseFragment() {
private lateinit var aMap: AMap
- override fun initData(savedInstanceState: Bundle?) {
- baseView.mapView.onCreate(savedInstanceState)
- aMap = baseView.mapView.map
+ override fun initView(savedInstanceState: Bundle?) {
+ bv.mapView.onCreate(savedInstanceState)
+ aMap = bv.mapView.map
val uiSettings = aMap.uiSettings
uiSettings.isCompassEnabled = true
- uiSettings.isMyLocationButtonEnabled = true
+ uiSettings.isMyLocationButtonEnabled = false
uiSettings.isScaleControlsEnabled = true
uiSettings.zoomPosition = AMapOptions.ZOOM_POSITION_RIGHT_CENTER
uiSettings.isRotateGesturesEnabled = false//不许地图随手势旋转角度
}
override fun initEvent() {
-
+ //移动到巡检起始经纬度
+ val cameraPosition = CameraPosition(LatLng(39.914199, 116.265785), 16f, 0f, 0f)
+ val cameraUpdate = CameraUpdateFactory.newCameraPosition(cameraPosition)
+ aMap.animateCamera(cameraUpdate, 1500, null)
+ //设置起点
+ addMarker(LatLng(39.914885, 116.272312), R.mipmap.start)
+ //设置终点
+ addMarker(LatLng(39.914716, 116.265097), R.mipmap.end)
+ //瞄点画线
+ val latLngPoints = ArrayList()
+ latLngPoints.add(LatLng(39.914885, 116.272312))
+ latLngPoints.add(LatLng(39.915148, 116.272312))
+ latLngPoints.add(LatLng(39.915399, 116.272302))
+ latLngPoints.add(LatLng(39.915436, 116.271787))
+ latLngPoints.add(LatLng(39.915477, 116.270886))
+ latLngPoints.add(LatLng(39.915477, 116.269968))
+ latLngPoints.add(LatLng(39.915469, 116.269544))
+ latLngPoints.add(LatLng(39.915481, 116.269196))
+ latLngPoints.add(LatLng(39.915452, 116.268472))
+ latLngPoints.add(LatLng(39.915444, 116.267722))
+ latLngPoints.add(LatLng(39.915415, 116.266755))
+ latLngPoints.add(LatLng(39.915403, 116.266165))
+ latLngPoints.add(LatLng(39.915395, 116.265703))
+ latLngPoints.add(LatLng(39.915366, 116.265119))
+ latLngPoints.add(LatLng(39.914716, 116.265097))
+ aMap.addPolyline(
+ PolylineOptions().addAll(latLngPoints).width(10.toFloat()).color(Color.RED)
+ )
}
- override fun initLayoutView(): Int = R.layout.fragment_home
+ override fun initLayoutRes(): Int = R.layout.fragment_home
override fun observeRequestState() {
@@ -36,25 +66,32 @@
}
+ private fun addMarker(point: LatLng, res: Int) {
+ val markerOption = MarkerOptions()
+ markerOption.position(point)
+ markerOption.icon(BitmapDescriptorFactory.fromResource(res))
+ aMap.addMarker(markerOption)
+ }
+
/***以下是地图生命周期管理************************************************************************/
override fun onResume() {
super.onResume()
- baseView.mapView.onResume()
+ bv.mapView.onResume()
}
override fun onPause() {
- baseView.mapView.onPause()
super.onPause()
+ bv.mapView.onPause()
}
override fun onSaveInstanceState(outState: Bundle) {
super.onSaveInstanceState(outState)
- baseView.mapView.onSaveInstanceState(outState)
+ bv.mapView.onSaveInstanceState(outState)
}
override fun onDestroy() {
- baseView.mapView.onDestroy()
super.onDestroy()
+ bv.mapView.onDestroy()
}
}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/br/ktd/fragment/MinePageFragment.kt b/app/src/main/java/com/casic/br/ktd/fragment/MinePageFragment.kt
index 90313ac..3212794 100644
--- a/app/src/main/java/com/casic/br/ktd/fragment/MinePageFragment.kt
+++ b/app/src/main/java/com/casic/br/ktd/fragment/MinePageFragment.kt
@@ -2,10 +2,11 @@
import android.os.Bundle
import com.casic.br.ktd.R
-import com.pengxh.kt.lite.base.KotlinBaseFragment
+import com.casic.br.ktd.base.KotlinBaseFragment
class MinePageFragment : KotlinBaseFragment() {
- override fun initData(savedInstanceState: Bundle?) {
+
+ override fun initView(savedInstanceState: Bundle?) {
}
@@ -13,7 +14,7 @@
}
- override fun initLayoutView(): Int = R.layout.fragment_mine
+ override fun initLayoutRes(): Int = R.layout.fragment_mine
override fun observeRequestState() {
diff --git a/app/src/main/java/com/casic/br/ktd/fragment/TaskPageFragment.kt b/app/src/main/java/com/casic/br/ktd/fragment/TaskPageFragment.kt
index 8f6abf0..6b82a54 100644
--- a/app/src/main/java/com/casic/br/ktd/fragment/TaskPageFragment.kt
+++ b/app/src/main/java/com/casic/br/ktd/fragment/TaskPageFragment.kt
@@ -8,6 +8,7 @@
import androidx.recyclerview.widget.RecyclerView
import com.casic.br.ktd.R
import com.casic.br.ktd.adapter.TaskAdapter
+import com.casic.br.ktd.base.KotlinBaseFragment
import com.casic.br.ktd.holder.SwipeViewHolder
import com.casic.br.ktd.model.TaskListModel
import com.casic.br.ktd.view.InspectionActivity
@@ -15,7 +16,6 @@
import com.casic.br.ktd.widgets.AlertControlDialog
import com.casic.br.ktd.widgets.AlertInputDialog
import com.casic.br.ktd.widgets.DateRangeActionSheet
-import com.pengxh.kt.lite.base.KotlinBaseFragment
import com.pengxh.kt.lite.extensions.navigatePageTo
import com.pengxh.kt.lite.extensions.show
import com.pengxh.kt.lite.utils.WeakReferenceHandler
@@ -36,7 +36,7 @@
private var startTime = ""
private var endTime = ""
- override fun initData(savedInstanceState: Bundle?) {
+ override fun initView(savedInstanceState: Bundle?) {
weakReferenceHandler = WeakReferenceHandler(this)
taskViewModel = ViewModelProvider(this)[TaskViewModel::class.java]
taskViewModel.taskList.observe(this) {
@@ -45,7 +45,7 @@
when {
isRefresh -> {
taskAdapter.setRefreshData(dataRows)
- baseView.taskLayout.finishRefresh()
+ bv.taskLayout.finishRefresh()
isRefresh = false
}
isLoadMore -> {
@@ -53,7 +53,7 @@
"到底了,别拉了".show(requireContext())
}
taskAdapter.setLoadMoreData(dataRows)
- baseView.taskLayout.finishLoadMore()
+ bv.taskLayout.finishLoadMore()
isLoadMore = false
}
else -> {
@@ -76,9 +76,9 @@
when (msg.what) {
2023070501 -> {
if (dataBeans.size == 0) {
- baseView.emptyLayout.visibility = View.VISIBLE
+ bv.emptyLayout.visibility = View.VISIBLE
} else {
- baseView.emptyLayout.visibility = View.GONE
+ bv.emptyLayout.visibility = View.GONE
taskAdapter = object : TaskAdapter(
requireContext(), R.layout.item_task_rv_l, dataBeans
) {
@@ -97,8 +97,8 @@
}
}
//绑定侧滑事件
- swipeAction.attachToRecyclerView(baseView.taskRecyclerView)
- baseView.taskRecyclerView.adapter = taskAdapter
+ swipeAction.attachToRecyclerView(bv.taskRecyclerView)
+ bv.taskRecyclerView.adapter = taskAdapter
taskAdapter.setOnItemCheckedListener(object :
TaskAdapter.OnItemCheckedListener {
override fun onItemChecked(items: ArrayList) {
@@ -168,7 +168,7 @@
override fun initEvent() {
- baseView.calendarView.setOnClickListener {
+ bv.calendarView.setOnClickListener {
DateRangeActionSheet.Builder().setContext(requireContext())
.setOnActionSheetListener(object :
DateRangeActionSheet.OnDateRangeSelectedListener {
@@ -177,12 +177,12 @@
endTime = endDate
//显示
- baseView.selectedDateView.text = "$startDate ~ $endDate"
+ bv.selectedDateView.text = "$startDate ~ $endDate"
}
}).build().show()
}
- baseView.addTaskButton.setOnClickListener {
+ bv.addTaskButton.setOnClickListener {
// AlertInputDialog.Builder()
// .setContext(requireContext())
// .setTitle("新建巡检任务")
@@ -200,11 +200,11 @@
requireContext().navigatePageTo()
}
- baseView.deleteTaskButton.setOnClickListener {
+ bv.deleteTaskButton.setOnClickListener {
selectedItems.size.toString().show(requireContext())
}
- baseView.taskSettingsButton.setOnClickListener {
+ bv.taskSettingsButton.setOnClickListener {
AlertInputDialog.Builder()
.setContext(requireContext())
.setTitle("设置阈值")
@@ -221,14 +221,14 @@
}).build().show()
}
- baseView.taskLayout.setOnRefreshListener {
+ bv.taskLayout.setOnRefreshListener {
isRefresh = true
//刷新之后页码重置
pageIndex = 1
getTaskList()
}
- baseView.taskLayout.setOnLoadMoreListener {
+ bv.taskLayout.setOnLoadMoreListener {
isLoadMore = true
pageIndex++
getTaskList()
@@ -239,13 +239,13 @@
taskViewModel.getTaskList(
startTime,
endTime,
- baseView.taskNameView.text.toString(),
- baseView.taskCodeView.text.toString(),
+ bv.taskNameView.text.toString(),
+ bv.taskCodeView.text.toString(),
pageIndex
)
}
- override fun initLayoutView(): Int = R.layout.fragment_task
+ override fun initLayoutRes(): Int = R.layout.fragment_task
override fun observeRequestState() {
diff --git a/app/src/main/java/com/casic/br/ktd/netty/ISocketListener.kt b/app/src/main/java/com/casic/br/ktd/netty/ISocketListener.kt
deleted file mode 100644
index dab98e1..0000000
--- a/app/src/main/java/com/casic/br/ktd/netty/ISocketListener.kt
+++ /dev/null
@@ -1,19 +0,0 @@
-package com.casic.br.ktd.netty
-
-interface ISocketListener {
- companion object {
- const val STATUS_CONNECT_SUCCESS: Byte = 1 //连接成功
- const val STATUS_CONNECT_CLOSED: Byte = 0 //关闭连接
- const val STATUS_CONNECT_ERROR: Byte = 0 //连接失败
- }
-
- /**
- * 当接收到系统消息
- */
- fun onMessageResponse(data: ByteArray?)
-
- /**
- * 当连接状态发生变化时调用
- */
- fun onServiceStatusConnectChanged(statusCode: Byte)
-}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/br/ktd/netty/SocketChannelHandle.kt b/app/src/main/java/com/casic/br/ktd/netty/SocketChannelHandle.kt
deleted file mode 100644
index 42eb310..0000000
--- a/app/src/main/java/com/casic/br/ktd/netty/SocketChannelHandle.kt
+++ /dev/null
@@ -1,51 +0,0 @@
-package com.casic.br.ktd.netty
-
-import android.util.Log
-import io.netty.channel.ChannelHandlerContext
-import io.netty.channel.SimpleChannelInboundHandler
-import io.netty.handler.timeout.IdleState
-import io.netty.handler.timeout.IdleStateEvent
-import java.nio.charset.StandardCharsets
-
-class SocketChannelHandle(private val listener: ISocketListener?) :
- SimpleChannelInboundHandler() {
-
- private val kTag = "SocketChannelHandle"
-
- override fun channelActive(ctx: ChannelHandlerContext) {
- super.channelActive(ctx)
- Log.d(kTag, "channelActive ===> 连接成功")
- listener?.onServiceStatusConnectChanged(ISocketListener.STATUS_CONNECT_SUCCESS)
- }
-
- override fun channelInactive(ctx: ChannelHandlerContext) {
- super.channelInactive(ctx)
- Log.e(kTag, "channelInactive: 连接断开")
- }
-
- override fun userEventTriggered(ctx: ChannelHandlerContext, evt: Any) {
- super.userEventTriggered(ctx, evt)
- if (evt is IdleStateEvent) {
- if (evt.state() == IdleState.WRITER_IDLE) {
- //写超时,此时可以发送心跳数据给服务器
- val temp = "FF"
- ctx.writeAndFlush(temp.toByteArray(StandardCharsets.UTF_8))
- } else if (evt.state() == IdleState.READER_IDLE) {
- //读超时,此时代表没有收到心跳返回可以关闭当前连接进行重连
- ctx.close()
- }
- }
- }
-
- override fun channelRead0(ctx: ChannelHandlerContext, data: ByteArray?) {
- listener?.onMessageResponse(data)
- }
-
- override fun exceptionCaught(ctx: ChannelHandlerContext, cause: Throwable) {
- super.exceptionCaught(ctx, cause)
- Log.d(kTag, "exceptionCaught ===> $cause")
- listener?.onServiceStatusConnectChanged(ISocketListener.STATUS_CONNECT_ERROR)
- cause.printStackTrace()
- ctx.close()
- }
-}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/br/ktd/netty/SocketClient.kt b/app/src/main/java/com/casic/br/ktd/netty/SocketClient.kt
deleted file mode 100644
index d05d335..0000000
--- a/app/src/main/java/com/casic/br/ktd/netty/SocketClient.kt
+++ /dev/null
@@ -1,153 +0,0 @@
-package com.casic.br.ktd.netty
-
-import android.os.SystemClock
-import android.util.Log
-import io.netty.bootstrap.Bootstrap
-import io.netty.channel.*
-import io.netty.channel.nio.NioEventLoopGroup
-import io.netty.channel.socket.SocketChannel
-import io.netty.channel.socket.nio.NioSocketChannel
-import io.netty.handler.codec.bytes.ByteArrayDecoder
-import io.netty.handler.codec.bytes.ByteArrayEncoder
-import io.netty.handler.timeout.IdleStateHandler
-
-class SocketClient {
-
- private val kTag = "SocketClient"
-
- private var host: String? = null
- private var port = 8000
- private var nioEventLoopGroup: NioEventLoopGroup? = null
- private var channel: Channel? = null
- private var listener: ISocketListener? = null
-
- //现在连接的状态
- var connectStatus = false //判断是否已连接
- private var reconnectNum = Int.MAX_VALUE //定义的重连到时候用
- private var isNeedReconnect = true //是否需要重连
- var isConnecting = false //是否正在连接
- private set
- private var reconnectIntervalTime: Long = 15000 //重连的时间
-
- //重连时间
- fun setReconnectNum(reconnectNum: Int) {
- this.reconnectNum = reconnectNum
- }
-
- fun setReconnectIntervalTime(reconnectIntervalTime: Long) {
- this.reconnectIntervalTime = reconnectIntervalTime
- }
-
- fun setSocketListener(listener: ISocketListener?) {
- this.listener = listener
- }
-
- fun connect(host: String, port: Int) {
- this.host = host
- this.port = port
- Log.d(kTag, "connect ===> 开始连接TCP服务器")
- if (isConnecting) {
- return
- }
- //起个线程
- val clientThread: Thread = object : Thread("client-Netty") {
- override fun run() {
- super.run()
- isNeedReconnect = true
- reconnectNum = Int.MAX_VALUE
- connectServer()
- }
- }
- clientThread.start()
- }
-
- private fun connectServer() {
- synchronized(this@SocketClient) {
- var channelFuture: ChannelFuture? = null //连接管理对象
- if (!connectStatus) {
- isConnecting = true
- nioEventLoopGroup = NioEventLoopGroup() //设置的连接group
- val bootstrap = Bootstrap()
- bootstrap.group(nioEventLoopGroup) //设置的一系列连接参数操作等
- .channel(NioSocketChannel::class.java)
- .option(ChannelOption.TCP_NODELAY, true) //无阻塞
- .option(ChannelOption.SO_KEEPALIVE, true) //长连接
- .option(
- ChannelOption.RCVBUF_ALLOCATOR,
- AdaptiveRecvByteBufAllocator(5000, 5000, 8000)
- ) //接收缓冲区 最小值太小时数据接收不全
- .handler(object : ChannelInitializer() {
- override fun initChannel(channel: SocketChannel) {
- val pipeline = channel.pipeline()
- //参数1:代表读套接字超时的时间,没收到数据会触发读超时回调;
- //参数2:代表写套接字超时时间,没进行写会触发写超时回调;
- //参数3:将在未执行读取或写入时触发超时回调,0代表不处理;
- //读超时尽量设置大于写超时,代表多次写超时时写心跳包,多次写了心跳数据仍然读超时代表当前连接错误,即可断开连接重新连接
- pipeline.addLast(IdleStateHandler(60, 10, 0))
- pipeline.addLast(ByteArrayDecoder())
- pipeline.addLast(ByteArrayEncoder())
- pipeline.addLast(SocketChannelHandle(listener))
- }
- })
- try {
- //连接监听
- channelFuture = bootstrap.connect(host, port)
- .addListener(object : ChannelFutureListener {
- override fun operationComplete(channelFuture: ChannelFuture) {
- if (channelFuture.isSuccess) {
- connectStatus = true
- channel = channelFuture.channel()
- } else {
- Log.e(kTag, "operationComplete: 连接失败")
- connectStatus = false
- }
- isConnecting = false
- }
- }).sync()
- // 等待连接关闭
- channelFuture.channel().closeFuture().sync()
- } catch (e: Exception) {
- e.printStackTrace()
- } finally {
- connectStatus = false
- listener?.onServiceStatusConnectChanged(ISocketListener.STATUS_CONNECT_CLOSED) //STATUS_CONNECT_CLOSED 这我自己定义的 接口标识
- if (null != channelFuture) {
- if (channelFuture.channel() != null && channelFuture.channel().isOpen) {
- channelFuture.channel().close()
- }
- }
- nioEventLoopGroup?.shutdownGracefully()
- reconnect() //重新连接
- }
- }
- }
- }
-
- //断开连接
- fun disconnect() {
- Log.d(kTag, "disconnect ===> 断开连接")
- isNeedReconnect = false
- nioEventLoopGroup?.shutdownGracefully()
- }
-
- //重新连接
- private fun reconnect() {
- if (isNeedReconnect && reconnectNum > 0 && !connectStatus) {
- reconnectNum--
- SystemClock.sleep(reconnectIntervalTime)
- if (isNeedReconnect && reconnectNum > 0 && !connectStatus) {
- Log.d(kTag, "reconnect ===> 重新连接")
- connectServer()
- }
- }
- }
-
- fun sendData(bytes: ByteArray) {
- channel?.writeAndFlush(bytes)?.addListener(ChannelFutureListener { future ->
- if (!future.isSuccess) {
- future.channel().close()
- nioEventLoopGroup!!.shutdownGracefully()
- }
- })
- }
-}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/br/ktd/netty/SocketManager.kt b/app/src/main/java/com/casic/br/ktd/netty/SocketManager.kt
deleted file mode 100644
index 17daf35..0000000
--- a/app/src/main/java/com/casic/br/ktd/netty/SocketManager.kt
+++ /dev/null
@@ -1,113 +0,0 @@
-package com.casic.br.ktd.netty
-
-import android.util.Log
-import com.casic.br.ktd.base.BaseApplication
-import com.casic.br.ktd.extensions.covertAngleValue
-import com.casic.br.ktd.extensions.covertDataValue
-import com.casic.br.ktd.extensions.toUnsignedByteArray
-import com.casic.br.ktd.model.SensorDataModel
-import com.casic.br.ktd.utils.LocaleConstant
-import com.pengxh.kt.lite.extensions.toJson
-import com.pengxh.kt.lite.utils.BroadcastManager
-
-class SocketManager private constructor() : ISocketListener {
-
- private val kTag = "SocketManager"
- private var nettyClient: SocketClient = SocketClient()
-
- companion object {
- val instance: SocketManager by lazy(mode = LazyThreadSafetyMode.SYNCHRONIZED) { SocketManager() }
- }
-
- fun connectNetty(hostname: String, port: Int) {
- Thread {
- if (!nettyClient.connectStatus) {
- nettyClient.setSocketListener(this)
- nettyClient.connect(hostname, port)
- } else {
- nettyClient.disconnect()
- }
- }.start()
- }
-
- override fun onMessageResponse(data: ByteArray?) {
-// Log.d(kTag, "onMessageResponse ===> " + Arrays.toString(data))
- /**
- * 0xFF,0x01,
- * 0x01,0x37,0xE6, 甲烷浓度值(数据码1* 65536 + 数据码2 * 256 + 数据码3)
- * 0x00, 激光甲烷模块工作状态(00表示设备正常,01表示温控故障,02表示设备激光未打开)
- * 0x00,0xB2,0x35, 激光强度值(数据码5* 65536 + 数据码6 * 256 + 数据码7)
- * 0x0A,0x3D, 云台水平角度([数据码8 * 256 + 数据码9]/100,单位为°,精确到0.01)
- * 0x05,0x6F, 云台垂直角度(首先计算Tangle=[数据码10 * 256 + 数据码11]/100,单位为°,精确到0.01。若Tangle在0~90范围内,则垂直角度值=Tangle;若Tangle在-1~-90范围内,则垂直角度值=Tangle-360)
- * 0xC1
- *
- * [-1, 1, 1, 55, -26, 0, 0, -78, 53, 10, 61, 5, 111, -63]
- * 甲烷浓度值为79638,计算为79638=0x01*65536+0x37*256+0xE6[0x01为数据码1,0x37为数据码2,0xE6为数据码3];
- * 激光甲烷设备状态值为0,表示状态正常,[0x00为数据码4];
- * 激光强度值为45621,计算为45621=0x00*65536+0xB2*256+0x35[0x00为数据码5,0xB2为数据码6,0x35为数据码7];
- *
- * =========================================================================================
- * 实际数据(1800-1950左右)
- * [-86, 1, 0, 7, 71, 0, 0, 62, -92, 57, 59, -118, -111, -64]
- * */
-
- if (data == null) {
- return
- }
- val bytes = data.toUnsignedByteArray()
- if (bytes.size == 14) {
- val dataModel = SensorDataModel(0, "激光未打开", 0, 0.0, 0.0)
-
- val methaneBytes = IntArray(3)
- System.arraycopy(bytes, 2, methaneBytes, 0, 3)
- dataModel.methane = methaneBytes.covertDataValue()
-
- dataModel.methaneState = when (bytes[5]) {
- 1 -> "温控故障"
- 2 -> "激光未打开"
- else -> "正常"
- }
-
- val laserBytes = IntArray(3)
- System.arraycopy(bytes, 6, laserBytes, 0, 3)
- dataModel.laser = laserBytes.covertDataValue()
-
- /**
- * 水平角度的实际范围为从水平零点开始,顺时针方向(从上往下看),0~360°
- * 垂直角度的实际范围为从垂直零点开始,以向上为正,-90°~90°,控制精度为0.01°
- * */
- val horizontalBytes = IntArray(2)
- System.arraycopy(bytes, 9, horizontalBytes, 0, 2)
- dataModel.horizontal = horizontalBytes.covertAngleValue()
-
- val verticalBytes = IntArray(2)
- System.arraycopy(bytes, 11, verticalBytes, 0, 2)
- dataModel.vertical = verticalBytes.covertAngleValue()
-
- //{"horizontal":26.21,"laser":45621,"methane":79846,"methaneState":"正常","vertical":13.91}
- BroadcastManager.obtainInstance(BaseApplication.get()).sendBroadcast(
- LocaleConstant.ACTION_UPDATE_DATA, dataModel.toJson()
- )
- }
- }
-
- override fun onServiceStatusConnectChanged(statusCode: Byte) {
- if (statusCode == ISocketListener.STATUS_CONNECT_SUCCESS) {
- if (nettyClient.connectStatus) {
- Log.d(kTag, "连接成功")
- }
- } else {
- if (!nettyClient.connectStatus) {
- Log.e(kTag, "onServiceStatusConnectChanged:$statusCode,连接断开,正在重连")
- }
- }
- }
-
- fun sendData(data: ByteArray) {
- nettyClient.sendData(data)
- }
-
- fun close() {
- nettyClient.disconnect()
- }
-}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/br/ktd/netty/tcp/ISocketListener.kt b/app/src/main/java/com/casic/br/ktd/netty/tcp/ISocketListener.kt
new file mode 100644
index 0000000..13c3084
--- /dev/null
+++ b/app/src/main/java/com/casic/br/ktd/netty/tcp/ISocketListener.kt
@@ -0,0 +1,19 @@
+package com.casic.br.ktd.netty.tcp
+
+interface ISocketListener {
+ companion object {
+ const val STATUS_CONNECT_SUCCESS: Byte = 1 //连接成功
+ const val STATUS_CONNECT_CLOSED: Byte = 0 //关闭连接
+ const val STATUS_CONNECT_ERROR: Byte = 0 //连接失败
+ }
+
+ /**
+ * 当接收到系统消息
+ */
+ fun onMessageResponse(data: ByteArray?)
+
+ /**
+ * 当连接状态发生变化时调用
+ */
+ fun onServiceStatusConnectChanged(statusCode: Byte)
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/br/ktd/netty/tcp/SocketChannelHandle.kt b/app/src/main/java/com/casic/br/ktd/netty/tcp/SocketChannelHandle.kt
new file mode 100644
index 0000000..8e2997f
--- /dev/null
+++ b/app/src/main/java/com/casic/br/ktd/netty/tcp/SocketChannelHandle.kt
@@ -0,0 +1,51 @@
+package com.casic.br.ktd.netty.tcp
+
+import android.util.Log
+import io.netty.channel.ChannelHandlerContext
+import io.netty.channel.SimpleChannelInboundHandler
+import io.netty.handler.timeout.IdleState
+import io.netty.handler.timeout.IdleStateEvent
+import java.nio.charset.StandardCharsets
+
+class SocketChannelHandle(private val listener: ISocketListener?) :
+ SimpleChannelInboundHandler() {
+
+ private val kTag = "SocketChannelHandle"
+
+ override fun channelActive(ctx: ChannelHandlerContext) {
+ super.channelActive(ctx)
+ Log.d(kTag, "channelActive ===> 连接成功")
+ listener?.onServiceStatusConnectChanged(ISocketListener.STATUS_CONNECT_SUCCESS)
+ }
+
+ override fun channelInactive(ctx: ChannelHandlerContext) {
+ super.channelInactive(ctx)
+ Log.e(kTag, "channelInactive: 连接断开")
+ }
+
+ override fun userEventTriggered(ctx: ChannelHandlerContext, evt: Any) {
+ super.userEventTriggered(ctx, evt)
+ if (evt is IdleStateEvent) {
+ if (evt.state() == IdleState.WRITER_IDLE) {
+ //写超时,此时可以发送心跳数据给服务器
+ val temp = "FF"
+ ctx.writeAndFlush(temp.toByteArray(StandardCharsets.UTF_8))
+ } else if (evt.state() == IdleState.READER_IDLE) {
+ //读超时,此时代表没有收到心跳返回可以关闭当前连接进行重连
+ ctx.close()
+ }
+ }
+ }
+
+ override fun channelRead0(ctx: ChannelHandlerContext, data: ByteArray?) {
+ listener?.onMessageResponse(data)
+ }
+
+ override fun exceptionCaught(ctx: ChannelHandlerContext, cause: Throwable) {
+ super.exceptionCaught(ctx, cause)
+ Log.d(kTag, "exceptionCaught ===> $cause")
+ listener?.onServiceStatusConnectChanged(ISocketListener.STATUS_CONNECT_ERROR)
+ cause.printStackTrace()
+ ctx.close()
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/br/ktd/netty/tcp/SocketClient.kt b/app/src/main/java/com/casic/br/ktd/netty/tcp/SocketClient.kt
new file mode 100644
index 0000000..34960a0
--- /dev/null
+++ b/app/src/main/java/com/casic/br/ktd/netty/tcp/SocketClient.kt
@@ -0,0 +1,153 @@
+package com.casic.br.ktd.netty.tcp
+
+import android.os.SystemClock
+import android.util.Log
+import io.netty.bootstrap.Bootstrap
+import io.netty.channel.*
+import io.netty.channel.nio.NioEventLoopGroup
+import io.netty.channel.socket.SocketChannel
+import io.netty.channel.socket.nio.NioSocketChannel
+import io.netty.handler.codec.bytes.ByteArrayDecoder
+import io.netty.handler.codec.bytes.ByteArrayEncoder
+import io.netty.handler.timeout.IdleStateHandler
+
+class SocketClient {
+
+ private val kTag = "SocketClient"
+
+ private var host: String? = null
+ private var port = 8000
+ private var nioEventLoopGroup: NioEventLoopGroup? = null
+ private var channel: Channel? = null
+ private var listener: ISocketListener? = null
+
+ //现在连接的状态
+ var connectStatus = false //判断是否已连接
+ private var reconnectNum = Int.MAX_VALUE //定义的重连到时候用
+ private var isNeedReconnect = true //是否需要重连
+ var isConnecting = false //是否正在连接
+ private set
+ private var reconnectIntervalTime: Long = 15000 //重连的时间
+
+ //重连时间
+ fun setReconnectNum(reconnectNum: Int) {
+ this.reconnectNum = reconnectNum
+ }
+
+ fun setReconnectIntervalTime(reconnectIntervalTime: Long) {
+ this.reconnectIntervalTime = reconnectIntervalTime
+ }
+
+ fun setSocketListener(listener: ISocketListener?) {
+ this.listener = listener
+ }
+
+ fun connect(host: String, port: Int) {
+ this.host = host
+ this.port = port
+ Log.d(kTag, "connect ===> 开始连接TCP服务器")
+ if (isConnecting) {
+ return
+ }
+ //起个线程
+ val clientThread: Thread = object : Thread("client-Netty") {
+ override fun run() {
+ super.run()
+ isNeedReconnect = true
+ reconnectNum = Int.MAX_VALUE
+ connectServer()
+ }
+ }
+ clientThread.start()
+ }
+
+ private fun connectServer() {
+ synchronized(this@SocketClient) {
+ var channelFuture: ChannelFuture? = null //连接管理对象
+ if (!connectStatus) {
+ isConnecting = true
+ nioEventLoopGroup = NioEventLoopGroup() //设置的连接group
+ val bootstrap = Bootstrap()
+ bootstrap.group(nioEventLoopGroup) //设置的一系列连接参数操作等
+ .channel(NioSocketChannel::class.java)
+ .option(ChannelOption.TCP_NODELAY, true) //无阻塞
+ .option(ChannelOption.SO_KEEPALIVE, true) //长连接
+ .option(
+ ChannelOption.RCVBUF_ALLOCATOR,
+ AdaptiveRecvByteBufAllocator(5000, 5000, 8000)
+ ) //接收缓冲区 最小值太小时数据接收不全
+ .handler(object : ChannelInitializer() {
+ override fun initChannel(channel: SocketChannel) {
+ val pipeline = channel.pipeline()
+ //参数1:代表读套接字超时的时间,没收到数据会触发读超时回调;
+ //参数2:代表写套接字超时时间,没进行写会触发写超时回调;
+ //参数3:将在未执行读取或写入时触发超时回调,0代表不处理;
+ //读超时尽量设置大于写超时,代表多次写超时时写心跳包,多次写了心跳数据仍然读超时代表当前连接错误,即可断开连接重新连接
+ pipeline.addLast(IdleStateHandler(60, 10, 0))
+ pipeline.addLast(ByteArrayDecoder())
+ pipeline.addLast(ByteArrayEncoder())
+ pipeline.addLast(SocketChannelHandle(listener))
+ }
+ })
+ try {
+ //连接监听
+ channelFuture = bootstrap.connect(host, port)
+ .addListener(object : ChannelFutureListener {
+ override fun operationComplete(channelFuture: ChannelFuture) {
+ if (channelFuture.isSuccess) {
+ connectStatus = true
+ channel = channelFuture.channel()
+ } else {
+ Log.e(kTag, "operationComplete: 连接失败")
+ connectStatus = false
+ }
+ isConnecting = false
+ }
+ }).sync()
+ // 等待连接关闭
+ channelFuture.channel().closeFuture().sync()
+ } catch (e: Exception) {
+ e.printStackTrace()
+ } finally {
+ connectStatus = false
+ listener?.onServiceStatusConnectChanged(ISocketListener.STATUS_CONNECT_CLOSED) //STATUS_CONNECT_CLOSED 这我自己定义的 接口标识
+ if (null != channelFuture) {
+ if (channelFuture.channel() != null && channelFuture.channel().isOpen) {
+ channelFuture.channel().close()
+ }
+ }
+ nioEventLoopGroup?.shutdownGracefully()
+ reconnect() //重新连接
+ }
+ }
+ }
+ }
+
+ //断开连接
+ fun disconnect() {
+ Log.d(kTag, "disconnect ===> 断开连接")
+ isNeedReconnect = false
+ nioEventLoopGroup?.shutdownGracefully()
+ }
+
+ //重新连接
+ private fun reconnect() {
+ if (isNeedReconnect && reconnectNum > 0 && !connectStatus) {
+ reconnectNum--
+ SystemClock.sleep(reconnectIntervalTime)
+ if (isNeedReconnect && reconnectNum > 0 && !connectStatus) {
+ Log.d(kTag, "reconnect ===> 重新连接")
+ connectServer()
+ }
+ }
+ }
+
+ fun sendData(bytes: ByteArray) {
+ channel?.writeAndFlush(bytes)?.addListener(ChannelFutureListener { future ->
+ if (!future.isSuccess) {
+ future.channel().close()
+ nioEventLoopGroup!!.shutdownGracefully()
+ }
+ })
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/br/ktd/netty/tcp/SocketManager.kt b/app/src/main/java/com/casic/br/ktd/netty/tcp/SocketManager.kt
new file mode 100644
index 0000000..35980b9
--- /dev/null
+++ b/app/src/main/java/com/casic/br/ktd/netty/tcp/SocketManager.kt
@@ -0,0 +1,113 @@
+package com.casic.br.ktd.netty.tcp
+
+import android.util.Log
+import com.casic.br.ktd.base.BaseApplication
+import com.casic.br.ktd.extensions.covertAngleValue
+import com.casic.br.ktd.extensions.covertDataValue
+import com.casic.br.ktd.extensions.toUnsignedByteArray
+import com.casic.br.ktd.model.SensorDataModel
+import com.casic.br.ktd.utils.LocaleConstant
+import com.pengxh.kt.lite.extensions.toJson
+import com.pengxh.kt.lite.utils.BroadcastManager
+
+class SocketManager private constructor() : ISocketListener {
+
+ private val kTag = "SocketManager"
+ private var nettyClient: SocketClient = SocketClient()
+
+ companion object {
+ val instance: SocketManager by lazy(mode = LazyThreadSafetyMode.SYNCHRONIZED) { SocketManager() }
+ }
+
+ fun connectNetty(hostname: String, port: Int) {
+ Thread {
+ if (!nettyClient.connectStatus) {
+ nettyClient.setSocketListener(this)
+ nettyClient.connect(hostname, port)
+ } else {
+ nettyClient.disconnect()
+ }
+ }.start()
+ }
+
+ override fun onMessageResponse(data: ByteArray?) {
+// Log.d(kTag, "onMessageResponse ===> " + Arrays.toString(data))
+ /**
+ * 0xFF,0x01,
+ * 0x01,0x37,0xE6, 甲烷浓度值(数据码1* 65536 + 数据码2 * 256 + 数据码3)
+ * 0x00, 激光甲烷模块工作状态(00表示设备正常,01表示温控故障,02表示设备激光未打开)
+ * 0x00,0xB2,0x35, 激光强度值(数据码5* 65536 + 数据码6 * 256 + 数据码7)
+ * 0x0A,0x3D, 云台水平角度([数据码8 * 256 + 数据码9]/100,单位为°,精确到0.01)
+ * 0x05,0x6F, 云台垂直角度(首先计算Tangle=[数据码10 * 256 + 数据码11]/100,单位为°,精确到0.01。若Tangle在0~90范围内,则垂直角度值=Tangle;若Tangle在-1~-90范围内,则垂直角度值=Tangle-360)
+ * 0xC1
+ *
+ * [-1, 1, 1, 55, -26, 0, 0, -78, 53, 10, 61, 5, 111, -63]
+ * 甲烷浓度值为79638,计算为79638=0x01*65536+0x37*256+0xE6[0x01为数据码1,0x37为数据码2,0xE6为数据码3];
+ * 激光甲烷设备状态值为0,表示状态正常,[0x00为数据码4];
+ * 激光强度值为45621,计算为45621=0x00*65536+0xB2*256+0x35[0x00为数据码5,0xB2为数据码6,0x35为数据码7];
+ *
+ * =========================================================================================
+ * 实际数据(1800-1950左右)
+ * [-86, 1, 0, 7, 71, 0, 0, 62, -92, 57, 59, -118, -111, -64]
+ * */
+
+ if (data == null) {
+ return
+ }
+ val bytes = data.toUnsignedByteArray()
+ if (bytes.size == 14) {
+ val dataModel = SensorDataModel(0, "激光未打开", 0, 0.0, 0.0)
+
+ val methaneBytes = IntArray(3)
+ System.arraycopy(bytes, 2, methaneBytes, 0, 3)
+ dataModel.methane = methaneBytes.covertDataValue()
+
+ dataModel.methaneState = when (bytes[5]) {
+ 1 -> "温控故障"
+ 2 -> "激光未打开"
+ else -> "正常"
+ }
+
+ val laserBytes = IntArray(3)
+ System.arraycopy(bytes, 6, laserBytes, 0, 3)
+ dataModel.laser = laserBytes.covertDataValue()
+
+ /**
+ * 水平角度的实际范围为从水平零点开始,顺时针方向(从上往下看),0~360°
+ * 垂直角度的实际范围为从垂直零点开始,以向上为正,-90°~90°,控制精度为0.01°
+ * */
+ val horizontalBytes = IntArray(2)
+ System.arraycopy(bytes, 9, horizontalBytes, 0, 2)
+ dataModel.horizontal = horizontalBytes.covertAngleValue()
+
+ val verticalBytes = IntArray(2)
+ System.arraycopy(bytes, 11, verticalBytes, 0, 2)
+ dataModel.vertical = verticalBytes.covertAngleValue()
+
+ //{"horizontal":26.21,"laser":45621,"methane":79846,"methaneState":"正常","vertical":13.91}
+ BroadcastManager.obtainInstance(BaseApplication.get()).sendBroadcast(
+ LocaleConstant.ACTION_UPDATE_DATA, dataModel.toJson()
+ )
+ }
+ }
+
+ override fun onServiceStatusConnectChanged(statusCode: Byte) {
+ if (statusCode == ISocketListener.STATUS_CONNECT_SUCCESS) {
+ if (nettyClient.connectStatus) {
+ Log.d(kTag, "连接成功")
+ }
+ } else {
+ if (!nettyClient.connectStatus) {
+ Log.e(kTag, "onServiceStatusConnectChanged:$statusCode,连接断开,正在重连")
+ }
+ }
+ }
+
+ fun sendData(data: ByteArray) {
+ nettyClient.sendData(data)
+ }
+
+ fun close() {
+ nettyClient.disconnect()
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/br/ktd/netty/udp/UdpChannelInboundHandler.kt b/app/src/main/java/com/casic/br/ktd/netty/udp/UdpChannelInboundHandler.kt
new file mode 100644
index 0000000..4d6f97c
--- /dev/null
+++ b/app/src/main/java/com/casic/br/ktd/netty/udp/UdpChannelInboundHandler.kt
@@ -0,0 +1,36 @@
+package com.casic.br.ktd.netty.udp
+
+import io.netty.channel.ChannelHandlerContext
+import io.netty.channel.SimpleChannelInboundHandler
+import io.netty.channel.socket.DatagramPacket
+import io.netty.util.CharsetUtil
+
+
+abstract class UdpChannelInboundHandler : SimpleChannelInboundHandler() {
+
+ private var handlerContext: ChannelHandlerContext? = null
+
+ override fun channelActive(ctx: ChannelHandlerContext?) {
+ super.channelActive(ctx)
+ handlerContext = ctx
+ }
+
+ override fun channelInactive(ctx: ChannelHandlerContext?) {
+ super.channelInactive(ctx)
+ handlerContext?.close()
+ }
+
+ fun sendDatagramPacket(obj: Any) {
+ handlerContext?.writeAndFlush(obj)
+ }
+
+ fun releasePort() {
+ handlerContext?.close()
+ }
+
+ override fun channelRead0(ctx: ChannelHandlerContext, datagramPacket: DatagramPacket) {
+ receivedMessage(datagramPacket.content().toString(CharsetUtil.UTF_8))
+ }
+
+ abstract fun receivedMessage(data: String)
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/br/ktd/netty/udp/UdpChannelInitializer.kt b/app/src/main/java/com/casic/br/ktd/netty/udp/UdpChannelInitializer.kt
new file mode 100644
index 0000000..416c5a1
--- /dev/null
+++ b/app/src/main/java/com/casic/br/ktd/netty/udp/UdpChannelInitializer.kt
@@ -0,0 +1,17 @@
+package com.casic.br.ktd.netty.udp
+
+import io.netty.channel.ChannelInitializer
+import io.netty.channel.socket.DatagramChannel
+import io.netty.handler.timeout.IdleStateHandler
+
+
+open class UdpChannelInitializer(private val handler: UdpChannelInboundHandler) :
+ ChannelInitializer() {
+
+ override fun initChannel(datagramChannel: DatagramChannel) {
+ val pipeline = datagramChannel.pipeline()
+ pipeline.addLast(
+ IdleStateHandler(12, 15, 0)
+ ).addLast(handler)
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/br/ktd/netty/udp/UdpClient.kt b/app/src/main/java/com/casic/br/ktd/netty/udp/UdpClient.kt
new file mode 100644
index 0000000..3893afa
--- /dev/null
+++ b/app/src/main/java/com/casic/br/ktd/netty/udp/UdpClient.kt
@@ -0,0 +1,103 @@
+package com.casic.br.ktd.netty.udp
+
+import com.casic.br.ktd.utils.LocaleConstant
+import com.pengxh.kt.lite.utils.SaveKeyValues
+import io.netty.bootstrap.Bootstrap
+import io.netty.buffer.ByteBuf
+import io.netty.buffer.Unpooled
+import io.netty.channel.ChannelOption
+import io.netty.channel.nio.NioEventLoopGroup
+import io.netty.channel.socket.DatagramPacket
+import io.netty.channel.socket.nio.NioDatagramChannel
+import io.netty.util.CharsetUtil
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.launch
+import kotlinx.coroutines.withContext
+import java.net.InetSocketAddress
+import java.util.concurrent.ExecutorService
+import java.util.concurrent.Executors
+
+
+class UdpClient : UdpChannelInboundHandler(), Runnable {
+
+ private val bootStrap by lazy { Bootstrap() }
+ private val eventLoopGroup by lazy { NioEventLoopGroup() }
+ private val udpChannelInitializer by lazy { UdpChannelInitializer(this) }
+ private var executorService: ExecutorService
+
+ init {
+ bootStrap.group(eventLoopGroup)
+ bootStrap.channel(NioDatagramChannel::class.java)
+ .option(ChannelOption.SO_RCVBUF, 1024)
+ .option(ChannelOption.SO_SNDBUF, 1024)
+ bootStrap.handler(udpChannelInitializer)
+
+ executorService = Executors.newSingleThreadExecutor()
+ executorService.execute(this)
+ }
+
+ override fun run() {
+ try {
+ val channelFuture = bootStrap.bind(LocaleConstant.LOCATION_UDP_PORT).sync()
+ channelFuture.channel().closeFuture().sync()
+ } catch (e: InterruptedException) {
+ e.printStackTrace()
+ } finally {
+ eventLoopGroup.shutdownGracefully()
+ }
+ }
+
+ fun send(value: String) {
+ CoroutineScope(Dispatchers.Main).launch {
+ withContext(Dispatchers.IO) {
+ val host = SaveKeyValues.getValue(
+ LocaleConstant.LOCATION_UDP_SERVER, "192.168.149.213"
+ ).toString()
+ val datagramPacket = DatagramPacket(
+ Unpooled.copiedBuffer(value, CharsetUtil.UTF_8),
+ InetSocketAddress(host, LocaleConstant.LOCATION_UDP_PORT)
+ )
+ sendDatagramPacket(datagramPacket)
+ }
+ }
+ }
+
+ fun send(value: ByteArray) {
+ CoroutineScope(Dispatchers.Main).launch {
+ withContext(Dispatchers.IO) {
+ val host = SaveKeyValues.getValue(
+ LocaleConstant.LOCATION_UDP_SERVER, "192.168.149.213"
+ ).toString()
+ val datagramPacket = DatagramPacket(
+ Unpooled.copiedBuffer(value),
+ InetSocketAddress(host, LocaleConstant.LOCATION_UDP_PORT)
+ )
+ sendDatagramPacket(datagramPacket)
+ }
+ }
+ }
+
+ fun send(value: ByteBuf) {
+ CoroutineScope(Dispatchers.Main).launch {
+ withContext(Dispatchers.IO) {
+ val host = SaveKeyValues.getValue(
+ LocaleConstant.LOCATION_UDP_SERVER, "192.168.149.213"
+ ).toString()
+ val datagramPacket = DatagramPacket(
+ Unpooled.copiedBuffer(value),
+ InetSocketAddress(host, LocaleConstant.LOCATION_UDP_PORT)
+ )
+ sendDatagramPacket(datagramPacket)
+ }
+ }
+ }
+
+ fun release() {
+ releasePort()
+ }
+
+ override fun receivedMessage(data: String) {
+
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/br/ktd/utils/LocaleConstant.kt b/app/src/main/java/com/casic/br/ktd/utils/LocaleConstant.kt
index 0dd119e..4c675df 100644
--- a/app/src/main/java/com/casic/br/ktd/utils/LocaleConstant.kt
+++ b/app/src/main/java/com/casic/br/ktd/utils/LocaleConstant.kt
@@ -50,6 +50,10 @@
const val DEV_NET_IP = "192.168.1.21"
const val DEV_NET_PORT = "8000"
+ //位置信息UDP端口
+ const val LOCATION_UDP_SERVER = "udpServer"
+ const val LOCATION_UDP_PORT = 7777
+
//BroadcastReceiver Action
const val ACTION_UPDATE_DATA = "update"
diff --git a/app/src/main/java/com/casic/br/ktd/utils/LocationHelper.kt b/app/src/main/java/com/casic/br/ktd/utils/LocationHelper.kt
index 8e31d3f..df6adb5 100644
--- a/app/src/main/java/com/casic/br/ktd/utils/LocationHelper.kt
+++ b/app/src/main/java/com/casic/br/ktd/utils/LocationHelper.kt
@@ -7,19 +7,40 @@
import android.location.LocationListener
import android.location.LocationManager
import android.os.Bundle
+import android.util.Log
import androidx.core.app.ActivityCompat
+import com.amap.api.location.AMapLocation
+import com.amap.api.location.AMapLocationClient
+import com.amap.api.location.AMapLocationClientOption
-object LocationHelper {
- fun obtainCurrentLocation(context: Context, listener: ILocationListener) {
+class LocationHelper private constructor() {
+
+ private val kTag = "LocationHelper"
+
+ companion object {
+ //Kotlin委托模式双重锁单例
+ val get: LocationHelper by lazy(mode = LazyThreadSafetyMode.SYNCHRONIZED) {
+ LocationHelper()
+ }
+ }
+
+ private val locationOption = AMapLocationClientOption()
+ private lateinit var locationClient: AMapLocationClient
+
+ init {
+ //设置定位模式为高精度模式,AMapLocationMode.Battery_Saving为低功耗模式,AMapLocationMode.Device_Sensors是仅设备模式
+ locationOption.locationMode = AMapLocationClientOption.AMapLocationMode.Hight_Accuracy
+ locationOption.isNeedAddress = true //设置是否返回地址信息(默认返回地址信息)
+ locationOption.isLocationCacheEnable = true //可选,设置是否使用缓存定位,默认为true
+ }
+
+ fun obtainLocation(context: Context, listener: ILocationListener) {
if (ActivityCompat.checkSelfPermission(
- context,
- Manifest.permission.ACCESS_LOCATION_EXTRA_COMMANDS
+ context, Manifest.permission.ACCESS_LOCATION_EXTRA_COMMANDS
) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(
- context,
- Manifest.permission.ACCESS_FINE_LOCATION
+ context, Manifest.permission.ACCESS_FINE_LOCATION
) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(
- context,
- Manifest.permission.ACCESS_COARSE_LOCATION
+ context, Manifest.permission.ACCESS_COARSE_LOCATION
) != PackageManager.PERMISSION_GRANTED
) {
return
@@ -38,7 +59,37 @@
})
}
+ /**
+ * 高德sdk定位
+ */
+ fun obtainLocationByGD(context: Context?, listener: ILocationListener) {
+ locationClient = AMapLocationClient(context)
+ //给定位客户端对象设置定位参数
+ locationClient.setLocationOption(locationOption)
+ //设置定位回调监听
+ locationClient.setLocationListener { aMapLocation ->
+ if (aMapLocation != null) {
+ if (aMapLocation.errorCode == 0) {
+ listener.onAMapLocationGet(aMapLocation)
+ } else {
+ Log.e(
+ kTag,
+ "ErrCode: ${aMapLocation.errorCode}, errInfo: ${aMapLocation.errorInfo}"
+ )
+ }
+ }
+ }
+ //启动定位
+ locationClient.startLocation()
+ }
+
+ fun stopLocation() {
+ locationClient.stopLocation()//停止定位
+ }
+
interface ILocationListener {
- fun onLocationGet(location: Location?) //高德定位数据
+ fun onLocationGet(location: Location?) //GPS定位数据
+
+ fun onAMapLocationGet(aMapLocation: AMapLocation?) //高德定位数据
}
}
\ No newline at end of file
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index e822df6..d72c1a5 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -7,6 +7,9 @@
+
+
+
@@ -46,5 +49,8 @@
+
+
+
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/br/ktd/base/KotlinBaseFragment.kt b/app/src/main/java/com/casic/br/ktd/base/KotlinBaseFragment.kt
new file mode 100644
index 0000000..2dac61c
--- /dev/null
+++ b/app/src/main/java/com/casic/br/ktd/base/KotlinBaseFragment.kt
@@ -0,0 +1,51 @@
+package com.casic.br.ktd.base
+
+import android.os.Bundle
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import androidx.annotation.LayoutRes
+import androidx.fragment.app.Fragment
+
+abstract class KotlinBaseFragment : Fragment() {
+
+ lateinit var bv: View
+
+ override fun onCreateView(
+ inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?
+ ): View? {
+ bv = inflater.inflate(initLayoutRes(), container, false)
+ initView(savedInstanceState)
+ setupTopBarLayout()
+ return bv
+ }
+
+ override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
+ super.onViewCreated(view, savedInstanceState)
+ observeRequestState()
+ initEvent()
+ }
+
+ @LayoutRes
+ abstract fun initLayoutRes(): Int
+
+ /**
+ * 沉浸式状态栏
+ */
+ abstract fun setupTopBarLayout()
+
+ /**
+ * 初始化布局以及控件
+ */
+ abstract fun initView(savedInstanceState: Bundle?)
+
+ /**
+ * 网络请求状态监听
+ */
+ abstract fun observeRequestState()
+
+ /**
+ * 业务逻辑,按钮等事件
+ */
+ abstract fun initEvent()
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/br/ktd/fragment/AlarmPageFragment.kt b/app/src/main/java/com/casic/br/ktd/fragment/AlarmPageFragment.kt
index 6c98a3b..9418169 100644
--- a/app/src/main/java/com/casic/br/ktd/fragment/AlarmPageFragment.kt
+++ b/app/src/main/java/com/casic/br/ktd/fragment/AlarmPageFragment.kt
@@ -2,28 +2,29 @@
import android.os.Bundle
import com.casic.br.ktd.R
+import com.casic.br.ktd.base.KotlinBaseFragment
import com.casic.br.ktd.widgets.DateRangeActionSheet
-import com.pengxh.kt.lite.base.KotlinBaseFragment
import kotlinx.android.synthetic.main.fragment_alarm.view.*
class AlarmPageFragment : KotlinBaseFragment() {
- override fun initData(savedInstanceState: Bundle?) {
+
+ override fun initView(savedInstanceState: Bundle?) {
}
override fun initEvent() {
- baseView.calendarView.setOnClickListener {
+ bv.calendarView.setOnClickListener {
DateRangeActionSheet.Builder().setContext(requireContext())
.setOnActionSheetListener(object :
DateRangeActionSheet.OnDateRangeSelectedListener {
override fun onDateRangeSelected(startDate: String, endDate: String) {
- baseView.selectedDateView.text = "$startDate ~ $endDate"
+ bv.selectedDateView.text = "$startDate ~ $endDate"
}
}).build().show()
}
}
- override fun initLayoutView(): Int = R.layout.fragment_alarm
+ override fun initLayoutRes(): Int = R.layout.fragment_alarm
override fun observeRequestState() {
diff --git a/app/src/main/java/com/casic/br/ktd/fragment/HomePageFragment.kt b/app/src/main/java/com/casic/br/ktd/fragment/HomePageFragment.kt
index 9961935..f3eba5c 100644
--- a/app/src/main/java/com/casic/br/ktd/fragment/HomePageFragment.kt
+++ b/app/src/main/java/com/casic/br/ktd/fragment/HomePageFragment.kt
@@ -1,32 +1,62 @@
package com.casic.br.ktd.fragment
+import android.graphics.Color
import android.os.Bundle
import com.amap.api.maps.AMap
import com.amap.api.maps.AMapOptions
+import com.amap.api.maps.CameraUpdateFactory
+import com.amap.api.maps.model.*
import com.casic.br.ktd.R
-import com.pengxh.kt.lite.base.KotlinBaseFragment
+import com.casic.br.ktd.base.KotlinBaseFragment
import kotlinx.android.synthetic.main.fragment_home.view.*
class HomePageFragment : KotlinBaseFragment() {
private lateinit var aMap: AMap
- override fun initData(savedInstanceState: Bundle?) {
- baseView.mapView.onCreate(savedInstanceState)
- aMap = baseView.mapView.map
+ override fun initView(savedInstanceState: Bundle?) {
+ bv.mapView.onCreate(savedInstanceState)
+ aMap = bv.mapView.map
val uiSettings = aMap.uiSettings
uiSettings.isCompassEnabled = true
- uiSettings.isMyLocationButtonEnabled = true
+ uiSettings.isMyLocationButtonEnabled = false
uiSettings.isScaleControlsEnabled = true
uiSettings.zoomPosition = AMapOptions.ZOOM_POSITION_RIGHT_CENTER
uiSettings.isRotateGesturesEnabled = false//不许地图随手势旋转角度
}
override fun initEvent() {
-
+ //移动到巡检起始经纬度
+ val cameraPosition = CameraPosition(LatLng(39.914199, 116.265785), 16f, 0f, 0f)
+ val cameraUpdate = CameraUpdateFactory.newCameraPosition(cameraPosition)
+ aMap.animateCamera(cameraUpdate, 1500, null)
+ //设置起点
+ addMarker(LatLng(39.914885, 116.272312), R.mipmap.start)
+ //设置终点
+ addMarker(LatLng(39.914716, 116.265097), R.mipmap.end)
+ //瞄点画线
+ val latLngPoints = ArrayList()
+ latLngPoints.add(LatLng(39.914885, 116.272312))
+ latLngPoints.add(LatLng(39.915148, 116.272312))
+ latLngPoints.add(LatLng(39.915399, 116.272302))
+ latLngPoints.add(LatLng(39.915436, 116.271787))
+ latLngPoints.add(LatLng(39.915477, 116.270886))
+ latLngPoints.add(LatLng(39.915477, 116.269968))
+ latLngPoints.add(LatLng(39.915469, 116.269544))
+ latLngPoints.add(LatLng(39.915481, 116.269196))
+ latLngPoints.add(LatLng(39.915452, 116.268472))
+ latLngPoints.add(LatLng(39.915444, 116.267722))
+ latLngPoints.add(LatLng(39.915415, 116.266755))
+ latLngPoints.add(LatLng(39.915403, 116.266165))
+ latLngPoints.add(LatLng(39.915395, 116.265703))
+ latLngPoints.add(LatLng(39.915366, 116.265119))
+ latLngPoints.add(LatLng(39.914716, 116.265097))
+ aMap.addPolyline(
+ PolylineOptions().addAll(latLngPoints).width(10.toFloat()).color(Color.RED)
+ )
}
- override fun initLayoutView(): Int = R.layout.fragment_home
+ override fun initLayoutRes(): Int = R.layout.fragment_home
override fun observeRequestState() {
@@ -36,25 +66,32 @@
}
+ private fun addMarker(point: LatLng, res: Int) {
+ val markerOption = MarkerOptions()
+ markerOption.position(point)
+ markerOption.icon(BitmapDescriptorFactory.fromResource(res))
+ aMap.addMarker(markerOption)
+ }
+
/***以下是地图生命周期管理************************************************************************/
override fun onResume() {
super.onResume()
- baseView.mapView.onResume()
+ bv.mapView.onResume()
}
override fun onPause() {
- baseView.mapView.onPause()
super.onPause()
+ bv.mapView.onPause()
}
override fun onSaveInstanceState(outState: Bundle) {
super.onSaveInstanceState(outState)
- baseView.mapView.onSaveInstanceState(outState)
+ bv.mapView.onSaveInstanceState(outState)
}
override fun onDestroy() {
- baseView.mapView.onDestroy()
super.onDestroy()
+ bv.mapView.onDestroy()
}
}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/br/ktd/fragment/MinePageFragment.kt b/app/src/main/java/com/casic/br/ktd/fragment/MinePageFragment.kt
index 90313ac..3212794 100644
--- a/app/src/main/java/com/casic/br/ktd/fragment/MinePageFragment.kt
+++ b/app/src/main/java/com/casic/br/ktd/fragment/MinePageFragment.kt
@@ -2,10 +2,11 @@
import android.os.Bundle
import com.casic.br.ktd.R
-import com.pengxh.kt.lite.base.KotlinBaseFragment
+import com.casic.br.ktd.base.KotlinBaseFragment
class MinePageFragment : KotlinBaseFragment() {
- override fun initData(savedInstanceState: Bundle?) {
+
+ override fun initView(savedInstanceState: Bundle?) {
}
@@ -13,7 +14,7 @@
}
- override fun initLayoutView(): Int = R.layout.fragment_mine
+ override fun initLayoutRes(): Int = R.layout.fragment_mine
override fun observeRequestState() {
diff --git a/app/src/main/java/com/casic/br/ktd/fragment/TaskPageFragment.kt b/app/src/main/java/com/casic/br/ktd/fragment/TaskPageFragment.kt
index 8f6abf0..6b82a54 100644
--- a/app/src/main/java/com/casic/br/ktd/fragment/TaskPageFragment.kt
+++ b/app/src/main/java/com/casic/br/ktd/fragment/TaskPageFragment.kt
@@ -8,6 +8,7 @@
import androidx.recyclerview.widget.RecyclerView
import com.casic.br.ktd.R
import com.casic.br.ktd.adapter.TaskAdapter
+import com.casic.br.ktd.base.KotlinBaseFragment
import com.casic.br.ktd.holder.SwipeViewHolder
import com.casic.br.ktd.model.TaskListModel
import com.casic.br.ktd.view.InspectionActivity
@@ -15,7 +16,6 @@
import com.casic.br.ktd.widgets.AlertControlDialog
import com.casic.br.ktd.widgets.AlertInputDialog
import com.casic.br.ktd.widgets.DateRangeActionSheet
-import com.pengxh.kt.lite.base.KotlinBaseFragment
import com.pengxh.kt.lite.extensions.navigatePageTo
import com.pengxh.kt.lite.extensions.show
import com.pengxh.kt.lite.utils.WeakReferenceHandler
@@ -36,7 +36,7 @@
private var startTime = ""
private var endTime = ""
- override fun initData(savedInstanceState: Bundle?) {
+ override fun initView(savedInstanceState: Bundle?) {
weakReferenceHandler = WeakReferenceHandler(this)
taskViewModel = ViewModelProvider(this)[TaskViewModel::class.java]
taskViewModel.taskList.observe(this) {
@@ -45,7 +45,7 @@
when {
isRefresh -> {
taskAdapter.setRefreshData(dataRows)
- baseView.taskLayout.finishRefresh()
+ bv.taskLayout.finishRefresh()
isRefresh = false
}
isLoadMore -> {
@@ -53,7 +53,7 @@
"到底了,别拉了".show(requireContext())
}
taskAdapter.setLoadMoreData(dataRows)
- baseView.taskLayout.finishLoadMore()
+ bv.taskLayout.finishLoadMore()
isLoadMore = false
}
else -> {
@@ -76,9 +76,9 @@
when (msg.what) {
2023070501 -> {
if (dataBeans.size == 0) {
- baseView.emptyLayout.visibility = View.VISIBLE
+ bv.emptyLayout.visibility = View.VISIBLE
} else {
- baseView.emptyLayout.visibility = View.GONE
+ bv.emptyLayout.visibility = View.GONE
taskAdapter = object : TaskAdapter(
requireContext(), R.layout.item_task_rv_l, dataBeans
) {
@@ -97,8 +97,8 @@
}
}
//绑定侧滑事件
- swipeAction.attachToRecyclerView(baseView.taskRecyclerView)
- baseView.taskRecyclerView.adapter = taskAdapter
+ swipeAction.attachToRecyclerView(bv.taskRecyclerView)
+ bv.taskRecyclerView.adapter = taskAdapter
taskAdapter.setOnItemCheckedListener(object :
TaskAdapter.OnItemCheckedListener {
override fun onItemChecked(items: ArrayList) {
@@ -168,7 +168,7 @@
override fun initEvent() {
- baseView.calendarView.setOnClickListener {
+ bv.calendarView.setOnClickListener {
DateRangeActionSheet.Builder().setContext(requireContext())
.setOnActionSheetListener(object :
DateRangeActionSheet.OnDateRangeSelectedListener {
@@ -177,12 +177,12 @@
endTime = endDate
//显示
- baseView.selectedDateView.text = "$startDate ~ $endDate"
+ bv.selectedDateView.text = "$startDate ~ $endDate"
}
}).build().show()
}
- baseView.addTaskButton.setOnClickListener {
+ bv.addTaskButton.setOnClickListener {
// AlertInputDialog.Builder()
// .setContext(requireContext())
// .setTitle("新建巡检任务")
@@ -200,11 +200,11 @@
requireContext().navigatePageTo()
}
- baseView.deleteTaskButton.setOnClickListener {
+ bv.deleteTaskButton.setOnClickListener {
selectedItems.size.toString().show(requireContext())
}
- baseView.taskSettingsButton.setOnClickListener {
+ bv.taskSettingsButton.setOnClickListener {
AlertInputDialog.Builder()
.setContext(requireContext())
.setTitle("设置阈值")
@@ -221,14 +221,14 @@
}).build().show()
}
- baseView.taskLayout.setOnRefreshListener {
+ bv.taskLayout.setOnRefreshListener {
isRefresh = true
//刷新之后页码重置
pageIndex = 1
getTaskList()
}
- baseView.taskLayout.setOnLoadMoreListener {
+ bv.taskLayout.setOnLoadMoreListener {
isLoadMore = true
pageIndex++
getTaskList()
@@ -239,13 +239,13 @@
taskViewModel.getTaskList(
startTime,
endTime,
- baseView.taskNameView.text.toString(),
- baseView.taskCodeView.text.toString(),
+ bv.taskNameView.text.toString(),
+ bv.taskCodeView.text.toString(),
pageIndex
)
}
- override fun initLayoutView(): Int = R.layout.fragment_task
+ override fun initLayoutRes(): Int = R.layout.fragment_task
override fun observeRequestState() {
diff --git a/app/src/main/java/com/casic/br/ktd/netty/ISocketListener.kt b/app/src/main/java/com/casic/br/ktd/netty/ISocketListener.kt
deleted file mode 100644
index dab98e1..0000000
--- a/app/src/main/java/com/casic/br/ktd/netty/ISocketListener.kt
+++ /dev/null
@@ -1,19 +0,0 @@
-package com.casic.br.ktd.netty
-
-interface ISocketListener {
- companion object {
- const val STATUS_CONNECT_SUCCESS: Byte = 1 //连接成功
- const val STATUS_CONNECT_CLOSED: Byte = 0 //关闭连接
- const val STATUS_CONNECT_ERROR: Byte = 0 //连接失败
- }
-
- /**
- * 当接收到系统消息
- */
- fun onMessageResponse(data: ByteArray?)
-
- /**
- * 当连接状态发生变化时调用
- */
- fun onServiceStatusConnectChanged(statusCode: Byte)
-}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/br/ktd/netty/SocketChannelHandle.kt b/app/src/main/java/com/casic/br/ktd/netty/SocketChannelHandle.kt
deleted file mode 100644
index 42eb310..0000000
--- a/app/src/main/java/com/casic/br/ktd/netty/SocketChannelHandle.kt
+++ /dev/null
@@ -1,51 +0,0 @@
-package com.casic.br.ktd.netty
-
-import android.util.Log
-import io.netty.channel.ChannelHandlerContext
-import io.netty.channel.SimpleChannelInboundHandler
-import io.netty.handler.timeout.IdleState
-import io.netty.handler.timeout.IdleStateEvent
-import java.nio.charset.StandardCharsets
-
-class SocketChannelHandle(private val listener: ISocketListener?) :
- SimpleChannelInboundHandler() {
-
- private val kTag = "SocketChannelHandle"
-
- override fun channelActive(ctx: ChannelHandlerContext) {
- super.channelActive(ctx)
- Log.d(kTag, "channelActive ===> 连接成功")
- listener?.onServiceStatusConnectChanged(ISocketListener.STATUS_CONNECT_SUCCESS)
- }
-
- override fun channelInactive(ctx: ChannelHandlerContext) {
- super.channelInactive(ctx)
- Log.e(kTag, "channelInactive: 连接断开")
- }
-
- override fun userEventTriggered(ctx: ChannelHandlerContext, evt: Any) {
- super.userEventTriggered(ctx, evt)
- if (evt is IdleStateEvent) {
- if (evt.state() == IdleState.WRITER_IDLE) {
- //写超时,此时可以发送心跳数据给服务器
- val temp = "FF"
- ctx.writeAndFlush(temp.toByteArray(StandardCharsets.UTF_8))
- } else if (evt.state() == IdleState.READER_IDLE) {
- //读超时,此时代表没有收到心跳返回可以关闭当前连接进行重连
- ctx.close()
- }
- }
- }
-
- override fun channelRead0(ctx: ChannelHandlerContext, data: ByteArray?) {
- listener?.onMessageResponse(data)
- }
-
- override fun exceptionCaught(ctx: ChannelHandlerContext, cause: Throwable) {
- super.exceptionCaught(ctx, cause)
- Log.d(kTag, "exceptionCaught ===> $cause")
- listener?.onServiceStatusConnectChanged(ISocketListener.STATUS_CONNECT_ERROR)
- cause.printStackTrace()
- ctx.close()
- }
-}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/br/ktd/netty/SocketClient.kt b/app/src/main/java/com/casic/br/ktd/netty/SocketClient.kt
deleted file mode 100644
index d05d335..0000000
--- a/app/src/main/java/com/casic/br/ktd/netty/SocketClient.kt
+++ /dev/null
@@ -1,153 +0,0 @@
-package com.casic.br.ktd.netty
-
-import android.os.SystemClock
-import android.util.Log
-import io.netty.bootstrap.Bootstrap
-import io.netty.channel.*
-import io.netty.channel.nio.NioEventLoopGroup
-import io.netty.channel.socket.SocketChannel
-import io.netty.channel.socket.nio.NioSocketChannel
-import io.netty.handler.codec.bytes.ByteArrayDecoder
-import io.netty.handler.codec.bytes.ByteArrayEncoder
-import io.netty.handler.timeout.IdleStateHandler
-
-class SocketClient {
-
- private val kTag = "SocketClient"
-
- private var host: String? = null
- private var port = 8000
- private var nioEventLoopGroup: NioEventLoopGroup? = null
- private var channel: Channel? = null
- private var listener: ISocketListener? = null
-
- //现在连接的状态
- var connectStatus = false //判断是否已连接
- private var reconnectNum = Int.MAX_VALUE //定义的重连到时候用
- private var isNeedReconnect = true //是否需要重连
- var isConnecting = false //是否正在连接
- private set
- private var reconnectIntervalTime: Long = 15000 //重连的时间
-
- //重连时间
- fun setReconnectNum(reconnectNum: Int) {
- this.reconnectNum = reconnectNum
- }
-
- fun setReconnectIntervalTime(reconnectIntervalTime: Long) {
- this.reconnectIntervalTime = reconnectIntervalTime
- }
-
- fun setSocketListener(listener: ISocketListener?) {
- this.listener = listener
- }
-
- fun connect(host: String, port: Int) {
- this.host = host
- this.port = port
- Log.d(kTag, "connect ===> 开始连接TCP服务器")
- if (isConnecting) {
- return
- }
- //起个线程
- val clientThread: Thread = object : Thread("client-Netty") {
- override fun run() {
- super.run()
- isNeedReconnect = true
- reconnectNum = Int.MAX_VALUE
- connectServer()
- }
- }
- clientThread.start()
- }
-
- private fun connectServer() {
- synchronized(this@SocketClient) {
- var channelFuture: ChannelFuture? = null //连接管理对象
- if (!connectStatus) {
- isConnecting = true
- nioEventLoopGroup = NioEventLoopGroup() //设置的连接group
- val bootstrap = Bootstrap()
- bootstrap.group(nioEventLoopGroup) //设置的一系列连接参数操作等
- .channel(NioSocketChannel::class.java)
- .option(ChannelOption.TCP_NODELAY, true) //无阻塞
- .option(ChannelOption.SO_KEEPALIVE, true) //长连接
- .option(
- ChannelOption.RCVBUF_ALLOCATOR,
- AdaptiveRecvByteBufAllocator(5000, 5000, 8000)
- ) //接收缓冲区 最小值太小时数据接收不全
- .handler(object : ChannelInitializer() {
- override fun initChannel(channel: SocketChannel) {
- val pipeline = channel.pipeline()
- //参数1:代表读套接字超时的时间,没收到数据会触发读超时回调;
- //参数2:代表写套接字超时时间,没进行写会触发写超时回调;
- //参数3:将在未执行读取或写入时触发超时回调,0代表不处理;
- //读超时尽量设置大于写超时,代表多次写超时时写心跳包,多次写了心跳数据仍然读超时代表当前连接错误,即可断开连接重新连接
- pipeline.addLast(IdleStateHandler(60, 10, 0))
- pipeline.addLast(ByteArrayDecoder())
- pipeline.addLast(ByteArrayEncoder())
- pipeline.addLast(SocketChannelHandle(listener))
- }
- })
- try {
- //连接监听
- channelFuture = bootstrap.connect(host, port)
- .addListener(object : ChannelFutureListener {
- override fun operationComplete(channelFuture: ChannelFuture) {
- if (channelFuture.isSuccess) {
- connectStatus = true
- channel = channelFuture.channel()
- } else {
- Log.e(kTag, "operationComplete: 连接失败")
- connectStatus = false
- }
- isConnecting = false
- }
- }).sync()
- // 等待连接关闭
- channelFuture.channel().closeFuture().sync()
- } catch (e: Exception) {
- e.printStackTrace()
- } finally {
- connectStatus = false
- listener?.onServiceStatusConnectChanged(ISocketListener.STATUS_CONNECT_CLOSED) //STATUS_CONNECT_CLOSED 这我自己定义的 接口标识
- if (null != channelFuture) {
- if (channelFuture.channel() != null && channelFuture.channel().isOpen) {
- channelFuture.channel().close()
- }
- }
- nioEventLoopGroup?.shutdownGracefully()
- reconnect() //重新连接
- }
- }
- }
- }
-
- //断开连接
- fun disconnect() {
- Log.d(kTag, "disconnect ===> 断开连接")
- isNeedReconnect = false
- nioEventLoopGroup?.shutdownGracefully()
- }
-
- //重新连接
- private fun reconnect() {
- if (isNeedReconnect && reconnectNum > 0 && !connectStatus) {
- reconnectNum--
- SystemClock.sleep(reconnectIntervalTime)
- if (isNeedReconnect && reconnectNum > 0 && !connectStatus) {
- Log.d(kTag, "reconnect ===> 重新连接")
- connectServer()
- }
- }
- }
-
- fun sendData(bytes: ByteArray) {
- channel?.writeAndFlush(bytes)?.addListener(ChannelFutureListener { future ->
- if (!future.isSuccess) {
- future.channel().close()
- nioEventLoopGroup!!.shutdownGracefully()
- }
- })
- }
-}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/br/ktd/netty/SocketManager.kt b/app/src/main/java/com/casic/br/ktd/netty/SocketManager.kt
deleted file mode 100644
index 17daf35..0000000
--- a/app/src/main/java/com/casic/br/ktd/netty/SocketManager.kt
+++ /dev/null
@@ -1,113 +0,0 @@
-package com.casic.br.ktd.netty
-
-import android.util.Log
-import com.casic.br.ktd.base.BaseApplication
-import com.casic.br.ktd.extensions.covertAngleValue
-import com.casic.br.ktd.extensions.covertDataValue
-import com.casic.br.ktd.extensions.toUnsignedByteArray
-import com.casic.br.ktd.model.SensorDataModel
-import com.casic.br.ktd.utils.LocaleConstant
-import com.pengxh.kt.lite.extensions.toJson
-import com.pengxh.kt.lite.utils.BroadcastManager
-
-class SocketManager private constructor() : ISocketListener {
-
- private val kTag = "SocketManager"
- private var nettyClient: SocketClient = SocketClient()
-
- companion object {
- val instance: SocketManager by lazy(mode = LazyThreadSafetyMode.SYNCHRONIZED) { SocketManager() }
- }
-
- fun connectNetty(hostname: String, port: Int) {
- Thread {
- if (!nettyClient.connectStatus) {
- nettyClient.setSocketListener(this)
- nettyClient.connect(hostname, port)
- } else {
- nettyClient.disconnect()
- }
- }.start()
- }
-
- override fun onMessageResponse(data: ByteArray?) {
-// Log.d(kTag, "onMessageResponse ===> " + Arrays.toString(data))
- /**
- * 0xFF,0x01,
- * 0x01,0x37,0xE6, 甲烷浓度值(数据码1* 65536 + 数据码2 * 256 + 数据码3)
- * 0x00, 激光甲烷模块工作状态(00表示设备正常,01表示温控故障,02表示设备激光未打开)
- * 0x00,0xB2,0x35, 激光强度值(数据码5* 65536 + 数据码6 * 256 + 数据码7)
- * 0x0A,0x3D, 云台水平角度([数据码8 * 256 + 数据码9]/100,单位为°,精确到0.01)
- * 0x05,0x6F, 云台垂直角度(首先计算Tangle=[数据码10 * 256 + 数据码11]/100,单位为°,精确到0.01。若Tangle在0~90范围内,则垂直角度值=Tangle;若Tangle在-1~-90范围内,则垂直角度值=Tangle-360)
- * 0xC1
- *
- * [-1, 1, 1, 55, -26, 0, 0, -78, 53, 10, 61, 5, 111, -63]
- * 甲烷浓度值为79638,计算为79638=0x01*65536+0x37*256+0xE6[0x01为数据码1,0x37为数据码2,0xE6为数据码3];
- * 激光甲烷设备状态值为0,表示状态正常,[0x00为数据码4];
- * 激光强度值为45621,计算为45621=0x00*65536+0xB2*256+0x35[0x00为数据码5,0xB2为数据码6,0x35为数据码7];
- *
- * =========================================================================================
- * 实际数据(1800-1950左右)
- * [-86, 1, 0, 7, 71, 0, 0, 62, -92, 57, 59, -118, -111, -64]
- * */
-
- if (data == null) {
- return
- }
- val bytes = data.toUnsignedByteArray()
- if (bytes.size == 14) {
- val dataModel = SensorDataModel(0, "激光未打开", 0, 0.0, 0.0)
-
- val methaneBytes = IntArray(3)
- System.arraycopy(bytes, 2, methaneBytes, 0, 3)
- dataModel.methane = methaneBytes.covertDataValue()
-
- dataModel.methaneState = when (bytes[5]) {
- 1 -> "温控故障"
- 2 -> "激光未打开"
- else -> "正常"
- }
-
- val laserBytes = IntArray(3)
- System.arraycopy(bytes, 6, laserBytes, 0, 3)
- dataModel.laser = laserBytes.covertDataValue()
-
- /**
- * 水平角度的实际范围为从水平零点开始,顺时针方向(从上往下看),0~360°
- * 垂直角度的实际范围为从垂直零点开始,以向上为正,-90°~90°,控制精度为0.01°
- * */
- val horizontalBytes = IntArray(2)
- System.arraycopy(bytes, 9, horizontalBytes, 0, 2)
- dataModel.horizontal = horizontalBytes.covertAngleValue()
-
- val verticalBytes = IntArray(2)
- System.arraycopy(bytes, 11, verticalBytes, 0, 2)
- dataModel.vertical = verticalBytes.covertAngleValue()
-
- //{"horizontal":26.21,"laser":45621,"methane":79846,"methaneState":"正常","vertical":13.91}
- BroadcastManager.obtainInstance(BaseApplication.get()).sendBroadcast(
- LocaleConstant.ACTION_UPDATE_DATA, dataModel.toJson()
- )
- }
- }
-
- override fun onServiceStatusConnectChanged(statusCode: Byte) {
- if (statusCode == ISocketListener.STATUS_CONNECT_SUCCESS) {
- if (nettyClient.connectStatus) {
- Log.d(kTag, "连接成功")
- }
- } else {
- if (!nettyClient.connectStatus) {
- Log.e(kTag, "onServiceStatusConnectChanged:$statusCode,连接断开,正在重连")
- }
- }
- }
-
- fun sendData(data: ByteArray) {
- nettyClient.sendData(data)
- }
-
- fun close() {
- nettyClient.disconnect()
- }
-}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/br/ktd/netty/tcp/ISocketListener.kt b/app/src/main/java/com/casic/br/ktd/netty/tcp/ISocketListener.kt
new file mode 100644
index 0000000..13c3084
--- /dev/null
+++ b/app/src/main/java/com/casic/br/ktd/netty/tcp/ISocketListener.kt
@@ -0,0 +1,19 @@
+package com.casic.br.ktd.netty.tcp
+
+interface ISocketListener {
+ companion object {
+ const val STATUS_CONNECT_SUCCESS: Byte = 1 //连接成功
+ const val STATUS_CONNECT_CLOSED: Byte = 0 //关闭连接
+ const val STATUS_CONNECT_ERROR: Byte = 0 //连接失败
+ }
+
+ /**
+ * 当接收到系统消息
+ */
+ fun onMessageResponse(data: ByteArray?)
+
+ /**
+ * 当连接状态发生变化时调用
+ */
+ fun onServiceStatusConnectChanged(statusCode: Byte)
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/br/ktd/netty/tcp/SocketChannelHandle.kt b/app/src/main/java/com/casic/br/ktd/netty/tcp/SocketChannelHandle.kt
new file mode 100644
index 0000000..8e2997f
--- /dev/null
+++ b/app/src/main/java/com/casic/br/ktd/netty/tcp/SocketChannelHandle.kt
@@ -0,0 +1,51 @@
+package com.casic.br.ktd.netty.tcp
+
+import android.util.Log
+import io.netty.channel.ChannelHandlerContext
+import io.netty.channel.SimpleChannelInboundHandler
+import io.netty.handler.timeout.IdleState
+import io.netty.handler.timeout.IdleStateEvent
+import java.nio.charset.StandardCharsets
+
+class SocketChannelHandle(private val listener: ISocketListener?) :
+ SimpleChannelInboundHandler() {
+
+ private val kTag = "SocketChannelHandle"
+
+ override fun channelActive(ctx: ChannelHandlerContext) {
+ super.channelActive(ctx)
+ Log.d(kTag, "channelActive ===> 连接成功")
+ listener?.onServiceStatusConnectChanged(ISocketListener.STATUS_CONNECT_SUCCESS)
+ }
+
+ override fun channelInactive(ctx: ChannelHandlerContext) {
+ super.channelInactive(ctx)
+ Log.e(kTag, "channelInactive: 连接断开")
+ }
+
+ override fun userEventTriggered(ctx: ChannelHandlerContext, evt: Any) {
+ super.userEventTriggered(ctx, evt)
+ if (evt is IdleStateEvent) {
+ if (evt.state() == IdleState.WRITER_IDLE) {
+ //写超时,此时可以发送心跳数据给服务器
+ val temp = "FF"
+ ctx.writeAndFlush(temp.toByteArray(StandardCharsets.UTF_8))
+ } else if (evt.state() == IdleState.READER_IDLE) {
+ //读超时,此时代表没有收到心跳返回可以关闭当前连接进行重连
+ ctx.close()
+ }
+ }
+ }
+
+ override fun channelRead0(ctx: ChannelHandlerContext, data: ByteArray?) {
+ listener?.onMessageResponse(data)
+ }
+
+ override fun exceptionCaught(ctx: ChannelHandlerContext, cause: Throwable) {
+ super.exceptionCaught(ctx, cause)
+ Log.d(kTag, "exceptionCaught ===> $cause")
+ listener?.onServiceStatusConnectChanged(ISocketListener.STATUS_CONNECT_ERROR)
+ cause.printStackTrace()
+ ctx.close()
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/br/ktd/netty/tcp/SocketClient.kt b/app/src/main/java/com/casic/br/ktd/netty/tcp/SocketClient.kt
new file mode 100644
index 0000000..34960a0
--- /dev/null
+++ b/app/src/main/java/com/casic/br/ktd/netty/tcp/SocketClient.kt
@@ -0,0 +1,153 @@
+package com.casic.br.ktd.netty.tcp
+
+import android.os.SystemClock
+import android.util.Log
+import io.netty.bootstrap.Bootstrap
+import io.netty.channel.*
+import io.netty.channel.nio.NioEventLoopGroup
+import io.netty.channel.socket.SocketChannel
+import io.netty.channel.socket.nio.NioSocketChannel
+import io.netty.handler.codec.bytes.ByteArrayDecoder
+import io.netty.handler.codec.bytes.ByteArrayEncoder
+import io.netty.handler.timeout.IdleStateHandler
+
+class SocketClient {
+
+ private val kTag = "SocketClient"
+
+ private var host: String? = null
+ private var port = 8000
+ private var nioEventLoopGroup: NioEventLoopGroup? = null
+ private var channel: Channel? = null
+ private var listener: ISocketListener? = null
+
+ //现在连接的状态
+ var connectStatus = false //判断是否已连接
+ private var reconnectNum = Int.MAX_VALUE //定义的重连到时候用
+ private var isNeedReconnect = true //是否需要重连
+ var isConnecting = false //是否正在连接
+ private set
+ private var reconnectIntervalTime: Long = 15000 //重连的时间
+
+ //重连时间
+ fun setReconnectNum(reconnectNum: Int) {
+ this.reconnectNum = reconnectNum
+ }
+
+ fun setReconnectIntervalTime(reconnectIntervalTime: Long) {
+ this.reconnectIntervalTime = reconnectIntervalTime
+ }
+
+ fun setSocketListener(listener: ISocketListener?) {
+ this.listener = listener
+ }
+
+ fun connect(host: String, port: Int) {
+ this.host = host
+ this.port = port
+ Log.d(kTag, "connect ===> 开始连接TCP服务器")
+ if (isConnecting) {
+ return
+ }
+ //起个线程
+ val clientThread: Thread = object : Thread("client-Netty") {
+ override fun run() {
+ super.run()
+ isNeedReconnect = true
+ reconnectNum = Int.MAX_VALUE
+ connectServer()
+ }
+ }
+ clientThread.start()
+ }
+
+ private fun connectServer() {
+ synchronized(this@SocketClient) {
+ var channelFuture: ChannelFuture? = null //连接管理对象
+ if (!connectStatus) {
+ isConnecting = true
+ nioEventLoopGroup = NioEventLoopGroup() //设置的连接group
+ val bootstrap = Bootstrap()
+ bootstrap.group(nioEventLoopGroup) //设置的一系列连接参数操作等
+ .channel(NioSocketChannel::class.java)
+ .option(ChannelOption.TCP_NODELAY, true) //无阻塞
+ .option(ChannelOption.SO_KEEPALIVE, true) //长连接
+ .option(
+ ChannelOption.RCVBUF_ALLOCATOR,
+ AdaptiveRecvByteBufAllocator(5000, 5000, 8000)
+ ) //接收缓冲区 最小值太小时数据接收不全
+ .handler(object : ChannelInitializer() {
+ override fun initChannel(channel: SocketChannel) {
+ val pipeline = channel.pipeline()
+ //参数1:代表读套接字超时的时间,没收到数据会触发读超时回调;
+ //参数2:代表写套接字超时时间,没进行写会触发写超时回调;
+ //参数3:将在未执行读取或写入时触发超时回调,0代表不处理;
+ //读超时尽量设置大于写超时,代表多次写超时时写心跳包,多次写了心跳数据仍然读超时代表当前连接错误,即可断开连接重新连接
+ pipeline.addLast(IdleStateHandler(60, 10, 0))
+ pipeline.addLast(ByteArrayDecoder())
+ pipeline.addLast(ByteArrayEncoder())
+ pipeline.addLast(SocketChannelHandle(listener))
+ }
+ })
+ try {
+ //连接监听
+ channelFuture = bootstrap.connect(host, port)
+ .addListener(object : ChannelFutureListener {
+ override fun operationComplete(channelFuture: ChannelFuture) {
+ if (channelFuture.isSuccess) {
+ connectStatus = true
+ channel = channelFuture.channel()
+ } else {
+ Log.e(kTag, "operationComplete: 连接失败")
+ connectStatus = false
+ }
+ isConnecting = false
+ }
+ }).sync()
+ // 等待连接关闭
+ channelFuture.channel().closeFuture().sync()
+ } catch (e: Exception) {
+ e.printStackTrace()
+ } finally {
+ connectStatus = false
+ listener?.onServiceStatusConnectChanged(ISocketListener.STATUS_CONNECT_CLOSED) //STATUS_CONNECT_CLOSED 这我自己定义的 接口标识
+ if (null != channelFuture) {
+ if (channelFuture.channel() != null && channelFuture.channel().isOpen) {
+ channelFuture.channel().close()
+ }
+ }
+ nioEventLoopGroup?.shutdownGracefully()
+ reconnect() //重新连接
+ }
+ }
+ }
+ }
+
+ //断开连接
+ fun disconnect() {
+ Log.d(kTag, "disconnect ===> 断开连接")
+ isNeedReconnect = false
+ nioEventLoopGroup?.shutdownGracefully()
+ }
+
+ //重新连接
+ private fun reconnect() {
+ if (isNeedReconnect && reconnectNum > 0 && !connectStatus) {
+ reconnectNum--
+ SystemClock.sleep(reconnectIntervalTime)
+ if (isNeedReconnect && reconnectNum > 0 && !connectStatus) {
+ Log.d(kTag, "reconnect ===> 重新连接")
+ connectServer()
+ }
+ }
+ }
+
+ fun sendData(bytes: ByteArray) {
+ channel?.writeAndFlush(bytes)?.addListener(ChannelFutureListener { future ->
+ if (!future.isSuccess) {
+ future.channel().close()
+ nioEventLoopGroup!!.shutdownGracefully()
+ }
+ })
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/br/ktd/netty/tcp/SocketManager.kt b/app/src/main/java/com/casic/br/ktd/netty/tcp/SocketManager.kt
new file mode 100644
index 0000000..35980b9
--- /dev/null
+++ b/app/src/main/java/com/casic/br/ktd/netty/tcp/SocketManager.kt
@@ -0,0 +1,113 @@
+package com.casic.br.ktd.netty.tcp
+
+import android.util.Log
+import com.casic.br.ktd.base.BaseApplication
+import com.casic.br.ktd.extensions.covertAngleValue
+import com.casic.br.ktd.extensions.covertDataValue
+import com.casic.br.ktd.extensions.toUnsignedByteArray
+import com.casic.br.ktd.model.SensorDataModel
+import com.casic.br.ktd.utils.LocaleConstant
+import com.pengxh.kt.lite.extensions.toJson
+import com.pengxh.kt.lite.utils.BroadcastManager
+
+class SocketManager private constructor() : ISocketListener {
+
+ private val kTag = "SocketManager"
+ private var nettyClient: SocketClient = SocketClient()
+
+ companion object {
+ val instance: SocketManager by lazy(mode = LazyThreadSafetyMode.SYNCHRONIZED) { SocketManager() }
+ }
+
+ fun connectNetty(hostname: String, port: Int) {
+ Thread {
+ if (!nettyClient.connectStatus) {
+ nettyClient.setSocketListener(this)
+ nettyClient.connect(hostname, port)
+ } else {
+ nettyClient.disconnect()
+ }
+ }.start()
+ }
+
+ override fun onMessageResponse(data: ByteArray?) {
+// Log.d(kTag, "onMessageResponse ===> " + Arrays.toString(data))
+ /**
+ * 0xFF,0x01,
+ * 0x01,0x37,0xE6, 甲烷浓度值(数据码1* 65536 + 数据码2 * 256 + 数据码3)
+ * 0x00, 激光甲烷模块工作状态(00表示设备正常,01表示温控故障,02表示设备激光未打开)
+ * 0x00,0xB2,0x35, 激光强度值(数据码5* 65536 + 数据码6 * 256 + 数据码7)
+ * 0x0A,0x3D, 云台水平角度([数据码8 * 256 + 数据码9]/100,单位为°,精确到0.01)
+ * 0x05,0x6F, 云台垂直角度(首先计算Tangle=[数据码10 * 256 + 数据码11]/100,单位为°,精确到0.01。若Tangle在0~90范围内,则垂直角度值=Tangle;若Tangle在-1~-90范围内,则垂直角度值=Tangle-360)
+ * 0xC1
+ *
+ * [-1, 1, 1, 55, -26, 0, 0, -78, 53, 10, 61, 5, 111, -63]
+ * 甲烷浓度值为79638,计算为79638=0x01*65536+0x37*256+0xE6[0x01为数据码1,0x37为数据码2,0xE6为数据码3];
+ * 激光甲烷设备状态值为0,表示状态正常,[0x00为数据码4];
+ * 激光强度值为45621,计算为45621=0x00*65536+0xB2*256+0x35[0x00为数据码5,0xB2为数据码6,0x35为数据码7];
+ *
+ * =========================================================================================
+ * 实际数据(1800-1950左右)
+ * [-86, 1, 0, 7, 71, 0, 0, 62, -92, 57, 59, -118, -111, -64]
+ * */
+
+ if (data == null) {
+ return
+ }
+ val bytes = data.toUnsignedByteArray()
+ if (bytes.size == 14) {
+ val dataModel = SensorDataModel(0, "激光未打开", 0, 0.0, 0.0)
+
+ val methaneBytes = IntArray(3)
+ System.arraycopy(bytes, 2, methaneBytes, 0, 3)
+ dataModel.methane = methaneBytes.covertDataValue()
+
+ dataModel.methaneState = when (bytes[5]) {
+ 1 -> "温控故障"
+ 2 -> "激光未打开"
+ else -> "正常"
+ }
+
+ val laserBytes = IntArray(3)
+ System.arraycopy(bytes, 6, laserBytes, 0, 3)
+ dataModel.laser = laserBytes.covertDataValue()
+
+ /**
+ * 水平角度的实际范围为从水平零点开始,顺时针方向(从上往下看),0~360°
+ * 垂直角度的实际范围为从垂直零点开始,以向上为正,-90°~90°,控制精度为0.01°
+ * */
+ val horizontalBytes = IntArray(2)
+ System.arraycopy(bytes, 9, horizontalBytes, 0, 2)
+ dataModel.horizontal = horizontalBytes.covertAngleValue()
+
+ val verticalBytes = IntArray(2)
+ System.arraycopy(bytes, 11, verticalBytes, 0, 2)
+ dataModel.vertical = verticalBytes.covertAngleValue()
+
+ //{"horizontal":26.21,"laser":45621,"methane":79846,"methaneState":"正常","vertical":13.91}
+ BroadcastManager.obtainInstance(BaseApplication.get()).sendBroadcast(
+ LocaleConstant.ACTION_UPDATE_DATA, dataModel.toJson()
+ )
+ }
+ }
+
+ override fun onServiceStatusConnectChanged(statusCode: Byte) {
+ if (statusCode == ISocketListener.STATUS_CONNECT_SUCCESS) {
+ if (nettyClient.connectStatus) {
+ Log.d(kTag, "连接成功")
+ }
+ } else {
+ if (!nettyClient.connectStatus) {
+ Log.e(kTag, "onServiceStatusConnectChanged:$statusCode,连接断开,正在重连")
+ }
+ }
+ }
+
+ fun sendData(data: ByteArray) {
+ nettyClient.sendData(data)
+ }
+
+ fun close() {
+ nettyClient.disconnect()
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/br/ktd/netty/udp/UdpChannelInboundHandler.kt b/app/src/main/java/com/casic/br/ktd/netty/udp/UdpChannelInboundHandler.kt
new file mode 100644
index 0000000..4d6f97c
--- /dev/null
+++ b/app/src/main/java/com/casic/br/ktd/netty/udp/UdpChannelInboundHandler.kt
@@ -0,0 +1,36 @@
+package com.casic.br.ktd.netty.udp
+
+import io.netty.channel.ChannelHandlerContext
+import io.netty.channel.SimpleChannelInboundHandler
+import io.netty.channel.socket.DatagramPacket
+import io.netty.util.CharsetUtil
+
+
+abstract class UdpChannelInboundHandler : SimpleChannelInboundHandler() {
+
+ private var handlerContext: ChannelHandlerContext? = null
+
+ override fun channelActive(ctx: ChannelHandlerContext?) {
+ super.channelActive(ctx)
+ handlerContext = ctx
+ }
+
+ override fun channelInactive(ctx: ChannelHandlerContext?) {
+ super.channelInactive(ctx)
+ handlerContext?.close()
+ }
+
+ fun sendDatagramPacket(obj: Any) {
+ handlerContext?.writeAndFlush(obj)
+ }
+
+ fun releasePort() {
+ handlerContext?.close()
+ }
+
+ override fun channelRead0(ctx: ChannelHandlerContext, datagramPacket: DatagramPacket) {
+ receivedMessage(datagramPacket.content().toString(CharsetUtil.UTF_8))
+ }
+
+ abstract fun receivedMessage(data: String)
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/br/ktd/netty/udp/UdpChannelInitializer.kt b/app/src/main/java/com/casic/br/ktd/netty/udp/UdpChannelInitializer.kt
new file mode 100644
index 0000000..416c5a1
--- /dev/null
+++ b/app/src/main/java/com/casic/br/ktd/netty/udp/UdpChannelInitializer.kt
@@ -0,0 +1,17 @@
+package com.casic.br.ktd.netty.udp
+
+import io.netty.channel.ChannelInitializer
+import io.netty.channel.socket.DatagramChannel
+import io.netty.handler.timeout.IdleStateHandler
+
+
+open class UdpChannelInitializer(private val handler: UdpChannelInboundHandler) :
+ ChannelInitializer() {
+
+ override fun initChannel(datagramChannel: DatagramChannel) {
+ val pipeline = datagramChannel.pipeline()
+ pipeline.addLast(
+ IdleStateHandler(12, 15, 0)
+ ).addLast(handler)
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/br/ktd/netty/udp/UdpClient.kt b/app/src/main/java/com/casic/br/ktd/netty/udp/UdpClient.kt
new file mode 100644
index 0000000..3893afa
--- /dev/null
+++ b/app/src/main/java/com/casic/br/ktd/netty/udp/UdpClient.kt
@@ -0,0 +1,103 @@
+package com.casic.br.ktd.netty.udp
+
+import com.casic.br.ktd.utils.LocaleConstant
+import com.pengxh.kt.lite.utils.SaveKeyValues
+import io.netty.bootstrap.Bootstrap
+import io.netty.buffer.ByteBuf
+import io.netty.buffer.Unpooled
+import io.netty.channel.ChannelOption
+import io.netty.channel.nio.NioEventLoopGroup
+import io.netty.channel.socket.DatagramPacket
+import io.netty.channel.socket.nio.NioDatagramChannel
+import io.netty.util.CharsetUtil
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.launch
+import kotlinx.coroutines.withContext
+import java.net.InetSocketAddress
+import java.util.concurrent.ExecutorService
+import java.util.concurrent.Executors
+
+
+class UdpClient : UdpChannelInboundHandler(), Runnable {
+
+ private val bootStrap by lazy { Bootstrap() }
+ private val eventLoopGroup by lazy { NioEventLoopGroup() }
+ private val udpChannelInitializer by lazy { UdpChannelInitializer(this) }
+ private var executorService: ExecutorService
+
+ init {
+ bootStrap.group(eventLoopGroup)
+ bootStrap.channel(NioDatagramChannel::class.java)
+ .option(ChannelOption.SO_RCVBUF, 1024)
+ .option(ChannelOption.SO_SNDBUF, 1024)
+ bootStrap.handler(udpChannelInitializer)
+
+ executorService = Executors.newSingleThreadExecutor()
+ executorService.execute(this)
+ }
+
+ override fun run() {
+ try {
+ val channelFuture = bootStrap.bind(LocaleConstant.LOCATION_UDP_PORT).sync()
+ channelFuture.channel().closeFuture().sync()
+ } catch (e: InterruptedException) {
+ e.printStackTrace()
+ } finally {
+ eventLoopGroup.shutdownGracefully()
+ }
+ }
+
+ fun send(value: String) {
+ CoroutineScope(Dispatchers.Main).launch {
+ withContext(Dispatchers.IO) {
+ val host = SaveKeyValues.getValue(
+ LocaleConstant.LOCATION_UDP_SERVER, "192.168.149.213"
+ ).toString()
+ val datagramPacket = DatagramPacket(
+ Unpooled.copiedBuffer(value, CharsetUtil.UTF_8),
+ InetSocketAddress(host, LocaleConstant.LOCATION_UDP_PORT)
+ )
+ sendDatagramPacket(datagramPacket)
+ }
+ }
+ }
+
+ fun send(value: ByteArray) {
+ CoroutineScope(Dispatchers.Main).launch {
+ withContext(Dispatchers.IO) {
+ val host = SaveKeyValues.getValue(
+ LocaleConstant.LOCATION_UDP_SERVER, "192.168.149.213"
+ ).toString()
+ val datagramPacket = DatagramPacket(
+ Unpooled.copiedBuffer(value),
+ InetSocketAddress(host, LocaleConstant.LOCATION_UDP_PORT)
+ )
+ sendDatagramPacket(datagramPacket)
+ }
+ }
+ }
+
+ fun send(value: ByteBuf) {
+ CoroutineScope(Dispatchers.Main).launch {
+ withContext(Dispatchers.IO) {
+ val host = SaveKeyValues.getValue(
+ LocaleConstant.LOCATION_UDP_SERVER, "192.168.149.213"
+ ).toString()
+ val datagramPacket = DatagramPacket(
+ Unpooled.copiedBuffer(value),
+ InetSocketAddress(host, LocaleConstant.LOCATION_UDP_PORT)
+ )
+ sendDatagramPacket(datagramPacket)
+ }
+ }
+ }
+
+ fun release() {
+ releasePort()
+ }
+
+ override fun receivedMessage(data: String) {
+
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/br/ktd/utils/LocaleConstant.kt b/app/src/main/java/com/casic/br/ktd/utils/LocaleConstant.kt
index 0dd119e..4c675df 100644
--- a/app/src/main/java/com/casic/br/ktd/utils/LocaleConstant.kt
+++ b/app/src/main/java/com/casic/br/ktd/utils/LocaleConstant.kt
@@ -50,6 +50,10 @@
const val DEV_NET_IP = "192.168.1.21"
const val DEV_NET_PORT = "8000"
+ //位置信息UDP端口
+ const val LOCATION_UDP_SERVER = "udpServer"
+ const val LOCATION_UDP_PORT = 7777
+
//BroadcastReceiver Action
const val ACTION_UPDATE_DATA = "update"
diff --git a/app/src/main/java/com/casic/br/ktd/utils/LocationHelper.kt b/app/src/main/java/com/casic/br/ktd/utils/LocationHelper.kt
index 8e31d3f..df6adb5 100644
--- a/app/src/main/java/com/casic/br/ktd/utils/LocationHelper.kt
+++ b/app/src/main/java/com/casic/br/ktd/utils/LocationHelper.kt
@@ -7,19 +7,40 @@
import android.location.LocationListener
import android.location.LocationManager
import android.os.Bundle
+import android.util.Log
import androidx.core.app.ActivityCompat
+import com.amap.api.location.AMapLocation
+import com.amap.api.location.AMapLocationClient
+import com.amap.api.location.AMapLocationClientOption
-object LocationHelper {
- fun obtainCurrentLocation(context: Context, listener: ILocationListener) {
+class LocationHelper private constructor() {
+
+ private val kTag = "LocationHelper"
+
+ companion object {
+ //Kotlin委托模式双重锁单例
+ val get: LocationHelper by lazy(mode = LazyThreadSafetyMode.SYNCHRONIZED) {
+ LocationHelper()
+ }
+ }
+
+ private val locationOption = AMapLocationClientOption()
+ private lateinit var locationClient: AMapLocationClient
+
+ init {
+ //设置定位模式为高精度模式,AMapLocationMode.Battery_Saving为低功耗模式,AMapLocationMode.Device_Sensors是仅设备模式
+ locationOption.locationMode = AMapLocationClientOption.AMapLocationMode.Hight_Accuracy
+ locationOption.isNeedAddress = true //设置是否返回地址信息(默认返回地址信息)
+ locationOption.isLocationCacheEnable = true //可选,设置是否使用缓存定位,默认为true
+ }
+
+ fun obtainLocation(context: Context, listener: ILocationListener) {
if (ActivityCompat.checkSelfPermission(
- context,
- Manifest.permission.ACCESS_LOCATION_EXTRA_COMMANDS
+ context, Manifest.permission.ACCESS_LOCATION_EXTRA_COMMANDS
) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(
- context,
- Manifest.permission.ACCESS_FINE_LOCATION
+ context, Manifest.permission.ACCESS_FINE_LOCATION
) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(
- context,
- Manifest.permission.ACCESS_COARSE_LOCATION
+ context, Manifest.permission.ACCESS_COARSE_LOCATION
) != PackageManager.PERMISSION_GRANTED
) {
return
@@ -38,7 +59,37 @@
})
}
+ /**
+ * 高德sdk定位
+ */
+ fun obtainLocationByGD(context: Context?, listener: ILocationListener) {
+ locationClient = AMapLocationClient(context)
+ //给定位客户端对象设置定位参数
+ locationClient.setLocationOption(locationOption)
+ //设置定位回调监听
+ locationClient.setLocationListener { aMapLocation ->
+ if (aMapLocation != null) {
+ if (aMapLocation.errorCode == 0) {
+ listener.onAMapLocationGet(aMapLocation)
+ } else {
+ Log.e(
+ kTag,
+ "ErrCode: ${aMapLocation.errorCode}, errInfo: ${aMapLocation.errorInfo}"
+ )
+ }
+ }
+ }
+ //启动定位
+ locationClient.startLocation()
+ }
+
+ fun stopLocation() {
+ locationClient.stopLocation()//停止定位
+ }
+
interface ILocationListener {
- fun onLocationGet(location: Location?) //高德定位数据
+ fun onLocationGet(location: Location?) //GPS定位数据
+
+ fun onAMapLocationGet(aMapLocation: AMapLocation?) //高德定位数据
}
}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/br/ktd/view/InspectionActivity.kt b/app/src/main/java/com/casic/br/ktd/view/InspectionActivity.kt
index 02c47f8..c893092 100644
--- a/app/src/main/java/com/casic/br/ktd/view/InspectionActivity.kt
+++ b/app/src/main/java/com/casic/br/ktd/view/InspectionActivity.kt
@@ -15,16 +15,21 @@
import android.view.SurfaceHolder
import android.view.View
import android.widget.AdapterView
-import com.amap.api.maps.*
+import com.amap.api.location.AMapLocation
+import com.amap.api.maps.AMap
+import com.amap.api.maps.CameraUpdateFactory
+import com.amap.api.maps.UiSettings
import com.amap.api.maps.model.CameraPosition
import com.amap.api.maps.model.LatLng
+import com.amap.api.maps.model.MyLocationStyle
import com.amap.api.maps.model.PolylineOptions
import com.casic.br.ktd.R
import com.casic.br.ktd.extensions.*
import com.casic.br.ktd.model.ChartPointModel
import com.casic.br.ktd.model.RouteModel
import com.casic.br.ktd.model.SensorDataModel
-import com.casic.br.ktd.netty.SocketManager
+import com.casic.br.ktd.netty.tcp.SocketManager
+import com.casic.br.ktd.netty.udp.UdpClient
import com.casic.br.ktd.utils.LocaleConstant
import com.casic.br.ktd.utils.LocationHelper
import com.casic.br.ktd.widgets.AlertControlDialog
@@ -49,6 +54,10 @@
import hcnetsdk.sdkhub.MessageCodeHub
import hcnetsdk.sdkhub.SDKGuider
import kotlinx.android.synthetic.main.activity_inspection.*
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.launch
+import kotlinx.coroutines.withContext
import java.text.DecimalFormat
import java.text.SimpleDateFormat
import java.util.*
@@ -60,10 +69,10 @@
private val hkSDK by lazy { HCNetSDK.getInstance() }
private val timeFormat by lazy { SimpleDateFormat("yyyyMMddHHmmss", Locale.CHINA) }
private val latlngs = LinkedList()
- private val speedTimer by lazy { Timer() }
private val tcpTimer by lazy { Timer() }
private val decimalFormat by lazy { DecimalFormat("##0.0") }
private val gson by lazy { Gson() }
+ private val udpClient by lazy { UdpClient() }
private var isLoginSuccess = false
private var previewHandle = -1
private var selectChannel = -1
@@ -103,28 +112,32 @@
private lateinit var aMap: AMap
private lateinit var uiSettings: UiSettings
+ /**
+ * 协程配置云台设备,缓解新进页面较卡的问题
+ * */
private fun setDeviceConfig() {
- Log.d(kTag, "setDeviceConfig => 配置设备IP和端口")
- val device = SDKGuider.sdkGuider.devManageGuider.DeviceItem()
- device.m_szDevName = ""
- device.m_struNetInfo = SDKGuider.sdkGuider.devManageGuider.DevNetInfo(
- LocaleConstant.HK_NET_IP,
- LocaleConstant.HK_NET_PORT,
- LocaleConstant.HK_NET_USERNAME,
- LocaleConstant.HK_NET_PASSWORD
- )
- if (device.m_szDevName.isEmpty()) {
- device.m_szDevName = device.m_struNetInfo.m_szIp
- }
- isLoginSuccess = if (
- SDKGuider.sdkGuider.devManageGuider.login_v40_jna(
- device.m_szDevName, device.m_struNetInfo
- )
- ) {
- "设备连接成功".show(this)
- true
- } else {
- false
+ CoroutineScope(Dispatchers.Main).launch {
+ isLoginSuccess = withContext(Dispatchers.IO) {
+ Log.d(kTag, "setDeviceConfig => 配置设备IP和端口")
+ val device = SDKGuider.sdkGuider.devManageGuider.DeviceItem()
+ device.m_szDevName = ""
+ device.m_struNetInfo = SDKGuider.sdkGuider.devManageGuider.DevNetInfo(
+ LocaleConstant.HK_NET_IP,
+ LocaleConstant.HK_NET_PORT,
+ LocaleConstant.HK_NET_USERNAME,
+ LocaleConstant.HK_NET_PASSWORD
+ )
+ if (device.m_szDevName.isEmpty()) {
+ device.m_szDevName = device.m_struNetInfo.m_szIp
+ }
+
+ SDKGuider.sdkGuider.devManageGuider.login_v40_jna(
+ device.m_szDevName, device.m_struNetInfo
+ )
+ }
+ if (isLoginSuccess) {
+ "设备连接成功".show(context)
+ }
}
}
@@ -148,17 +161,74 @@
/**
* 手机GPS定位
* */
- val converter = CoordinateConverter(this)
- LocationHelper.obtainCurrentLocation(this, object : LocationHelper.ILocationListener {
+// val converter = CoordinateConverter(this)
+// LocationHelper.get.obtainLocation(this, object : LocationHelper.ILocationListener {
+// override fun onLocationGet(location: Location?) {
+// if (location == null) {
+// "当前信号弱,无法定位".show(context)
+// return
+// }
+//
+// //发送位置信息给UDP服务端
+// udpClient.send("${location.longitude}, ${location.latitude}")
+// Log.d(kTag, "onLocationGet => 速度:${location.speed}")
+//
+// //WGS-84要转为高德坐标系
+// converter.from(CoordinateConverter.CoordType.GPS)
+// converter.coord(LatLng(location.latitude, location.longitude))
+// val latLng = converter.convert()
+// latlngs.add(latLng)
+//
+// //移动到指定经纬度
+// val cameraPosition = CameraPosition(latLng, 13f, 0f, 0f)
+// val cameraUpdate = CameraUpdateFactory.newCameraPosition(cameraPosition)
+// aMap.animateCamera(cameraUpdate, 1500, null)
+//
+// //绘制线
+// aMap.addPolyline(
+// PolylineOptions().addAll(latlngs).width(12f).color(Color.RED)
+// )
+//
+// if (isStartInspect) {
+// val route = LinkedList()
+// latlngs.forEach {
+// route.add(RouteModel(it.latitude, it.longitude))
+// }
+// }
+// }
+//
+// override fun onAMapLocationGet(aMapLocation: AMapLocation?) {
+//
+// }
+// })
+
+ /**
+ * 高德定位
+ * */
+ LocationHelper.get.obtainLocationByGD(this, object : LocationHelper.ILocationListener {
override fun onLocationGet(location: Location?) {
- if (location == null) {
+
+ }
+
+ override fun onAMapLocationGet(aMapLocation: AMapLocation?) {
+ if (aMapLocation == null) {
"当前信号弱,无法定位".show(context)
return
}
+
+ //发送位置信息给UDP服务端
+ udpClient.send(
+ "${aMapLocation.longitude}, ${aMapLocation.latitude}, ${
+ System.currentTimeMillis().timestampToCompleteDate()
+ }"
+ )
+ //速度 转为 km/h
+ Log.d(kTag, "onLocationGet => 速度:${aMapLocation.speed}")
+ speed = decimalFormat.format(aMapLocation.speed * 3.6).toFloat()
+ carSpeedView.text = String.format("${speed}Km/h")
+
//WGS-84要转为高德坐标系
- converter.from(CoordinateConverter.CoordType.GPS)
- converter.coord(LatLng(location.latitude, location.longitude))
- val latLng = converter.convert()
+ val latLng = LatLng(aMapLocation.latitude, aMapLocation.longitude)
latlngs.add(latLng)
//移动到指定经纬度
@@ -168,7 +238,7 @@
//绘制线
aMap.addPolyline(
- PolylineOptions().addAll(latlngs).width(12f).color(Color.RED)
+ PolylineOptions().addAll(latlngs).width(10f).color(Color.RED)
)
if (isStartInspect) {
@@ -181,27 +251,6 @@
})
/**
- * 计算速度,微分原理,3s计算一次速度
- * */
- speedTimer.schedule(object : TimerTask() {
- override fun run() {
- //经纬度链表数据小于2,无法计算速度,默认为0
- speed = if (latlngs.size < 2) 0.0f else {
- val temp = AMapUtils.calculateLineDistance(
- latlngs.last(), latlngs[latlngs.size - 2]
- ) / 3
- //转为 km/h
- decimalFormat.format(temp * 3.6).toFloat()
- }
-
- //切换到UI线程更新界面数据
- runOnUiThread {
- carSpeedView.text = String.format("${speed}Km/h")
- }
- }
- }, 0, 3000)
-
- /**
* TCP初始化
* ***/
SocketManager.instance.connectNetty(
@@ -632,6 +681,8 @@
stopPreview()
BroadcastManager.obtainInstance(this).destroy(LocaleConstant.ACTION_UPDATE_DATA)
mapView.onDestroy()
+ udpClient.release()
+ LocationHelper.get.stopLocation()
}
override fun handleMessage(msg: Message): Boolean {
@@ -716,38 +767,13 @@
uiSettings.isZoomControlsEnabled = true
uiSettings.isTiltGesturesEnabled = false//不许地图随手势倾斜角度
-// val locationStyle = MyLocationStyle()
-// locationStyle.interval(2000)
-// locationStyle.showMyLocation(true)
-// locationStyle.myLocationType(MyLocationStyle.LOCATION_TYPE_LOCATION_ROTATE)
-// aMap.myLocationStyle = locationStyle
-// aMap.isMyLocationEnabled = true
-// aMap.animateCamera(CameraUpdateFactory.zoomTo(13f))
-// aMap.setOnMyLocationChangeListener(this)
+ //显示定位小蓝点
+ val locationStyle = MyLocationStyle()
+ locationStyle.showMyLocation(true)//设置是否显示定位小蓝点
+ aMap.myLocationStyle = locationStyle
+ aMap.isMyLocationEnabled = true
}
-// override fun onMyLocationChange(aMapLocation: Location?) {
-// if (aMapLocation == null) {
-// "当前信号弱,无法定位".show(context)
-// return
-// }
-// val latitude = aMapLocation.latitude
-// val longitude = aMapLocation.longitude
-// latlngs.add(LatLng(latitude, longitude))
-//
-// //绘制线
-// aMap.addPolyline(
-// PolylineOptions().addAll(latlngs).width(15f).color(Color.RED)
-// )
-//
-// if (isStartInspect) {
-// val route = LinkedList()
-// latlngs.forEach {
-// route.add(RouteModel(it.latitude, it.longitude))
-// }
-// }
-// }
-
/***以下是地图生命周期管理************************************************************************/
override fun onResume() {
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index e822df6..d72c1a5 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -7,6 +7,9 @@
+
+
+
@@ -46,5 +49,8 @@
+
+
+
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/br/ktd/base/KotlinBaseFragment.kt b/app/src/main/java/com/casic/br/ktd/base/KotlinBaseFragment.kt
new file mode 100644
index 0000000..2dac61c
--- /dev/null
+++ b/app/src/main/java/com/casic/br/ktd/base/KotlinBaseFragment.kt
@@ -0,0 +1,51 @@
+package com.casic.br.ktd.base
+
+import android.os.Bundle
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import androidx.annotation.LayoutRes
+import androidx.fragment.app.Fragment
+
+abstract class KotlinBaseFragment : Fragment() {
+
+ lateinit var bv: View
+
+ override fun onCreateView(
+ inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?
+ ): View? {
+ bv = inflater.inflate(initLayoutRes(), container, false)
+ initView(savedInstanceState)
+ setupTopBarLayout()
+ return bv
+ }
+
+ override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
+ super.onViewCreated(view, savedInstanceState)
+ observeRequestState()
+ initEvent()
+ }
+
+ @LayoutRes
+ abstract fun initLayoutRes(): Int
+
+ /**
+ * 沉浸式状态栏
+ */
+ abstract fun setupTopBarLayout()
+
+ /**
+ * 初始化布局以及控件
+ */
+ abstract fun initView(savedInstanceState: Bundle?)
+
+ /**
+ * 网络请求状态监听
+ */
+ abstract fun observeRequestState()
+
+ /**
+ * 业务逻辑,按钮等事件
+ */
+ abstract fun initEvent()
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/br/ktd/fragment/AlarmPageFragment.kt b/app/src/main/java/com/casic/br/ktd/fragment/AlarmPageFragment.kt
index 6c98a3b..9418169 100644
--- a/app/src/main/java/com/casic/br/ktd/fragment/AlarmPageFragment.kt
+++ b/app/src/main/java/com/casic/br/ktd/fragment/AlarmPageFragment.kt
@@ -2,28 +2,29 @@
import android.os.Bundle
import com.casic.br.ktd.R
+import com.casic.br.ktd.base.KotlinBaseFragment
import com.casic.br.ktd.widgets.DateRangeActionSheet
-import com.pengxh.kt.lite.base.KotlinBaseFragment
import kotlinx.android.synthetic.main.fragment_alarm.view.*
class AlarmPageFragment : KotlinBaseFragment() {
- override fun initData(savedInstanceState: Bundle?) {
+
+ override fun initView(savedInstanceState: Bundle?) {
}
override fun initEvent() {
- baseView.calendarView.setOnClickListener {
+ bv.calendarView.setOnClickListener {
DateRangeActionSheet.Builder().setContext(requireContext())
.setOnActionSheetListener(object :
DateRangeActionSheet.OnDateRangeSelectedListener {
override fun onDateRangeSelected(startDate: String, endDate: String) {
- baseView.selectedDateView.text = "$startDate ~ $endDate"
+ bv.selectedDateView.text = "$startDate ~ $endDate"
}
}).build().show()
}
}
- override fun initLayoutView(): Int = R.layout.fragment_alarm
+ override fun initLayoutRes(): Int = R.layout.fragment_alarm
override fun observeRequestState() {
diff --git a/app/src/main/java/com/casic/br/ktd/fragment/HomePageFragment.kt b/app/src/main/java/com/casic/br/ktd/fragment/HomePageFragment.kt
index 9961935..f3eba5c 100644
--- a/app/src/main/java/com/casic/br/ktd/fragment/HomePageFragment.kt
+++ b/app/src/main/java/com/casic/br/ktd/fragment/HomePageFragment.kt
@@ -1,32 +1,62 @@
package com.casic.br.ktd.fragment
+import android.graphics.Color
import android.os.Bundle
import com.amap.api.maps.AMap
import com.amap.api.maps.AMapOptions
+import com.amap.api.maps.CameraUpdateFactory
+import com.amap.api.maps.model.*
import com.casic.br.ktd.R
-import com.pengxh.kt.lite.base.KotlinBaseFragment
+import com.casic.br.ktd.base.KotlinBaseFragment
import kotlinx.android.synthetic.main.fragment_home.view.*
class HomePageFragment : KotlinBaseFragment() {
private lateinit var aMap: AMap
- override fun initData(savedInstanceState: Bundle?) {
- baseView.mapView.onCreate(savedInstanceState)
- aMap = baseView.mapView.map
+ override fun initView(savedInstanceState: Bundle?) {
+ bv.mapView.onCreate(savedInstanceState)
+ aMap = bv.mapView.map
val uiSettings = aMap.uiSettings
uiSettings.isCompassEnabled = true
- uiSettings.isMyLocationButtonEnabled = true
+ uiSettings.isMyLocationButtonEnabled = false
uiSettings.isScaleControlsEnabled = true
uiSettings.zoomPosition = AMapOptions.ZOOM_POSITION_RIGHT_CENTER
uiSettings.isRotateGesturesEnabled = false//不许地图随手势旋转角度
}
override fun initEvent() {
-
+ //移动到巡检起始经纬度
+ val cameraPosition = CameraPosition(LatLng(39.914199, 116.265785), 16f, 0f, 0f)
+ val cameraUpdate = CameraUpdateFactory.newCameraPosition(cameraPosition)
+ aMap.animateCamera(cameraUpdate, 1500, null)
+ //设置起点
+ addMarker(LatLng(39.914885, 116.272312), R.mipmap.start)
+ //设置终点
+ addMarker(LatLng(39.914716, 116.265097), R.mipmap.end)
+ //瞄点画线
+ val latLngPoints = ArrayList()
+ latLngPoints.add(LatLng(39.914885, 116.272312))
+ latLngPoints.add(LatLng(39.915148, 116.272312))
+ latLngPoints.add(LatLng(39.915399, 116.272302))
+ latLngPoints.add(LatLng(39.915436, 116.271787))
+ latLngPoints.add(LatLng(39.915477, 116.270886))
+ latLngPoints.add(LatLng(39.915477, 116.269968))
+ latLngPoints.add(LatLng(39.915469, 116.269544))
+ latLngPoints.add(LatLng(39.915481, 116.269196))
+ latLngPoints.add(LatLng(39.915452, 116.268472))
+ latLngPoints.add(LatLng(39.915444, 116.267722))
+ latLngPoints.add(LatLng(39.915415, 116.266755))
+ latLngPoints.add(LatLng(39.915403, 116.266165))
+ latLngPoints.add(LatLng(39.915395, 116.265703))
+ latLngPoints.add(LatLng(39.915366, 116.265119))
+ latLngPoints.add(LatLng(39.914716, 116.265097))
+ aMap.addPolyline(
+ PolylineOptions().addAll(latLngPoints).width(10.toFloat()).color(Color.RED)
+ )
}
- override fun initLayoutView(): Int = R.layout.fragment_home
+ override fun initLayoutRes(): Int = R.layout.fragment_home
override fun observeRequestState() {
@@ -36,25 +66,32 @@
}
+ private fun addMarker(point: LatLng, res: Int) {
+ val markerOption = MarkerOptions()
+ markerOption.position(point)
+ markerOption.icon(BitmapDescriptorFactory.fromResource(res))
+ aMap.addMarker(markerOption)
+ }
+
/***以下是地图生命周期管理************************************************************************/
override fun onResume() {
super.onResume()
- baseView.mapView.onResume()
+ bv.mapView.onResume()
}
override fun onPause() {
- baseView.mapView.onPause()
super.onPause()
+ bv.mapView.onPause()
}
override fun onSaveInstanceState(outState: Bundle) {
super.onSaveInstanceState(outState)
- baseView.mapView.onSaveInstanceState(outState)
+ bv.mapView.onSaveInstanceState(outState)
}
override fun onDestroy() {
- baseView.mapView.onDestroy()
super.onDestroy()
+ bv.mapView.onDestroy()
}
}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/br/ktd/fragment/MinePageFragment.kt b/app/src/main/java/com/casic/br/ktd/fragment/MinePageFragment.kt
index 90313ac..3212794 100644
--- a/app/src/main/java/com/casic/br/ktd/fragment/MinePageFragment.kt
+++ b/app/src/main/java/com/casic/br/ktd/fragment/MinePageFragment.kt
@@ -2,10 +2,11 @@
import android.os.Bundle
import com.casic.br.ktd.R
-import com.pengxh.kt.lite.base.KotlinBaseFragment
+import com.casic.br.ktd.base.KotlinBaseFragment
class MinePageFragment : KotlinBaseFragment() {
- override fun initData(savedInstanceState: Bundle?) {
+
+ override fun initView(savedInstanceState: Bundle?) {
}
@@ -13,7 +14,7 @@
}
- override fun initLayoutView(): Int = R.layout.fragment_mine
+ override fun initLayoutRes(): Int = R.layout.fragment_mine
override fun observeRequestState() {
diff --git a/app/src/main/java/com/casic/br/ktd/fragment/TaskPageFragment.kt b/app/src/main/java/com/casic/br/ktd/fragment/TaskPageFragment.kt
index 8f6abf0..6b82a54 100644
--- a/app/src/main/java/com/casic/br/ktd/fragment/TaskPageFragment.kt
+++ b/app/src/main/java/com/casic/br/ktd/fragment/TaskPageFragment.kt
@@ -8,6 +8,7 @@
import androidx.recyclerview.widget.RecyclerView
import com.casic.br.ktd.R
import com.casic.br.ktd.adapter.TaskAdapter
+import com.casic.br.ktd.base.KotlinBaseFragment
import com.casic.br.ktd.holder.SwipeViewHolder
import com.casic.br.ktd.model.TaskListModel
import com.casic.br.ktd.view.InspectionActivity
@@ -15,7 +16,6 @@
import com.casic.br.ktd.widgets.AlertControlDialog
import com.casic.br.ktd.widgets.AlertInputDialog
import com.casic.br.ktd.widgets.DateRangeActionSheet
-import com.pengxh.kt.lite.base.KotlinBaseFragment
import com.pengxh.kt.lite.extensions.navigatePageTo
import com.pengxh.kt.lite.extensions.show
import com.pengxh.kt.lite.utils.WeakReferenceHandler
@@ -36,7 +36,7 @@
private var startTime = ""
private var endTime = ""
- override fun initData(savedInstanceState: Bundle?) {
+ override fun initView(savedInstanceState: Bundle?) {
weakReferenceHandler = WeakReferenceHandler(this)
taskViewModel = ViewModelProvider(this)[TaskViewModel::class.java]
taskViewModel.taskList.observe(this) {
@@ -45,7 +45,7 @@
when {
isRefresh -> {
taskAdapter.setRefreshData(dataRows)
- baseView.taskLayout.finishRefresh()
+ bv.taskLayout.finishRefresh()
isRefresh = false
}
isLoadMore -> {
@@ -53,7 +53,7 @@
"到底了,别拉了".show(requireContext())
}
taskAdapter.setLoadMoreData(dataRows)
- baseView.taskLayout.finishLoadMore()
+ bv.taskLayout.finishLoadMore()
isLoadMore = false
}
else -> {
@@ -76,9 +76,9 @@
when (msg.what) {
2023070501 -> {
if (dataBeans.size == 0) {
- baseView.emptyLayout.visibility = View.VISIBLE
+ bv.emptyLayout.visibility = View.VISIBLE
} else {
- baseView.emptyLayout.visibility = View.GONE
+ bv.emptyLayout.visibility = View.GONE
taskAdapter = object : TaskAdapter(
requireContext(), R.layout.item_task_rv_l, dataBeans
) {
@@ -97,8 +97,8 @@
}
}
//绑定侧滑事件
- swipeAction.attachToRecyclerView(baseView.taskRecyclerView)
- baseView.taskRecyclerView.adapter = taskAdapter
+ swipeAction.attachToRecyclerView(bv.taskRecyclerView)
+ bv.taskRecyclerView.adapter = taskAdapter
taskAdapter.setOnItemCheckedListener(object :
TaskAdapter.OnItemCheckedListener {
override fun onItemChecked(items: ArrayList) {
@@ -168,7 +168,7 @@
override fun initEvent() {
- baseView.calendarView.setOnClickListener {
+ bv.calendarView.setOnClickListener {
DateRangeActionSheet.Builder().setContext(requireContext())
.setOnActionSheetListener(object :
DateRangeActionSheet.OnDateRangeSelectedListener {
@@ -177,12 +177,12 @@
endTime = endDate
//显示
- baseView.selectedDateView.text = "$startDate ~ $endDate"
+ bv.selectedDateView.text = "$startDate ~ $endDate"
}
}).build().show()
}
- baseView.addTaskButton.setOnClickListener {
+ bv.addTaskButton.setOnClickListener {
// AlertInputDialog.Builder()
// .setContext(requireContext())
// .setTitle("新建巡检任务")
@@ -200,11 +200,11 @@
requireContext().navigatePageTo()
}
- baseView.deleteTaskButton.setOnClickListener {
+ bv.deleteTaskButton.setOnClickListener {
selectedItems.size.toString().show(requireContext())
}
- baseView.taskSettingsButton.setOnClickListener {
+ bv.taskSettingsButton.setOnClickListener {
AlertInputDialog.Builder()
.setContext(requireContext())
.setTitle("设置阈值")
@@ -221,14 +221,14 @@
}).build().show()
}
- baseView.taskLayout.setOnRefreshListener {
+ bv.taskLayout.setOnRefreshListener {
isRefresh = true
//刷新之后页码重置
pageIndex = 1
getTaskList()
}
- baseView.taskLayout.setOnLoadMoreListener {
+ bv.taskLayout.setOnLoadMoreListener {
isLoadMore = true
pageIndex++
getTaskList()
@@ -239,13 +239,13 @@
taskViewModel.getTaskList(
startTime,
endTime,
- baseView.taskNameView.text.toString(),
- baseView.taskCodeView.text.toString(),
+ bv.taskNameView.text.toString(),
+ bv.taskCodeView.text.toString(),
pageIndex
)
}
- override fun initLayoutView(): Int = R.layout.fragment_task
+ override fun initLayoutRes(): Int = R.layout.fragment_task
override fun observeRequestState() {
diff --git a/app/src/main/java/com/casic/br/ktd/netty/ISocketListener.kt b/app/src/main/java/com/casic/br/ktd/netty/ISocketListener.kt
deleted file mode 100644
index dab98e1..0000000
--- a/app/src/main/java/com/casic/br/ktd/netty/ISocketListener.kt
+++ /dev/null
@@ -1,19 +0,0 @@
-package com.casic.br.ktd.netty
-
-interface ISocketListener {
- companion object {
- const val STATUS_CONNECT_SUCCESS: Byte = 1 //连接成功
- const val STATUS_CONNECT_CLOSED: Byte = 0 //关闭连接
- const val STATUS_CONNECT_ERROR: Byte = 0 //连接失败
- }
-
- /**
- * 当接收到系统消息
- */
- fun onMessageResponse(data: ByteArray?)
-
- /**
- * 当连接状态发生变化时调用
- */
- fun onServiceStatusConnectChanged(statusCode: Byte)
-}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/br/ktd/netty/SocketChannelHandle.kt b/app/src/main/java/com/casic/br/ktd/netty/SocketChannelHandle.kt
deleted file mode 100644
index 42eb310..0000000
--- a/app/src/main/java/com/casic/br/ktd/netty/SocketChannelHandle.kt
+++ /dev/null
@@ -1,51 +0,0 @@
-package com.casic.br.ktd.netty
-
-import android.util.Log
-import io.netty.channel.ChannelHandlerContext
-import io.netty.channel.SimpleChannelInboundHandler
-import io.netty.handler.timeout.IdleState
-import io.netty.handler.timeout.IdleStateEvent
-import java.nio.charset.StandardCharsets
-
-class SocketChannelHandle(private val listener: ISocketListener?) :
- SimpleChannelInboundHandler() {
-
- private val kTag = "SocketChannelHandle"
-
- override fun channelActive(ctx: ChannelHandlerContext) {
- super.channelActive(ctx)
- Log.d(kTag, "channelActive ===> 连接成功")
- listener?.onServiceStatusConnectChanged(ISocketListener.STATUS_CONNECT_SUCCESS)
- }
-
- override fun channelInactive(ctx: ChannelHandlerContext) {
- super.channelInactive(ctx)
- Log.e(kTag, "channelInactive: 连接断开")
- }
-
- override fun userEventTriggered(ctx: ChannelHandlerContext, evt: Any) {
- super.userEventTriggered(ctx, evt)
- if (evt is IdleStateEvent) {
- if (evt.state() == IdleState.WRITER_IDLE) {
- //写超时,此时可以发送心跳数据给服务器
- val temp = "FF"
- ctx.writeAndFlush(temp.toByteArray(StandardCharsets.UTF_8))
- } else if (evt.state() == IdleState.READER_IDLE) {
- //读超时,此时代表没有收到心跳返回可以关闭当前连接进行重连
- ctx.close()
- }
- }
- }
-
- override fun channelRead0(ctx: ChannelHandlerContext, data: ByteArray?) {
- listener?.onMessageResponse(data)
- }
-
- override fun exceptionCaught(ctx: ChannelHandlerContext, cause: Throwable) {
- super.exceptionCaught(ctx, cause)
- Log.d(kTag, "exceptionCaught ===> $cause")
- listener?.onServiceStatusConnectChanged(ISocketListener.STATUS_CONNECT_ERROR)
- cause.printStackTrace()
- ctx.close()
- }
-}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/br/ktd/netty/SocketClient.kt b/app/src/main/java/com/casic/br/ktd/netty/SocketClient.kt
deleted file mode 100644
index d05d335..0000000
--- a/app/src/main/java/com/casic/br/ktd/netty/SocketClient.kt
+++ /dev/null
@@ -1,153 +0,0 @@
-package com.casic.br.ktd.netty
-
-import android.os.SystemClock
-import android.util.Log
-import io.netty.bootstrap.Bootstrap
-import io.netty.channel.*
-import io.netty.channel.nio.NioEventLoopGroup
-import io.netty.channel.socket.SocketChannel
-import io.netty.channel.socket.nio.NioSocketChannel
-import io.netty.handler.codec.bytes.ByteArrayDecoder
-import io.netty.handler.codec.bytes.ByteArrayEncoder
-import io.netty.handler.timeout.IdleStateHandler
-
-class SocketClient {
-
- private val kTag = "SocketClient"
-
- private var host: String? = null
- private var port = 8000
- private var nioEventLoopGroup: NioEventLoopGroup? = null
- private var channel: Channel? = null
- private var listener: ISocketListener? = null
-
- //现在连接的状态
- var connectStatus = false //判断是否已连接
- private var reconnectNum = Int.MAX_VALUE //定义的重连到时候用
- private var isNeedReconnect = true //是否需要重连
- var isConnecting = false //是否正在连接
- private set
- private var reconnectIntervalTime: Long = 15000 //重连的时间
-
- //重连时间
- fun setReconnectNum(reconnectNum: Int) {
- this.reconnectNum = reconnectNum
- }
-
- fun setReconnectIntervalTime(reconnectIntervalTime: Long) {
- this.reconnectIntervalTime = reconnectIntervalTime
- }
-
- fun setSocketListener(listener: ISocketListener?) {
- this.listener = listener
- }
-
- fun connect(host: String, port: Int) {
- this.host = host
- this.port = port
- Log.d(kTag, "connect ===> 开始连接TCP服务器")
- if (isConnecting) {
- return
- }
- //起个线程
- val clientThread: Thread = object : Thread("client-Netty") {
- override fun run() {
- super.run()
- isNeedReconnect = true
- reconnectNum = Int.MAX_VALUE
- connectServer()
- }
- }
- clientThread.start()
- }
-
- private fun connectServer() {
- synchronized(this@SocketClient) {
- var channelFuture: ChannelFuture? = null //连接管理对象
- if (!connectStatus) {
- isConnecting = true
- nioEventLoopGroup = NioEventLoopGroup() //设置的连接group
- val bootstrap = Bootstrap()
- bootstrap.group(nioEventLoopGroup) //设置的一系列连接参数操作等
- .channel(NioSocketChannel::class.java)
- .option(ChannelOption.TCP_NODELAY, true) //无阻塞
- .option(ChannelOption.SO_KEEPALIVE, true) //长连接
- .option(
- ChannelOption.RCVBUF_ALLOCATOR,
- AdaptiveRecvByteBufAllocator(5000, 5000, 8000)
- ) //接收缓冲区 最小值太小时数据接收不全
- .handler(object : ChannelInitializer() {
- override fun initChannel(channel: SocketChannel) {
- val pipeline = channel.pipeline()
- //参数1:代表读套接字超时的时间,没收到数据会触发读超时回调;
- //参数2:代表写套接字超时时间,没进行写会触发写超时回调;
- //参数3:将在未执行读取或写入时触发超时回调,0代表不处理;
- //读超时尽量设置大于写超时,代表多次写超时时写心跳包,多次写了心跳数据仍然读超时代表当前连接错误,即可断开连接重新连接
- pipeline.addLast(IdleStateHandler(60, 10, 0))
- pipeline.addLast(ByteArrayDecoder())
- pipeline.addLast(ByteArrayEncoder())
- pipeline.addLast(SocketChannelHandle(listener))
- }
- })
- try {
- //连接监听
- channelFuture = bootstrap.connect(host, port)
- .addListener(object : ChannelFutureListener {
- override fun operationComplete(channelFuture: ChannelFuture) {
- if (channelFuture.isSuccess) {
- connectStatus = true
- channel = channelFuture.channel()
- } else {
- Log.e(kTag, "operationComplete: 连接失败")
- connectStatus = false
- }
- isConnecting = false
- }
- }).sync()
- // 等待连接关闭
- channelFuture.channel().closeFuture().sync()
- } catch (e: Exception) {
- e.printStackTrace()
- } finally {
- connectStatus = false
- listener?.onServiceStatusConnectChanged(ISocketListener.STATUS_CONNECT_CLOSED) //STATUS_CONNECT_CLOSED 这我自己定义的 接口标识
- if (null != channelFuture) {
- if (channelFuture.channel() != null && channelFuture.channel().isOpen) {
- channelFuture.channel().close()
- }
- }
- nioEventLoopGroup?.shutdownGracefully()
- reconnect() //重新连接
- }
- }
- }
- }
-
- //断开连接
- fun disconnect() {
- Log.d(kTag, "disconnect ===> 断开连接")
- isNeedReconnect = false
- nioEventLoopGroup?.shutdownGracefully()
- }
-
- //重新连接
- private fun reconnect() {
- if (isNeedReconnect && reconnectNum > 0 && !connectStatus) {
- reconnectNum--
- SystemClock.sleep(reconnectIntervalTime)
- if (isNeedReconnect && reconnectNum > 0 && !connectStatus) {
- Log.d(kTag, "reconnect ===> 重新连接")
- connectServer()
- }
- }
- }
-
- fun sendData(bytes: ByteArray) {
- channel?.writeAndFlush(bytes)?.addListener(ChannelFutureListener { future ->
- if (!future.isSuccess) {
- future.channel().close()
- nioEventLoopGroup!!.shutdownGracefully()
- }
- })
- }
-}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/br/ktd/netty/SocketManager.kt b/app/src/main/java/com/casic/br/ktd/netty/SocketManager.kt
deleted file mode 100644
index 17daf35..0000000
--- a/app/src/main/java/com/casic/br/ktd/netty/SocketManager.kt
+++ /dev/null
@@ -1,113 +0,0 @@
-package com.casic.br.ktd.netty
-
-import android.util.Log
-import com.casic.br.ktd.base.BaseApplication
-import com.casic.br.ktd.extensions.covertAngleValue
-import com.casic.br.ktd.extensions.covertDataValue
-import com.casic.br.ktd.extensions.toUnsignedByteArray
-import com.casic.br.ktd.model.SensorDataModel
-import com.casic.br.ktd.utils.LocaleConstant
-import com.pengxh.kt.lite.extensions.toJson
-import com.pengxh.kt.lite.utils.BroadcastManager
-
-class SocketManager private constructor() : ISocketListener {
-
- private val kTag = "SocketManager"
- private var nettyClient: SocketClient = SocketClient()
-
- companion object {
- val instance: SocketManager by lazy(mode = LazyThreadSafetyMode.SYNCHRONIZED) { SocketManager() }
- }
-
- fun connectNetty(hostname: String, port: Int) {
- Thread {
- if (!nettyClient.connectStatus) {
- nettyClient.setSocketListener(this)
- nettyClient.connect(hostname, port)
- } else {
- nettyClient.disconnect()
- }
- }.start()
- }
-
- override fun onMessageResponse(data: ByteArray?) {
-// Log.d(kTag, "onMessageResponse ===> " + Arrays.toString(data))
- /**
- * 0xFF,0x01,
- * 0x01,0x37,0xE6, 甲烷浓度值(数据码1* 65536 + 数据码2 * 256 + 数据码3)
- * 0x00, 激光甲烷模块工作状态(00表示设备正常,01表示温控故障,02表示设备激光未打开)
- * 0x00,0xB2,0x35, 激光强度值(数据码5* 65536 + 数据码6 * 256 + 数据码7)
- * 0x0A,0x3D, 云台水平角度([数据码8 * 256 + 数据码9]/100,单位为°,精确到0.01)
- * 0x05,0x6F, 云台垂直角度(首先计算Tangle=[数据码10 * 256 + 数据码11]/100,单位为°,精确到0.01。若Tangle在0~90范围内,则垂直角度值=Tangle;若Tangle在-1~-90范围内,则垂直角度值=Tangle-360)
- * 0xC1
- *
- * [-1, 1, 1, 55, -26, 0, 0, -78, 53, 10, 61, 5, 111, -63]
- * 甲烷浓度值为79638,计算为79638=0x01*65536+0x37*256+0xE6[0x01为数据码1,0x37为数据码2,0xE6为数据码3];
- * 激光甲烷设备状态值为0,表示状态正常,[0x00为数据码4];
- * 激光强度值为45621,计算为45621=0x00*65536+0xB2*256+0x35[0x00为数据码5,0xB2为数据码6,0x35为数据码7];
- *
- * =========================================================================================
- * 实际数据(1800-1950左右)
- * [-86, 1, 0, 7, 71, 0, 0, 62, -92, 57, 59, -118, -111, -64]
- * */
-
- if (data == null) {
- return
- }
- val bytes = data.toUnsignedByteArray()
- if (bytes.size == 14) {
- val dataModel = SensorDataModel(0, "激光未打开", 0, 0.0, 0.0)
-
- val methaneBytes = IntArray(3)
- System.arraycopy(bytes, 2, methaneBytes, 0, 3)
- dataModel.methane = methaneBytes.covertDataValue()
-
- dataModel.methaneState = when (bytes[5]) {
- 1 -> "温控故障"
- 2 -> "激光未打开"
- else -> "正常"
- }
-
- val laserBytes = IntArray(3)
- System.arraycopy(bytes, 6, laserBytes, 0, 3)
- dataModel.laser = laserBytes.covertDataValue()
-
- /**
- * 水平角度的实际范围为从水平零点开始,顺时针方向(从上往下看),0~360°
- * 垂直角度的实际范围为从垂直零点开始,以向上为正,-90°~90°,控制精度为0.01°
- * */
- val horizontalBytes = IntArray(2)
- System.arraycopy(bytes, 9, horizontalBytes, 0, 2)
- dataModel.horizontal = horizontalBytes.covertAngleValue()
-
- val verticalBytes = IntArray(2)
- System.arraycopy(bytes, 11, verticalBytes, 0, 2)
- dataModel.vertical = verticalBytes.covertAngleValue()
-
- //{"horizontal":26.21,"laser":45621,"methane":79846,"methaneState":"正常","vertical":13.91}
- BroadcastManager.obtainInstance(BaseApplication.get()).sendBroadcast(
- LocaleConstant.ACTION_UPDATE_DATA, dataModel.toJson()
- )
- }
- }
-
- override fun onServiceStatusConnectChanged(statusCode: Byte) {
- if (statusCode == ISocketListener.STATUS_CONNECT_SUCCESS) {
- if (nettyClient.connectStatus) {
- Log.d(kTag, "连接成功")
- }
- } else {
- if (!nettyClient.connectStatus) {
- Log.e(kTag, "onServiceStatusConnectChanged:$statusCode,连接断开,正在重连")
- }
- }
- }
-
- fun sendData(data: ByteArray) {
- nettyClient.sendData(data)
- }
-
- fun close() {
- nettyClient.disconnect()
- }
-}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/br/ktd/netty/tcp/ISocketListener.kt b/app/src/main/java/com/casic/br/ktd/netty/tcp/ISocketListener.kt
new file mode 100644
index 0000000..13c3084
--- /dev/null
+++ b/app/src/main/java/com/casic/br/ktd/netty/tcp/ISocketListener.kt
@@ -0,0 +1,19 @@
+package com.casic.br.ktd.netty.tcp
+
+interface ISocketListener {
+ companion object {
+ const val STATUS_CONNECT_SUCCESS: Byte = 1 //连接成功
+ const val STATUS_CONNECT_CLOSED: Byte = 0 //关闭连接
+ const val STATUS_CONNECT_ERROR: Byte = 0 //连接失败
+ }
+
+ /**
+ * 当接收到系统消息
+ */
+ fun onMessageResponse(data: ByteArray?)
+
+ /**
+ * 当连接状态发生变化时调用
+ */
+ fun onServiceStatusConnectChanged(statusCode: Byte)
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/br/ktd/netty/tcp/SocketChannelHandle.kt b/app/src/main/java/com/casic/br/ktd/netty/tcp/SocketChannelHandle.kt
new file mode 100644
index 0000000..8e2997f
--- /dev/null
+++ b/app/src/main/java/com/casic/br/ktd/netty/tcp/SocketChannelHandle.kt
@@ -0,0 +1,51 @@
+package com.casic.br.ktd.netty.tcp
+
+import android.util.Log
+import io.netty.channel.ChannelHandlerContext
+import io.netty.channel.SimpleChannelInboundHandler
+import io.netty.handler.timeout.IdleState
+import io.netty.handler.timeout.IdleStateEvent
+import java.nio.charset.StandardCharsets
+
+class SocketChannelHandle(private val listener: ISocketListener?) :
+ SimpleChannelInboundHandler() {
+
+ private val kTag = "SocketChannelHandle"
+
+ override fun channelActive(ctx: ChannelHandlerContext) {
+ super.channelActive(ctx)
+ Log.d(kTag, "channelActive ===> 连接成功")
+ listener?.onServiceStatusConnectChanged(ISocketListener.STATUS_CONNECT_SUCCESS)
+ }
+
+ override fun channelInactive(ctx: ChannelHandlerContext) {
+ super.channelInactive(ctx)
+ Log.e(kTag, "channelInactive: 连接断开")
+ }
+
+ override fun userEventTriggered(ctx: ChannelHandlerContext, evt: Any) {
+ super.userEventTriggered(ctx, evt)
+ if (evt is IdleStateEvent) {
+ if (evt.state() == IdleState.WRITER_IDLE) {
+ //写超时,此时可以发送心跳数据给服务器
+ val temp = "FF"
+ ctx.writeAndFlush(temp.toByteArray(StandardCharsets.UTF_8))
+ } else if (evt.state() == IdleState.READER_IDLE) {
+ //读超时,此时代表没有收到心跳返回可以关闭当前连接进行重连
+ ctx.close()
+ }
+ }
+ }
+
+ override fun channelRead0(ctx: ChannelHandlerContext, data: ByteArray?) {
+ listener?.onMessageResponse(data)
+ }
+
+ override fun exceptionCaught(ctx: ChannelHandlerContext, cause: Throwable) {
+ super.exceptionCaught(ctx, cause)
+ Log.d(kTag, "exceptionCaught ===> $cause")
+ listener?.onServiceStatusConnectChanged(ISocketListener.STATUS_CONNECT_ERROR)
+ cause.printStackTrace()
+ ctx.close()
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/br/ktd/netty/tcp/SocketClient.kt b/app/src/main/java/com/casic/br/ktd/netty/tcp/SocketClient.kt
new file mode 100644
index 0000000..34960a0
--- /dev/null
+++ b/app/src/main/java/com/casic/br/ktd/netty/tcp/SocketClient.kt
@@ -0,0 +1,153 @@
+package com.casic.br.ktd.netty.tcp
+
+import android.os.SystemClock
+import android.util.Log
+import io.netty.bootstrap.Bootstrap
+import io.netty.channel.*
+import io.netty.channel.nio.NioEventLoopGroup
+import io.netty.channel.socket.SocketChannel
+import io.netty.channel.socket.nio.NioSocketChannel
+import io.netty.handler.codec.bytes.ByteArrayDecoder
+import io.netty.handler.codec.bytes.ByteArrayEncoder
+import io.netty.handler.timeout.IdleStateHandler
+
+class SocketClient {
+
+ private val kTag = "SocketClient"
+
+ private var host: String? = null
+ private var port = 8000
+ private var nioEventLoopGroup: NioEventLoopGroup? = null
+ private var channel: Channel? = null
+ private var listener: ISocketListener? = null
+
+ //现在连接的状态
+ var connectStatus = false //判断是否已连接
+ private var reconnectNum = Int.MAX_VALUE //定义的重连到时候用
+ private var isNeedReconnect = true //是否需要重连
+ var isConnecting = false //是否正在连接
+ private set
+ private var reconnectIntervalTime: Long = 15000 //重连的时间
+
+ //重连时间
+ fun setReconnectNum(reconnectNum: Int) {
+ this.reconnectNum = reconnectNum
+ }
+
+ fun setReconnectIntervalTime(reconnectIntervalTime: Long) {
+ this.reconnectIntervalTime = reconnectIntervalTime
+ }
+
+ fun setSocketListener(listener: ISocketListener?) {
+ this.listener = listener
+ }
+
+ fun connect(host: String, port: Int) {
+ this.host = host
+ this.port = port
+ Log.d(kTag, "connect ===> 开始连接TCP服务器")
+ if (isConnecting) {
+ return
+ }
+ //起个线程
+ val clientThread: Thread = object : Thread("client-Netty") {
+ override fun run() {
+ super.run()
+ isNeedReconnect = true
+ reconnectNum = Int.MAX_VALUE
+ connectServer()
+ }
+ }
+ clientThread.start()
+ }
+
+ private fun connectServer() {
+ synchronized(this@SocketClient) {
+ var channelFuture: ChannelFuture? = null //连接管理对象
+ if (!connectStatus) {
+ isConnecting = true
+ nioEventLoopGroup = NioEventLoopGroup() //设置的连接group
+ val bootstrap = Bootstrap()
+ bootstrap.group(nioEventLoopGroup) //设置的一系列连接参数操作等
+ .channel(NioSocketChannel::class.java)
+ .option(ChannelOption.TCP_NODELAY, true) //无阻塞
+ .option(ChannelOption.SO_KEEPALIVE, true) //长连接
+ .option(
+ ChannelOption.RCVBUF_ALLOCATOR,
+ AdaptiveRecvByteBufAllocator(5000, 5000, 8000)
+ ) //接收缓冲区 最小值太小时数据接收不全
+ .handler(object : ChannelInitializer() {
+ override fun initChannel(channel: SocketChannel) {
+ val pipeline = channel.pipeline()
+ //参数1:代表读套接字超时的时间,没收到数据会触发读超时回调;
+ //参数2:代表写套接字超时时间,没进行写会触发写超时回调;
+ //参数3:将在未执行读取或写入时触发超时回调,0代表不处理;
+ //读超时尽量设置大于写超时,代表多次写超时时写心跳包,多次写了心跳数据仍然读超时代表当前连接错误,即可断开连接重新连接
+ pipeline.addLast(IdleStateHandler(60, 10, 0))
+ pipeline.addLast(ByteArrayDecoder())
+ pipeline.addLast(ByteArrayEncoder())
+ pipeline.addLast(SocketChannelHandle(listener))
+ }
+ })
+ try {
+ //连接监听
+ channelFuture = bootstrap.connect(host, port)
+ .addListener(object : ChannelFutureListener {
+ override fun operationComplete(channelFuture: ChannelFuture) {
+ if (channelFuture.isSuccess) {
+ connectStatus = true
+ channel = channelFuture.channel()
+ } else {
+ Log.e(kTag, "operationComplete: 连接失败")
+ connectStatus = false
+ }
+ isConnecting = false
+ }
+ }).sync()
+ // 等待连接关闭
+ channelFuture.channel().closeFuture().sync()
+ } catch (e: Exception) {
+ e.printStackTrace()
+ } finally {
+ connectStatus = false
+ listener?.onServiceStatusConnectChanged(ISocketListener.STATUS_CONNECT_CLOSED) //STATUS_CONNECT_CLOSED 这我自己定义的 接口标识
+ if (null != channelFuture) {
+ if (channelFuture.channel() != null && channelFuture.channel().isOpen) {
+ channelFuture.channel().close()
+ }
+ }
+ nioEventLoopGroup?.shutdownGracefully()
+ reconnect() //重新连接
+ }
+ }
+ }
+ }
+
+ //断开连接
+ fun disconnect() {
+ Log.d(kTag, "disconnect ===> 断开连接")
+ isNeedReconnect = false
+ nioEventLoopGroup?.shutdownGracefully()
+ }
+
+ //重新连接
+ private fun reconnect() {
+ if (isNeedReconnect && reconnectNum > 0 && !connectStatus) {
+ reconnectNum--
+ SystemClock.sleep(reconnectIntervalTime)
+ if (isNeedReconnect && reconnectNum > 0 && !connectStatus) {
+ Log.d(kTag, "reconnect ===> 重新连接")
+ connectServer()
+ }
+ }
+ }
+
+ fun sendData(bytes: ByteArray) {
+ channel?.writeAndFlush(bytes)?.addListener(ChannelFutureListener { future ->
+ if (!future.isSuccess) {
+ future.channel().close()
+ nioEventLoopGroup!!.shutdownGracefully()
+ }
+ })
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/br/ktd/netty/tcp/SocketManager.kt b/app/src/main/java/com/casic/br/ktd/netty/tcp/SocketManager.kt
new file mode 100644
index 0000000..35980b9
--- /dev/null
+++ b/app/src/main/java/com/casic/br/ktd/netty/tcp/SocketManager.kt
@@ -0,0 +1,113 @@
+package com.casic.br.ktd.netty.tcp
+
+import android.util.Log
+import com.casic.br.ktd.base.BaseApplication
+import com.casic.br.ktd.extensions.covertAngleValue
+import com.casic.br.ktd.extensions.covertDataValue
+import com.casic.br.ktd.extensions.toUnsignedByteArray
+import com.casic.br.ktd.model.SensorDataModel
+import com.casic.br.ktd.utils.LocaleConstant
+import com.pengxh.kt.lite.extensions.toJson
+import com.pengxh.kt.lite.utils.BroadcastManager
+
+class SocketManager private constructor() : ISocketListener {
+
+ private val kTag = "SocketManager"
+ private var nettyClient: SocketClient = SocketClient()
+
+ companion object {
+ val instance: SocketManager by lazy(mode = LazyThreadSafetyMode.SYNCHRONIZED) { SocketManager() }
+ }
+
+ fun connectNetty(hostname: String, port: Int) {
+ Thread {
+ if (!nettyClient.connectStatus) {
+ nettyClient.setSocketListener(this)
+ nettyClient.connect(hostname, port)
+ } else {
+ nettyClient.disconnect()
+ }
+ }.start()
+ }
+
+ override fun onMessageResponse(data: ByteArray?) {
+// Log.d(kTag, "onMessageResponse ===> " + Arrays.toString(data))
+ /**
+ * 0xFF,0x01,
+ * 0x01,0x37,0xE6, 甲烷浓度值(数据码1* 65536 + 数据码2 * 256 + 数据码3)
+ * 0x00, 激光甲烷模块工作状态(00表示设备正常,01表示温控故障,02表示设备激光未打开)
+ * 0x00,0xB2,0x35, 激光强度值(数据码5* 65536 + 数据码6 * 256 + 数据码7)
+ * 0x0A,0x3D, 云台水平角度([数据码8 * 256 + 数据码9]/100,单位为°,精确到0.01)
+ * 0x05,0x6F, 云台垂直角度(首先计算Tangle=[数据码10 * 256 + 数据码11]/100,单位为°,精确到0.01。若Tangle在0~90范围内,则垂直角度值=Tangle;若Tangle在-1~-90范围内,则垂直角度值=Tangle-360)
+ * 0xC1
+ *
+ * [-1, 1, 1, 55, -26, 0, 0, -78, 53, 10, 61, 5, 111, -63]
+ * 甲烷浓度值为79638,计算为79638=0x01*65536+0x37*256+0xE6[0x01为数据码1,0x37为数据码2,0xE6为数据码3];
+ * 激光甲烷设备状态值为0,表示状态正常,[0x00为数据码4];
+ * 激光强度值为45621,计算为45621=0x00*65536+0xB2*256+0x35[0x00为数据码5,0xB2为数据码6,0x35为数据码7];
+ *
+ * =========================================================================================
+ * 实际数据(1800-1950左右)
+ * [-86, 1, 0, 7, 71, 0, 0, 62, -92, 57, 59, -118, -111, -64]
+ * */
+
+ if (data == null) {
+ return
+ }
+ val bytes = data.toUnsignedByteArray()
+ if (bytes.size == 14) {
+ val dataModel = SensorDataModel(0, "激光未打开", 0, 0.0, 0.0)
+
+ val methaneBytes = IntArray(3)
+ System.arraycopy(bytes, 2, methaneBytes, 0, 3)
+ dataModel.methane = methaneBytes.covertDataValue()
+
+ dataModel.methaneState = when (bytes[5]) {
+ 1 -> "温控故障"
+ 2 -> "激光未打开"
+ else -> "正常"
+ }
+
+ val laserBytes = IntArray(3)
+ System.arraycopy(bytes, 6, laserBytes, 0, 3)
+ dataModel.laser = laserBytes.covertDataValue()
+
+ /**
+ * 水平角度的实际范围为从水平零点开始,顺时针方向(从上往下看),0~360°
+ * 垂直角度的实际范围为从垂直零点开始,以向上为正,-90°~90°,控制精度为0.01°
+ * */
+ val horizontalBytes = IntArray(2)
+ System.arraycopy(bytes, 9, horizontalBytes, 0, 2)
+ dataModel.horizontal = horizontalBytes.covertAngleValue()
+
+ val verticalBytes = IntArray(2)
+ System.arraycopy(bytes, 11, verticalBytes, 0, 2)
+ dataModel.vertical = verticalBytes.covertAngleValue()
+
+ //{"horizontal":26.21,"laser":45621,"methane":79846,"methaneState":"正常","vertical":13.91}
+ BroadcastManager.obtainInstance(BaseApplication.get()).sendBroadcast(
+ LocaleConstant.ACTION_UPDATE_DATA, dataModel.toJson()
+ )
+ }
+ }
+
+ override fun onServiceStatusConnectChanged(statusCode: Byte) {
+ if (statusCode == ISocketListener.STATUS_CONNECT_SUCCESS) {
+ if (nettyClient.connectStatus) {
+ Log.d(kTag, "连接成功")
+ }
+ } else {
+ if (!nettyClient.connectStatus) {
+ Log.e(kTag, "onServiceStatusConnectChanged:$statusCode,连接断开,正在重连")
+ }
+ }
+ }
+
+ fun sendData(data: ByteArray) {
+ nettyClient.sendData(data)
+ }
+
+ fun close() {
+ nettyClient.disconnect()
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/br/ktd/netty/udp/UdpChannelInboundHandler.kt b/app/src/main/java/com/casic/br/ktd/netty/udp/UdpChannelInboundHandler.kt
new file mode 100644
index 0000000..4d6f97c
--- /dev/null
+++ b/app/src/main/java/com/casic/br/ktd/netty/udp/UdpChannelInboundHandler.kt
@@ -0,0 +1,36 @@
+package com.casic.br.ktd.netty.udp
+
+import io.netty.channel.ChannelHandlerContext
+import io.netty.channel.SimpleChannelInboundHandler
+import io.netty.channel.socket.DatagramPacket
+import io.netty.util.CharsetUtil
+
+
+abstract class UdpChannelInboundHandler : SimpleChannelInboundHandler() {
+
+ private var handlerContext: ChannelHandlerContext? = null
+
+ override fun channelActive(ctx: ChannelHandlerContext?) {
+ super.channelActive(ctx)
+ handlerContext = ctx
+ }
+
+ override fun channelInactive(ctx: ChannelHandlerContext?) {
+ super.channelInactive(ctx)
+ handlerContext?.close()
+ }
+
+ fun sendDatagramPacket(obj: Any) {
+ handlerContext?.writeAndFlush(obj)
+ }
+
+ fun releasePort() {
+ handlerContext?.close()
+ }
+
+ override fun channelRead0(ctx: ChannelHandlerContext, datagramPacket: DatagramPacket) {
+ receivedMessage(datagramPacket.content().toString(CharsetUtil.UTF_8))
+ }
+
+ abstract fun receivedMessage(data: String)
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/br/ktd/netty/udp/UdpChannelInitializer.kt b/app/src/main/java/com/casic/br/ktd/netty/udp/UdpChannelInitializer.kt
new file mode 100644
index 0000000..416c5a1
--- /dev/null
+++ b/app/src/main/java/com/casic/br/ktd/netty/udp/UdpChannelInitializer.kt
@@ -0,0 +1,17 @@
+package com.casic.br.ktd.netty.udp
+
+import io.netty.channel.ChannelInitializer
+import io.netty.channel.socket.DatagramChannel
+import io.netty.handler.timeout.IdleStateHandler
+
+
+open class UdpChannelInitializer(private val handler: UdpChannelInboundHandler) :
+ ChannelInitializer() {
+
+ override fun initChannel(datagramChannel: DatagramChannel) {
+ val pipeline = datagramChannel.pipeline()
+ pipeline.addLast(
+ IdleStateHandler(12, 15, 0)
+ ).addLast(handler)
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/br/ktd/netty/udp/UdpClient.kt b/app/src/main/java/com/casic/br/ktd/netty/udp/UdpClient.kt
new file mode 100644
index 0000000..3893afa
--- /dev/null
+++ b/app/src/main/java/com/casic/br/ktd/netty/udp/UdpClient.kt
@@ -0,0 +1,103 @@
+package com.casic.br.ktd.netty.udp
+
+import com.casic.br.ktd.utils.LocaleConstant
+import com.pengxh.kt.lite.utils.SaveKeyValues
+import io.netty.bootstrap.Bootstrap
+import io.netty.buffer.ByteBuf
+import io.netty.buffer.Unpooled
+import io.netty.channel.ChannelOption
+import io.netty.channel.nio.NioEventLoopGroup
+import io.netty.channel.socket.DatagramPacket
+import io.netty.channel.socket.nio.NioDatagramChannel
+import io.netty.util.CharsetUtil
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.launch
+import kotlinx.coroutines.withContext
+import java.net.InetSocketAddress
+import java.util.concurrent.ExecutorService
+import java.util.concurrent.Executors
+
+
+class UdpClient : UdpChannelInboundHandler(), Runnable {
+
+ private val bootStrap by lazy { Bootstrap() }
+ private val eventLoopGroup by lazy { NioEventLoopGroup() }
+ private val udpChannelInitializer by lazy { UdpChannelInitializer(this) }
+ private var executorService: ExecutorService
+
+ init {
+ bootStrap.group(eventLoopGroup)
+ bootStrap.channel(NioDatagramChannel::class.java)
+ .option(ChannelOption.SO_RCVBUF, 1024)
+ .option(ChannelOption.SO_SNDBUF, 1024)
+ bootStrap.handler(udpChannelInitializer)
+
+ executorService = Executors.newSingleThreadExecutor()
+ executorService.execute(this)
+ }
+
+ override fun run() {
+ try {
+ val channelFuture = bootStrap.bind(LocaleConstant.LOCATION_UDP_PORT).sync()
+ channelFuture.channel().closeFuture().sync()
+ } catch (e: InterruptedException) {
+ e.printStackTrace()
+ } finally {
+ eventLoopGroup.shutdownGracefully()
+ }
+ }
+
+ fun send(value: String) {
+ CoroutineScope(Dispatchers.Main).launch {
+ withContext(Dispatchers.IO) {
+ val host = SaveKeyValues.getValue(
+ LocaleConstant.LOCATION_UDP_SERVER, "192.168.149.213"
+ ).toString()
+ val datagramPacket = DatagramPacket(
+ Unpooled.copiedBuffer(value, CharsetUtil.UTF_8),
+ InetSocketAddress(host, LocaleConstant.LOCATION_UDP_PORT)
+ )
+ sendDatagramPacket(datagramPacket)
+ }
+ }
+ }
+
+ fun send(value: ByteArray) {
+ CoroutineScope(Dispatchers.Main).launch {
+ withContext(Dispatchers.IO) {
+ val host = SaveKeyValues.getValue(
+ LocaleConstant.LOCATION_UDP_SERVER, "192.168.149.213"
+ ).toString()
+ val datagramPacket = DatagramPacket(
+ Unpooled.copiedBuffer(value),
+ InetSocketAddress(host, LocaleConstant.LOCATION_UDP_PORT)
+ )
+ sendDatagramPacket(datagramPacket)
+ }
+ }
+ }
+
+ fun send(value: ByteBuf) {
+ CoroutineScope(Dispatchers.Main).launch {
+ withContext(Dispatchers.IO) {
+ val host = SaveKeyValues.getValue(
+ LocaleConstant.LOCATION_UDP_SERVER, "192.168.149.213"
+ ).toString()
+ val datagramPacket = DatagramPacket(
+ Unpooled.copiedBuffer(value),
+ InetSocketAddress(host, LocaleConstant.LOCATION_UDP_PORT)
+ )
+ sendDatagramPacket(datagramPacket)
+ }
+ }
+ }
+
+ fun release() {
+ releasePort()
+ }
+
+ override fun receivedMessage(data: String) {
+
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/br/ktd/utils/LocaleConstant.kt b/app/src/main/java/com/casic/br/ktd/utils/LocaleConstant.kt
index 0dd119e..4c675df 100644
--- a/app/src/main/java/com/casic/br/ktd/utils/LocaleConstant.kt
+++ b/app/src/main/java/com/casic/br/ktd/utils/LocaleConstant.kt
@@ -50,6 +50,10 @@
const val DEV_NET_IP = "192.168.1.21"
const val DEV_NET_PORT = "8000"
+ //位置信息UDP端口
+ const val LOCATION_UDP_SERVER = "udpServer"
+ const val LOCATION_UDP_PORT = 7777
+
//BroadcastReceiver Action
const val ACTION_UPDATE_DATA = "update"
diff --git a/app/src/main/java/com/casic/br/ktd/utils/LocationHelper.kt b/app/src/main/java/com/casic/br/ktd/utils/LocationHelper.kt
index 8e31d3f..df6adb5 100644
--- a/app/src/main/java/com/casic/br/ktd/utils/LocationHelper.kt
+++ b/app/src/main/java/com/casic/br/ktd/utils/LocationHelper.kt
@@ -7,19 +7,40 @@
import android.location.LocationListener
import android.location.LocationManager
import android.os.Bundle
+import android.util.Log
import androidx.core.app.ActivityCompat
+import com.amap.api.location.AMapLocation
+import com.amap.api.location.AMapLocationClient
+import com.amap.api.location.AMapLocationClientOption
-object LocationHelper {
- fun obtainCurrentLocation(context: Context, listener: ILocationListener) {
+class LocationHelper private constructor() {
+
+ private val kTag = "LocationHelper"
+
+ companion object {
+ //Kotlin委托模式双重锁单例
+ val get: LocationHelper by lazy(mode = LazyThreadSafetyMode.SYNCHRONIZED) {
+ LocationHelper()
+ }
+ }
+
+ private val locationOption = AMapLocationClientOption()
+ private lateinit var locationClient: AMapLocationClient
+
+ init {
+ //设置定位模式为高精度模式,AMapLocationMode.Battery_Saving为低功耗模式,AMapLocationMode.Device_Sensors是仅设备模式
+ locationOption.locationMode = AMapLocationClientOption.AMapLocationMode.Hight_Accuracy
+ locationOption.isNeedAddress = true //设置是否返回地址信息(默认返回地址信息)
+ locationOption.isLocationCacheEnable = true //可选,设置是否使用缓存定位,默认为true
+ }
+
+ fun obtainLocation(context: Context, listener: ILocationListener) {
if (ActivityCompat.checkSelfPermission(
- context,
- Manifest.permission.ACCESS_LOCATION_EXTRA_COMMANDS
+ context, Manifest.permission.ACCESS_LOCATION_EXTRA_COMMANDS
) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(
- context,
- Manifest.permission.ACCESS_FINE_LOCATION
+ context, Manifest.permission.ACCESS_FINE_LOCATION
) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(
- context,
- Manifest.permission.ACCESS_COARSE_LOCATION
+ context, Manifest.permission.ACCESS_COARSE_LOCATION
) != PackageManager.PERMISSION_GRANTED
) {
return
@@ -38,7 +59,37 @@
})
}
+ /**
+ * 高德sdk定位
+ */
+ fun obtainLocationByGD(context: Context?, listener: ILocationListener) {
+ locationClient = AMapLocationClient(context)
+ //给定位客户端对象设置定位参数
+ locationClient.setLocationOption(locationOption)
+ //设置定位回调监听
+ locationClient.setLocationListener { aMapLocation ->
+ if (aMapLocation != null) {
+ if (aMapLocation.errorCode == 0) {
+ listener.onAMapLocationGet(aMapLocation)
+ } else {
+ Log.e(
+ kTag,
+ "ErrCode: ${aMapLocation.errorCode}, errInfo: ${aMapLocation.errorInfo}"
+ )
+ }
+ }
+ }
+ //启动定位
+ locationClient.startLocation()
+ }
+
+ fun stopLocation() {
+ locationClient.stopLocation()//停止定位
+ }
+
interface ILocationListener {
- fun onLocationGet(location: Location?) //高德定位数据
+ fun onLocationGet(location: Location?) //GPS定位数据
+
+ fun onAMapLocationGet(aMapLocation: AMapLocation?) //高德定位数据
}
}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/br/ktd/view/InspectionActivity.kt b/app/src/main/java/com/casic/br/ktd/view/InspectionActivity.kt
index 02c47f8..c893092 100644
--- a/app/src/main/java/com/casic/br/ktd/view/InspectionActivity.kt
+++ b/app/src/main/java/com/casic/br/ktd/view/InspectionActivity.kt
@@ -15,16 +15,21 @@
import android.view.SurfaceHolder
import android.view.View
import android.widget.AdapterView
-import com.amap.api.maps.*
+import com.amap.api.location.AMapLocation
+import com.amap.api.maps.AMap
+import com.amap.api.maps.CameraUpdateFactory
+import com.amap.api.maps.UiSettings
import com.amap.api.maps.model.CameraPosition
import com.amap.api.maps.model.LatLng
+import com.amap.api.maps.model.MyLocationStyle
import com.amap.api.maps.model.PolylineOptions
import com.casic.br.ktd.R
import com.casic.br.ktd.extensions.*
import com.casic.br.ktd.model.ChartPointModel
import com.casic.br.ktd.model.RouteModel
import com.casic.br.ktd.model.SensorDataModel
-import com.casic.br.ktd.netty.SocketManager
+import com.casic.br.ktd.netty.tcp.SocketManager
+import com.casic.br.ktd.netty.udp.UdpClient
import com.casic.br.ktd.utils.LocaleConstant
import com.casic.br.ktd.utils.LocationHelper
import com.casic.br.ktd.widgets.AlertControlDialog
@@ -49,6 +54,10 @@
import hcnetsdk.sdkhub.MessageCodeHub
import hcnetsdk.sdkhub.SDKGuider
import kotlinx.android.synthetic.main.activity_inspection.*
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.launch
+import kotlinx.coroutines.withContext
import java.text.DecimalFormat
import java.text.SimpleDateFormat
import java.util.*
@@ -60,10 +69,10 @@
private val hkSDK by lazy { HCNetSDK.getInstance() }
private val timeFormat by lazy { SimpleDateFormat("yyyyMMddHHmmss", Locale.CHINA) }
private val latlngs = LinkedList()
- private val speedTimer by lazy { Timer() }
private val tcpTimer by lazy { Timer() }
private val decimalFormat by lazy { DecimalFormat("##0.0") }
private val gson by lazy { Gson() }
+ private val udpClient by lazy { UdpClient() }
private var isLoginSuccess = false
private var previewHandle = -1
private var selectChannel = -1
@@ -103,28 +112,32 @@
private lateinit var aMap: AMap
private lateinit var uiSettings: UiSettings
+ /**
+ * 协程配置云台设备,缓解新进页面较卡的问题
+ * */
private fun setDeviceConfig() {
- Log.d(kTag, "setDeviceConfig => 配置设备IP和端口")
- val device = SDKGuider.sdkGuider.devManageGuider.DeviceItem()
- device.m_szDevName = ""
- device.m_struNetInfo = SDKGuider.sdkGuider.devManageGuider.DevNetInfo(
- LocaleConstant.HK_NET_IP,
- LocaleConstant.HK_NET_PORT,
- LocaleConstant.HK_NET_USERNAME,
- LocaleConstant.HK_NET_PASSWORD
- )
- if (device.m_szDevName.isEmpty()) {
- device.m_szDevName = device.m_struNetInfo.m_szIp
- }
- isLoginSuccess = if (
- SDKGuider.sdkGuider.devManageGuider.login_v40_jna(
- device.m_szDevName, device.m_struNetInfo
- )
- ) {
- "设备连接成功".show(this)
- true
- } else {
- false
+ CoroutineScope(Dispatchers.Main).launch {
+ isLoginSuccess = withContext(Dispatchers.IO) {
+ Log.d(kTag, "setDeviceConfig => 配置设备IP和端口")
+ val device = SDKGuider.sdkGuider.devManageGuider.DeviceItem()
+ device.m_szDevName = ""
+ device.m_struNetInfo = SDKGuider.sdkGuider.devManageGuider.DevNetInfo(
+ LocaleConstant.HK_NET_IP,
+ LocaleConstant.HK_NET_PORT,
+ LocaleConstant.HK_NET_USERNAME,
+ LocaleConstant.HK_NET_PASSWORD
+ )
+ if (device.m_szDevName.isEmpty()) {
+ device.m_szDevName = device.m_struNetInfo.m_szIp
+ }
+
+ SDKGuider.sdkGuider.devManageGuider.login_v40_jna(
+ device.m_szDevName, device.m_struNetInfo
+ )
+ }
+ if (isLoginSuccess) {
+ "设备连接成功".show(context)
+ }
}
}
@@ -148,17 +161,74 @@
/**
* 手机GPS定位
* */
- val converter = CoordinateConverter(this)
- LocationHelper.obtainCurrentLocation(this, object : LocationHelper.ILocationListener {
+// val converter = CoordinateConverter(this)
+// LocationHelper.get.obtainLocation(this, object : LocationHelper.ILocationListener {
+// override fun onLocationGet(location: Location?) {
+// if (location == null) {
+// "当前信号弱,无法定位".show(context)
+// return
+// }
+//
+// //发送位置信息给UDP服务端
+// udpClient.send("${location.longitude}, ${location.latitude}")
+// Log.d(kTag, "onLocationGet => 速度:${location.speed}")
+//
+// //WGS-84要转为高德坐标系
+// converter.from(CoordinateConverter.CoordType.GPS)
+// converter.coord(LatLng(location.latitude, location.longitude))
+// val latLng = converter.convert()
+// latlngs.add(latLng)
+//
+// //移动到指定经纬度
+// val cameraPosition = CameraPosition(latLng, 13f, 0f, 0f)
+// val cameraUpdate = CameraUpdateFactory.newCameraPosition(cameraPosition)
+// aMap.animateCamera(cameraUpdate, 1500, null)
+//
+// //绘制线
+// aMap.addPolyline(
+// PolylineOptions().addAll(latlngs).width(12f).color(Color.RED)
+// )
+//
+// if (isStartInspect) {
+// val route = LinkedList()
+// latlngs.forEach {
+// route.add(RouteModel(it.latitude, it.longitude))
+// }
+// }
+// }
+//
+// override fun onAMapLocationGet(aMapLocation: AMapLocation?) {
+//
+// }
+// })
+
+ /**
+ * 高德定位
+ * */
+ LocationHelper.get.obtainLocationByGD(this, object : LocationHelper.ILocationListener {
override fun onLocationGet(location: Location?) {
- if (location == null) {
+
+ }
+
+ override fun onAMapLocationGet(aMapLocation: AMapLocation?) {
+ if (aMapLocation == null) {
"当前信号弱,无法定位".show(context)
return
}
+
+ //发送位置信息给UDP服务端
+ udpClient.send(
+ "${aMapLocation.longitude}, ${aMapLocation.latitude}, ${
+ System.currentTimeMillis().timestampToCompleteDate()
+ }"
+ )
+ //速度 转为 km/h
+ Log.d(kTag, "onLocationGet => 速度:${aMapLocation.speed}")
+ speed = decimalFormat.format(aMapLocation.speed * 3.6).toFloat()
+ carSpeedView.text = String.format("${speed}Km/h")
+
//WGS-84要转为高德坐标系
- converter.from(CoordinateConverter.CoordType.GPS)
- converter.coord(LatLng(location.latitude, location.longitude))
- val latLng = converter.convert()
+ val latLng = LatLng(aMapLocation.latitude, aMapLocation.longitude)
latlngs.add(latLng)
//移动到指定经纬度
@@ -168,7 +238,7 @@
//绘制线
aMap.addPolyline(
- PolylineOptions().addAll(latlngs).width(12f).color(Color.RED)
+ PolylineOptions().addAll(latlngs).width(10f).color(Color.RED)
)
if (isStartInspect) {
@@ -181,27 +251,6 @@
})
/**
- * 计算速度,微分原理,3s计算一次速度
- * */
- speedTimer.schedule(object : TimerTask() {
- override fun run() {
- //经纬度链表数据小于2,无法计算速度,默认为0
- speed = if (latlngs.size < 2) 0.0f else {
- val temp = AMapUtils.calculateLineDistance(
- latlngs.last(), latlngs[latlngs.size - 2]
- ) / 3
- //转为 km/h
- decimalFormat.format(temp * 3.6).toFloat()
- }
-
- //切换到UI线程更新界面数据
- runOnUiThread {
- carSpeedView.text = String.format("${speed}Km/h")
- }
- }
- }, 0, 3000)
-
- /**
* TCP初始化
* ***/
SocketManager.instance.connectNetty(
@@ -632,6 +681,8 @@
stopPreview()
BroadcastManager.obtainInstance(this).destroy(LocaleConstant.ACTION_UPDATE_DATA)
mapView.onDestroy()
+ udpClient.release()
+ LocationHelper.get.stopLocation()
}
override fun handleMessage(msg: Message): Boolean {
@@ -716,38 +767,13 @@
uiSettings.isZoomControlsEnabled = true
uiSettings.isTiltGesturesEnabled = false//不许地图随手势倾斜角度
-// val locationStyle = MyLocationStyle()
-// locationStyle.interval(2000)
-// locationStyle.showMyLocation(true)
-// locationStyle.myLocationType(MyLocationStyle.LOCATION_TYPE_LOCATION_ROTATE)
-// aMap.myLocationStyle = locationStyle
-// aMap.isMyLocationEnabled = true
-// aMap.animateCamera(CameraUpdateFactory.zoomTo(13f))
-// aMap.setOnMyLocationChangeListener(this)
+ //显示定位小蓝点
+ val locationStyle = MyLocationStyle()
+ locationStyle.showMyLocation(true)//设置是否显示定位小蓝点
+ aMap.myLocationStyle = locationStyle
+ aMap.isMyLocationEnabled = true
}
-// override fun onMyLocationChange(aMapLocation: Location?) {
-// if (aMapLocation == null) {
-// "当前信号弱,无法定位".show(context)
-// return
-// }
-// val latitude = aMapLocation.latitude
-// val longitude = aMapLocation.longitude
-// latlngs.add(LatLng(latitude, longitude))
-//
-// //绘制线
-// aMap.addPolyline(
-// PolylineOptions().addAll(latlngs).width(15f).color(Color.RED)
-// )
-//
-// if (isStartInspect) {
-// val route = LinkedList()
-// latlngs.forEach {
-// route.add(RouteModel(it.latitude, it.longitude))
-// }
-// }
-// }
-
/***以下是地图生命周期管理************************************************************************/
override fun onResume() {
diff --git a/app/src/main/res/layout/fragment_alarm.xml b/app/src/main/res/layout/fragment_alarm.xml
index a3ebc88..929529f 100644
--- a/app/src/main/res/layout/fragment_alarm.xml
+++ b/app/src/main/res/layout/fragment_alarm.xml
@@ -31,7 +31,7 @@
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index e822df6..d72c1a5 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -7,6 +7,9 @@
+
+
+
@@ -46,5 +49,8 @@
+
+
+
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/br/ktd/base/KotlinBaseFragment.kt b/app/src/main/java/com/casic/br/ktd/base/KotlinBaseFragment.kt
new file mode 100644
index 0000000..2dac61c
--- /dev/null
+++ b/app/src/main/java/com/casic/br/ktd/base/KotlinBaseFragment.kt
@@ -0,0 +1,51 @@
+package com.casic.br.ktd.base
+
+import android.os.Bundle
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import androidx.annotation.LayoutRes
+import androidx.fragment.app.Fragment
+
+abstract class KotlinBaseFragment : Fragment() {
+
+ lateinit var bv: View
+
+ override fun onCreateView(
+ inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?
+ ): View? {
+ bv = inflater.inflate(initLayoutRes(), container, false)
+ initView(savedInstanceState)
+ setupTopBarLayout()
+ return bv
+ }
+
+ override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
+ super.onViewCreated(view, savedInstanceState)
+ observeRequestState()
+ initEvent()
+ }
+
+ @LayoutRes
+ abstract fun initLayoutRes(): Int
+
+ /**
+ * 沉浸式状态栏
+ */
+ abstract fun setupTopBarLayout()
+
+ /**
+ * 初始化布局以及控件
+ */
+ abstract fun initView(savedInstanceState: Bundle?)
+
+ /**
+ * 网络请求状态监听
+ */
+ abstract fun observeRequestState()
+
+ /**
+ * 业务逻辑,按钮等事件
+ */
+ abstract fun initEvent()
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/br/ktd/fragment/AlarmPageFragment.kt b/app/src/main/java/com/casic/br/ktd/fragment/AlarmPageFragment.kt
index 6c98a3b..9418169 100644
--- a/app/src/main/java/com/casic/br/ktd/fragment/AlarmPageFragment.kt
+++ b/app/src/main/java/com/casic/br/ktd/fragment/AlarmPageFragment.kt
@@ -2,28 +2,29 @@
import android.os.Bundle
import com.casic.br.ktd.R
+import com.casic.br.ktd.base.KotlinBaseFragment
import com.casic.br.ktd.widgets.DateRangeActionSheet
-import com.pengxh.kt.lite.base.KotlinBaseFragment
import kotlinx.android.synthetic.main.fragment_alarm.view.*
class AlarmPageFragment : KotlinBaseFragment() {
- override fun initData(savedInstanceState: Bundle?) {
+
+ override fun initView(savedInstanceState: Bundle?) {
}
override fun initEvent() {
- baseView.calendarView.setOnClickListener {
+ bv.calendarView.setOnClickListener {
DateRangeActionSheet.Builder().setContext(requireContext())
.setOnActionSheetListener(object :
DateRangeActionSheet.OnDateRangeSelectedListener {
override fun onDateRangeSelected(startDate: String, endDate: String) {
- baseView.selectedDateView.text = "$startDate ~ $endDate"
+ bv.selectedDateView.text = "$startDate ~ $endDate"
}
}).build().show()
}
}
- override fun initLayoutView(): Int = R.layout.fragment_alarm
+ override fun initLayoutRes(): Int = R.layout.fragment_alarm
override fun observeRequestState() {
diff --git a/app/src/main/java/com/casic/br/ktd/fragment/HomePageFragment.kt b/app/src/main/java/com/casic/br/ktd/fragment/HomePageFragment.kt
index 9961935..f3eba5c 100644
--- a/app/src/main/java/com/casic/br/ktd/fragment/HomePageFragment.kt
+++ b/app/src/main/java/com/casic/br/ktd/fragment/HomePageFragment.kt
@@ -1,32 +1,62 @@
package com.casic.br.ktd.fragment
+import android.graphics.Color
import android.os.Bundle
import com.amap.api.maps.AMap
import com.amap.api.maps.AMapOptions
+import com.amap.api.maps.CameraUpdateFactory
+import com.amap.api.maps.model.*
import com.casic.br.ktd.R
-import com.pengxh.kt.lite.base.KotlinBaseFragment
+import com.casic.br.ktd.base.KotlinBaseFragment
import kotlinx.android.synthetic.main.fragment_home.view.*
class HomePageFragment : KotlinBaseFragment() {
private lateinit var aMap: AMap
- override fun initData(savedInstanceState: Bundle?) {
- baseView.mapView.onCreate(savedInstanceState)
- aMap = baseView.mapView.map
+ override fun initView(savedInstanceState: Bundle?) {
+ bv.mapView.onCreate(savedInstanceState)
+ aMap = bv.mapView.map
val uiSettings = aMap.uiSettings
uiSettings.isCompassEnabled = true
- uiSettings.isMyLocationButtonEnabled = true
+ uiSettings.isMyLocationButtonEnabled = false
uiSettings.isScaleControlsEnabled = true
uiSettings.zoomPosition = AMapOptions.ZOOM_POSITION_RIGHT_CENTER
uiSettings.isRotateGesturesEnabled = false//不许地图随手势旋转角度
}
override fun initEvent() {
-
+ //移动到巡检起始经纬度
+ val cameraPosition = CameraPosition(LatLng(39.914199, 116.265785), 16f, 0f, 0f)
+ val cameraUpdate = CameraUpdateFactory.newCameraPosition(cameraPosition)
+ aMap.animateCamera(cameraUpdate, 1500, null)
+ //设置起点
+ addMarker(LatLng(39.914885, 116.272312), R.mipmap.start)
+ //设置终点
+ addMarker(LatLng(39.914716, 116.265097), R.mipmap.end)
+ //瞄点画线
+ val latLngPoints = ArrayList()
+ latLngPoints.add(LatLng(39.914885, 116.272312))
+ latLngPoints.add(LatLng(39.915148, 116.272312))
+ latLngPoints.add(LatLng(39.915399, 116.272302))
+ latLngPoints.add(LatLng(39.915436, 116.271787))
+ latLngPoints.add(LatLng(39.915477, 116.270886))
+ latLngPoints.add(LatLng(39.915477, 116.269968))
+ latLngPoints.add(LatLng(39.915469, 116.269544))
+ latLngPoints.add(LatLng(39.915481, 116.269196))
+ latLngPoints.add(LatLng(39.915452, 116.268472))
+ latLngPoints.add(LatLng(39.915444, 116.267722))
+ latLngPoints.add(LatLng(39.915415, 116.266755))
+ latLngPoints.add(LatLng(39.915403, 116.266165))
+ latLngPoints.add(LatLng(39.915395, 116.265703))
+ latLngPoints.add(LatLng(39.915366, 116.265119))
+ latLngPoints.add(LatLng(39.914716, 116.265097))
+ aMap.addPolyline(
+ PolylineOptions().addAll(latLngPoints).width(10.toFloat()).color(Color.RED)
+ )
}
- override fun initLayoutView(): Int = R.layout.fragment_home
+ override fun initLayoutRes(): Int = R.layout.fragment_home
override fun observeRequestState() {
@@ -36,25 +66,32 @@
}
+ private fun addMarker(point: LatLng, res: Int) {
+ val markerOption = MarkerOptions()
+ markerOption.position(point)
+ markerOption.icon(BitmapDescriptorFactory.fromResource(res))
+ aMap.addMarker(markerOption)
+ }
+
/***以下是地图生命周期管理************************************************************************/
override fun onResume() {
super.onResume()
- baseView.mapView.onResume()
+ bv.mapView.onResume()
}
override fun onPause() {
- baseView.mapView.onPause()
super.onPause()
+ bv.mapView.onPause()
}
override fun onSaveInstanceState(outState: Bundle) {
super.onSaveInstanceState(outState)
- baseView.mapView.onSaveInstanceState(outState)
+ bv.mapView.onSaveInstanceState(outState)
}
override fun onDestroy() {
- baseView.mapView.onDestroy()
super.onDestroy()
+ bv.mapView.onDestroy()
}
}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/br/ktd/fragment/MinePageFragment.kt b/app/src/main/java/com/casic/br/ktd/fragment/MinePageFragment.kt
index 90313ac..3212794 100644
--- a/app/src/main/java/com/casic/br/ktd/fragment/MinePageFragment.kt
+++ b/app/src/main/java/com/casic/br/ktd/fragment/MinePageFragment.kt
@@ -2,10 +2,11 @@
import android.os.Bundle
import com.casic.br.ktd.R
-import com.pengxh.kt.lite.base.KotlinBaseFragment
+import com.casic.br.ktd.base.KotlinBaseFragment
class MinePageFragment : KotlinBaseFragment() {
- override fun initData(savedInstanceState: Bundle?) {
+
+ override fun initView(savedInstanceState: Bundle?) {
}
@@ -13,7 +14,7 @@
}
- override fun initLayoutView(): Int = R.layout.fragment_mine
+ override fun initLayoutRes(): Int = R.layout.fragment_mine
override fun observeRequestState() {
diff --git a/app/src/main/java/com/casic/br/ktd/fragment/TaskPageFragment.kt b/app/src/main/java/com/casic/br/ktd/fragment/TaskPageFragment.kt
index 8f6abf0..6b82a54 100644
--- a/app/src/main/java/com/casic/br/ktd/fragment/TaskPageFragment.kt
+++ b/app/src/main/java/com/casic/br/ktd/fragment/TaskPageFragment.kt
@@ -8,6 +8,7 @@
import androidx.recyclerview.widget.RecyclerView
import com.casic.br.ktd.R
import com.casic.br.ktd.adapter.TaskAdapter
+import com.casic.br.ktd.base.KotlinBaseFragment
import com.casic.br.ktd.holder.SwipeViewHolder
import com.casic.br.ktd.model.TaskListModel
import com.casic.br.ktd.view.InspectionActivity
@@ -15,7 +16,6 @@
import com.casic.br.ktd.widgets.AlertControlDialog
import com.casic.br.ktd.widgets.AlertInputDialog
import com.casic.br.ktd.widgets.DateRangeActionSheet
-import com.pengxh.kt.lite.base.KotlinBaseFragment
import com.pengxh.kt.lite.extensions.navigatePageTo
import com.pengxh.kt.lite.extensions.show
import com.pengxh.kt.lite.utils.WeakReferenceHandler
@@ -36,7 +36,7 @@
private var startTime = ""
private var endTime = ""
- override fun initData(savedInstanceState: Bundle?) {
+ override fun initView(savedInstanceState: Bundle?) {
weakReferenceHandler = WeakReferenceHandler(this)
taskViewModel = ViewModelProvider(this)[TaskViewModel::class.java]
taskViewModel.taskList.observe(this) {
@@ -45,7 +45,7 @@
when {
isRefresh -> {
taskAdapter.setRefreshData(dataRows)
- baseView.taskLayout.finishRefresh()
+ bv.taskLayout.finishRefresh()
isRefresh = false
}
isLoadMore -> {
@@ -53,7 +53,7 @@
"到底了,别拉了".show(requireContext())
}
taskAdapter.setLoadMoreData(dataRows)
- baseView.taskLayout.finishLoadMore()
+ bv.taskLayout.finishLoadMore()
isLoadMore = false
}
else -> {
@@ -76,9 +76,9 @@
when (msg.what) {
2023070501 -> {
if (dataBeans.size == 0) {
- baseView.emptyLayout.visibility = View.VISIBLE
+ bv.emptyLayout.visibility = View.VISIBLE
} else {
- baseView.emptyLayout.visibility = View.GONE
+ bv.emptyLayout.visibility = View.GONE
taskAdapter = object : TaskAdapter(
requireContext(), R.layout.item_task_rv_l, dataBeans
) {
@@ -97,8 +97,8 @@
}
}
//绑定侧滑事件
- swipeAction.attachToRecyclerView(baseView.taskRecyclerView)
- baseView.taskRecyclerView.adapter = taskAdapter
+ swipeAction.attachToRecyclerView(bv.taskRecyclerView)
+ bv.taskRecyclerView.adapter = taskAdapter
taskAdapter.setOnItemCheckedListener(object :
TaskAdapter.OnItemCheckedListener {
override fun onItemChecked(items: ArrayList) {
@@ -168,7 +168,7 @@
override fun initEvent() {
- baseView.calendarView.setOnClickListener {
+ bv.calendarView.setOnClickListener {
DateRangeActionSheet.Builder().setContext(requireContext())
.setOnActionSheetListener(object :
DateRangeActionSheet.OnDateRangeSelectedListener {
@@ -177,12 +177,12 @@
endTime = endDate
//显示
- baseView.selectedDateView.text = "$startDate ~ $endDate"
+ bv.selectedDateView.text = "$startDate ~ $endDate"
}
}).build().show()
}
- baseView.addTaskButton.setOnClickListener {
+ bv.addTaskButton.setOnClickListener {
// AlertInputDialog.Builder()
// .setContext(requireContext())
// .setTitle("新建巡检任务")
@@ -200,11 +200,11 @@
requireContext().navigatePageTo()
}
- baseView.deleteTaskButton.setOnClickListener {
+ bv.deleteTaskButton.setOnClickListener {
selectedItems.size.toString().show(requireContext())
}
- baseView.taskSettingsButton.setOnClickListener {
+ bv.taskSettingsButton.setOnClickListener {
AlertInputDialog.Builder()
.setContext(requireContext())
.setTitle("设置阈值")
@@ -221,14 +221,14 @@
}).build().show()
}
- baseView.taskLayout.setOnRefreshListener {
+ bv.taskLayout.setOnRefreshListener {
isRefresh = true
//刷新之后页码重置
pageIndex = 1
getTaskList()
}
- baseView.taskLayout.setOnLoadMoreListener {
+ bv.taskLayout.setOnLoadMoreListener {
isLoadMore = true
pageIndex++
getTaskList()
@@ -239,13 +239,13 @@
taskViewModel.getTaskList(
startTime,
endTime,
- baseView.taskNameView.text.toString(),
- baseView.taskCodeView.text.toString(),
+ bv.taskNameView.text.toString(),
+ bv.taskCodeView.text.toString(),
pageIndex
)
}
- override fun initLayoutView(): Int = R.layout.fragment_task
+ override fun initLayoutRes(): Int = R.layout.fragment_task
override fun observeRequestState() {
diff --git a/app/src/main/java/com/casic/br/ktd/netty/ISocketListener.kt b/app/src/main/java/com/casic/br/ktd/netty/ISocketListener.kt
deleted file mode 100644
index dab98e1..0000000
--- a/app/src/main/java/com/casic/br/ktd/netty/ISocketListener.kt
+++ /dev/null
@@ -1,19 +0,0 @@
-package com.casic.br.ktd.netty
-
-interface ISocketListener {
- companion object {
- const val STATUS_CONNECT_SUCCESS: Byte = 1 //连接成功
- const val STATUS_CONNECT_CLOSED: Byte = 0 //关闭连接
- const val STATUS_CONNECT_ERROR: Byte = 0 //连接失败
- }
-
- /**
- * 当接收到系统消息
- */
- fun onMessageResponse(data: ByteArray?)
-
- /**
- * 当连接状态发生变化时调用
- */
- fun onServiceStatusConnectChanged(statusCode: Byte)
-}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/br/ktd/netty/SocketChannelHandle.kt b/app/src/main/java/com/casic/br/ktd/netty/SocketChannelHandle.kt
deleted file mode 100644
index 42eb310..0000000
--- a/app/src/main/java/com/casic/br/ktd/netty/SocketChannelHandle.kt
+++ /dev/null
@@ -1,51 +0,0 @@
-package com.casic.br.ktd.netty
-
-import android.util.Log
-import io.netty.channel.ChannelHandlerContext
-import io.netty.channel.SimpleChannelInboundHandler
-import io.netty.handler.timeout.IdleState
-import io.netty.handler.timeout.IdleStateEvent
-import java.nio.charset.StandardCharsets
-
-class SocketChannelHandle(private val listener: ISocketListener?) :
- SimpleChannelInboundHandler() {
-
- private val kTag = "SocketChannelHandle"
-
- override fun channelActive(ctx: ChannelHandlerContext) {
- super.channelActive(ctx)
- Log.d(kTag, "channelActive ===> 连接成功")
- listener?.onServiceStatusConnectChanged(ISocketListener.STATUS_CONNECT_SUCCESS)
- }
-
- override fun channelInactive(ctx: ChannelHandlerContext) {
- super.channelInactive(ctx)
- Log.e(kTag, "channelInactive: 连接断开")
- }
-
- override fun userEventTriggered(ctx: ChannelHandlerContext, evt: Any) {
- super.userEventTriggered(ctx, evt)
- if (evt is IdleStateEvent) {
- if (evt.state() == IdleState.WRITER_IDLE) {
- //写超时,此时可以发送心跳数据给服务器
- val temp = "FF"
- ctx.writeAndFlush(temp.toByteArray(StandardCharsets.UTF_8))
- } else if (evt.state() == IdleState.READER_IDLE) {
- //读超时,此时代表没有收到心跳返回可以关闭当前连接进行重连
- ctx.close()
- }
- }
- }
-
- override fun channelRead0(ctx: ChannelHandlerContext, data: ByteArray?) {
- listener?.onMessageResponse(data)
- }
-
- override fun exceptionCaught(ctx: ChannelHandlerContext, cause: Throwable) {
- super.exceptionCaught(ctx, cause)
- Log.d(kTag, "exceptionCaught ===> $cause")
- listener?.onServiceStatusConnectChanged(ISocketListener.STATUS_CONNECT_ERROR)
- cause.printStackTrace()
- ctx.close()
- }
-}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/br/ktd/netty/SocketClient.kt b/app/src/main/java/com/casic/br/ktd/netty/SocketClient.kt
deleted file mode 100644
index d05d335..0000000
--- a/app/src/main/java/com/casic/br/ktd/netty/SocketClient.kt
+++ /dev/null
@@ -1,153 +0,0 @@
-package com.casic.br.ktd.netty
-
-import android.os.SystemClock
-import android.util.Log
-import io.netty.bootstrap.Bootstrap
-import io.netty.channel.*
-import io.netty.channel.nio.NioEventLoopGroup
-import io.netty.channel.socket.SocketChannel
-import io.netty.channel.socket.nio.NioSocketChannel
-import io.netty.handler.codec.bytes.ByteArrayDecoder
-import io.netty.handler.codec.bytes.ByteArrayEncoder
-import io.netty.handler.timeout.IdleStateHandler
-
-class SocketClient {
-
- private val kTag = "SocketClient"
-
- private var host: String? = null
- private var port = 8000
- private var nioEventLoopGroup: NioEventLoopGroup? = null
- private var channel: Channel? = null
- private var listener: ISocketListener? = null
-
- //现在连接的状态
- var connectStatus = false //判断是否已连接
- private var reconnectNum = Int.MAX_VALUE //定义的重连到时候用
- private var isNeedReconnect = true //是否需要重连
- var isConnecting = false //是否正在连接
- private set
- private var reconnectIntervalTime: Long = 15000 //重连的时间
-
- //重连时间
- fun setReconnectNum(reconnectNum: Int) {
- this.reconnectNum = reconnectNum
- }
-
- fun setReconnectIntervalTime(reconnectIntervalTime: Long) {
- this.reconnectIntervalTime = reconnectIntervalTime
- }
-
- fun setSocketListener(listener: ISocketListener?) {
- this.listener = listener
- }
-
- fun connect(host: String, port: Int) {
- this.host = host
- this.port = port
- Log.d(kTag, "connect ===> 开始连接TCP服务器")
- if (isConnecting) {
- return
- }
- //起个线程
- val clientThread: Thread = object : Thread("client-Netty") {
- override fun run() {
- super.run()
- isNeedReconnect = true
- reconnectNum = Int.MAX_VALUE
- connectServer()
- }
- }
- clientThread.start()
- }
-
- private fun connectServer() {
- synchronized(this@SocketClient) {
- var channelFuture: ChannelFuture? = null //连接管理对象
- if (!connectStatus) {
- isConnecting = true
- nioEventLoopGroup = NioEventLoopGroup() //设置的连接group
- val bootstrap = Bootstrap()
- bootstrap.group(nioEventLoopGroup) //设置的一系列连接参数操作等
- .channel(NioSocketChannel::class.java)
- .option(ChannelOption.TCP_NODELAY, true) //无阻塞
- .option(ChannelOption.SO_KEEPALIVE, true) //长连接
- .option(
- ChannelOption.RCVBUF_ALLOCATOR,
- AdaptiveRecvByteBufAllocator(5000, 5000, 8000)
- ) //接收缓冲区 最小值太小时数据接收不全
- .handler(object : ChannelInitializer() {
- override fun initChannel(channel: SocketChannel) {
- val pipeline = channel.pipeline()
- //参数1:代表读套接字超时的时间,没收到数据会触发读超时回调;
- //参数2:代表写套接字超时时间,没进行写会触发写超时回调;
- //参数3:将在未执行读取或写入时触发超时回调,0代表不处理;
- //读超时尽量设置大于写超时,代表多次写超时时写心跳包,多次写了心跳数据仍然读超时代表当前连接错误,即可断开连接重新连接
- pipeline.addLast(IdleStateHandler(60, 10, 0))
- pipeline.addLast(ByteArrayDecoder())
- pipeline.addLast(ByteArrayEncoder())
- pipeline.addLast(SocketChannelHandle(listener))
- }
- })
- try {
- //连接监听
- channelFuture = bootstrap.connect(host, port)
- .addListener(object : ChannelFutureListener {
- override fun operationComplete(channelFuture: ChannelFuture) {
- if (channelFuture.isSuccess) {
- connectStatus = true
- channel = channelFuture.channel()
- } else {
- Log.e(kTag, "operationComplete: 连接失败")
- connectStatus = false
- }
- isConnecting = false
- }
- }).sync()
- // 等待连接关闭
- channelFuture.channel().closeFuture().sync()
- } catch (e: Exception) {
- e.printStackTrace()
- } finally {
- connectStatus = false
- listener?.onServiceStatusConnectChanged(ISocketListener.STATUS_CONNECT_CLOSED) //STATUS_CONNECT_CLOSED 这我自己定义的 接口标识
- if (null != channelFuture) {
- if (channelFuture.channel() != null && channelFuture.channel().isOpen) {
- channelFuture.channel().close()
- }
- }
- nioEventLoopGroup?.shutdownGracefully()
- reconnect() //重新连接
- }
- }
- }
- }
-
- //断开连接
- fun disconnect() {
- Log.d(kTag, "disconnect ===> 断开连接")
- isNeedReconnect = false
- nioEventLoopGroup?.shutdownGracefully()
- }
-
- //重新连接
- private fun reconnect() {
- if (isNeedReconnect && reconnectNum > 0 && !connectStatus) {
- reconnectNum--
- SystemClock.sleep(reconnectIntervalTime)
- if (isNeedReconnect && reconnectNum > 0 && !connectStatus) {
- Log.d(kTag, "reconnect ===> 重新连接")
- connectServer()
- }
- }
- }
-
- fun sendData(bytes: ByteArray) {
- channel?.writeAndFlush(bytes)?.addListener(ChannelFutureListener { future ->
- if (!future.isSuccess) {
- future.channel().close()
- nioEventLoopGroup!!.shutdownGracefully()
- }
- })
- }
-}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/br/ktd/netty/SocketManager.kt b/app/src/main/java/com/casic/br/ktd/netty/SocketManager.kt
deleted file mode 100644
index 17daf35..0000000
--- a/app/src/main/java/com/casic/br/ktd/netty/SocketManager.kt
+++ /dev/null
@@ -1,113 +0,0 @@
-package com.casic.br.ktd.netty
-
-import android.util.Log
-import com.casic.br.ktd.base.BaseApplication
-import com.casic.br.ktd.extensions.covertAngleValue
-import com.casic.br.ktd.extensions.covertDataValue
-import com.casic.br.ktd.extensions.toUnsignedByteArray
-import com.casic.br.ktd.model.SensorDataModel
-import com.casic.br.ktd.utils.LocaleConstant
-import com.pengxh.kt.lite.extensions.toJson
-import com.pengxh.kt.lite.utils.BroadcastManager
-
-class SocketManager private constructor() : ISocketListener {
-
- private val kTag = "SocketManager"
- private var nettyClient: SocketClient = SocketClient()
-
- companion object {
- val instance: SocketManager by lazy(mode = LazyThreadSafetyMode.SYNCHRONIZED) { SocketManager() }
- }
-
- fun connectNetty(hostname: String, port: Int) {
- Thread {
- if (!nettyClient.connectStatus) {
- nettyClient.setSocketListener(this)
- nettyClient.connect(hostname, port)
- } else {
- nettyClient.disconnect()
- }
- }.start()
- }
-
- override fun onMessageResponse(data: ByteArray?) {
-// Log.d(kTag, "onMessageResponse ===> " + Arrays.toString(data))
- /**
- * 0xFF,0x01,
- * 0x01,0x37,0xE6, 甲烷浓度值(数据码1* 65536 + 数据码2 * 256 + 数据码3)
- * 0x00, 激光甲烷模块工作状态(00表示设备正常,01表示温控故障,02表示设备激光未打开)
- * 0x00,0xB2,0x35, 激光强度值(数据码5* 65536 + 数据码6 * 256 + 数据码7)
- * 0x0A,0x3D, 云台水平角度([数据码8 * 256 + 数据码9]/100,单位为°,精确到0.01)
- * 0x05,0x6F, 云台垂直角度(首先计算Tangle=[数据码10 * 256 + 数据码11]/100,单位为°,精确到0.01。若Tangle在0~90范围内,则垂直角度值=Tangle;若Tangle在-1~-90范围内,则垂直角度值=Tangle-360)
- * 0xC1
- *
- * [-1, 1, 1, 55, -26, 0, 0, -78, 53, 10, 61, 5, 111, -63]
- * 甲烷浓度值为79638,计算为79638=0x01*65536+0x37*256+0xE6[0x01为数据码1,0x37为数据码2,0xE6为数据码3];
- * 激光甲烷设备状态值为0,表示状态正常,[0x00为数据码4];
- * 激光强度值为45621,计算为45621=0x00*65536+0xB2*256+0x35[0x00为数据码5,0xB2为数据码6,0x35为数据码7];
- *
- * =========================================================================================
- * 实际数据(1800-1950左右)
- * [-86, 1, 0, 7, 71, 0, 0, 62, -92, 57, 59, -118, -111, -64]
- * */
-
- if (data == null) {
- return
- }
- val bytes = data.toUnsignedByteArray()
- if (bytes.size == 14) {
- val dataModel = SensorDataModel(0, "激光未打开", 0, 0.0, 0.0)
-
- val methaneBytes = IntArray(3)
- System.arraycopy(bytes, 2, methaneBytes, 0, 3)
- dataModel.methane = methaneBytes.covertDataValue()
-
- dataModel.methaneState = when (bytes[5]) {
- 1 -> "温控故障"
- 2 -> "激光未打开"
- else -> "正常"
- }
-
- val laserBytes = IntArray(3)
- System.arraycopy(bytes, 6, laserBytes, 0, 3)
- dataModel.laser = laserBytes.covertDataValue()
-
- /**
- * 水平角度的实际范围为从水平零点开始,顺时针方向(从上往下看),0~360°
- * 垂直角度的实际范围为从垂直零点开始,以向上为正,-90°~90°,控制精度为0.01°
- * */
- val horizontalBytes = IntArray(2)
- System.arraycopy(bytes, 9, horizontalBytes, 0, 2)
- dataModel.horizontal = horizontalBytes.covertAngleValue()
-
- val verticalBytes = IntArray(2)
- System.arraycopy(bytes, 11, verticalBytes, 0, 2)
- dataModel.vertical = verticalBytes.covertAngleValue()
-
- //{"horizontal":26.21,"laser":45621,"methane":79846,"methaneState":"正常","vertical":13.91}
- BroadcastManager.obtainInstance(BaseApplication.get()).sendBroadcast(
- LocaleConstant.ACTION_UPDATE_DATA, dataModel.toJson()
- )
- }
- }
-
- override fun onServiceStatusConnectChanged(statusCode: Byte) {
- if (statusCode == ISocketListener.STATUS_CONNECT_SUCCESS) {
- if (nettyClient.connectStatus) {
- Log.d(kTag, "连接成功")
- }
- } else {
- if (!nettyClient.connectStatus) {
- Log.e(kTag, "onServiceStatusConnectChanged:$statusCode,连接断开,正在重连")
- }
- }
- }
-
- fun sendData(data: ByteArray) {
- nettyClient.sendData(data)
- }
-
- fun close() {
- nettyClient.disconnect()
- }
-}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/br/ktd/netty/tcp/ISocketListener.kt b/app/src/main/java/com/casic/br/ktd/netty/tcp/ISocketListener.kt
new file mode 100644
index 0000000..13c3084
--- /dev/null
+++ b/app/src/main/java/com/casic/br/ktd/netty/tcp/ISocketListener.kt
@@ -0,0 +1,19 @@
+package com.casic.br.ktd.netty.tcp
+
+interface ISocketListener {
+ companion object {
+ const val STATUS_CONNECT_SUCCESS: Byte = 1 //连接成功
+ const val STATUS_CONNECT_CLOSED: Byte = 0 //关闭连接
+ const val STATUS_CONNECT_ERROR: Byte = 0 //连接失败
+ }
+
+ /**
+ * 当接收到系统消息
+ */
+ fun onMessageResponse(data: ByteArray?)
+
+ /**
+ * 当连接状态发生变化时调用
+ */
+ fun onServiceStatusConnectChanged(statusCode: Byte)
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/br/ktd/netty/tcp/SocketChannelHandle.kt b/app/src/main/java/com/casic/br/ktd/netty/tcp/SocketChannelHandle.kt
new file mode 100644
index 0000000..8e2997f
--- /dev/null
+++ b/app/src/main/java/com/casic/br/ktd/netty/tcp/SocketChannelHandle.kt
@@ -0,0 +1,51 @@
+package com.casic.br.ktd.netty.tcp
+
+import android.util.Log
+import io.netty.channel.ChannelHandlerContext
+import io.netty.channel.SimpleChannelInboundHandler
+import io.netty.handler.timeout.IdleState
+import io.netty.handler.timeout.IdleStateEvent
+import java.nio.charset.StandardCharsets
+
+class SocketChannelHandle(private val listener: ISocketListener?) :
+ SimpleChannelInboundHandler() {
+
+ private val kTag = "SocketChannelHandle"
+
+ override fun channelActive(ctx: ChannelHandlerContext) {
+ super.channelActive(ctx)
+ Log.d(kTag, "channelActive ===> 连接成功")
+ listener?.onServiceStatusConnectChanged(ISocketListener.STATUS_CONNECT_SUCCESS)
+ }
+
+ override fun channelInactive(ctx: ChannelHandlerContext) {
+ super.channelInactive(ctx)
+ Log.e(kTag, "channelInactive: 连接断开")
+ }
+
+ override fun userEventTriggered(ctx: ChannelHandlerContext, evt: Any) {
+ super.userEventTriggered(ctx, evt)
+ if (evt is IdleStateEvent) {
+ if (evt.state() == IdleState.WRITER_IDLE) {
+ //写超时,此时可以发送心跳数据给服务器
+ val temp = "FF"
+ ctx.writeAndFlush(temp.toByteArray(StandardCharsets.UTF_8))
+ } else if (evt.state() == IdleState.READER_IDLE) {
+ //读超时,此时代表没有收到心跳返回可以关闭当前连接进行重连
+ ctx.close()
+ }
+ }
+ }
+
+ override fun channelRead0(ctx: ChannelHandlerContext, data: ByteArray?) {
+ listener?.onMessageResponse(data)
+ }
+
+ override fun exceptionCaught(ctx: ChannelHandlerContext, cause: Throwable) {
+ super.exceptionCaught(ctx, cause)
+ Log.d(kTag, "exceptionCaught ===> $cause")
+ listener?.onServiceStatusConnectChanged(ISocketListener.STATUS_CONNECT_ERROR)
+ cause.printStackTrace()
+ ctx.close()
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/br/ktd/netty/tcp/SocketClient.kt b/app/src/main/java/com/casic/br/ktd/netty/tcp/SocketClient.kt
new file mode 100644
index 0000000..34960a0
--- /dev/null
+++ b/app/src/main/java/com/casic/br/ktd/netty/tcp/SocketClient.kt
@@ -0,0 +1,153 @@
+package com.casic.br.ktd.netty.tcp
+
+import android.os.SystemClock
+import android.util.Log
+import io.netty.bootstrap.Bootstrap
+import io.netty.channel.*
+import io.netty.channel.nio.NioEventLoopGroup
+import io.netty.channel.socket.SocketChannel
+import io.netty.channel.socket.nio.NioSocketChannel
+import io.netty.handler.codec.bytes.ByteArrayDecoder
+import io.netty.handler.codec.bytes.ByteArrayEncoder
+import io.netty.handler.timeout.IdleStateHandler
+
+class SocketClient {
+
+ private val kTag = "SocketClient"
+
+ private var host: String? = null
+ private var port = 8000
+ private var nioEventLoopGroup: NioEventLoopGroup? = null
+ private var channel: Channel? = null
+ private var listener: ISocketListener? = null
+
+ //现在连接的状态
+ var connectStatus = false //判断是否已连接
+ private var reconnectNum = Int.MAX_VALUE //定义的重连到时候用
+ private var isNeedReconnect = true //是否需要重连
+ var isConnecting = false //是否正在连接
+ private set
+ private var reconnectIntervalTime: Long = 15000 //重连的时间
+
+ //重连时间
+ fun setReconnectNum(reconnectNum: Int) {
+ this.reconnectNum = reconnectNum
+ }
+
+ fun setReconnectIntervalTime(reconnectIntervalTime: Long) {
+ this.reconnectIntervalTime = reconnectIntervalTime
+ }
+
+ fun setSocketListener(listener: ISocketListener?) {
+ this.listener = listener
+ }
+
+ fun connect(host: String, port: Int) {
+ this.host = host
+ this.port = port
+ Log.d(kTag, "connect ===> 开始连接TCP服务器")
+ if (isConnecting) {
+ return
+ }
+ //起个线程
+ val clientThread: Thread = object : Thread("client-Netty") {
+ override fun run() {
+ super.run()
+ isNeedReconnect = true
+ reconnectNum = Int.MAX_VALUE
+ connectServer()
+ }
+ }
+ clientThread.start()
+ }
+
+ private fun connectServer() {
+ synchronized(this@SocketClient) {
+ var channelFuture: ChannelFuture? = null //连接管理对象
+ if (!connectStatus) {
+ isConnecting = true
+ nioEventLoopGroup = NioEventLoopGroup() //设置的连接group
+ val bootstrap = Bootstrap()
+ bootstrap.group(nioEventLoopGroup) //设置的一系列连接参数操作等
+ .channel(NioSocketChannel::class.java)
+ .option(ChannelOption.TCP_NODELAY, true) //无阻塞
+ .option(ChannelOption.SO_KEEPALIVE, true) //长连接
+ .option(
+ ChannelOption.RCVBUF_ALLOCATOR,
+ AdaptiveRecvByteBufAllocator(5000, 5000, 8000)
+ ) //接收缓冲区 最小值太小时数据接收不全
+ .handler(object : ChannelInitializer() {
+ override fun initChannel(channel: SocketChannel) {
+ val pipeline = channel.pipeline()
+ //参数1:代表读套接字超时的时间,没收到数据会触发读超时回调;
+ //参数2:代表写套接字超时时间,没进行写会触发写超时回调;
+ //参数3:将在未执行读取或写入时触发超时回调,0代表不处理;
+ //读超时尽量设置大于写超时,代表多次写超时时写心跳包,多次写了心跳数据仍然读超时代表当前连接错误,即可断开连接重新连接
+ pipeline.addLast(IdleStateHandler(60, 10, 0))
+ pipeline.addLast(ByteArrayDecoder())
+ pipeline.addLast(ByteArrayEncoder())
+ pipeline.addLast(SocketChannelHandle(listener))
+ }
+ })
+ try {
+ //连接监听
+ channelFuture = bootstrap.connect(host, port)
+ .addListener(object : ChannelFutureListener {
+ override fun operationComplete(channelFuture: ChannelFuture) {
+ if (channelFuture.isSuccess) {
+ connectStatus = true
+ channel = channelFuture.channel()
+ } else {
+ Log.e(kTag, "operationComplete: 连接失败")
+ connectStatus = false
+ }
+ isConnecting = false
+ }
+ }).sync()
+ // 等待连接关闭
+ channelFuture.channel().closeFuture().sync()
+ } catch (e: Exception) {
+ e.printStackTrace()
+ } finally {
+ connectStatus = false
+ listener?.onServiceStatusConnectChanged(ISocketListener.STATUS_CONNECT_CLOSED) //STATUS_CONNECT_CLOSED 这我自己定义的 接口标识
+ if (null != channelFuture) {
+ if (channelFuture.channel() != null && channelFuture.channel().isOpen) {
+ channelFuture.channel().close()
+ }
+ }
+ nioEventLoopGroup?.shutdownGracefully()
+ reconnect() //重新连接
+ }
+ }
+ }
+ }
+
+ //断开连接
+ fun disconnect() {
+ Log.d(kTag, "disconnect ===> 断开连接")
+ isNeedReconnect = false
+ nioEventLoopGroup?.shutdownGracefully()
+ }
+
+ //重新连接
+ private fun reconnect() {
+ if (isNeedReconnect && reconnectNum > 0 && !connectStatus) {
+ reconnectNum--
+ SystemClock.sleep(reconnectIntervalTime)
+ if (isNeedReconnect && reconnectNum > 0 && !connectStatus) {
+ Log.d(kTag, "reconnect ===> 重新连接")
+ connectServer()
+ }
+ }
+ }
+
+ fun sendData(bytes: ByteArray) {
+ channel?.writeAndFlush(bytes)?.addListener(ChannelFutureListener { future ->
+ if (!future.isSuccess) {
+ future.channel().close()
+ nioEventLoopGroup!!.shutdownGracefully()
+ }
+ })
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/br/ktd/netty/tcp/SocketManager.kt b/app/src/main/java/com/casic/br/ktd/netty/tcp/SocketManager.kt
new file mode 100644
index 0000000..35980b9
--- /dev/null
+++ b/app/src/main/java/com/casic/br/ktd/netty/tcp/SocketManager.kt
@@ -0,0 +1,113 @@
+package com.casic.br.ktd.netty.tcp
+
+import android.util.Log
+import com.casic.br.ktd.base.BaseApplication
+import com.casic.br.ktd.extensions.covertAngleValue
+import com.casic.br.ktd.extensions.covertDataValue
+import com.casic.br.ktd.extensions.toUnsignedByteArray
+import com.casic.br.ktd.model.SensorDataModel
+import com.casic.br.ktd.utils.LocaleConstant
+import com.pengxh.kt.lite.extensions.toJson
+import com.pengxh.kt.lite.utils.BroadcastManager
+
+class SocketManager private constructor() : ISocketListener {
+
+ private val kTag = "SocketManager"
+ private var nettyClient: SocketClient = SocketClient()
+
+ companion object {
+ val instance: SocketManager by lazy(mode = LazyThreadSafetyMode.SYNCHRONIZED) { SocketManager() }
+ }
+
+ fun connectNetty(hostname: String, port: Int) {
+ Thread {
+ if (!nettyClient.connectStatus) {
+ nettyClient.setSocketListener(this)
+ nettyClient.connect(hostname, port)
+ } else {
+ nettyClient.disconnect()
+ }
+ }.start()
+ }
+
+ override fun onMessageResponse(data: ByteArray?) {
+// Log.d(kTag, "onMessageResponse ===> " + Arrays.toString(data))
+ /**
+ * 0xFF,0x01,
+ * 0x01,0x37,0xE6, 甲烷浓度值(数据码1* 65536 + 数据码2 * 256 + 数据码3)
+ * 0x00, 激光甲烷模块工作状态(00表示设备正常,01表示温控故障,02表示设备激光未打开)
+ * 0x00,0xB2,0x35, 激光强度值(数据码5* 65536 + 数据码6 * 256 + 数据码7)
+ * 0x0A,0x3D, 云台水平角度([数据码8 * 256 + 数据码9]/100,单位为°,精确到0.01)
+ * 0x05,0x6F, 云台垂直角度(首先计算Tangle=[数据码10 * 256 + 数据码11]/100,单位为°,精确到0.01。若Tangle在0~90范围内,则垂直角度值=Tangle;若Tangle在-1~-90范围内,则垂直角度值=Tangle-360)
+ * 0xC1
+ *
+ * [-1, 1, 1, 55, -26, 0, 0, -78, 53, 10, 61, 5, 111, -63]
+ * 甲烷浓度值为79638,计算为79638=0x01*65536+0x37*256+0xE6[0x01为数据码1,0x37为数据码2,0xE6为数据码3];
+ * 激光甲烷设备状态值为0,表示状态正常,[0x00为数据码4];
+ * 激光强度值为45621,计算为45621=0x00*65536+0xB2*256+0x35[0x00为数据码5,0xB2为数据码6,0x35为数据码7];
+ *
+ * =========================================================================================
+ * 实际数据(1800-1950左右)
+ * [-86, 1, 0, 7, 71, 0, 0, 62, -92, 57, 59, -118, -111, -64]
+ * */
+
+ if (data == null) {
+ return
+ }
+ val bytes = data.toUnsignedByteArray()
+ if (bytes.size == 14) {
+ val dataModel = SensorDataModel(0, "激光未打开", 0, 0.0, 0.0)
+
+ val methaneBytes = IntArray(3)
+ System.arraycopy(bytes, 2, methaneBytes, 0, 3)
+ dataModel.methane = methaneBytes.covertDataValue()
+
+ dataModel.methaneState = when (bytes[5]) {
+ 1 -> "温控故障"
+ 2 -> "激光未打开"
+ else -> "正常"
+ }
+
+ val laserBytes = IntArray(3)
+ System.arraycopy(bytes, 6, laserBytes, 0, 3)
+ dataModel.laser = laserBytes.covertDataValue()
+
+ /**
+ * 水平角度的实际范围为从水平零点开始,顺时针方向(从上往下看),0~360°
+ * 垂直角度的实际范围为从垂直零点开始,以向上为正,-90°~90°,控制精度为0.01°
+ * */
+ val horizontalBytes = IntArray(2)
+ System.arraycopy(bytes, 9, horizontalBytes, 0, 2)
+ dataModel.horizontal = horizontalBytes.covertAngleValue()
+
+ val verticalBytes = IntArray(2)
+ System.arraycopy(bytes, 11, verticalBytes, 0, 2)
+ dataModel.vertical = verticalBytes.covertAngleValue()
+
+ //{"horizontal":26.21,"laser":45621,"methane":79846,"methaneState":"正常","vertical":13.91}
+ BroadcastManager.obtainInstance(BaseApplication.get()).sendBroadcast(
+ LocaleConstant.ACTION_UPDATE_DATA, dataModel.toJson()
+ )
+ }
+ }
+
+ override fun onServiceStatusConnectChanged(statusCode: Byte) {
+ if (statusCode == ISocketListener.STATUS_CONNECT_SUCCESS) {
+ if (nettyClient.connectStatus) {
+ Log.d(kTag, "连接成功")
+ }
+ } else {
+ if (!nettyClient.connectStatus) {
+ Log.e(kTag, "onServiceStatusConnectChanged:$statusCode,连接断开,正在重连")
+ }
+ }
+ }
+
+ fun sendData(data: ByteArray) {
+ nettyClient.sendData(data)
+ }
+
+ fun close() {
+ nettyClient.disconnect()
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/br/ktd/netty/udp/UdpChannelInboundHandler.kt b/app/src/main/java/com/casic/br/ktd/netty/udp/UdpChannelInboundHandler.kt
new file mode 100644
index 0000000..4d6f97c
--- /dev/null
+++ b/app/src/main/java/com/casic/br/ktd/netty/udp/UdpChannelInboundHandler.kt
@@ -0,0 +1,36 @@
+package com.casic.br.ktd.netty.udp
+
+import io.netty.channel.ChannelHandlerContext
+import io.netty.channel.SimpleChannelInboundHandler
+import io.netty.channel.socket.DatagramPacket
+import io.netty.util.CharsetUtil
+
+
+abstract class UdpChannelInboundHandler : SimpleChannelInboundHandler() {
+
+ private var handlerContext: ChannelHandlerContext? = null
+
+ override fun channelActive(ctx: ChannelHandlerContext?) {
+ super.channelActive(ctx)
+ handlerContext = ctx
+ }
+
+ override fun channelInactive(ctx: ChannelHandlerContext?) {
+ super.channelInactive(ctx)
+ handlerContext?.close()
+ }
+
+ fun sendDatagramPacket(obj: Any) {
+ handlerContext?.writeAndFlush(obj)
+ }
+
+ fun releasePort() {
+ handlerContext?.close()
+ }
+
+ override fun channelRead0(ctx: ChannelHandlerContext, datagramPacket: DatagramPacket) {
+ receivedMessage(datagramPacket.content().toString(CharsetUtil.UTF_8))
+ }
+
+ abstract fun receivedMessage(data: String)
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/br/ktd/netty/udp/UdpChannelInitializer.kt b/app/src/main/java/com/casic/br/ktd/netty/udp/UdpChannelInitializer.kt
new file mode 100644
index 0000000..416c5a1
--- /dev/null
+++ b/app/src/main/java/com/casic/br/ktd/netty/udp/UdpChannelInitializer.kt
@@ -0,0 +1,17 @@
+package com.casic.br.ktd.netty.udp
+
+import io.netty.channel.ChannelInitializer
+import io.netty.channel.socket.DatagramChannel
+import io.netty.handler.timeout.IdleStateHandler
+
+
+open class UdpChannelInitializer(private val handler: UdpChannelInboundHandler) :
+ ChannelInitializer() {
+
+ override fun initChannel(datagramChannel: DatagramChannel) {
+ val pipeline = datagramChannel.pipeline()
+ pipeline.addLast(
+ IdleStateHandler(12, 15, 0)
+ ).addLast(handler)
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/br/ktd/netty/udp/UdpClient.kt b/app/src/main/java/com/casic/br/ktd/netty/udp/UdpClient.kt
new file mode 100644
index 0000000..3893afa
--- /dev/null
+++ b/app/src/main/java/com/casic/br/ktd/netty/udp/UdpClient.kt
@@ -0,0 +1,103 @@
+package com.casic.br.ktd.netty.udp
+
+import com.casic.br.ktd.utils.LocaleConstant
+import com.pengxh.kt.lite.utils.SaveKeyValues
+import io.netty.bootstrap.Bootstrap
+import io.netty.buffer.ByteBuf
+import io.netty.buffer.Unpooled
+import io.netty.channel.ChannelOption
+import io.netty.channel.nio.NioEventLoopGroup
+import io.netty.channel.socket.DatagramPacket
+import io.netty.channel.socket.nio.NioDatagramChannel
+import io.netty.util.CharsetUtil
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.launch
+import kotlinx.coroutines.withContext
+import java.net.InetSocketAddress
+import java.util.concurrent.ExecutorService
+import java.util.concurrent.Executors
+
+
+class UdpClient : UdpChannelInboundHandler(), Runnable {
+
+ private val bootStrap by lazy { Bootstrap() }
+ private val eventLoopGroup by lazy { NioEventLoopGroup() }
+ private val udpChannelInitializer by lazy { UdpChannelInitializer(this) }
+ private var executorService: ExecutorService
+
+ init {
+ bootStrap.group(eventLoopGroup)
+ bootStrap.channel(NioDatagramChannel::class.java)
+ .option(ChannelOption.SO_RCVBUF, 1024)
+ .option(ChannelOption.SO_SNDBUF, 1024)
+ bootStrap.handler(udpChannelInitializer)
+
+ executorService = Executors.newSingleThreadExecutor()
+ executorService.execute(this)
+ }
+
+ override fun run() {
+ try {
+ val channelFuture = bootStrap.bind(LocaleConstant.LOCATION_UDP_PORT).sync()
+ channelFuture.channel().closeFuture().sync()
+ } catch (e: InterruptedException) {
+ e.printStackTrace()
+ } finally {
+ eventLoopGroup.shutdownGracefully()
+ }
+ }
+
+ fun send(value: String) {
+ CoroutineScope(Dispatchers.Main).launch {
+ withContext(Dispatchers.IO) {
+ val host = SaveKeyValues.getValue(
+ LocaleConstant.LOCATION_UDP_SERVER, "192.168.149.213"
+ ).toString()
+ val datagramPacket = DatagramPacket(
+ Unpooled.copiedBuffer(value, CharsetUtil.UTF_8),
+ InetSocketAddress(host, LocaleConstant.LOCATION_UDP_PORT)
+ )
+ sendDatagramPacket(datagramPacket)
+ }
+ }
+ }
+
+ fun send(value: ByteArray) {
+ CoroutineScope(Dispatchers.Main).launch {
+ withContext(Dispatchers.IO) {
+ val host = SaveKeyValues.getValue(
+ LocaleConstant.LOCATION_UDP_SERVER, "192.168.149.213"
+ ).toString()
+ val datagramPacket = DatagramPacket(
+ Unpooled.copiedBuffer(value),
+ InetSocketAddress(host, LocaleConstant.LOCATION_UDP_PORT)
+ )
+ sendDatagramPacket(datagramPacket)
+ }
+ }
+ }
+
+ fun send(value: ByteBuf) {
+ CoroutineScope(Dispatchers.Main).launch {
+ withContext(Dispatchers.IO) {
+ val host = SaveKeyValues.getValue(
+ LocaleConstant.LOCATION_UDP_SERVER, "192.168.149.213"
+ ).toString()
+ val datagramPacket = DatagramPacket(
+ Unpooled.copiedBuffer(value),
+ InetSocketAddress(host, LocaleConstant.LOCATION_UDP_PORT)
+ )
+ sendDatagramPacket(datagramPacket)
+ }
+ }
+ }
+
+ fun release() {
+ releasePort()
+ }
+
+ override fun receivedMessage(data: String) {
+
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/br/ktd/utils/LocaleConstant.kt b/app/src/main/java/com/casic/br/ktd/utils/LocaleConstant.kt
index 0dd119e..4c675df 100644
--- a/app/src/main/java/com/casic/br/ktd/utils/LocaleConstant.kt
+++ b/app/src/main/java/com/casic/br/ktd/utils/LocaleConstant.kt
@@ -50,6 +50,10 @@
const val DEV_NET_IP = "192.168.1.21"
const val DEV_NET_PORT = "8000"
+ //位置信息UDP端口
+ const val LOCATION_UDP_SERVER = "udpServer"
+ const val LOCATION_UDP_PORT = 7777
+
//BroadcastReceiver Action
const val ACTION_UPDATE_DATA = "update"
diff --git a/app/src/main/java/com/casic/br/ktd/utils/LocationHelper.kt b/app/src/main/java/com/casic/br/ktd/utils/LocationHelper.kt
index 8e31d3f..df6adb5 100644
--- a/app/src/main/java/com/casic/br/ktd/utils/LocationHelper.kt
+++ b/app/src/main/java/com/casic/br/ktd/utils/LocationHelper.kt
@@ -7,19 +7,40 @@
import android.location.LocationListener
import android.location.LocationManager
import android.os.Bundle
+import android.util.Log
import androidx.core.app.ActivityCompat
+import com.amap.api.location.AMapLocation
+import com.amap.api.location.AMapLocationClient
+import com.amap.api.location.AMapLocationClientOption
-object LocationHelper {
- fun obtainCurrentLocation(context: Context, listener: ILocationListener) {
+class LocationHelper private constructor() {
+
+ private val kTag = "LocationHelper"
+
+ companion object {
+ //Kotlin委托模式双重锁单例
+ val get: LocationHelper by lazy(mode = LazyThreadSafetyMode.SYNCHRONIZED) {
+ LocationHelper()
+ }
+ }
+
+ private val locationOption = AMapLocationClientOption()
+ private lateinit var locationClient: AMapLocationClient
+
+ init {
+ //设置定位模式为高精度模式,AMapLocationMode.Battery_Saving为低功耗模式,AMapLocationMode.Device_Sensors是仅设备模式
+ locationOption.locationMode = AMapLocationClientOption.AMapLocationMode.Hight_Accuracy
+ locationOption.isNeedAddress = true //设置是否返回地址信息(默认返回地址信息)
+ locationOption.isLocationCacheEnable = true //可选,设置是否使用缓存定位,默认为true
+ }
+
+ fun obtainLocation(context: Context, listener: ILocationListener) {
if (ActivityCompat.checkSelfPermission(
- context,
- Manifest.permission.ACCESS_LOCATION_EXTRA_COMMANDS
+ context, Manifest.permission.ACCESS_LOCATION_EXTRA_COMMANDS
) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(
- context,
- Manifest.permission.ACCESS_FINE_LOCATION
+ context, Manifest.permission.ACCESS_FINE_LOCATION
) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(
- context,
- Manifest.permission.ACCESS_COARSE_LOCATION
+ context, Manifest.permission.ACCESS_COARSE_LOCATION
) != PackageManager.PERMISSION_GRANTED
) {
return
@@ -38,7 +59,37 @@
})
}
+ /**
+ * 高德sdk定位
+ */
+ fun obtainLocationByGD(context: Context?, listener: ILocationListener) {
+ locationClient = AMapLocationClient(context)
+ //给定位客户端对象设置定位参数
+ locationClient.setLocationOption(locationOption)
+ //设置定位回调监听
+ locationClient.setLocationListener { aMapLocation ->
+ if (aMapLocation != null) {
+ if (aMapLocation.errorCode == 0) {
+ listener.onAMapLocationGet(aMapLocation)
+ } else {
+ Log.e(
+ kTag,
+ "ErrCode: ${aMapLocation.errorCode}, errInfo: ${aMapLocation.errorInfo}"
+ )
+ }
+ }
+ }
+ //启动定位
+ locationClient.startLocation()
+ }
+
+ fun stopLocation() {
+ locationClient.stopLocation()//停止定位
+ }
+
interface ILocationListener {
- fun onLocationGet(location: Location?) //高德定位数据
+ fun onLocationGet(location: Location?) //GPS定位数据
+
+ fun onAMapLocationGet(aMapLocation: AMapLocation?) //高德定位数据
}
}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/br/ktd/view/InspectionActivity.kt b/app/src/main/java/com/casic/br/ktd/view/InspectionActivity.kt
index 02c47f8..c893092 100644
--- a/app/src/main/java/com/casic/br/ktd/view/InspectionActivity.kt
+++ b/app/src/main/java/com/casic/br/ktd/view/InspectionActivity.kt
@@ -15,16 +15,21 @@
import android.view.SurfaceHolder
import android.view.View
import android.widget.AdapterView
-import com.amap.api.maps.*
+import com.amap.api.location.AMapLocation
+import com.amap.api.maps.AMap
+import com.amap.api.maps.CameraUpdateFactory
+import com.amap.api.maps.UiSettings
import com.amap.api.maps.model.CameraPosition
import com.amap.api.maps.model.LatLng
+import com.amap.api.maps.model.MyLocationStyle
import com.amap.api.maps.model.PolylineOptions
import com.casic.br.ktd.R
import com.casic.br.ktd.extensions.*
import com.casic.br.ktd.model.ChartPointModel
import com.casic.br.ktd.model.RouteModel
import com.casic.br.ktd.model.SensorDataModel
-import com.casic.br.ktd.netty.SocketManager
+import com.casic.br.ktd.netty.tcp.SocketManager
+import com.casic.br.ktd.netty.udp.UdpClient
import com.casic.br.ktd.utils.LocaleConstant
import com.casic.br.ktd.utils.LocationHelper
import com.casic.br.ktd.widgets.AlertControlDialog
@@ -49,6 +54,10 @@
import hcnetsdk.sdkhub.MessageCodeHub
import hcnetsdk.sdkhub.SDKGuider
import kotlinx.android.synthetic.main.activity_inspection.*
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.launch
+import kotlinx.coroutines.withContext
import java.text.DecimalFormat
import java.text.SimpleDateFormat
import java.util.*
@@ -60,10 +69,10 @@
private val hkSDK by lazy { HCNetSDK.getInstance() }
private val timeFormat by lazy { SimpleDateFormat("yyyyMMddHHmmss", Locale.CHINA) }
private val latlngs = LinkedList()
- private val speedTimer by lazy { Timer() }
private val tcpTimer by lazy { Timer() }
private val decimalFormat by lazy { DecimalFormat("##0.0") }
private val gson by lazy { Gson() }
+ private val udpClient by lazy { UdpClient() }
private var isLoginSuccess = false
private var previewHandle = -1
private var selectChannel = -1
@@ -103,28 +112,32 @@
private lateinit var aMap: AMap
private lateinit var uiSettings: UiSettings
+ /**
+ * 协程配置云台设备,缓解新进页面较卡的问题
+ * */
private fun setDeviceConfig() {
- Log.d(kTag, "setDeviceConfig => 配置设备IP和端口")
- val device = SDKGuider.sdkGuider.devManageGuider.DeviceItem()
- device.m_szDevName = ""
- device.m_struNetInfo = SDKGuider.sdkGuider.devManageGuider.DevNetInfo(
- LocaleConstant.HK_NET_IP,
- LocaleConstant.HK_NET_PORT,
- LocaleConstant.HK_NET_USERNAME,
- LocaleConstant.HK_NET_PASSWORD
- )
- if (device.m_szDevName.isEmpty()) {
- device.m_szDevName = device.m_struNetInfo.m_szIp
- }
- isLoginSuccess = if (
- SDKGuider.sdkGuider.devManageGuider.login_v40_jna(
- device.m_szDevName, device.m_struNetInfo
- )
- ) {
- "设备连接成功".show(this)
- true
- } else {
- false
+ CoroutineScope(Dispatchers.Main).launch {
+ isLoginSuccess = withContext(Dispatchers.IO) {
+ Log.d(kTag, "setDeviceConfig => 配置设备IP和端口")
+ val device = SDKGuider.sdkGuider.devManageGuider.DeviceItem()
+ device.m_szDevName = ""
+ device.m_struNetInfo = SDKGuider.sdkGuider.devManageGuider.DevNetInfo(
+ LocaleConstant.HK_NET_IP,
+ LocaleConstant.HK_NET_PORT,
+ LocaleConstant.HK_NET_USERNAME,
+ LocaleConstant.HK_NET_PASSWORD
+ )
+ if (device.m_szDevName.isEmpty()) {
+ device.m_szDevName = device.m_struNetInfo.m_szIp
+ }
+
+ SDKGuider.sdkGuider.devManageGuider.login_v40_jna(
+ device.m_szDevName, device.m_struNetInfo
+ )
+ }
+ if (isLoginSuccess) {
+ "设备连接成功".show(context)
+ }
}
}
@@ -148,17 +161,74 @@
/**
* 手机GPS定位
* */
- val converter = CoordinateConverter(this)
- LocationHelper.obtainCurrentLocation(this, object : LocationHelper.ILocationListener {
+// val converter = CoordinateConverter(this)
+// LocationHelper.get.obtainLocation(this, object : LocationHelper.ILocationListener {
+// override fun onLocationGet(location: Location?) {
+// if (location == null) {
+// "当前信号弱,无法定位".show(context)
+// return
+// }
+//
+// //发送位置信息给UDP服务端
+// udpClient.send("${location.longitude}, ${location.latitude}")
+// Log.d(kTag, "onLocationGet => 速度:${location.speed}")
+//
+// //WGS-84要转为高德坐标系
+// converter.from(CoordinateConverter.CoordType.GPS)
+// converter.coord(LatLng(location.latitude, location.longitude))
+// val latLng = converter.convert()
+// latlngs.add(latLng)
+//
+// //移动到指定经纬度
+// val cameraPosition = CameraPosition(latLng, 13f, 0f, 0f)
+// val cameraUpdate = CameraUpdateFactory.newCameraPosition(cameraPosition)
+// aMap.animateCamera(cameraUpdate, 1500, null)
+//
+// //绘制线
+// aMap.addPolyline(
+// PolylineOptions().addAll(latlngs).width(12f).color(Color.RED)
+// )
+//
+// if (isStartInspect) {
+// val route = LinkedList()
+// latlngs.forEach {
+// route.add(RouteModel(it.latitude, it.longitude))
+// }
+// }
+// }
+//
+// override fun onAMapLocationGet(aMapLocation: AMapLocation?) {
+//
+// }
+// })
+
+ /**
+ * 高德定位
+ * */
+ LocationHelper.get.obtainLocationByGD(this, object : LocationHelper.ILocationListener {
override fun onLocationGet(location: Location?) {
- if (location == null) {
+
+ }
+
+ override fun onAMapLocationGet(aMapLocation: AMapLocation?) {
+ if (aMapLocation == null) {
"当前信号弱,无法定位".show(context)
return
}
+
+ //发送位置信息给UDP服务端
+ udpClient.send(
+ "${aMapLocation.longitude}, ${aMapLocation.latitude}, ${
+ System.currentTimeMillis().timestampToCompleteDate()
+ }"
+ )
+ //速度 转为 km/h
+ Log.d(kTag, "onLocationGet => 速度:${aMapLocation.speed}")
+ speed = decimalFormat.format(aMapLocation.speed * 3.6).toFloat()
+ carSpeedView.text = String.format("${speed}Km/h")
+
//WGS-84要转为高德坐标系
- converter.from(CoordinateConverter.CoordType.GPS)
- converter.coord(LatLng(location.latitude, location.longitude))
- val latLng = converter.convert()
+ val latLng = LatLng(aMapLocation.latitude, aMapLocation.longitude)
latlngs.add(latLng)
//移动到指定经纬度
@@ -168,7 +238,7 @@
//绘制线
aMap.addPolyline(
- PolylineOptions().addAll(latlngs).width(12f).color(Color.RED)
+ PolylineOptions().addAll(latlngs).width(10f).color(Color.RED)
)
if (isStartInspect) {
@@ -181,27 +251,6 @@
})
/**
- * 计算速度,微分原理,3s计算一次速度
- * */
- speedTimer.schedule(object : TimerTask() {
- override fun run() {
- //经纬度链表数据小于2,无法计算速度,默认为0
- speed = if (latlngs.size < 2) 0.0f else {
- val temp = AMapUtils.calculateLineDistance(
- latlngs.last(), latlngs[latlngs.size - 2]
- ) / 3
- //转为 km/h
- decimalFormat.format(temp * 3.6).toFloat()
- }
-
- //切换到UI线程更新界面数据
- runOnUiThread {
- carSpeedView.text = String.format("${speed}Km/h")
- }
- }
- }, 0, 3000)
-
- /**
* TCP初始化
* ***/
SocketManager.instance.connectNetty(
@@ -632,6 +681,8 @@
stopPreview()
BroadcastManager.obtainInstance(this).destroy(LocaleConstant.ACTION_UPDATE_DATA)
mapView.onDestroy()
+ udpClient.release()
+ LocationHelper.get.stopLocation()
}
override fun handleMessage(msg: Message): Boolean {
@@ -716,38 +767,13 @@
uiSettings.isZoomControlsEnabled = true
uiSettings.isTiltGesturesEnabled = false//不许地图随手势倾斜角度
-// val locationStyle = MyLocationStyle()
-// locationStyle.interval(2000)
-// locationStyle.showMyLocation(true)
-// locationStyle.myLocationType(MyLocationStyle.LOCATION_TYPE_LOCATION_ROTATE)
-// aMap.myLocationStyle = locationStyle
-// aMap.isMyLocationEnabled = true
-// aMap.animateCamera(CameraUpdateFactory.zoomTo(13f))
-// aMap.setOnMyLocationChangeListener(this)
+ //显示定位小蓝点
+ val locationStyle = MyLocationStyle()
+ locationStyle.showMyLocation(true)//设置是否显示定位小蓝点
+ aMap.myLocationStyle = locationStyle
+ aMap.isMyLocationEnabled = true
}
-// override fun onMyLocationChange(aMapLocation: Location?) {
-// if (aMapLocation == null) {
-// "当前信号弱,无法定位".show(context)
-// return
-// }
-// val latitude = aMapLocation.latitude
-// val longitude = aMapLocation.longitude
-// latlngs.add(LatLng(latitude, longitude))
-//
-// //绘制线
-// aMap.addPolyline(
-// PolylineOptions().addAll(latlngs).width(15f).color(Color.RED)
-// )
-//
-// if (isStartInspect) {
-// val route = LinkedList()
-// latlngs.forEach {
-// route.add(RouteModel(it.latitude, it.longitude))
-// }
-// }
-// }
-
/***以下是地图生命周期管理************************************************************************/
override fun onResume() {
diff --git a/app/src/main/res/layout/fragment_alarm.xml b/app/src/main/res/layout/fragment_alarm.xml
index a3ebc88..929529f 100644
--- a/app/src/main/res/layout/fragment_alarm.xml
+++ b/app/src/main/res/layout/fragment_alarm.xml
@@ -31,7 +31,7 @@
diff --git a/app/src/main/res/layout/fragment_task.xml b/app/src/main/res/layout/fragment_task.xml
index 35cb1a3..58d852e 100644
--- a/app/src/main/res/layout/fragment_task.xml
+++ b/app/src/main/res/layout/fragment_task.xml
@@ -31,7 +31,7 @@
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index e822df6..d72c1a5 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -7,6 +7,9 @@
+
+
+
@@ -46,5 +49,8 @@
+
+
+
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/br/ktd/base/KotlinBaseFragment.kt b/app/src/main/java/com/casic/br/ktd/base/KotlinBaseFragment.kt
new file mode 100644
index 0000000..2dac61c
--- /dev/null
+++ b/app/src/main/java/com/casic/br/ktd/base/KotlinBaseFragment.kt
@@ -0,0 +1,51 @@
+package com.casic.br.ktd.base
+
+import android.os.Bundle
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import androidx.annotation.LayoutRes
+import androidx.fragment.app.Fragment
+
+abstract class KotlinBaseFragment : Fragment() {
+
+ lateinit var bv: View
+
+ override fun onCreateView(
+ inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?
+ ): View? {
+ bv = inflater.inflate(initLayoutRes(), container, false)
+ initView(savedInstanceState)
+ setupTopBarLayout()
+ return bv
+ }
+
+ override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
+ super.onViewCreated(view, savedInstanceState)
+ observeRequestState()
+ initEvent()
+ }
+
+ @LayoutRes
+ abstract fun initLayoutRes(): Int
+
+ /**
+ * 沉浸式状态栏
+ */
+ abstract fun setupTopBarLayout()
+
+ /**
+ * 初始化布局以及控件
+ */
+ abstract fun initView(savedInstanceState: Bundle?)
+
+ /**
+ * 网络请求状态监听
+ */
+ abstract fun observeRequestState()
+
+ /**
+ * 业务逻辑,按钮等事件
+ */
+ abstract fun initEvent()
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/br/ktd/fragment/AlarmPageFragment.kt b/app/src/main/java/com/casic/br/ktd/fragment/AlarmPageFragment.kt
index 6c98a3b..9418169 100644
--- a/app/src/main/java/com/casic/br/ktd/fragment/AlarmPageFragment.kt
+++ b/app/src/main/java/com/casic/br/ktd/fragment/AlarmPageFragment.kt
@@ -2,28 +2,29 @@
import android.os.Bundle
import com.casic.br.ktd.R
+import com.casic.br.ktd.base.KotlinBaseFragment
import com.casic.br.ktd.widgets.DateRangeActionSheet
-import com.pengxh.kt.lite.base.KotlinBaseFragment
import kotlinx.android.synthetic.main.fragment_alarm.view.*
class AlarmPageFragment : KotlinBaseFragment() {
- override fun initData(savedInstanceState: Bundle?) {
+
+ override fun initView(savedInstanceState: Bundle?) {
}
override fun initEvent() {
- baseView.calendarView.setOnClickListener {
+ bv.calendarView.setOnClickListener {
DateRangeActionSheet.Builder().setContext(requireContext())
.setOnActionSheetListener(object :
DateRangeActionSheet.OnDateRangeSelectedListener {
override fun onDateRangeSelected(startDate: String, endDate: String) {
- baseView.selectedDateView.text = "$startDate ~ $endDate"
+ bv.selectedDateView.text = "$startDate ~ $endDate"
}
}).build().show()
}
}
- override fun initLayoutView(): Int = R.layout.fragment_alarm
+ override fun initLayoutRes(): Int = R.layout.fragment_alarm
override fun observeRequestState() {
diff --git a/app/src/main/java/com/casic/br/ktd/fragment/HomePageFragment.kt b/app/src/main/java/com/casic/br/ktd/fragment/HomePageFragment.kt
index 9961935..f3eba5c 100644
--- a/app/src/main/java/com/casic/br/ktd/fragment/HomePageFragment.kt
+++ b/app/src/main/java/com/casic/br/ktd/fragment/HomePageFragment.kt
@@ -1,32 +1,62 @@
package com.casic.br.ktd.fragment
+import android.graphics.Color
import android.os.Bundle
import com.amap.api.maps.AMap
import com.amap.api.maps.AMapOptions
+import com.amap.api.maps.CameraUpdateFactory
+import com.amap.api.maps.model.*
import com.casic.br.ktd.R
-import com.pengxh.kt.lite.base.KotlinBaseFragment
+import com.casic.br.ktd.base.KotlinBaseFragment
import kotlinx.android.synthetic.main.fragment_home.view.*
class HomePageFragment : KotlinBaseFragment() {
private lateinit var aMap: AMap
- override fun initData(savedInstanceState: Bundle?) {
- baseView.mapView.onCreate(savedInstanceState)
- aMap = baseView.mapView.map
+ override fun initView(savedInstanceState: Bundle?) {
+ bv.mapView.onCreate(savedInstanceState)
+ aMap = bv.mapView.map
val uiSettings = aMap.uiSettings
uiSettings.isCompassEnabled = true
- uiSettings.isMyLocationButtonEnabled = true
+ uiSettings.isMyLocationButtonEnabled = false
uiSettings.isScaleControlsEnabled = true
uiSettings.zoomPosition = AMapOptions.ZOOM_POSITION_RIGHT_CENTER
uiSettings.isRotateGesturesEnabled = false//不许地图随手势旋转角度
}
override fun initEvent() {
-
+ //移动到巡检起始经纬度
+ val cameraPosition = CameraPosition(LatLng(39.914199, 116.265785), 16f, 0f, 0f)
+ val cameraUpdate = CameraUpdateFactory.newCameraPosition(cameraPosition)
+ aMap.animateCamera(cameraUpdate, 1500, null)
+ //设置起点
+ addMarker(LatLng(39.914885, 116.272312), R.mipmap.start)
+ //设置终点
+ addMarker(LatLng(39.914716, 116.265097), R.mipmap.end)
+ //瞄点画线
+ val latLngPoints = ArrayList()
+ latLngPoints.add(LatLng(39.914885, 116.272312))
+ latLngPoints.add(LatLng(39.915148, 116.272312))
+ latLngPoints.add(LatLng(39.915399, 116.272302))
+ latLngPoints.add(LatLng(39.915436, 116.271787))
+ latLngPoints.add(LatLng(39.915477, 116.270886))
+ latLngPoints.add(LatLng(39.915477, 116.269968))
+ latLngPoints.add(LatLng(39.915469, 116.269544))
+ latLngPoints.add(LatLng(39.915481, 116.269196))
+ latLngPoints.add(LatLng(39.915452, 116.268472))
+ latLngPoints.add(LatLng(39.915444, 116.267722))
+ latLngPoints.add(LatLng(39.915415, 116.266755))
+ latLngPoints.add(LatLng(39.915403, 116.266165))
+ latLngPoints.add(LatLng(39.915395, 116.265703))
+ latLngPoints.add(LatLng(39.915366, 116.265119))
+ latLngPoints.add(LatLng(39.914716, 116.265097))
+ aMap.addPolyline(
+ PolylineOptions().addAll(latLngPoints).width(10.toFloat()).color(Color.RED)
+ )
}
- override fun initLayoutView(): Int = R.layout.fragment_home
+ override fun initLayoutRes(): Int = R.layout.fragment_home
override fun observeRequestState() {
@@ -36,25 +66,32 @@
}
+ private fun addMarker(point: LatLng, res: Int) {
+ val markerOption = MarkerOptions()
+ markerOption.position(point)
+ markerOption.icon(BitmapDescriptorFactory.fromResource(res))
+ aMap.addMarker(markerOption)
+ }
+
/***以下是地图生命周期管理************************************************************************/
override fun onResume() {
super.onResume()
- baseView.mapView.onResume()
+ bv.mapView.onResume()
}
override fun onPause() {
- baseView.mapView.onPause()
super.onPause()
+ bv.mapView.onPause()
}
override fun onSaveInstanceState(outState: Bundle) {
super.onSaveInstanceState(outState)
- baseView.mapView.onSaveInstanceState(outState)
+ bv.mapView.onSaveInstanceState(outState)
}
override fun onDestroy() {
- baseView.mapView.onDestroy()
super.onDestroy()
+ bv.mapView.onDestroy()
}
}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/br/ktd/fragment/MinePageFragment.kt b/app/src/main/java/com/casic/br/ktd/fragment/MinePageFragment.kt
index 90313ac..3212794 100644
--- a/app/src/main/java/com/casic/br/ktd/fragment/MinePageFragment.kt
+++ b/app/src/main/java/com/casic/br/ktd/fragment/MinePageFragment.kt
@@ -2,10 +2,11 @@
import android.os.Bundle
import com.casic.br.ktd.R
-import com.pengxh.kt.lite.base.KotlinBaseFragment
+import com.casic.br.ktd.base.KotlinBaseFragment
class MinePageFragment : KotlinBaseFragment() {
- override fun initData(savedInstanceState: Bundle?) {
+
+ override fun initView(savedInstanceState: Bundle?) {
}
@@ -13,7 +14,7 @@
}
- override fun initLayoutView(): Int = R.layout.fragment_mine
+ override fun initLayoutRes(): Int = R.layout.fragment_mine
override fun observeRequestState() {
diff --git a/app/src/main/java/com/casic/br/ktd/fragment/TaskPageFragment.kt b/app/src/main/java/com/casic/br/ktd/fragment/TaskPageFragment.kt
index 8f6abf0..6b82a54 100644
--- a/app/src/main/java/com/casic/br/ktd/fragment/TaskPageFragment.kt
+++ b/app/src/main/java/com/casic/br/ktd/fragment/TaskPageFragment.kt
@@ -8,6 +8,7 @@
import androidx.recyclerview.widget.RecyclerView
import com.casic.br.ktd.R
import com.casic.br.ktd.adapter.TaskAdapter
+import com.casic.br.ktd.base.KotlinBaseFragment
import com.casic.br.ktd.holder.SwipeViewHolder
import com.casic.br.ktd.model.TaskListModel
import com.casic.br.ktd.view.InspectionActivity
@@ -15,7 +16,6 @@
import com.casic.br.ktd.widgets.AlertControlDialog
import com.casic.br.ktd.widgets.AlertInputDialog
import com.casic.br.ktd.widgets.DateRangeActionSheet
-import com.pengxh.kt.lite.base.KotlinBaseFragment
import com.pengxh.kt.lite.extensions.navigatePageTo
import com.pengxh.kt.lite.extensions.show
import com.pengxh.kt.lite.utils.WeakReferenceHandler
@@ -36,7 +36,7 @@
private var startTime = ""
private var endTime = ""
- override fun initData(savedInstanceState: Bundle?) {
+ override fun initView(savedInstanceState: Bundle?) {
weakReferenceHandler = WeakReferenceHandler(this)
taskViewModel = ViewModelProvider(this)[TaskViewModel::class.java]
taskViewModel.taskList.observe(this) {
@@ -45,7 +45,7 @@
when {
isRefresh -> {
taskAdapter.setRefreshData(dataRows)
- baseView.taskLayout.finishRefresh()
+ bv.taskLayout.finishRefresh()
isRefresh = false
}
isLoadMore -> {
@@ -53,7 +53,7 @@
"到底了,别拉了".show(requireContext())
}
taskAdapter.setLoadMoreData(dataRows)
- baseView.taskLayout.finishLoadMore()
+ bv.taskLayout.finishLoadMore()
isLoadMore = false
}
else -> {
@@ -76,9 +76,9 @@
when (msg.what) {
2023070501 -> {
if (dataBeans.size == 0) {
- baseView.emptyLayout.visibility = View.VISIBLE
+ bv.emptyLayout.visibility = View.VISIBLE
} else {
- baseView.emptyLayout.visibility = View.GONE
+ bv.emptyLayout.visibility = View.GONE
taskAdapter = object : TaskAdapter(
requireContext(), R.layout.item_task_rv_l, dataBeans
) {
@@ -97,8 +97,8 @@
}
}
//绑定侧滑事件
- swipeAction.attachToRecyclerView(baseView.taskRecyclerView)
- baseView.taskRecyclerView.adapter = taskAdapter
+ swipeAction.attachToRecyclerView(bv.taskRecyclerView)
+ bv.taskRecyclerView.adapter = taskAdapter
taskAdapter.setOnItemCheckedListener(object :
TaskAdapter.OnItemCheckedListener {
override fun onItemChecked(items: ArrayList) {
@@ -168,7 +168,7 @@
override fun initEvent() {
- baseView.calendarView.setOnClickListener {
+ bv.calendarView.setOnClickListener {
DateRangeActionSheet.Builder().setContext(requireContext())
.setOnActionSheetListener(object :
DateRangeActionSheet.OnDateRangeSelectedListener {
@@ -177,12 +177,12 @@
endTime = endDate
//显示
- baseView.selectedDateView.text = "$startDate ~ $endDate"
+ bv.selectedDateView.text = "$startDate ~ $endDate"
}
}).build().show()
}
- baseView.addTaskButton.setOnClickListener {
+ bv.addTaskButton.setOnClickListener {
// AlertInputDialog.Builder()
// .setContext(requireContext())
// .setTitle("新建巡检任务")
@@ -200,11 +200,11 @@
requireContext().navigatePageTo()
}
- baseView.deleteTaskButton.setOnClickListener {
+ bv.deleteTaskButton.setOnClickListener {
selectedItems.size.toString().show(requireContext())
}
- baseView.taskSettingsButton.setOnClickListener {
+ bv.taskSettingsButton.setOnClickListener {
AlertInputDialog.Builder()
.setContext(requireContext())
.setTitle("设置阈值")
@@ -221,14 +221,14 @@
}).build().show()
}
- baseView.taskLayout.setOnRefreshListener {
+ bv.taskLayout.setOnRefreshListener {
isRefresh = true
//刷新之后页码重置
pageIndex = 1
getTaskList()
}
- baseView.taskLayout.setOnLoadMoreListener {
+ bv.taskLayout.setOnLoadMoreListener {
isLoadMore = true
pageIndex++
getTaskList()
@@ -239,13 +239,13 @@
taskViewModel.getTaskList(
startTime,
endTime,
- baseView.taskNameView.text.toString(),
- baseView.taskCodeView.text.toString(),
+ bv.taskNameView.text.toString(),
+ bv.taskCodeView.text.toString(),
pageIndex
)
}
- override fun initLayoutView(): Int = R.layout.fragment_task
+ override fun initLayoutRes(): Int = R.layout.fragment_task
override fun observeRequestState() {
diff --git a/app/src/main/java/com/casic/br/ktd/netty/ISocketListener.kt b/app/src/main/java/com/casic/br/ktd/netty/ISocketListener.kt
deleted file mode 100644
index dab98e1..0000000
--- a/app/src/main/java/com/casic/br/ktd/netty/ISocketListener.kt
+++ /dev/null
@@ -1,19 +0,0 @@
-package com.casic.br.ktd.netty
-
-interface ISocketListener {
- companion object {
- const val STATUS_CONNECT_SUCCESS: Byte = 1 //连接成功
- const val STATUS_CONNECT_CLOSED: Byte = 0 //关闭连接
- const val STATUS_CONNECT_ERROR: Byte = 0 //连接失败
- }
-
- /**
- * 当接收到系统消息
- */
- fun onMessageResponse(data: ByteArray?)
-
- /**
- * 当连接状态发生变化时调用
- */
- fun onServiceStatusConnectChanged(statusCode: Byte)
-}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/br/ktd/netty/SocketChannelHandle.kt b/app/src/main/java/com/casic/br/ktd/netty/SocketChannelHandle.kt
deleted file mode 100644
index 42eb310..0000000
--- a/app/src/main/java/com/casic/br/ktd/netty/SocketChannelHandle.kt
+++ /dev/null
@@ -1,51 +0,0 @@
-package com.casic.br.ktd.netty
-
-import android.util.Log
-import io.netty.channel.ChannelHandlerContext
-import io.netty.channel.SimpleChannelInboundHandler
-import io.netty.handler.timeout.IdleState
-import io.netty.handler.timeout.IdleStateEvent
-import java.nio.charset.StandardCharsets
-
-class SocketChannelHandle(private val listener: ISocketListener?) :
- SimpleChannelInboundHandler() {
-
- private val kTag = "SocketChannelHandle"
-
- override fun channelActive(ctx: ChannelHandlerContext) {
- super.channelActive(ctx)
- Log.d(kTag, "channelActive ===> 连接成功")
- listener?.onServiceStatusConnectChanged(ISocketListener.STATUS_CONNECT_SUCCESS)
- }
-
- override fun channelInactive(ctx: ChannelHandlerContext) {
- super.channelInactive(ctx)
- Log.e(kTag, "channelInactive: 连接断开")
- }
-
- override fun userEventTriggered(ctx: ChannelHandlerContext, evt: Any) {
- super.userEventTriggered(ctx, evt)
- if (evt is IdleStateEvent) {
- if (evt.state() == IdleState.WRITER_IDLE) {
- //写超时,此时可以发送心跳数据给服务器
- val temp = "FF"
- ctx.writeAndFlush(temp.toByteArray(StandardCharsets.UTF_8))
- } else if (evt.state() == IdleState.READER_IDLE) {
- //读超时,此时代表没有收到心跳返回可以关闭当前连接进行重连
- ctx.close()
- }
- }
- }
-
- override fun channelRead0(ctx: ChannelHandlerContext, data: ByteArray?) {
- listener?.onMessageResponse(data)
- }
-
- override fun exceptionCaught(ctx: ChannelHandlerContext, cause: Throwable) {
- super.exceptionCaught(ctx, cause)
- Log.d(kTag, "exceptionCaught ===> $cause")
- listener?.onServiceStatusConnectChanged(ISocketListener.STATUS_CONNECT_ERROR)
- cause.printStackTrace()
- ctx.close()
- }
-}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/br/ktd/netty/SocketClient.kt b/app/src/main/java/com/casic/br/ktd/netty/SocketClient.kt
deleted file mode 100644
index d05d335..0000000
--- a/app/src/main/java/com/casic/br/ktd/netty/SocketClient.kt
+++ /dev/null
@@ -1,153 +0,0 @@
-package com.casic.br.ktd.netty
-
-import android.os.SystemClock
-import android.util.Log
-import io.netty.bootstrap.Bootstrap
-import io.netty.channel.*
-import io.netty.channel.nio.NioEventLoopGroup
-import io.netty.channel.socket.SocketChannel
-import io.netty.channel.socket.nio.NioSocketChannel
-import io.netty.handler.codec.bytes.ByteArrayDecoder
-import io.netty.handler.codec.bytes.ByteArrayEncoder
-import io.netty.handler.timeout.IdleStateHandler
-
-class SocketClient {
-
- private val kTag = "SocketClient"
-
- private var host: String? = null
- private var port = 8000
- private var nioEventLoopGroup: NioEventLoopGroup? = null
- private var channel: Channel? = null
- private var listener: ISocketListener? = null
-
- //现在连接的状态
- var connectStatus = false //判断是否已连接
- private var reconnectNum = Int.MAX_VALUE //定义的重连到时候用
- private var isNeedReconnect = true //是否需要重连
- var isConnecting = false //是否正在连接
- private set
- private var reconnectIntervalTime: Long = 15000 //重连的时间
-
- //重连时间
- fun setReconnectNum(reconnectNum: Int) {
- this.reconnectNum = reconnectNum
- }
-
- fun setReconnectIntervalTime(reconnectIntervalTime: Long) {
- this.reconnectIntervalTime = reconnectIntervalTime
- }
-
- fun setSocketListener(listener: ISocketListener?) {
- this.listener = listener
- }
-
- fun connect(host: String, port: Int) {
- this.host = host
- this.port = port
- Log.d(kTag, "connect ===> 开始连接TCP服务器")
- if (isConnecting) {
- return
- }
- //起个线程
- val clientThread: Thread = object : Thread("client-Netty") {
- override fun run() {
- super.run()
- isNeedReconnect = true
- reconnectNum = Int.MAX_VALUE
- connectServer()
- }
- }
- clientThread.start()
- }
-
- private fun connectServer() {
- synchronized(this@SocketClient) {
- var channelFuture: ChannelFuture? = null //连接管理对象
- if (!connectStatus) {
- isConnecting = true
- nioEventLoopGroup = NioEventLoopGroup() //设置的连接group
- val bootstrap = Bootstrap()
- bootstrap.group(nioEventLoopGroup) //设置的一系列连接参数操作等
- .channel(NioSocketChannel::class.java)
- .option(ChannelOption.TCP_NODELAY, true) //无阻塞
- .option(ChannelOption.SO_KEEPALIVE, true) //长连接
- .option(
- ChannelOption.RCVBUF_ALLOCATOR,
- AdaptiveRecvByteBufAllocator(5000, 5000, 8000)
- ) //接收缓冲区 最小值太小时数据接收不全
- .handler(object : ChannelInitializer() {
- override fun initChannel(channel: SocketChannel) {
- val pipeline = channel.pipeline()
- //参数1:代表读套接字超时的时间,没收到数据会触发读超时回调;
- //参数2:代表写套接字超时时间,没进行写会触发写超时回调;
- //参数3:将在未执行读取或写入时触发超时回调,0代表不处理;
- //读超时尽量设置大于写超时,代表多次写超时时写心跳包,多次写了心跳数据仍然读超时代表当前连接错误,即可断开连接重新连接
- pipeline.addLast(IdleStateHandler(60, 10, 0))
- pipeline.addLast(ByteArrayDecoder())
- pipeline.addLast(ByteArrayEncoder())
- pipeline.addLast(SocketChannelHandle(listener))
- }
- })
- try {
- //连接监听
- channelFuture = bootstrap.connect(host, port)
- .addListener(object : ChannelFutureListener {
- override fun operationComplete(channelFuture: ChannelFuture) {
- if (channelFuture.isSuccess) {
- connectStatus = true
- channel = channelFuture.channel()
- } else {
- Log.e(kTag, "operationComplete: 连接失败")
- connectStatus = false
- }
- isConnecting = false
- }
- }).sync()
- // 等待连接关闭
- channelFuture.channel().closeFuture().sync()
- } catch (e: Exception) {
- e.printStackTrace()
- } finally {
- connectStatus = false
- listener?.onServiceStatusConnectChanged(ISocketListener.STATUS_CONNECT_CLOSED) //STATUS_CONNECT_CLOSED 这我自己定义的 接口标识
- if (null != channelFuture) {
- if (channelFuture.channel() != null && channelFuture.channel().isOpen) {
- channelFuture.channel().close()
- }
- }
- nioEventLoopGroup?.shutdownGracefully()
- reconnect() //重新连接
- }
- }
- }
- }
-
- //断开连接
- fun disconnect() {
- Log.d(kTag, "disconnect ===> 断开连接")
- isNeedReconnect = false
- nioEventLoopGroup?.shutdownGracefully()
- }
-
- //重新连接
- private fun reconnect() {
- if (isNeedReconnect && reconnectNum > 0 && !connectStatus) {
- reconnectNum--
- SystemClock.sleep(reconnectIntervalTime)
- if (isNeedReconnect && reconnectNum > 0 && !connectStatus) {
- Log.d(kTag, "reconnect ===> 重新连接")
- connectServer()
- }
- }
- }
-
- fun sendData(bytes: ByteArray) {
- channel?.writeAndFlush(bytes)?.addListener(ChannelFutureListener { future ->
- if (!future.isSuccess) {
- future.channel().close()
- nioEventLoopGroup!!.shutdownGracefully()
- }
- })
- }
-}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/br/ktd/netty/SocketManager.kt b/app/src/main/java/com/casic/br/ktd/netty/SocketManager.kt
deleted file mode 100644
index 17daf35..0000000
--- a/app/src/main/java/com/casic/br/ktd/netty/SocketManager.kt
+++ /dev/null
@@ -1,113 +0,0 @@
-package com.casic.br.ktd.netty
-
-import android.util.Log
-import com.casic.br.ktd.base.BaseApplication
-import com.casic.br.ktd.extensions.covertAngleValue
-import com.casic.br.ktd.extensions.covertDataValue
-import com.casic.br.ktd.extensions.toUnsignedByteArray
-import com.casic.br.ktd.model.SensorDataModel
-import com.casic.br.ktd.utils.LocaleConstant
-import com.pengxh.kt.lite.extensions.toJson
-import com.pengxh.kt.lite.utils.BroadcastManager
-
-class SocketManager private constructor() : ISocketListener {
-
- private val kTag = "SocketManager"
- private var nettyClient: SocketClient = SocketClient()
-
- companion object {
- val instance: SocketManager by lazy(mode = LazyThreadSafetyMode.SYNCHRONIZED) { SocketManager() }
- }
-
- fun connectNetty(hostname: String, port: Int) {
- Thread {
- if (!nettyClient.connectStatus) {
- nettyClient.setSocketListener(this)
- nettyClient.connect(hostname, port)
- } else {
- nettyClient.disconnect()
- }
- }.start()
- }
-
- override fun onMessageResponse(data: ByteArray?) {
-// Log.d(kTag, "onMessageResponse ===> " + Arrays.toString(data))
- /**
- * 0xFF,0x01,
- * 0x01,0x37,0xE6, 甲烷浓度值(数据码1* 65536 + 数据码2 * 256 + 数据码3)
- * 0x00, 激光甲烷模块工作状态(00表示设备正常,01表示温控故障,02表示设备激光未打开)
- * 0x00,0xB2,0x35, 激光强度值(数据码5* 65536 + 数据码6 * 256 + 数据码7)
- * 0x0A,0x3D, 云台水平角度([数据码8 * 256 + 数据码9]/100,单位为°,精确到0.01)
- * 0x05,0x6F, 云台垂直角度(首先计算Tangle=[数据码10 * 256 + 数据码11]/100,单位为°,精确到0.01。若Tangle在0~90范围内,则垂直角度值=Tangle;若Tangle在-1~-90范围内,则垂直角度值=Tangle-360)
- * 0xC1
- *
- * [-1, 1, 1, 55, -26, 0, 0, -78, 53, 10, 61, 5, 111, -63]
- * 甲烷浓度值为79638,计算为79638=0x01*65536+0x37*256+0xE6[0x01为数据码1,0x37为数据码2,0xE6为数据码3];
- * 激光甲烷设备状态值为0,表示状态正常,[0x00为数据码4];
- * 激光强度值为45621,计算为45621=0x00*65536+0xB2*256+0x35[0x00为数据码5,0xB2为数据码6,0x35为数据码7];
- *
- * =========================================================================================
- * 实际数据(1800-1950左右)
- * [-86, 1, 0, 7, 71, 0, 0, 62, -92, 57, 59, -118, -111, -64]
- * */
-
- if (data == null) {
- return
- }
- val bytes = data.toUnsignedByteArray()
- if (bytes.size == 14) {
- val dataModel = SensorDataModel(0, "激光未打开", 0, 0.0, 0.0)
-
- val methaneBytes = IntArray(3)
- System.arraycopy(bytes, 2, methaneBytes, 0, 3)
- dataModel.methane = methaneBytes.covertDataValue()
-
- dataModel.methaneState = when (bytes[5]) {
- 1 -> "温控故障"
- 2 -> "激光未打开"
- else -> "正常"
- }
-
- val laserBytes = IntArray(3)
- System.arraycopy(bytes, 6, laserBytes, 0, 3)
- dataModel.laser = laserBytes.covertDataValue()
-
- /**
- * 水平角度的实际范围为从水平零点开始,顺时针方向(从上往下看),0~360°
- * 垂直角度的实际范围为从垂直零点开始,以向上为正,-90°~90°,控制精度为0.01°
- * */
- val horizontalBytes = IntArray(2)
- System.arraycopy(bytes, 9, horizontalBytes, 0, 2)
- dataModel.horizontal = horizontalBytes.covertAngleValue()
-
- val verticalBytes = IntArray(2)
- System.arraycopy(bytes, 11, verticalBytes, 0, 2)
- dataModel.vertical = verticalBytes.covertAngleValue()
-
- //{"horizontal":26.21,"laser":45621,"methane":79846,"methaneState":"正常","vertical":13.91}
- BroadcastManager.obtainInstance(BaseApplication.get()).sendBroadcast(
- LocaleConstant.ACTION_UPDATE_DATA, dataModel.toJson()
- )
- }
- }
-
- override fun onServiceStatusConnectChanged(statusCode: Byte) {
- if (statusCode == ISocketListener.STATUS_CONNECT_SUCCESS) {
- if (nettyClient.connectStatus) {
- Log.d(kTag, "连接成功")
- }
- } else {
- if (!nettyClient.connectStatus) {
- Log.e(kTag, "onServiceStatusConnectChanged:$statusCode,连接断开,正在重连")
- }
- }
- }
-
- fun sendData(data: ByteArray) {
- nettyClient.sendData(data)
- }
-
- fun close() {
- nettyClient.disconnect()
- }
-}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/br/ktd/netty/tcp/ISocketListener.kt b/app/src/main/java/com/casic/br/ktd/netty/tcp/ISocketListener.kt
new file mode 100644
index 0000000..13c3084
--- /dev/null
+++ b/app/src/main/java/com/casic/br/ktd/netty/tcp/ISocketListener.kt
@@ -0,0 +1,19 @@
+package com.casic.br.ktd.netty.tcp
+
+interface ISocketListener {
+ companion object {
+ const val STATUS_CONNECT_SUCCESS: Byte = 1 //连接成功
+ const val STATUS_CONNECT_CLOSED: Byte = 0 //关闭连接
+ const val STATUS_CONNECT_ERROR: Byte = 0 //连接失败
+ }
+
+ /**
+ * 当接收到系统消息
+ */
+ fun onMessageResponse(data: ByteArray?)
+
+ /**
+ * 当连接状态发生变化时调用
+ */
+ fun onServiceStatusConnectChanged(statusCode: Byte)
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/br/ktd/netty/tcp/SocketChannelHandle.kt b/app/src/main/java/com/casic/br/ktd/netty/tcp/SocketChannelHandle.kt
new file mode 100644
index 0000000..8e2997f
--- /dev/null
+++ b/app/src/main/java/com/casic/br/ktd/netty/tcp/SocketChannelHandle.kt
@@ -0,0 +1,51 @@
+package com.casic.br.ktd.netty.tcp
+
+import android.util.Log
+import io.netty.channel.ChannelHandlerContext
+import io.netty.channel.SimpleChannelInboundHandler
+import io.netty.handler.timeout.IdleState
+import io.netty.handler.timeout.IdleStateEvent
+import java.nio.charset.StandardCharsets
+
+class SocketChannelHandle(private val listener: ISocketListener?) :
+ SimpleChannelInboundHandler() {
+
+ private val kTag = "SocketChannelHandle"
+
+ override fun channelActive(ctx: ChannelHandlerContext) {
+ super.channelActive(ctx)
+ Log.d(kTag, "channelActive ===> 连接成功")
+ listener?.onServiceStatusConnectChanged(ISocketListener.STATUS_CONNECT_SUCCESS)
+ }
+
+ override fun channelInactive(ctx: ChannelHandlerContext) {
+ super.channelInactive(ctx)
+ Log.e(kTag, "channelInactive: 连接断开")
+ }
+
+ override fun userEventTriggered(ctx: ChannelHandlerContext, evt: Any) {
+ super.userEventTriggered(ctx, evt)
+ if (evt is IdleStateEvent) {
+ if (evt.state() == IdleState.WRITER_IDLE) {
+ //写超时,此时可以发送心跳数据给服务器
+ val temp = "FF"
+ ctx.writeAndFlush(temp.toByteArray(StandardCharsets.UTF_8))
+ } else if (evt.state() == IdleState.READER_IDLE) {
+ //读超时,此时代表没有收到心跳返回可以关闭当前连接进行重连
+ ctx.close()
+ }
+ }
+ }
+
+ override fun channelRead0(ctx: ChannelHandlerContext, data: ByteArray?) {
+ listener?.onMessageResponse(data)
+ }
+
+ override fun exceptionCaught(ctx: ChannelHandlerContext, cause: Throwable) {
+ super.exceptionCaught(ctx, cause)
+ Log.d(kTag, "exceptionCaught ===> $cause")
+ listener?.onServiceStatusConnectChanged(ISocketListener.STATUS_CONNECT_ERROR)
+ cause.printStackTrace()
+ ctx.close()
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/br/ktd/netty/tcp/SocketClient.kt b/app/src/main/java/com/casic/br/ktd/netty/tcp/SocketClient.kt
new file mode 100644
index 0000000..34960a0
--- /dev/null
+++ b/app/src/main/java/com/casic/br/ktd/netty/tcp/SocketClient.kt
@@ -0,0 +1,153 @@
+package com.casic.br.ktd.netty.tcp
+
+import android.os.SystemClock
+import android.util.Log
+import io.netty.bootstrap.Bootstrap
+import io.netty.channel.*
+import io.netty.channel.nio.NioEventLoopGroup
+import io.netty.channel.socket.SocketChannel
+import io.netty.channel.socket.nio.NioSocketChannel
+import io.netty.handler.codec.bytes.ByteArrayDecoder
+import io.netty.handler.codec.bytes.ByteArrayEncoder
+import io.netty.handler.timeout.IdleStateHandler
+
+class SocketClient {
+
+ private val kTag = "SocketClient"
+
+ private var host: String? = null
+ private var port = 8000
+ private var nioEventLoopGroup: NioEventLoopGroup? = null
+ private var channel: Channel? = null
+ private var listener: ISocketListener? = null
+
+ //现在连接的状态
+ var connectStatus = false //判断是否已连接
+ private var reconnectNum = Int.MAX_VALUE //定义的重连到时候用
+ private var isNeedReconnect = true //是否需要重连
+ var isConnecting = false //是否正在连接
+ private set
+ private var reconnectIntervalTime: Long = 15000 //重连的时间
+
+ //重连时间
+ fun setReconnectNum(reconnectNum: Int) {
+ this.reconnectNum = reconnectNum
+ }
+
+ fun setReconnectIntervalTime(reconnectIntervalTime: Long) {
+ this.reconnectIntervalTime = reconnectIntervalTime
+ }
+
+ fun setSocketListener(listener: ISocketListener?) {
+ this.listener = listener
+ }
+
+ fun connect(host: String, port: Int) {
+ this.host = host
+ this.port = port
+ Log.d(kTag, "connect ===> 开始连接TCP服务器")
+ if (isConnecting) {
+ return
+ }
+ //起个线程
+ val clientThread: Thread = object : Thread("client-Netty") {
+ override fun run() {
+ super.run()
+ isNeedReconnect = true
+ reconnectNum = Int.MAX_VALUE
+ connectServer()
+ }
+ }
+ clientThread.start()
+ }
+
+ private fun connectServer() {
+ synchronized(this@SocketClient) {
+ var channelFuture: ChannelFuture? = null //连接管理对象
+ if (!connectStatus) {
+ isConnecting = true
+ nioEventLoopGroup = NioEventLoopGroup() //设置的连接group
+ val bootstrap = Bootstrap()
+ bootstrap.group(nioEventLoopGroup) //设置的一系列连接参数操作等
+ .channel(NioSocketChannel::class.java)
+ .option(ChannelOption.TCP_NODELAY, true) //无阻塞
+ .option(ChannelOption.SO_KEEPALIVE, true) //长连接
+ .option(
+ ChannelOption.RCVBUF_ALLOCATOR,
+ AdaptiveRecvByteBufAllocator(5000, 5000, 8000)
+ ) //接收缓冲区 最小值太小时数据接收不全
+ .handler(object : ChannelInitializer() {
+ override fun initChannel(channel: SocketChannel) {
+ val pipeline = channel.pipeline()
+ //参数1:代表读套接字超时的时间,没收到数据会触发读超时回调;
+ //参数2:代表写套接字超时时间,没进行写会触发写超时回调;
+ //参数3:将在未执行读取或写入时触发超时回调,0代表不处理;
+ //读超时尽量设置大于写超时,代表多次写超时时写心跳包,多次写了心跳数据仍然读超时代表当前连接错误,即可断开连接重新连接
+ pipeline.addLast(IdleStateHandler(60, 10, 0))
+ pipeline.addLast(ByteArrayDecoder())
+ pipeline.addLast(ByteArrayEncoder())
+ pipeline.addLast(SocketChannelHandle(listener))
+ }
+ })
+ try {
+ //连接监听
+ channelFuture = bootstrap.connect(host, port)
+ .addListener(object : ChannelFutureListener {
+ override fun operationComplete(channelFuture: ChannelFuture) {
+ if (channelFuture.isSuccess) {
+ connectStatus = true
+ channel = channelFuture.channel()
+ } else {
+ Log.e(kTag, "operationComplete: 连接失败")
+ connectStatus = false
+ }
+ isConnecting = false
+ }
+ }).sync()
+ // 等待连接关闭
+ channelFuture.channel().closeFuture().sync()
+ } catch (e: Exception) {
+ e.printStackTrace()
+ } finally {
+ connectStatus = false
+ listener?.onServiceStatusConnectChanged(ISocketListener.STATUS_CONNECT_CLOSED) //STATUS_CONNECT_CLOSED 这我自己定义的 接口标识
+ if (null != channelFuture) {
+ if (channelFuture.channel() != null && channelFuture.channel().isOpen) {
+ channelFuture.channel().close()
+ }
+ }
+ nioEventLoopGroup?.shutdownGracefully()
+ reconnect() //重新连接
+ }
+ }
+ }
+ }
+
+ //断开连接
+ fun disconnect() {
+ Log.d(kTag, "disconnect ===> 断开连接")
+ isNeedReconnect = false
+ nioEventLoopGroup?.shutdownGracefully()
+ }
+
+ //重新连接
+ private fun reconnect() {
+ if (isNeedReconnect && reconnectNum > 0 && !connectStatus) {
+ reconnectNum--
+ SystemClock.sleep(reconnectIntervalTime)
+ if (isNeedReconnect && reconnectNum > 0 && !connectStatus) {
+ Log.d(kTag, "reconnect ===> 重新连接")
+ connectServer()
+ }
+ }
+ }
+
+ fun sendData(bytes: ByteArray) {
+ channel?.writeAndFlush(bytes)?.addListener(ChannelFutureListener { future ->
+ if (!future.isSuccess) {
+ future.channel().close()
+ nioEventLoopGroup!!.shutdownGracefully()
+ }
+ })
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/br/ktd/netty/tcp/SocketManager.kt b/app/src/main/java/com/casic/br/ktd/netty/tcp/SocketManager.kt
new file mode 100644
index 0000000..35980b9
--- /dev/null
+++ b/app/src/main/java/com/casic/br/ktd/netty/tcp/SocketManager.kt
@@ -0,0 +1,113 @@
+package com.casic.br.ktd.netty.tcp
+
+import android.util.Log
+import com.casic.br.ktd.base.BaseApplication
+import com.casic.br.ktd.extensions.covertAngleValue
+import com.casic.br.ktd.extensions.covertDataValue
+import com.casic.br.ktd.extensions.toUnsignedByteArray
+import com.casic.br.ktd.model.SensorDataModel
+import com.casic.br.ktd.utils.LocaleConstant
+import com.pengxh.kt.lite.extensions.toJson
+import com.pengxh.kt.lite.utils.BroadcastManager
+
+class SocketManager private constructor() : ISocketListener {
+
+ private val kTag = "SocketManager"
+ private var nettyClient: SocketClient = SocketClient()
+
+ companion object {
+ val instance: SocketManager by lazy(mode = LazyThreadSafetyMode.SYNCHRONIZED) { SocketManager() }
+ }
+
+ fun connectNetty(hostname: String, port: Int) {
+ Thread {
+ if (!nettyClient.connectStatus) {
+ nettyClient.setSocketListener(this)
+ nettyClient.connect(hostname, port)
+ } else {
+ nettyClient.disconnect()
+ }
+ }.start()
+ }
+
+ override fun onMessageResponse(data: ByteArray?) {
+// Log.d(kTag, "onMessageResponse ===> " + Arrays.toString(data))
+ /**
+ * 0xFF,0x01,
+ * 0x01,0x37,0xE6, 甲烷浓度值(数据码1* 65536 + 数据码2 * 256 + 数据码3)
+ * 0x00, 激光甲烷模块工作状态(00表示设备正常,01表示温控故障,02表示设备激光未打开)
+ * 0x00,0xB2,0x35, 激光强度值(数据码5* 65536 + 数据码6 * 256 + 数据码7)
+ * 0x0A,0x3D, 云台水平角度([数据码8 * 256 + 数据码9]/100,单位为°,精确到0.01)
+ * 0x05,0x6F, 云台垂直角度(首先计算Tangle=[数据码10 * 256 + 数据码11]/100,单位为°,精确到0.01。若Tangle在0~90范围内,则垂直角度值=Tangle;若Tangle在-1~-90范围内,则垂直角度值=Tangle-360)
+ * 0xC1
+ *
+ * [-1, 1, 1, 55, -26, 0, 0, -78, 53, 10, 61, 5, 111, -63]
+ * 甲烷浓度值为79638,计算为79638=0x01*65536+0x37*256+0xE6[0x01为数据码1,0x37为数据码2,0xE6为数据码3];
+ * 激光甲烷设备状态值为0,表示状态正常,[0x00为数据码4];
+ * 激光强度值为45621,计算为45621=0x00*65536+0xB2*256+0x35[0x00为数据码5,0xB2为数据码6,0x35为数据码7];
+ *
+ * =========================================================================================
+ * 实际数据(1800-1950左右)
+ * [-86, 1, 0, 7, 71, 0, 0, 62, -92, 57, 59, -118, -111, -64]
+ * */
+
+ if (data == null) {
+ return
+ }
+ val bytes = data.toUnsignedByteArray()
+ if (bytes.size == 14) {
+ val dataModel = SensorDataModel(0, "激光未打开", 0, 0.0, 0.0)
+
+ val methaneBytes = IntArray(3)
+ System.arraycopy(bytes, 2, methaneBytes, 0, 3)
+ dataModel.methane = methaneBytes.covertDataValue()
+
+ dataModel.methaneState = when (bytes[5]) {
+ 1 -> "温控故障"
+ 2 -> "激光未打开"
+ else -> "正常"
+ }
+
+ val laserBytes = IntArray(3)
+ System.arraycopy(bytes, 6, laserBytes, 0, 3)
+ dataModel.laser = laserBytes.covertDataValue()
+
+ /**
+ * 水平角度的实际范围为从水平零点开始,顺时针方向(从上往下看),0~360°
+ * 垂直角度的实际范围为从垂直零点开始,以向上为正,-90°~90°,控制精度为0.01°
+ * */
+ val horizontalBytes = IntArray(2)
+ System.arraycopy(bytes, 9, horizontalBytes, 0, 2)
+ dataModel.horizontal = horizontalBytes.covertAngleValue()
+
+ val verticalBytes = IntArray(2)
+ System.arraycopy(bytes, 11, verticalBytes, 0, 2)
+ dataModel.vertical = verticalBytes.covertAngleValue()
+
+ //{"horizontal":26.21,"laser":45621,"methane":79846,"methaneState":"正常","vertical":13.91}
+ BroadcastManager.obtainInstance(BaseApplication.get()).sendBroadcast(
+ LocaleConstant.ACTION_UPDATE_DATA, dataModel.toJson()
+ )
+ }
+ }
+
+ override fun onServiceStatusConnectChanged(statusCode: Byte) {
+ if (statusCode == ISocketListener.STATUS_CONNECT_SUCCESS) {
+ if (nettyClient.connectStatus) {
+ Log.d(kTag, "连接成功")
+ }
+ } else {
+ if (!nettyClient.connectStatus) {
+ Log.e(kTag, "onServiceStatusConnectChanged:$statusCode,连接断开,正在重连")
+ }
+ }
+ }
+
+ fun sendData(data: ByteArray) {
+ nettyClient.sendData(data)
+ }
+
+ fun close() {
+ nettyClient.disconnect()
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/br/ktd/netty/udp/UdpChannelInboundHandler.kt b/app/src/main/java/com/casic/br/ktd/netty/udp/UdpChannelInboundHandler.kt
new file mode 100644
index 0000000..4d6f97c
--- /dev/null
+++ b/app/src/main/java/com/casic/br/ktd/netty/udp/UdpChannelInboundHandler.kt
@@ -0,0 +1,36 @@
+package com.casic.br.ktd.netty.udp
+
+import io.netty.channel.ChannelHandlerContext
+import io.netty.channel.SimpleChannelInboundHandler
+import io.netty.channel.socket.DatagramPacket
+import io.netty.util.CharsetUtil
+
+
+abstract class UdpChannelInboundHandler : SimpleChannelInboundHandler() {
+
+ private var handlerContext: ChannelHandlerContext? = null
+
+ override fun channelActive(ctx: ChannelHandlerContext?) {
+ super.channelActive(ctx)
+ handlerContext = ctx
+ }
+
+ override fun channelInactive(ctx: ChannelHandlerContext?) {
+ super.channelInactive(ctx)
+ handlerContext?.close()
+ }
+
+ fun sendDatagramPacket(obj: Any) {
+ handlerContext?.writeAndFlush(obj)
+ }
+
+ fun releasePort() {
+ handlerContext?.close()
+ }
+
+ override fun channelRead0(ctx: ChannelHandlerContext, datagramPacket: DatagramPacket) {
+ receivedMessage(datagramPacket.content().toString(CharsetUtil.UTF_8))
+ }
+
+ abstract fun receivedMessage(data: String)
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/br/ktd/netty/udp/UdpChannelInitializer.kt b/app/src/main/java/com/casic/br/ktd/netty/udp/UdpChannelInitializer.kt
new file mode 100644
index 0000000..416c5a1
--- /dev/null
+++ b/app/src/main/java/com/casic/br/ktd/netty/udp/UdpChannelInitializer.kt
@@ -0,0 +1,17 @@
+package com.casic.br.ktd.netty.udp
+
+import io.netty.channel.ChannelInitializer
+import io.netty.channel.socket.DatagramChannel
+import io.netty.handler.timeout.IdleStateHandler
+
+
+open class UdpChannelInitializer(private val handler: UdpChannelInboundHandler) :
+ ChannelInitializer() {
+
+ override fun initChannel(datagramChannel: DatagramChannel) {
+ val pipeline = datagramChannel.pipeline()
+ pipeline.addLast(
+ IdleStateHandler(12, 15, 0)
+ ).addLast(handler)
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/br/ktd/netty/udp/UdpClient.kt b/app/src/main/java/com/casic/br/ktd/netty/udp/UdpClient.kt
new file mode 100644
index 0000000..3893afa
--- /dev/null
+++ b/app/src/main/java/com/casic/br/ktd/netty/udp/UdpClient.kt
@@ -0,0 +1,103 @@
+package com.casic.br.ktd.netty.udp
+
+import com.casic.br.ktd.utils.LocaleConstant
+import com.pengxh.kt.lite.utils.SaveKeyValues
+import io.netty.bootstrap.Bootstrap
+import io.netty.buffer.ByteBuf
+import io.netty.buffer.Unpooled
+import io.netty.channel.ChannelOption
+import io.netty.channel.nio.NioEventLoopGroup
+import io.netty.channel.socket.DatagramPacket
+import io.netty.channel.socket.nio.NioDatagramChannel
+import io.netty.util.CharsetUtil
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.launch
+import kotlinx.coroutines.withContext
+import java.net.InetSocketAddress
+import java.util.concurrent.ExecutorService
+import java.util.concurrent.Executors
+
+
+class UdpClient : UdpChannelInboundHandler(), Runnable {
+
+ private val bootStrap by lazy { Bootstrap() }
+ private val eventLoopGroup by lazy { NioEventLoopGroup() }
+ private val udpChannelInitializer by lazy { UdpChannelInitializer(this) }
+ private var executorService: ExecutorService
+
+ init {
+ bootStrap.group(eventLoopGroup)
+ bootStrap.channel(NioDatagramChannel::class.java)
+ .option(ChannelOption.SO_RCVBUF, 1024)
+ .option(ChannelOption.SO_SNDBUF, 1024)
+ bootStrap.handler(udpChannelInitializer)
+
+ executorService = Executors.newSingleThreadExecutor()
+ executorService.execute(this)
+ }
+
+ override fun run() {
+ try {
+ val channelFuture = bootStrap.bind(LocaleConstant.LOCATION_UDP_PORT).sync()
+ channelFuture.channel().closeFuture().sync()
+ } catch (e: InterruptedException) {
+ e.printStackTrace()
+ } finally {
+ eventLoopGroup.shutdownGracefully()
+ }
+ }
+
+ fun send(value: String) {
+ CoroutineScope(Dispatchers.Main).launch {
+ withContext(Dispatchers.IO) {
+ val host = SaveKeyValues.getValue(
+ LocaleConstant.LOCATION_UDP_SERVER, "192.168.149.213"
+ ).toString()
+ val datagramPacket = DatagramPacket(
+ Unpooled.copiedBuffer(value, CharsetUtil.UTF_8),
+ InetSocketAddress(host, LocaleConstant.LOCATION_UDP_PORT)
+ )
+ sendDatagramPacket(datagramPacket)
+ }
+ }
+ }
+
+ fun send(value: ByteArray) {
+ CoroutineScope(Dispatchers.Main).launch {
+ withContext(Dispatchers.IO) {
+ val host = SaveKeyValues.getValue(
+ LocaleConstant.LOCATION_UDP_SERVER, "192.168.149.213"
+ ).toString()
+ val datagramPacket = DatagramPacket(
+ Unpooled.copiedBuffer(value),
+ InetSocketAddress(host, LocaleConstant.LOCATION_UDP_PORT)
+ )
+ sendDatagramPacket(datagramPacket)
+ }
+ }
+ }
+
+ fun send(value: ByteBuf) {
+ CoroutineScope(Dispatchers.Main).launch {
+ withContext(Dispatchers.IO) {
+ val host = SaveKeyValues.getValue(
+ LocaleConstant.LOCATION_UDP_SERVER, "192.168.149.213"
+ ).toString()
+ val datagramPacket = DatagramPacket(
+ Unpooled.copiedBuffer(value),
+ InetSocketAddress(host, LocaleConstant.LOCATION_UDP_PORT)
+ )
+ sendDatagramPacket(datagramPacket)
+ }
+ }
+ }
+
+ fun release() {
+ releasePort()
+ }
+
+ override fun receivedMessage(data: String) {
+
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/br/ktd/utils/LocaleConstant.kt b/app/src/main/java/com/casic/br/ktd/utils/LocaleConstant.kt
index 0dd119e..4c675df 100644
--- a/app/src/main/java/com/casic/br/ktd/utils/LocaleConstant.kt
+++ b/app/src/main/java/com/casic/br/ktd/utils/LocaleConstant.kt
@@ -50,6 +50,10 @@
const val DEV_NET_IP = "192.168.1.21"
const val DEV_NET_PORT = "8000"
+ //位置信息UDP端口
+ const val LOCATION_UDP_SERVER = "udpServer"
+ const val LOCATION_UDP_PORT = 7777
+
//BroadcastReceiver Action
const val ACTION_UPDATE_DATA = "update"
diff --git a/app/src/main/java/com/casic/br/ktd/utils/LocationHelper.kt b/app/src/main/java/com/casic/br/ktd/utils/LocationHelper.kt
index 8e31d3f..df6adb5 100644
--- a/app/src/main/java/com/casic/br/ktd/utils/LocationHelper.kt
+++ b/app/src/main/java/com/casic/br/ktd/utils/LocationHelper.kt
@@ -7,19 +7,40 @@
import android.location.LocationListener
import android.location.LocationManager
import android.os.Bundle
+import android.util.Log
import androidx.core.app.ActivityCompat
+import com.amap.api.location.AMapLocation
+import com.amap.api.location.AMapLocationClient
+import com.amap.api.location.AMapLocationClientOption
-object LocationHelper {
- fun obtainCurrentLocation(context: Context, listener: ILocationListener) {
+class LocationHelper private constructor() {
+
+ private val kTag = "LocationHelper"
+
+ companion object {
+ //Kotlin委托模式双重锁单例
+ val get: LocationHelper by lazy(mode = LazyThreadSafetyMode.SYNCHRONIZED) {
+ LocationHelper()
+ }
+ }
+
+ private val locationOption = AMapLocationClientOption()
+ private lateinit var locationClient: AMapLocationClient
+
+ init {
+ //设置定位模式为高精度模式,AMapLocationMode.Battery_Saving为低功耗模式,AMapLocationMode.Device_Sensors是仅设备模式
+ locationOption.locationMode = AMapLocationClientOption.AMapLocationMode.Hight_Accuracy
+ locationOption.isNeedAddress = true //设置是否返回地址信息(默认返回地址信息)
+ locationOption.isLocationCacheEnable = true //可选,设置是否使用缓存定位,默认为true
+ }
+
+ fun obtainLocation(context: Context, listener: ILocationListener) {
if (ActivityCompat.checkSelfPermission(
- context,
- Manifest.permission.ACCESS_LOCATION_EXTRA_COMMANDS
+ context, Manifest.permission.ACCESS_LOCATION_EXTRA_COMMANDS
) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(
- context,
- Manifest.permission.ACCESS_FINE_LOCATION
+ context, Manifest.permission.ACCESS_FINE_LOCATION
) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(
- context,
- Manifest.permission.ACCESS_COARSE_LOCATION
+ context, Manifest.permission.ACCESS_COARSE_LOCATION
) != PackageManager.PERMISSION_GRANTED
) {
return
@@ -38,7 +59,37 @@
})
}
+ /**
+ * 高德sdk定位
+ */
+ fun obtainLocationByGD(context: Context?, listener: ILocationListener) {
+ locationClient = AMapLocationClient(context)
+ //给定位客户端对象设置定位参数
+ locationClient.setLocationOption(locationOption)
+ //设置定位回调监听
+ locationClient.setLocationListener { aMapLocation ->
+ if (aMapLocation != null) {
+ if (aMapLocation.errorCode == 0) {
+ listener.onAMapLocationGet(aMapLocation)
+ } else {
+ Log.e(
+ kTag,
+ "ErrCode: ${aMapLocation.errorCode}, errInfo: ${aMapLocation.errorInfo}"
+ )
+ }
+ }
+ }
+ //启动定位
+ locationClient.startLocation()
+ }
+
+ fun stopLocation() {
+ locationClient.stopLocation()//停止定位
+ }
+
interface ILocationListener {
- fun onLocationGet(location: Location?) //高德定位数据
+ fun onLocationGet(location: Location?) //GPS定位数据
+
+ fun onAMapLocationGet(aMapLocation: AMapLocation?) //高德定位数据
}
}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/br/ktd/view/InspectionActivity.kt b/app/src/main/java/com/casic/br/ktd/view/InspectionActivity.kt
index 02c47f8..c893092 100644
--- a/app/src/main/java/com/casic/br/ktd/view/InspectionActivity.kt
+++ b/app/src/main/java/com/casic/br/ktd/view/InspectionActivity.kt
@@ -15,16 +15,21 @@
import android.view.SurfaceHolder
import android.view.View
import android.widget.AdapterView
-import com.amap.api.maps.*
+import com.amap.api.location.AMapLocation
+import com.amap.api.maps.AMap
+import com.amap.api.maps.CameraUpdateFactory
+import com.amap.api.maps.UiSettings
import com.amap.api.maps.model.CameraPosition
import com.amap.api.maps.model.LatLng
+import com.amap.api.maps.model.MyLocationStyle
import com.amap.api.maps.model.PolylineOptions
import com.casic.br.ktd.R
import com.casic.br.ktd.extensions.*
import com.casic.br.ktd.model.ChartPointModel
import com.casic.br.ktd.model.RouteModel
import com.casic.br.ktd.model.SensorDataModel
-import com.casic.br.ktd.netty.SocketManager
+import com.casic.br.ktd.netty.tcp.SocketManager
+import com.casic.br.ktd.netty.udp.UdpClient
import com.casic.br.ktd.utils.LocaleConstant
import com.casic.br.ktd.utils.LocationHelper
import com.casic.br.ktd.widgets.AlertControlDialog
@@ -49,6 +54,10 @@
import hcnetsdk.sdkhub.MessageCodeHub
import hcnetsdk.sdkhub.SDKGuider
import kotlinx.android.synthetic.main.activity_inspection.*
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.launch
+import kotlinx.coroutines.withContext
import java.text.DecimalFormat
import java.text.SimpleDateFormat
import java.util.*
@@ -60,10 +69,10 @@
private val hkSDK by lazy { HCNetSDK.getInstance() }
private val timeFormat by lazy { SimpleDateFormat("yyyyMMddHHmmss", Locale.CHINA) }
private val latlngs = LinkedList()
- private val speedTimer by lazy { Timer() }
private val tcpTimer by lazy { Timer() }
private val decimalFormat by lazy { DecimalFormat("##0.0") }
private val gson by lazy { Gson() }
+ private val udpClient by lazy { UdpClient() }
private var isLoginSuccess = false
private var previewHandle = -1
private var selectChannel = -1
@@ -103,28 +112,32 @@
private lateinit var aMap: AMap
private lateinit var uiSettings: UiSettings
+ /**
+ * 协程配置云台设备,缓解新进页面较卡的问题
+ * */
private fun setDeviceConfig() {
- Log.d(kTag, "setDeviceConfig => 配置设备IP和端口")
- val device = SDKGuider.sdkGuider.devManageGuider.DeviceItem()
- device.m_szDevName = ""
- device.m_struNetInfo = SDKGuider.sdkGuider.devManageGuider.DevNetInfo(
- LocaleConstant.HK_NET_IP,
- LocaleConstant.HK_NET_PORT,
- LocaleConstant.HK_NET_USERNAME,
- LocaleConstant.HK_NET_PASSWORD
- )
- if (device.m_szDevName.isEmpty()) {
- device.m_szDevName = device.m_struNetInfo.m_szIp
- }
- isLoginSuccess = if (
- SDKGuider.sdkGuider.devManageGuider.login_v40_jna(
- device.m_szDevName, device.m_struNetInfo
- )
- ) {
- "设备连接成功".show(this)
- true
- } else {
- false
+ CoroutineScope(Dispatchers.Main).launch {
+ isLoginSuccess = withContext(Dispatchers.IO) {
+ Log.d(kTag, "setDeviceConfig => 配置设备IP和端口")
+ val device = SDKGuider.sdkGuider.devManageGuider.DeviceItem()
+ device.m_szDevName = ""
+ device.m_struNetInfo = SDKGuider.sdkGuider.devManageGuider.DevNetInfo(
+ LocaleConstant.HK_NET_IP,
+ LocaleConstant.HK_NET_PORT,
+ LocaleConstant.HK_NET_USERNAME,
+ LocaleConstant.HK_NET_PASSWORD
+ )
+ if (device.m_szDevName.isEmpty()) {
+ device.m_szDevName = device.m_struNetInfo.m_szIp
+ }
+
+ SDKGuider.sdkGuider.devManageGuider.login_v40_jna(
+ device.m_szDevName, device.m_struNetInfo
+ )
+ }
+ if (isLoginSuccess) {
+ "设备连接成功".show(context)
+ }
}
}
@@ -148,17 +161,74 @@
/**
* 手机GPS定位
* */
- val converter = CoordinateConverter(this)
- LocationHelper.obtainCurrentLocation(this, object : LocationHelper.ILocationListener {
+// val converter = CoordinateConverter(this)
+// LocationHelper.get.obtainLocation(this, object : LocationHelper.ILocationListener {
+// override fun onLocationGet(location: Location?) {
+// if (location == null) {
+// "当前信号弱,无法定位".show(context)
+// return
+// }
+//
+// //发送位置信息给UDP服务端
+// udpClient.send("${location.longitude}, ${location.latitude}")
+// Log.d(kTag, "onLocationGet => 速度:${location.speed}")
+//
+// //WGS-84要转为高德坐标系
+// converter.from(CoordinateConverter.CoordType.GPS)
+// converter.coord(LatLng(location.latitude, location.longitude))
+// val latLng = converter.convert()
+// latlngs.add(latLng)
+//
+// //移动到指定经纬度
+// val cameraPosition = CameraPosition(latLng, 13f, 0f, 0f)
+// val cameraUpdate = CameraUpdateFactory.newCameraPosition(cameraPosition)
+// aMap.animateCamera(cameraUpdate, 1500, null)
+//
+// //绘制线
+// aMap.addPolyline(
+// PolylineOptions().addAll(latlngs).width(12f).color(Color.RED)
+// )
+//
+// if (isStartInspect) {
+// val route = LinkedList()
+// latlngs.forEach {
+// route.add(RouteModel(it.latitude, it.longitude))
+// }
+// }
+// }
+//
+// override fun onAMapLocationGet(aMapLocation: AMapLocation?) {
+//
+// }
+// })
+
+ /**
+ * 高德定位
+ * */
+ LocationHelper.get.obtainLocationByGD(this, object : LocationHelper.ILocationListener {
override fun onLocationGet(location: Location?) {
- if (location == null) {
+
+ }
+
+ override fun onAMapLocationGet(aMapLocation: AMapLocation?) {
+ if (aMapLocation == null) {
"当前信号弱,无法定位".show(context)
return
}
+
+ //发送位置信息给UDP服务端
+ udpClient.send(
+ "${aMapLocation.longitude}, ${aMapLocation.latitude}, ${
+ System.currentTimeMillis().timestampToCompleteDate()
+ }"
+ )
+ //速度 转为 km/h
+ Log.d(kTag, "onLocationGet => 速度:${aMapLocation.speed}")
+ speed = decimalFormat.format(aMapLocation.speed * 3.6).toFloat()
+ carSpeedView.text = String.format("${speed}Km/h")
+
//WGS-84要转为高德坐标系
- converter.from(CoordinateConverter.CoordType.GPS)
- converter.coord(LatLng(location.latitude, location.longitude))
- val latLng = converter.convert()
+ val latLng = LatLng(aMapLocation.latitude, aMapLocation.longitude)
latlngs.add(latLng)
//移动到指定经纬度
@@ -168,7 +238,7 @@
//绘制线
aMap.addPolyline(
- PolylineOptions().addAll(latlngs).width(12f).color(Color.RED)
+ PolylineOptions().addAll(latlngs).width(10f).color(Color.RED)
)
if (isStartInspect) {
@@ -181,27 +251,6 @@
})
/**
- * 计算速度,微分原理,3s计算一次速度
- * */
- speedTimer.schedule(object : TimerTask() {
- override fun run() {
- //经纬度链表数据小于2,无法计算速度,默认为0
- speed = if (latlngs.size < 2) 0.0f else {
- val temp = AMapUtils.calculateLineDistance(
- latlngs.last(), latlngs[latlngs.size - 2]
- ) / 3
- //转为 km/h
- decimalFormat.format(temp * 3.6).toFloat()
- }
-
- //切换到UI线程更新界面数据
- runOnUiThread {
- carSpeedView.text = String.format("${speed}Km/h")
- }
- }
- }, 0, 3000)
-
- /**
* TCP初始化
* ***/
SocketManager.instance.connectNetty(
@@ -632,6 +681,8 @@
stopPreview()
BroadcastManager.obtainInstance(this).destroy(LocaleConstant.ACTION_UPDATE_DATA)
mapView.onDestroy()
+ udpClient.release()
+ LocationHelper.get.stopLocation()
}
override fun handleMessage(msg: Message): Boolean {
@@ -716,38 +767,13 @@
uiSettings.isZoomControlsEnabled = true
uiSettings.isTiltGesturesEnabled = false//不许地图随手势倾斜角度
-// val locationStyle = MyLocationStyle()
-// locationStyle.interval(2000)
-// locationStyle.showMyLocation(true)
-// locationStyle.myLocationType(MyLocationStyle.LOCATION_TYPE_LOCATION_ROTATE)
-// aMap.myLocationStyle = locationStyle
-// aMap.isMyLocationEnabled = true
-// aMap.animateCamera(CameraUpdateFactory.zoomTo(13f))
-// aMap.setOnMyLocationChangeListener(this)
+ //显示定位小蓝点
+ val locationStyle = MyLocationStyle()
+ locationStyle.showMyLocation(true)//设置是否显示定位小蓝点
+ aMap.myLocationStyle = locationStyle
+ aMap.isMyLocationEnabled = true
}
-// override fun onMyLocationChange(aMapLocation: Location?) {
-// if (aMapLocation == null) {
-// "当前信号弱,无法定位".show(context)
-// return
-// }
-// val latitude = aMapLocation.latitude
-// val longitude = aMapLocation.longitude
-// latlngs.add(LatLng(latitude, longitude))
-//
-// //绘制线
-// aMap.addPolyline(
-// PolylineOptions().addAll(latlngs).width(15f).color(Color.RED)
-// )
-//
-// if (isStartInspect) {
-// val route = LinkedList()
-// latlngs.forEach {
-// route.add(RouteModel(it.latitude, it.longitude))
-// }
-// }
-// }
-
/***以下是地图生命周期管理************************************************************************/
override fun onResume() {
diff --git a/app/src/main/res/layout/fragment_alarm.xml b/app/src/main/res/layout/fragment_alarm.xml
index a3ebc88..929529f 100644
--- a/app/src/main/res/layout/fragment_alarm.xml
+++ b/app/src/main/res/layout/fragment_alarm.xml
@@ -31,7 +31,7 @@
diff --git a/app/src/main/res/layout/fragment_task.xml b/app/src/main/res/layout/fragment_task.xml
index 35cb1a3..58d852e 100644
--- a/app/src/main/res/layout/fragment_task.xml
+++ b/app/src/main/res/layout/fragment_task.xml
@@ -31,7 +31,7 @@
diff --git a/app/src/main/res/mipmap-hdpi/end.png b/app/src/main/res/mipmap-hdpi/end.png
new file mode 100644
index 0000000..f31385b
--- /dev/null
+++ b/app/src/main/res/mipmap-hdpi/end.png
Binary files differ
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index e822df6..d72c1a5 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -7,6 +7,9 @@
+
+
+
@@ -46,5 +49,8 @@
+
+
+
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/br/ktd/base/KotlinBaseFragment.kt b/app/src/main/java/com/casic/br/ktd/base/KotlinBaseFragment.kt
new file mode 100644
index 0000000..2dac61c
--- /dev/null
+++ b/app/src/main/java/com/casic/br/ktd/base/KotlinBaseFragment.kt
@@ -0,0 +1,51 @@
+package com.casic.br.ktd.base
+
+import android.os.Bundle
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import androidx.annotation.LayoutRes
+import androidx.fragment.app.Fragment
+
+abstract class KotlinBaseFragment : Fragment() {
+
+ lateinit var bv: View
+
+ override fun onCreateView(
+ inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?
+ ): View? {
+ bv = inflater.inflate(initLayoutRes(), container, false)
+ initView(savedInstanceState)
+ setupTopBarLayout()
+ return bv
+ }
+
+ override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
+ super.onViewCreated(view, savedInstanceState)
+ observeRequestState()
+ initEvent()
+ }
+
+ @LayoutRes
+ abstract fun initLayoutRes(): Int
+
+ /**
+ * 沉浸式状态栏
+ */
+ abstract fun setupTopBarLayout()
+
+ /**
+ * 初始化布局以及控件
+ */
+ abstract fun initView(savedInstanceState: Bundle?)
+
+ /**
+ * 网络请求状态监听
+ */
+ abstract fun observeRequestState()
+
+ /**
+ * 业务逻辑,按钮等事件
+ */
+ abstract fun initEvent()
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/br/ktd/fragment/AlarmPageFragment.kt b/app/src/main/java/com/casic/br/ktd/fragment/AlarmPageFragment.kt
index 6c98a3b..9418169 100644
--- a/app/src/main/java/com/casic/br/ktd/fragment/AlarmPageFragment.kt
+++ b/app/src/main/java/com/casic/br/ktd/fragment/AlarmPageFragment.kt
@@ -2,28 +2,29 @@
import android.os.Bundle
import com.casic.br.ktd.R
+import com.casic.br.ktd.base.KotlinBaseFragment
import com.casic.br.ktd.widgets.DateRangeActionSheet
-import com.pengxh.kt.lite.base.KotlinBaseFragment
import kotlinx.android.synthetic.main.fragment_alarm.view.*
class AlarmPageFragment : KotlinBaseFragment() {
- override fun initData(savedInstanceState: Bundle?) {
+
+ override fun initView(savedInstanceState: Bundle?) {
}
override fun initEvent() {
- baseView.calendarView.setOnClickListener {
+ bv.calendarView.setOnClickListener {
DateRangeActionSheet.Builder().setContext(requireContext())
.setOnActionSheetListener(object :
DateRangeActionSheet.OnDateRangeSelectedListener {
override fun onDateRangeSelected(startDate: String, endDate: String) {
- baseView.selectedDateView.text = "$startDate ~ $endDate"
+ bv.selectedDateView.text = "$startDate ~ $endDate"
}
}).build().show()
}
}
- override fun initLayoutView(): Int = R.layout.fragment_alarm
+ override fun initLayoutRes(): Int = R.layout.fragment_alarm
override fun observeRequestState() {
diff --git a/app/src/main/java/com/casic/br/ktd/fragment/HomePageFragment.kt b/app/src/main/java/com/casic/br/ktd/fragment/HomePageFragment.kt
index 9961935..f3eba5c 100644
--- a/app/src/main/java/com/casic/br/ktd/fragment/HomePageFragment.kt
+++ b/app/src/main/java/com/casic/br/ktd/fragment/HomePageFragment.kt
@@ -1,32 +1,62 @@
package com.casic.br.ktd.fragment
+import android.graphics.Color
import android.os.Bundle
import com.amap.api.maps.AMap
import com.amap.api.maps.AMapOptions
+import com.amap.api.maps.CameraUpdateFactory
+import com.amap.api.maps.model.*
import com.casic.br.ktd.R
-import com.pengxh.kt.lite.base.KotlinBaseFragment
+import com.casic.br.ktd.base.KotlinBaseFragment
import kotlinx.android.synthetic.main.fragment_home.view.*
class HomePageFragment : KotlinBaseFragment() {
private lateinit var aMap: AMap
- override fun initData(savedInstanceState: Bundle?) {
- baseView.mapView.onCreate(savedInstanceState)
- aMap = baseView.mapView.map
+ override fun initView(savedInstanceState: Bundle?) {
+ bv.mapView.onCreate(savedInstanceState)
+ aMap = bv.mapView.map
val uiSettings = aMap.uiSettings
uiSettings.isCompassEnabled = true
- uiSettings.isMyLocationButtonEnabled = true
+ uiSettings.isMyLocationButtonEnabled = false
uiSettings.isScaleControlsEnabled = true
uiSettings.zoomPosition = AMapOptions.ZOOM_POSITION_RIGHT_CENTER
uiSettings.isRotateGesturesEnabled = false//不许地图随手势旋转角度
}
override fun initEvent() {
-
+ //移动到巡检起始经纬度
+ val cameraPosition = CameraPosition(LatLng(39.914199, 116.265785), 16f, 0f, 0f)
+ val cameraUpdate = CameraUpdateFactory.newCameraPosition(cameraPosition)
+ aMap.animateCamera(cameraUpdate, 1500, null)
+ //设置起点
+ addMarker(LatLng(39.914885, 116.272312), R.mipmap.start)
+ //设置终点
+ addMarker(LatLng(39.914716, 116.265097), R.mipmap.end)
+ //瞄点画线
+ val latLngPoints = ArrayList()
+ latLngPoints.add(LatLng(39.914885, 116.272312))
+ latLngPoints.add(LatLng(39.915148, 116.272312))
+ latLngPoints.add(LatLng(39.915399, 116.272302))
+ latLngPoints.add(LatLng(39.915436, 116.271787))
+ latLngPoints.add(LatLng(39.915477, 116.270886))
+ latLngPoints.add(LatLng(39.915477, 116.269968))
+ latLngPoints.add(LatLng(39.915469, 116.269544))
+ latLngPoints.add(LatLng(39.915481, 116.269196))
+ latLngPoints.add(LatLng(39.915452, 116.268472))
+ latLngPoints.add(LatLng(39.915444, 116.267722))
+ latLngPoints.add(LatLng(39.915415, 116.266755))
+ latLngPoints.add(LatLng(39.915403, 116.266165))
+ latLngPoints.add(LatLng(39.915395, 116.265703))
+ latLngPoints.add(LatLng(39.915366, 116.265119))
+ latLngPoints.add(LatLng(39.914716, 116.265097))
+ aMap.addPolyline(
+ PolylineOptions().addAll(latLngPoints).width(10.toFloat()).color(Color.RED)
+ )
}
- override fun initLayoutView(): Int = R.layout.fragment_home
+ override fun initLayoutRes(): Int = R.layout.fragment_home
override fun observeRequestState() {
@@ -36,25 +66,32 @@
}
+ private fun addMarker(point: LatLng, res: Int) {
+ val markerOption = MarkerOptions()
+ markerOption.position(point)
+ markerOption.icon(BitmapDescriptorFactory.fromResource(res))
+ aMap.addMarker(markerOption)
+ }
+
/***以下是地图生命周期管理************************************************************************/
override fun onResume() {
super.onResume()
- baseView.mapView.onResume()
+ bv.mapView.onResume()
}
override fun onPause() {
- baseView.mapView.onPause()
super.onPause()
+ bv.mapView.onPause()
}
override fun onSaveInstanceState(outState: Bundle) {
super.onSaveInstanceState(outState)
- baseView.mapView.onSaveInstanceState(outState)
+ bv.mapView.onSaveInstanceState(outState)
}
override fun onDestroy() {
- baseView.mapView.onDestroy()
super.onDestroy()
+ bv.mapView.onDestroy()
}
}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/br/ktd/fragment/MinePageFragment.kt b/app/src/main/java/com/casic/br/ktd/fragment/MinePageFragment.kt
index 90313ac..3212794 100644
--- a/app/src/main/java/com/casic/br/ktd/fragment/MinePageFragment.kt
+++ b/app/src/main/java/com/casic/br/ktd/fragment/MinePageFragment.kt
@@ -2,10 +2,11 @@
import android.os.Bundle
import com.casic.br.ktd.R
-import com.pengxh.kt.lite.base.KotlinBaseFragment
+import com.casic.br.ktd.base.KotlinBaseFragment
class MinePageFragment : KotlinBaseFragment() {
- override fun initData(savedInstanceState: Bundle?) {
+
+ override fun initView(savedInstanceState: Bundle?) {
}
@@ -13,7 +14,7 @@
}
- override fun initLayoutView(): Int = R.layout.fragment_mine
+ override fun initLayoutRes(): Int = R.layout.fragment_mine
override fun observeRequestState() {
diff --git a/app/src/main/java/com/casic/br/ktd/fragment/TaskPageFragment.kt b/app/src/main/java/com/casic/br/ktd/fragment/TaskPageFragment.kt
index 8f6abf0..6b82a54 100644
--- a/app/src/main/java/com/casic/br/ktd/fragment/TaskPageFragment.kt
+++ b/app/src/main/java/com/casic/br/ktd/fragment/TaskPageFragment.kt
@@ -8,6 +8,7 @@
import androidx.recyclerview.widget.RecyclerView
import com.casic.br.ktd.R
import com.casic.br.ktd.adapter.TaskAdapter
+import com.casic.br.ktd.base.KotlinBaseFragment
import com.casic.br.ktd.holder.SwipeViewHolder
import com.casic.br.ktd.model.TaskListModel
import com.casic.br.ktd.view.InspectionActivity
@@ -15,7 +16,6 @@
import com.casic.br.ktd.widgets.AlertControlDialog
import com.casic.br.ktd.widgets.AlertInputDialog
import com.casic.br.ktd.widgets.DateRangeActionSheet
-import com.pengxh.kt.lite.base.KotlinBaseFragment
import com.pengxh.kt.lite.extensions.navigatePageTo
import com.pengxh.kt.lite.extensions.show
import com.pengxh.kt.lite.utils.WeakReferenceHandler
@@ -36,7 +36,7 @@
private var startTime = ""
private var endTime = ""
- override fun initData(savedInstanceState: Bundle?) {
+ override fun initView(savedInstanceState: Bundle?) {
weakReferenceHandler = WeakReferenceHandler(this)
taskViewModel = ViewModelProvider(this)[TaskViewModel::class.java]
taskViewModel.taskList.observe(this) {
@@ -45,7 +45,7 @@
when {
isRefresh -> {
taskAdapter.setRefreshData(dataRows)
- baseView.taskLayout.finishRefresh()
+ bv.taskLayout.finishRefresh()
isRefresh = false
}
isLoadMore -> {
@@ -53,7 +53,7 @@
"到底了,别拉了".show(requireContext())
}
taskAdapter.setLoadMoreData(dataRows)
- baseView.taskLayout.finishLoadMore()
+ bv.taskLayout.finishLoadMore()
isLoadMore = false
}
else -> {
@@ -76,9 +76,9 @@
when (msg.what) {
2023070501 -> {
if (dataBeans.size == 0) {
- baseView.emptyLayout.visibility = View.VISIBLE
+ bv.emptyLayout.visibility = View.VISIBLE
} else {
- baseView.emptyLayout.visibility = View.GONE
+ bv.emptyLayout.visibility = View.GONE
taskAdapter = object : TaskAdapter(
requireContext(), R.layout.item_task_rv_l, dataBeans
) {
@@ -97,8 +97,8 @@
}
}
//绑定侧滑事件
- swipeAction.attachToRecyclerView(baseView.taskRecyclerView)
- baseView.taskRecyclerView.adapter = taskAdapter
+ swipeAction.attachToRecyclerView(bv.taskRecyclerView)
+ bv.taskRecyclerView.adapter = taskAdapter
taskAdapter.setOnItemCheckedListener(object :
TaskAdapter.OnItemCheckedListener {
override fun onItemChecked(items: ArrayList) {
@@ -168,7 +168,7 @@
override fun initEvent() {
- baseView.calendarView.setOnClickListener {
+ bv.calendarView.setOnClickListener {
DateRangeActionSheet.Builder().setContext(requireContext())
.setOnActionSheetListener(object :
DateRangeActionSheet.OnDateRangeSelectedListener {
@@ -177,12 +177,12 @@
endTime = endDate
//显示
- baseView.selectedDateView.text = "$startDate ~ $endDate"
+ bv.selectedDateView.text = "$startDate ~ $endDate"
}
}).build().show()
}
- baseView.addTaskButton.setOnClickListener {
+ bv.addTaskButton.setOnClickListener {
// AlertInputDialog.Builder()
// .setContext(requireContext())
// .setTitle("新建巡检任务")
@@ -200,11 +200,11 @@
requireContext().navigatePageTo()
}
- baseView.deleteTaskButton.setOnClickListener {
+ bv.deleteTaskButton.setOnClickListener {
selectedItems.size.toString().show(requireContext())
}
- baseView.taskSettingsButton.setOnClickListener {
+ bv.taskSettingsButton.setOnClickListener {
AlertInputDialog.Builder()
.setContext(requireContext())
.setTitle("设置阈值")
@@ -221,14 +221,14 @@
}).build().show()
}
- baseView.taskLayout.setOnRefreshListener {
+ bv.taskLayout.setOnRefreshListener {
isRefresh = true
//刷新之后页码重置
pageIndex = 1
getTaskList()
}
- baseView.taskLayout.setOnLoadMoreListener {
+ bv.taskLayout.setOnLoadMoreListener {
isLoadMore = true
pageIndex++
getTaskList()
@@ -239,13 +239,13 @@
taskViewModel.getTaskList(
startTime,
endTime,
- baseView.taskNameView.text.toString(),
- baseView.taskCodeView.text.toString(),
+ bv.taskNameView.text.toString(),
+ bv.taskCodeView.text.toString(),
pageIndex
)
}
- override fun initLayoutView(): Int = R.layout.fragment_task
+ override fun initLayoutRes(): Int = R.layout.fragment_task
override fun observeRequestState() {
diff --git a/app/src/main/java/com/casic/br/ktd/netty/ISocketListener.kt b/app/src/main/java/com/casic/br/ktd/netty/ISocketListener.kt
deleted file mode 100644
index dab98e1..0000000
--- a/app/src/main/java/com/casic/br/ktd/netty/ISocketListener.kt
+++ /dev/null
@@ -1,19 +0,0 @@
-package com.casic.br.ktd.netty
-
-interface ISocketListener {
- companion object {
- const val STATUS_CONNECT_SUCCESS: Byte = 1 //连接成功
- const val STATUS_CONNECT_CLOSED: Byte = 0 //关闭连接
- const val STATUS_CONNECT_ERROR: Byte = 0 //连接失败
- }
-
- /**
- * 当接收到系统消息
- */
- fun onMessageResponse(data: ByteArray?)
-
- /**
- * 当连接状态发生变化时调用
- */
- fun onServiceStatusConnectChanged(statusCode: Byte)
-}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/br/ktd/netty/SocketChannelHandle.kt b/app/src/main/java/com/casic/br/ktd/netty/SocketChannelHandle.kt
deleted file mode 100644
index 42eb310..0000000
--- a/app/src/main/java/com/casic/br/ktd/netty/SocketChannelHandle.kt
+++ /dev/null
@@ -1,51 +0,0 @@
-package com.casic.br.ktd.netty
-
-import android.util.Log
-import io.netty.channel.ChannelHandlerContext
-import io.netty.channel.SimpleChannelInboundHandler
-import io.netty.handler.timeout.IdleState
-import io.netty.handler.timeout.IdleStateEvent
-import java.nio.charset.StandardCharsets
-
-class SocketChannelHandle(private val listener: ISocketListener?) :
- SimpleChannelInboundHandler() {
-
- private val kTag = "SocketChannelHandle"
-
- override fun channelActive(ctx: ChannelHandlerContext) {
- super.channelActive(ctx)
- Log.d(kTag, "channelActive ===> 连接成功")
- listener?.onServiceStatusConnectChanged(ISocketListener.STATUS_CONNECT_SUCCESS)
- }
-
- override fun channelInactive(ctx: ChannelHandlerContext) {
- super.channelInactive(ctx)
- Log.e(kTag, "channelInactive: 连接断开")
- }
-
- override fun userEventTriggered(ctx: ChannelHandlerContext, evt: Any) {
- super.userEventTriggered(ctx, evt)
- if (evt is IdleStateEvent) {
- if (evt.state() == IdleState.WRITER_IDLE) {
- //写超时,此时可以发送心跳数据给服务器
- val temp = "FF"
- ctx.writeAndFlush(temp.toByteArray(StandardCharsets.UTF_8))
- } else if (evt.state() == IdleState.READER_IDLE) {
- //读超时,此时代表没有收到心跳返回可以关闭当前连接进行重连
- ctx.close()
- }
- }
- }
-
- override fun channelRead0(ctx: ChannelHandlerContext, data: ByteArray?) {
- listener?.onMessageResponse(data)
- }
-
- override fun exceptionCaught(ctx: ChannelHandlerContext, cause: Throwable) {
- super.exceptionCaught(ctx, cause)
- Log.d(kTag, "exceptionCaught ===> $cause")
- listener?.onServiceStatusConnectChanged(ISocketListener.STATUS_CONNECT_ERROR)
- cause.printStackTrace()
- ctx.close()
- }
-}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/br/ktd/netty/SocketClient.kt b/app/src/main/java/com/casic/br/ktd/netty/SocketClient.kt
deleted file mode 100644
index d05d335..0000000
--- a/app/src/main/java/com/casic/br/ktd/netty/SocketClient.kt
+++ /dev/null
@@ -1,153 +0,0 @@
-package com.casic.br.ktd.netty
-
-import android.os.SystemClock
-import android.util.Log
-import io.netty.bootstrap.Bootstrap
-import io.netty.channel.*
-import io.netty.channel.nio.NioEventLoopGroup
-import io.netty.channel.socket.SocketChannel
-import io.netty.channel.socket.nio.NioSocketChannel
-import io.netty.handler.codec.bytes.ByteArrayDecoder
-import io.netty.handler.codec.bytes.ByteArrayEncoder
-import io.netty.handler.timeout.IdleStateHandler
-
-class SocketClient {
-
- private val kTag = "SocketClient"
-
- private var host: String? = null
- private var port = 8000
- private var nioEventLoopGroup: NioEventLoopGroup? = null
- private var channel: Channel? = null
- private var listener: ISocketListener? = null
-
- //现在连接的状态
- var connectStatus = false //判断是否已连接
- private var reconnectNum = Int.MAX_VALUE //定义的重连到时候用
- private var isNeedReconnect = true //是否需要重连
- var isConnecting = false //是否正在连接
- private set
- private var reconnectIntervalTime: Long = 15000 //重连的时间
-
- //重连时间
- fun setReconnectNum(reconnectNum: Int) {
- this.reconnectNum = reconnectNum
- }
-
- fun setReconnectIntervalTime(reconnectIntervalTime: Long) {
- this.reconnectIntervalTime = reconnectIntervalTime
- }
-
- fun setSocketListener(listener: ISocketListener?) {
- this.listener = listener
- }
-
- fun connect(host: String, port: Int) {
- this.host = host
- this.port = port
- Log.d(kTag, "connect ===> 开始连接TCP服务器")
- if (isConnecting) {
- return
- }
- //起个线程
- val clientThread: Thread = object : Thread("client-Netty") {
- override fun run() {
- super.run()
- isNeedReconnect = true
- reconnectNum = Int.MAX_VALUE
- connectServer()
- }
- }
- clientThread.start()
- }
-
- private fun connectServer() {
- synchronized(this@SocketClient) {
- var channelFuture: ChannelFuture? = null //连接管理对象
- if (!connectStatus) {
- isConnecting = true
- nioEventLoopGroup = NioEventLoopGroup() //设置的连接group
- val bootstrap = Bootstrap()
- bootstrap.group(nioEventLoopGroup) //设置的一系列连接参数操作等
- .channel(NioSocketChannel::class.java)
- .option(ChannelOption.TCP_NODELAY, true) //无阻塞
- .option(ChannelOption.SO_KEEPALIVE, true) //长连接
- .option(
- ChannelOption.RCVBUF_ALLOCATOR,
- AdaptiveRecvByteBufAllocator(5000, 5000, 8000)
- ) //接收缓冲区 最小值太小时数据接收不全
- .handler(object : ChannelInitializer() {
- override fun initChannel(channel: SocketChannel) {
- val pipeline = channel.pipeline()
- //参数1:代表读套接字超时的时间,没收到数据会触发读超时回调;
- //参数2:代表写套接字超时时间,没进行写会触发写超时回调;
- //参数3:将在未执行读取或写入时触发超时回调,0代表不处理;
- //读超时尽量设置大于写超时,代表多次写超时时写心跳包,多次写了心跳数据仍然读超时代表当前连接错误,即可断开连接重新连接
- pipeline.addLast(IdleStateHandler(60, 10, 0))
- pipeline.addLast(ByteArrayDecoder())
- pipeline.addLast(ByteArrayEncoder())
- pipeline.addLast(SocketChannelHandle(listener))
- }
- })
- try {
- //连接监听
- channelFuture = bootstrap.connect(host, port)
- .addListener(object : ChannelFutureListener {
- override fun operationComplete(channelFuture: ChannelFuture) {
- if (channelFuture.isSuccess) {
- connectStatus = true
- channel = channelFuture.channel()
- } else {
- Log.e(kTag, "operationComplete: 连接失败")
- connectStatus = false
- }
- isConnecting = false
- }
- }).sync()
- // 等待连接关闭
- channelFuture.channel().closeFuture().sync()
- } catch (e: Exception) {
- e.printStackTrace()
- } finally {
- connectStatus = false
- listener?.onServiceStatusConnectChanged(ISocketListener.STATUS_CONNECT_CLOSED) //STATUS_CONNECT_CLOSED 这我自己定义的 接口标识
- if (null != channelFuture) {
- if (channelFuture.channel() != null && channelFuture.channel().isOpen) {
- channelFuture.channel().close()
- }
- }
- nioEventLoopGroup?.shutdownGracefully()
- reconnect() //重新连接
- }
- }
- }
- }
-
- //断开连接
- fun disconnect() {
- Log.d(kTag, "disconnect ===> 断开连接")
- isNeedReconnect = false
- nioEventLoopGroup?.shutdownGracefully()
- }
-
- //重新连接
- private fun reconnect() {
- if (isNeedReconnect && reconnectNum > 0 && !connectStatus) {
- reconnectNum--
- SystemClock.sleep(reconnectIntervalTime)
- if (isNeedReconnect && reconnectNum > 0 && !connectStatus) {
- Log.d(kTag, "reconnect ===> 重新连接")
- connectServer()
- }
- }
- }
-
- fun sendData(bytes: ByteArray) {
- channel?.writeAndFlush(bytes)?.addListener(ChannelFutureListener { future ->
- if (!future.isSuccess) {
- future.channel().close()
- nioEventLoopGroup!!.shutdownGracefully()
- }
- })
- }
-}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/br/ktd/netty/SocketManager.kt b/app/src/main/java/com/casic/br/ktd/netty/SocketManager.kt
deleted file mode 100644
index 17daf35..0000000
--- a/app/src/main/java/com/casic/br/ktd/netty/SocketManager.kt
+++ /dev/null
@@ -1,113 +0,0 @@
-package com.casic.br.ktd.netty
-
-import android.util.Log
-import com.casic.br.ktd.base.BaseApplication
-import com.casic.br.ktd.extensions.covertAngleValue
-import com.casic.br.ktd.extensions.covertDataValue
-import com.casic.br.ktd.extensions.toUnsignedByteArray
-import com.casic.br.ktd.model.SensorDataModel
-import com.casic.br.ktd.utils.LocaleConstant
-import com.pengxh.kt.lite.extensions.toJson
-import com.pengxh.kt.lite.utils.BroadcastManager
-
-class SocketManager private constructor() : ISocketListener {
-
- private val kTag = "SocketManager"
- private var nettyClient: SocketClient = SocketClient()
-
- companion object {
- val instance: SocketManager by lazy(mode = LazyThreadSafetyMode.SYNCHRONIZED) { SocketManager() }
- }
-
- fun connectNetty(hostname: String, port: Int) {
- Thread {
- if (!nettyClient.connectStatus) {
- nettyClient.setSocketListener(this)
- nettyClient.connect(hostname, port)
- } else {
- nettyClient.disconnect()
- }
- }.start()
- }
-
- override fun onMessageResponse(data: ByteArray?) {
-// Log.d(kTag, "onMessageResponse ===> " + Arrays.toString(data))
- /**
- * 0xFF,0x01,
- * 0x01,0x37,0xE6, 甲烷浓度值(数据码1* 65536 + 数据码2 * 256 + 数据码3)
- * 0x00, 激光甲烷模块工作状态(00表示设备正常,01表示温控故障,02表示设备激光未打开)
- * 0x00,0xB2,0x35, 激光强度值(数据码5* 65536 + 数据码6 * 256 + 数据码7)
- * 0x0A,0x3D, 云台水平角度([数据码8 * 256 + 数据码9]/100,单位为°,精确到0.01)
- * 0x05,0x6F, 云台垂直角度(首先计算Tangle=[数据码10 * 256 + 数据码11]/100,单位为°,精确到0.01。若Tangle在0~90范围内,则垂直角度值=Tangle;若Tangle在-1~-90范围内,则垂直角度值=Tangle-360)
- * 0xC1
- *
- * [-1, 1, 1, 55, -26, 0, 0, -78, 53, 10, 61, 5, 111, -63]
- * 甲烷浓度值为79638,计算为79638=0x01*65536+0x37*256+0xE6[0x01为数据码1,0x37为数据码2,0xE6为数据码3];
- * 激光甲烷设备状态值为0,表示状态正常,[0x00为数据码4];
- * 激光强度值为45621,计算为45621=0x00*65536+0xB2*256+0x35[0x00为数据码5,0xB2为数据码6,0x35为数据码7];
- *
- * =========================================================================================
- * 实际数据(1800-1950左右)
- * [-86, 1, 0, 7, 71, 0, 0, 62, -92, 57, 59, -118, -111, -64]
- * */
-
- if (data == null) {
- return
- }
- val bytes = data.toUnsignedByteArray()
- if (bytes.size == 14) {
- val dataModel = SensorDataModel(0, "激光未打开", 0, 0.0, 0.0)
-
- val methaneBytes = IntArray(3)
- System.arraycopy(bytes, 2, methaneBytes, 0, 3)
- dataModel.methane = methaneBytes.covertDataValue()
-
- dataModel.methaneState = when (bytes[5]) {
- 1 -> "温控故障"
- 2 -> "激光未打开"
- else -> "正常"
- }
-
- val laserBytes = IntArray(3)
- System.arraycopy(bytes, 6, laserBytes, 0, 3)
- dataModel.laser = laserBytes.covertDataValue()
-
- /**
- * 水平角度的实际范围为从水平零点开始,顺时针方向(从上往下看),0~360°
- * 垂直角度的实际范围为从垂直零点开始,以向上为正,-90°~90°,控制精度为0.01°
- * */
- val horizontalBytes = IntArray(2)
- System.arraycopy(bytes, 9, horizontalBytes, 0, 2)
- dataModel.horizontal = horizontalBytes.covertAngleValue()
-
- val verticalBytes = IntArray(2)
- System.arraycopy(bytes, 11, verticalBytes, 0, 2)
- dataModel.vertical = verticalBytes.covertAngleValue()
-
- //{"horizontal":26.21,"laser":45621,"methane":79846,"methaneState":"正常","vertical":13.91}
- BroadcastManager.obtainInstance(BaseApplication.get()).sendBroadcast(
- LocaleConstant.ACTION_UPDATE_DATA, dataModel.toJson()
- )
- }
- }
-
- override fun onServiceStatusConnectChanged(statusCode: Byte) {
- if (statusCode == ISocketListener.STATUS_CONNECT_SUCCESS) {
- if (nettyClient.connectStatus) {
- Log.d(kTag, "连接成功")
- }
- } else {
- if (!nettyClient.connectStatus) {
- Log.e(kTag, "onServiceStatusConnectChanged:$statusCode,连接断开,正在重连")
- }
- }
- }
-
- fun sendData(data: ByteArray) {
- nettyClient.sendData(data)
- }
-
- fun close() {
- nettyClient.disconnect()
- }
-}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/br/ktd/netty/tcp/ISocketListener.kt b/app/src/main/java/com/casic/br/ktd/netty/tcp/ISocketListener.kt
new file mode 100644
index 0000000..13c3084
--- /dev/null
+++ b/app/src/main/java/com/casic/br/ktd/netty/tcp/ISocketListener.kt
@@ -0,0 +1,19 @@
+package com.casic.br.ktd.netty.tcp
+
+interface ISocketListener {
+ companion object {
+ const val STATUS_CONNECT_SUCCESS: Byte = 1 //连接成功
+ const val STATUS_CONNECT_CLOSED: Byte = 0 //关闭连接
+ const val STATUS_CONNECT_ERROR: Byte = 0 //连接失败
+ }
+
+ /**
+ * 当接收到系统消息
+ */
+ fun onMessageResponse(data: ByteArray?)
+
+ /**
+ * 当连接状态发生变化时调用
+ */
+ fun onServiceStatusConnectChanged(statusCode: Byte)
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/br/ktd/netty/tcp/SocketChannelHandle.kt b/app/src/main/java/com/casic/br/ktd/netty/tcp/SocketChannelHandle.kt
new file mode 100644
index 0000000..8e2997f
--- /dev/null
+++ b/app/src/main/java/com/casic/br/ktd/netty/tcp/SocketChannelHandle.kt
@@ -0,0 +1,51 @@
+package com.casic.br.ktd.netty.tcp
+
+import android.util.Log
+import io.netty.channel.ChannelHandlerContext
+import io.netty.channel.SimpleChannelInboundHandler
+import io.netty.handler.timeout.IdleState
+import io.netty.handler.timeout.IdleStateEvent
+import java.nio.charset.StandardCharsets
+
+class SocketChannelHandle(private val listener: ISocketListener?) :
+ SimpleChannelInboundHandler() {
+
+ private val kTag = "SocketChannelHandle"
+
+ override fun channelActive(ctx: ChannelHandlerContext) {
+ super.channelActive(ctx)
+ Log.d(kTag, "channelActive ===> 连接成功")
+ listener?.onServiceStatusConnectChanged(ISocketListener.STATUS_CONNECT_SUCCESS)
+ }
+
+ override fun channelInactive(ctx: ChannelHandlerContext) {
+ super.channelInactive(ctx)
+ Log.e(kTag, "channelInactive: 连接断开")
+ }
+
+ override fun userEventTriggered(ctx: ChannelHandlerContext, evt: Any) {
+ super.userEventTriggered(ctx, evt)
+ if (evt is IdleStateEvent) {
+ if (evt.state() == IdleState.WRITER_IDLE) {
+ //写超时,此时可以发送心跳数据给服务器
+ val temp = "FF"
+ ctx.writeAndFlush(temp.toByteArray(StandardCharsets.UTF_8))
+ } else if (evt.state() == IdleState.READER_IDLE) {
+ //读超时,此时代表没有收到心跳返回可以关闭当前连接进行重连
+ ctx.close()
+ }
+ }
+ }
+
+ override fun channelRead0(ctx: ChannelHandlerContext, data: ByteArray?) {
+ listener?.onMessageResponse(data)
+ }
+
+ override fun exceptionCaught(ctx: ChannelHandlerContext, cause: Throwable) {
+ super.exceptionCaught(ctx, cause)
+ Log.d(kTag, "exceptionCaught ===> $cause")
+ listener?.onServiceStatusConnectChanged(ISocketListener.STATUS_CONNECT_ERROR)
+ cause.printStackTrace()
+ ctx.close()
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/br/ktd/netty/tcp/SocketClient.kt b/app/src/main/java/com/casic/br/ktd/netty/tcp/SocketClient.kt
new file mode 100644
index 0000000..34960a0
--- /dev/null
+++ b/app/src/main/java/com/casic/br/ktd/netty/tcp/SocketClient.kt
@@ -0,0 +1,153 @@
+package com.casic.br.ktd.netty.tcp
+
+import android.os.SystemClock
+import android.util.Log
+import io.netty.bootstrap.Bootstrap
+import io.netty.channel.*
+import io.netty.channel.nio.NioEventLoopGroup
+import io.netty.channel.socket.SocketChannel
+import io.netty.channel.socket.nio.NioSocketChannel
+import io.netty.handler.codec.bytes.ByteArrayDecoder
+import io.netty.handler.codec.bytes.ByteArrayEncoder
+import io.netty.handler.timeout.IdleStateHandler
+
+class SocketClient {
+
+ private val kTag = "SocketClient"
+
+ private var host: String? = null
+ private var port = 8000
+ private var nioEventLoopGroup: NioEventLoopGroup? = null
+ private var channel: Channel? = null
+ private var listener: ISocketListener? = null
+
+ //现在连接的状态
+ var connectStatus = false //判断是否已连接
+ private var reconnectNum = Int.MAX_VALUE //定义的重连到时候用
+ private var isNeedReconnect = true //是否需要重连
+ var isConnecting = false //是否正在连接
+ private set
+ private var reconnectIntervalTime: Long = 15000 //重连的时间
+
+ //重连时间
+ fun setReconnectNum(reconnectNum: Int) {
+ this.reconnectNum = reconnectNum
+ }
+
+ fun setReconnectIntervalTime(reconnectIntervalTime: Long) {
+ this.reconnectIntervalTime = reconnectIntervalTime
+ }
+
+ fun setSocketListener(listener: ISocketListener?) {
+ this.listener = listener
+ }
+
+ fun connect(host: String, port: Int) {
+ this.host = host
+ this.port = port
+ Log.d(kTag, "connect ===> 开始连接TCP服务器")
+ if (isConnecting) {
+ return
+ }
+ //起个线程
+ val clientThread: Thread = object : Thread("client-Netty") {
+ override fun run() {
+ super.run()
+ isNeedReconnect = true
+ reconnectNum = Int.MAX_VALUE
+ connectServer()
+ }
+ }
+ clientThread.start()
+ }
+
+ private fun connectServer() {
+ synchronized(this@SocketClient) {
+ var channelFuture: ChannelFuture? = null //连接管理对象
+ if (!connectStatus) {
+ isConnecting = true
+ nioEventLoopGroup = NioEventLoopGroup() //设置的连接group
+ val bootstrap = Bootstrap()
+ bootstrap.group(nioEventLoopGroup) //设置的一系列连接参数操作等
+ .channel(NioSocketChannel::class.java)
+ .option(ChannelOption.TCP_NODELAY, true) //无阻塞
+ .option(ChannelOption.SO_KEEPALIVE, true) //长连接
+ .option(
+ ChannelOption.RCVBUF_ALLOCATOR,
+ AdaptiveRecvByteBufAllocator(5000, 5000, 8000)
+ ) //接收缓冲区 最小值太小时数据接收不全
+ .handler(object : ChannelInitializer() {
+ override fun initChannel(channel: SocketChannel) {
+ val pipeline = channel.pipeline()
+ //参数1:代表读套接字超时的时间,没收到数据会触发读超时回调;
+ //参数2:代表写套接字超时时间,没进行写会触发写超时回调;
+ //参数3:将在未执行读取或写入时触发超时回调,0代表不处理;
+ //读超时尽量设置大于写超时,代表多次写超时时写心跳包,多次写了心跳数据仍然读超时代表当前连接错误,即可断开连接重新连接
+ pipeline.addLast(IdleStateHandler(60, 10, 0))
+ pipeline.addLast(ByteArrayDecoder())
+ pipeline.addLast(ByteArrayEncoder())
+ pipeline.addLast(SocketChannelHandle(listener))
+ }
+ })
+ try {
+ //连接监听
+ channelFuture = bootstrap.connect(host, port)
+ .addListener(object : ChannelFutureListener {
+ override fun operationComplete(channelFuture: ChannelFuture) {
+ if (channelFuture.isSuccess) {
+ connectStatus = true
+ channel = channelFuture.channel()
+ } else {
+ Log.e(kTag, "operationComplete: 连接失败")
+ connectStatus = false
+ }
+ isConnecting = false
+ }
+ }).sync()
+ // 等待连接关闭
+ channelFuture.channel().closeFuture().sync()
+ } catch (e: Exception) {
+ e.printStackTrace()
+ } finally {
+ connectStatus = false
+ listener?.onServiceStatusConnectChanged(ISocketListener.STATUS_CONNECT_CLOSED) //STATUS_CONNECT_CLOSED 这我自己定义的 接口标识
+ if (null != channelFuture) {
+ if (channelFuture.channel() != null && channelFuture.channel().isOpen) {
+ channelFuture.channel().close()
+ }
+ }
+ nioEventLoopGroup?.shutdownGracefully()
+ reconnect() //重新连接
+ }
+ }
+ }
+ }
+
+ //断开连接
+ fun disconnect() {
+ Log.d(kTag, "disconnect ===> 断开连接")
+ isNeedReconnect = false
+ nioEventLoopGroup?.shutdownGracefully()
+ }
+
+ //重新连接
+ private fun reconnect() {
+ if (isNeedReconnect && reconnectNum > 0 && !connectStatus) {
+ reconnectNum--
+ SystemClock.sleep(reconnectIntervalTime)
+ if (isNeedReconnect && reconnectNum > 0 && !connectStatus) {
+ Log.d(kTag, "reconnect ===> 重新连接")
+ connectServer()
+ }
+ }
+ }
+
+ fun sendData(bytes: ByteArray) {
+ channel?.writeAndFlush(bytes)?.addListener(ChannelFutureListener { future ->
+ if (!future.isSuccess) {
+ future.channel().close()
+ nioEventLoopGroup!!.shutdownGracefully()
+ }
+ })
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/br/ktd/netty/tcp/SocketManager.kt b/app/src/main/java/com/casic/br/ktd/netty/tcp/SocketManager.kt
new file mode 100644
index 0000000..35980b9
--- /dev/null
+++ b/app/src/main/java/com/casic/br/ktd/netty/tcp/SocketManager.kt
@@ -0,0 +1,113 @@
+package com.casic.br.ktd.netty.tcp
+
+import android.util.Log
+import com.casic.br.ktd.base.BaseApplication
+import com.casic.br.ktd.extensions.covertAngleValue
+import com.casic.br.ktd.extensions.covertDataValue
+import com.casic.br.ktd.extensions.toUnsignedByteArray
+import com.casic.br.ktd.model.SensorDataModel
+import com.casic.br.ktd.utils.LocaleConstant
+import com.pengxh.kt.lite.extensions.toJson
+import com.pengxh.kt.lite.utils.BroadcastManager
+
+class SocketManager private constructor() : ISocketListener {
+
+ private val kTag = "SocketManager"
+ private var nettyClient: SocketClient = SocketClient()
+
+ companion object {
+ val instance: SocketManager by lazy(mode = LazyThreadSafetyMode.SYNCHRONIZED) { SocketManager() }
+ }
+
+ fun connectNetty(hostname: String, port: Int) {
+ Thread {
+ if (!nettyClient.connectStatus) {
+ nettyClient.setSocketListener(this)
+ nettyClient.connect(hostname, port)
+ } else {
+ nettyClient.disconnect()
+ }
+ }.start()
+ }
+
+ override fun onMessageResponse(data: ByteArray?) {
+// Log.d(kTag, "onMessageResponse ===> " + Arrays.toString(data))
+ /**
+ * 0xFF,0x01,
+ * 0x01,0x37,0xE6, 甲烷浓度值(数据码1* 65536 + 数据码2 * 256 + 数据码3)
+ * 0x00, 激光甲烷模块工作状态(00表示设备正常,01表示温控故障,02表示设备激光未打开)
+ * 0x00,0xB2,0x35, 激光强度值(数据码5* 65536 + 数据码6 * 256 + 数据码7)
+ * 0x0A,0x3D, 云台水平角度([数据码8 * 256 + 数据码9]/100,单位为°,精确到0.01)
+ * 0x05,0x6F, 云台垂直角度(首先计算Tangle=[数据码10 * 256 + 数据码11]/100,单位为°,精确到0.01。若Tangle在0~90范围内,则垂直角度值=Tangle;若Tangle在-1~-90范围内,则垂直角度值=Tangle-360)
+ * 0xC1
+ *
+ * [-1, 1, 1, 55, -26, 0, 0, -78, 53, 10, 61, 5, 111, -63]
+ * 甲烷浓度值为79638,计算为79638=0x01*65536+0x37*256+0xE6[0x01为数据码1,0x37为数据码2,0xE6为数据码3];
+ * 激光甲烷设备状态值为0,表示状态正常,[0x00为数据码4];
+ * 激光强度值为45621,计算为45621=0x00*65536+0xB2*256+0x35[0x00为数据码5,0xB2为数据码6,0x35为数据码7];
+ *
+ * =========================================================================================
+ * 实际数据(1800-1950左右)
+ * [-86, 1, 0, 7, 71, 0, 0, 62, -92, 57, 59, -118, -111, -64]
+ * */
+
+ if (data == null) {
+ return
+ }
+ val bytes = data.toUnsignedByteArray()
+ if (bytes.size == 14) {
+ val dataModel = SensorDataModel(0, "激光未打开", 0, 0.0, 0.0)
+
+ val methaneBytes = IntArray(3)
+ System.arraycopy(bytes, 2, methaneBytes, 0, 3)
+ dataModel.methane = methaneBytes.covertDataValue()
+
+ dataModel.methaneState = when (bytes[5]) {
+ 1 -> "温控故障"
+ 2 -> "激光未打开"
+ else -> "正常"
+ }
+
+ val laserBytes = IntArray(3)
+ System.arraycopy(bytes, 6, laserBytes, 0, 3)
+ dataModel.laser = laserBytes.covertDataValue()
+
+ /**
+ * 水平角度的实际范围为从水平零点开始,顺时针方向(从上往下看),0~360°
+ * 垂直角度的实际范围为从垂直零点开始,以向上为正,-90°~90°,控制精度为0.01°
+ * */
+ val horizontalBytes = IntArray(2)
+ System.arraycopy(bytes, 9, horizontalBytes, 0, 2)
+ dataModel.horizontal = horizontalBytes.covertAngleValue()
+
+ val verticalBytes = IntArray(2)
+ System.arraycopy(bytes, 11, verticalBytes, 0, 2)
+ dataModel.vertical = verticalBytes.covertAngleValue()
+
+ //{"horizontal":26.21,"laser":45621,"methane":79846,"methaneState":"正常","vertical":13.91}
+ BroadcastManager.obtainInstance(BaseApplication.get()).sendBroadcast(
+ LocaleConstant.ACTION_UPDATE_DATA, dataModel.toJson()
+ )
+ }
+ }
+
+ override fun onServiceStatusConnectChanged(statusCode: Byte) {
+ if (statusCode == ISocketListener.STATUS_CONNECT_SUCCESS) {
+ if (nettyClient.connectStatus) {
+ Log.d(kTag, "连接成功")
+ }
+ } else {
+ if (!nettyClient.connectStatus) {
+ Log.e(kTag, "onServiceStatusConnectChanged:$statusCode,连接断开,正在重连")
+ }
+ }
+ }
+
+ fun sendData(data: ByteArray) {
+ nettyClient.sendData(data)
+ }
+
+ fun close() {
+ nettyClient.disconnect()
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/br/ktd/netty/udp/UdpChannelInboundHandler.kt b/app/src/main/java/com/casic/br/ktd/netty/udp/UdpChannelInboundHandler.kt
new file mode 100644
index 0000000..4d6f97c
--- /dev/null
+++ b/app/src/main/java/com/casic/br/ktd/netty/udp/UdpChannelInboundHandler.kt
@@ -0,0 +1,36 @@
+package com.casic.br.ktd.netty.udp
+
+import io.netty.channel.ChannelHandlerContext
+import io.netty.channel.SimpleChannelInboundHandler
+import io.netty.channel.socket.DatagramPacket
+import io.netty.util.CharsetUtil
+
+
+abstract class UdpChannelInboundHandler : SimpleChannelInboundHandler() {
+
+ private var handlerContext: ChannelHandlerContext? = null
+
+ override fun channelActive(ctx: ChannelHandlerContext?) {
+ super.channelActive(ctx)
+ handlerContext = ctx
+ }
+
+ override fun channelInactive(ctx: ChannelHandlerContext?) {
+ super.channelInactive(ctx)
+ handlerContext?.close()
+ }
+
+ fun sendDatagramPacket(obj: Any) {
+ handlerContext?.writeAndFlush(obj)
+ }
+
+ fun releasePort() {
+ handlerContext?.close()
+ }
+
+ override fun channelRead0(ctx: ChannelHandlerContext, datagramPacket: DatagramPacket) {
+ receivedMessage(datagramPacket.content().toString(CharsetUtil.UTF_8))
+ }
+
+ abstract fun receivedMessage(data: String)
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/br/ktd/netty/udp/UdpChannelInitializer.kt b/app/src/main/java/com/casic/br/ktd/netty/udp/UdpChannelInitializer.kt
new file mode 100644
index 0000000..416c5a1
--- /dev/null
+++ b/app/src/main/java/com/casic/br/ktd/netty/udp/UdpChannelInitializer.kt
@@ -0,0 +1,17 @@
+package com.casic.br.ktd.netty.udp
+
+import io.netty.channel.ChannelInitializer
+import io.netty.channel.socket.DatagramChannel
+import io.netty.handler.timeout.IdleStateHandler
+
+
+open class UdpChannelInitializer(private val handler: UdpChannelInboundHandler) :
+ ChannelInitializer() {
+
+ override fun initChannel(datagramChannel: DatagramChannel) {
+ val pipeline = datagramChannel.pipeline()
+ pipeline.addLast(
+ IdleStateHandler(12, 15, 0)
+ ).addLast(handler)
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/br/ktd/netty/udp/UdpClient.kt b/app/src/main/java/com/casic/br/ktd/netty/udp/UdpClient.kt
new file mode 100644
index 0000000..3893afa
--- /dev/null
+++ b/app/src/main/java/com/casic/br/ktd/netty/udp/UdpClient.kt
@@ -0,0 +1,103 @@
+package com.casic.br.ktd.netty.udp
+
+import com.casic.br.ktd.utils.LocaleConstant
+import com.pengxh.kt.lite.utils.SaveKeyValues
+import io.netty.bootstrap.Bootstrap
+import io.netty.buffer.ByteBuf
+import io.netty.buffer.Unpooled
+import io.netty.channel.ChannelOption
+import io.netty.channel.nio.NioEventLoopGroup
+import io.netty.channel.socket.DatagramPacket
+import io.netty.channel.socket.nio.NioDatagramChannel
+import io.netty.util.CharsetUtil
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.launch
+import kotlinx.coroutines.withContext
+import java.net.InetSocketAddress
+import java.util.concurrent.ExecutorService
+import java.util.concurrent.Executors
+
+
+class UdpClient : UdpChannelInboundHandler(), Runnable {
+
+ private val bootStrap by lazy { Bootstrap() }
+ private val eventLoopGroup by lazy { NioEventLoopGroup() }
+ private val udpChannelInitializer by lazy { UdpChannelInitializer(this) }
+ private var executorService: ExecutorService
+
+ init {
+ bootStrap.group(eventLoopGroup)
+ bootStrap.channel(NioDatagramChannel::class.java)
+ .option(ChannelOption.SO_RCVBUF, 1024)
+ .option(ChannelOption.SO_SNDBUF, 1024)
+ bootStrap.handler(udpChannelInitializer)
+
+ executorService = Executors.newSingleThreadExecutor()
+ executorService.execute(this)
+ }
+
+ override fun run() {
+ try {
+ val channelFuture = bootStrap.bind(LocaleConstant.LOCATION_UDP_PORT).sync()
+ channelFuture.channel().closeFuture().sync()
+ } catch (e: InterruptedException) {
+ e.printStackTrace()
+ } finally {
+ eventLoopGroup.shutdownGracefully()
+ }
+ }
+
+ fun send(value: String) {
+ CoroutineScope(Dispatchers.Main).launch {
+ withContext(Dispatchers.IO) {
+ val host = SaveKeyValues.getValue(
+ LocaleConstant.LOCATION_UDP_SERVER, "192.168.149.213"
+ ).toString()
+ val datagramPacket = DatagramPacket(
+ Unpooled.copiedBuffer(value, CharsetUtil.UTF_8),
+ InetSocketAddress(host, LocaleConstant.LOCATION_UDP_PORT)
+ )
+ sendDatagramPacket(datagramPacket)
+ }
+ }
+ }
+
+ fun send(value: ByteArray) {
+ CoroutineScope(Dispatchers.Main).launch {
+ withContext(Dispatchers.IO) {
+ val host = SaveKeyValues.getValue(
+ LocaleConstant.LOCATION_UDP_SERVER, "192.168.149.213"
+ ).toString()
+ val datagramPacket = DatagramPacket(
+ Unpooled.copiedBuffer(value),
+ InetSocketAddress(host, LocaleConstant.LOCATION_UDP_PORT)
+ )
+ sendDatagramPacket(datagramPacket)
+ }
+ }
+ }
+
+ fun send(value: ByteBuf) {
+ CoroutineScope(Dispatchers.Main).launch {
+ withContext(Dispatchers.IO) {
+ val host = SaveKeyValues.getValue(
+ LocaleConstant.LOCATION_UDP_SERVER, "192.168.149.213"
+ ).toString()
+ val datagramPacket = DatagramPacket(
+ Unpooled.copiedBuffer(value),
+ InetSocketAddress(host, LocaleConstant.LOCATION_UDP_PORT)
+ )
+ sendDatagramPacket(datagramPacket)
+ }
+ }
+ }
+
+ fun release() {
+ releasePort()
+ }
+
+ override fun receivedMessage(data: String) {
+
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/br/ktd/utils/LocaleConstant.kt b/app/src/main/java/com/casic/br/ktd/utils/LocaleConstant.kt
index 0dd119e..4c675df 100644
--- a/app/src/main/java/com/casic/br/ktd/utils/LocaleConstant.kt
+++ b/app/src/main/java/com/casic/br/ktd/utils/LocaleConstant.kt
@@ -50,6 +50,10 @@
const val DEV_NET_IP = "192.168.1.21"
const val DEV_NET_PORT = "8000"
+ //位置信息UDP端口
+ const val LOCATION_UDP_SERVER = "udpServer"
+ const val LOCATION_UDP_PORT = 7777
+
//BroadcastReceiver Action
const val ACTION_UPDATE_DATA = "update"
diff --git a/app/src/main/java/com/casic/br/ktd/utils/LocationHelper.kt b/app/src/main/java/com/casic/br/ktd/utils/LocationHelper.kt
index 8e31d3f..df6adb5 100644
--- a/app/src/main/java/com/casic/br/ktd/utils/LocationHelper.kt
+++ b/app/src/main/java/com/casic/br/ktd/utils/LocationHelper.kt
@@ -7,19 +7,40 @@
import android.location.LocationListener
import android.location.LocationManager
import android.os.Bundle
+import android.util.Log
import androidx.core.app.ActivityCompat
+import com.amap.api.location.AMapLocation
+import com.amap.api.location.AMapLocationClient
+import com.amap.api.location.AMapLocationClientOption
-object LocationHelper {
- fun obtainCurrentLocation(context: Context, listener: ILocationListener) {
+class LocationHelper private constructor() {
+
+ private val kTag = "LocationHelper"
+
+ companion object {
+ //Kotlin委托模式双重锁单例
+ val get: LocationHelper by lazy(mode = LazyThreadSafetyMode.SYNCHRONIZED) {
+ LocationHelper()
+ }
+ }
+
+ private val locationOption = AMapLocationClientOption()
+ private lateinit var locationClient: AMapLocationClient
+
+ init {
+ //设置定位模式为高精度模式,AMapLocationMode.Battery_Saving为低功耗模式,AMapLocationMode.Device_Sensors是仅设备模式
+ locationOption.locationMode = AMapLocationClientOption.AMapLocationMode.Hight_Accuracy
+ locationOption.isNeedAddress = true //设置是否返回地址信息(默认返回地址信息)
+ locationOption.isLocationCacheEnable = true //可选,设置是否使用缓存定位,默认为true
+ }
+
+ fun obtainLocation(context: Context, listener: ILocationListener) {
if (ActivityCompat.checkSelfPermission(
- context,
- Manifest.permission.ACCESS_LOCATION_EXTRA_COMMANDS
+ context, Manifest.permission.ACCESS_LOCATION_EXTRA_COMMANDS
) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(
- context,
- Manifest.permission.ACCESS_FINE_LOCATION
+ context, Manifest.permission.ACCESS_FINE_LOCATION
) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(
- context,
- Manifest.permission.ACCESS_COARSE_LOCATION
+ context, Manifest.permission.ACCESS_COARSE_LOCATION
) != PackageManager.PERMISSION_GRANTED
) {
return
@@ -38,7 +59,37 @@
})
}
+ /**
+ * 高德sdk定位
+ */
+ fun obtainLocationByGD(context: Context?, listener: ILocationListener) {
+ locationClient = AMapLocationClient(context)
+ //给定位客户端对象设置定位参数
+ locationClient.setLocationOption(locationOption)
+ //设置定位回调监听
+ locationClient.setLocationListener { aMapLocation ->
+ if (aMapLocation != null) {
+ if (aMapLocation.errorCode == 0) {
+ listener.onAMapLocationGet(aMapLocation)
+ } else {
+ Log.e(
+ kTag,
+ "ErrCode: ${aMapLocation.errorCode}, errInfo: ${aMapLocation.errorInfo}"
+ )
+ }
+ }
+ }
+ //启动定位
+ locationClient.startLocation()
+ }
+
+ fun stopLocation() {
+ locationClient.stopLocation()//停止定位
+ }
+
interface ILocationListener {
- fun onLocationGet(location: Location?) //高德定位数据
+ fun onLocationGet(location: Location?) //GPS定位数据
+
+ fun onAMapLocationGet(aMapLocation: AMapLocation?) //高德定位数据
}
}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/br/ktd/view/InspectionActivity.kt b/app/src/main/java/com/casic/br/ktd/view/InspectionActivity.kt
index 02c47f8..c893092 100644
--- a/app/src/main/java/com/casic/br/ktd/view/InspectionActivity.kt
+++ b/app/src/main/java/com/casic/br/ktd/view/InspectionActivity.kt
@@ -15,16 +15,21 @@
import android.view.SurfaceHolder
import android.view.View
import android.widget.AdapterView
-import com.amap.api.maps.*
+import com.amap.api.location.AMapLocation
+import com.amap.api.maps.AMap
+import com.amap.api.maps.CameraUpdateFactory
+import com.amap.api.maps.UiSettings
import com.amap.api.maps.model.CameraPosition
import com.amap.api.maps.model.LatLng
+import com.amap.api.maps.model.MyLocationStyle
import com.amap.api.maps.model.PolylineOptions
import com.casic.br.ktd.R
import com.casic.br.ktd.extensions.*
import com.casic.br.ktd.model.ChartPointModel
import com.casic.br.ktd.model.RouteModel
import com.casic.br.ktd.model.SensorDataModel
-import com.casic.br.ktd.netty.SocketManager
+import com.casic.br.ktd.netty.tcp.SocketManager
+import com.casic.br.ktd.netty.udp.UdpClient
import com.casic.br.ktd.utils.LocaleConstant
import com.casic.br.ktd.utils.LocationHelper
import com.casic.br.ktd.widgets.AlertControlDialog
@@ -49,6 +54,10 @@
import hcnetsdk.sdkhub.MessageCodeHub
import hcnetsdk.sdkhub.SDKGuider
import kotlinx.android.synthetic.main.activity_inspection.*
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.launch
+import kotlinx.coroutines.withContext
import java.text.DecimalFormat
import java.text.SimpleDateFormat
import java.util.*
@@ -60,10 +69,10 @@
private val hkSDK by lazy { HCNetSDK.getInstance() }
private val timeFormat by lazy { SimpleDateFormat("yyyyMMddHHmmss", Locale.CHINA) }
private val latlngs = LinkedList()
- private val speedTimer by lazy { Timer() }
private val tcpTimer by lazy { Timer() }
private val decimalFormat by lazy { DecimalFormat("##0.0") }
private val gson by lazy { Gson() }
+ private val udpClient by lazy { UdpClient() }
private var isLoginSuccess = false
private var previewHandle = -1
private var selectChannel = -1
@@ -103,28 +112,32 @@
private lateinit var aMap: AMap
private lateinit var uiSettings: UiSettings
+ /**
+ * 协程配置云台设备,缓解新进页面较卡的问题
+ * */
private fun setDeviceConfig() {
- Log.d(kTag, "setDeviceConfig => 配置设备IP和端口")
- val device = SDKGuider.sdkGuider.devManageGuider.DeviceItem()
- device.m_szDevName = ""
- device.m_struNetInfo = SDKGuider.sdkGuider.devManageGuider.DevNetInfo(
- LocaleConstant.HK_NET_IP,
- LocaleConstant.HK_NET_PORT,
- LocaleConstant.HK_NET_USERNAME,
- LocaleConstant.HK_NET_PASSWORD
- )
- if (device.m_szDevName.isEmpty()) {
- device.m_szDevName = device.m_struNetInfo.m_szIp
- }
- isLoginSuccess = if (
- SDKGuider.sdkGuider.devManageGuider.login_v40_jna(
- device.m_szDevName, device.m_struNetInfo
- )
- ) {
- "设备连接成功".show(this)
- true
- } else {
- false
+ CoroutineScope(Dispatchers.Main).launch {
+ isLoginSuccess = withContext(Dispatchers.IO) {
+ Log.d(kTag, "setDeviceConfig => 配置设备IP和端口")
+ val device = SDKGuider.sdkGuider.devManageGuider.DeviceItem()
+ device.m_szDevName = ""
+ device.m_struNetInfo = SDKGuider.sdkGuider.devManageGuider.DevNetInfo(
+ LocaleConstant.HK_NET_IP,
+ LocaleConstant.HK_NET_PORT,
+ LocaleConstant.HK_NET_USERNAME,
+ LocaleConstant.HK_NET_PASSWORD
+ )
+ if (device.m_szDevName.isEmpty()) {
+ device.m_szDevName = device.m_struNetInfo.m_szIp
+ }
+
+ SDKGuider.sdkGuider.devManageGuider.login_v40_jna(
+ device.m_szDevName, device.m_struNetInfo
+ )
+ }
+ if (isLoginSuccess) {
+ "设备连接成功".show(context)
+ }
}
}
@@ -148,17 +161,74 @@
/**
* 手机GPS定位
* */
- val converter = CoordinateConverter(this)
- LocationHelper.obtainCurrentLocation(this, object : LocationHelper.ILocationListener {
+// val converter = CoordinateConverter(this)
+// LocationHelper.get.obtainLocation(this, object : LocationHelper.ILocationListener {
+// override fun onLocationGet(location: Location?) {
+// if (location == null) {
+// "当前信号弱,无法定位".show(context)
+// return
+// }
+//
+// //发送位置信息给UDP服务端
+// udpClient.send("${location.longitude}, ${location.latitude}")
+// Log.d(kTag, "onLocationGet => 速度:${location.speed}")
+//
+// //WGS-84要转为高德坐标系
+// converter.from(CoordinateConverter.CoordType.GPS)
+// converter.coord(LatLng(location.latitude, location.longitude))
+// val latLng = converter.convert()
+// latlngs.add(latLng)
+//
+// //移动到指定经纬度
+// val cameraPosition = CameraPosition(latLng, 13f, 0f, 0f)
+// val cameraUpdate = CameraUpdateFactory.newCameraPosition(cameraPosition)
+// aMap.animateCamera(cameraUpdate, 1500, null)
+//
+// //绘制线
+// aMap.addPolyline(
+// PolylineOptions().addAll(latlngs).width(12f).color(Color.RED)
+// )
+//
+// if (isStartInspect) {
+// val route = LinkedList()
+// latlngs.forEach {
+// route.add(RouteModel(it.latitude, it.longitude))
+// }
+// }
+// }
+//
+// override fun onAMapLocationGet(aMapLocation: AMapLocation?) {
+//
+// }
+// })
+
+ /**
+ * 高德定位
+ * */
+ LocationHelper.get.obtainLocationByGD(this, object : LocationHelper.ILocationListener {
override fun onLocationGet(location: Location?) {
- if (location == null) {
+
+ }
+
+ override fun onAMapLocationGet(aMapLocation: AMapLocation?) {
+ if (aMapLocation == null) {
"当前信号弱,无法定位".show(context)
return
}
+
+ //发送位置信息给UDP服务端
+ udpClient.send(
+ "${aMapLocation.longitude}, ${aMapLocation.latitude}, ${
+ System.currentTimeMillis().timestampToCompleteDate()
+ }"
+ )
+ //速度 转为 km/h
+ Log.d(kTag, "onLocationGet => 速度:${aMapLocation.speed}")
+ speed = decimalFormat.format(aMapLocation.speed * 3.6).toFloat()
+ carSpeedView.text = String.format("${speed}Km/h")
+
//WGS-84要转为高德坐标系
- converter.from(CoordinateConverter.CoordType.GPS)
- converter.coord(LatLng(location.latitude, location.longitude))
- val latLng = converter.convert()
+ val latLng = LatLng(aMapLocation.latitude, aMapLocation.longitude)
latlngs.add(latLng)
//移动到指定经纬度
@@ -168,7 +238,7 @@
//绘制线
aMap.addPolyline(
- PolylineOptions().addAll(latlngs).width(12f).color(Color.RED)
+ PolylineOptions().addAll(latlngs).width(10f).color(Color.RED)
)
if (isStartInspect) {
@@ -181,27 +251,6 @@
})
/**
- * 计算速度,微分原理,3s计算一次速度
- * */
- speedTimer.schedule(object : TimerTask() {
- override fun run() {
- //经纬度链表数据小于2,无法计算速度,默认为0
- speed = if (latlngs.size < 2) 0.0f else {
- val temp = AMapUtils.calculateLineDistance(
- latlngs.last(), latlngs[latlngs.size - 2]
- ) / 3
- //转为 km/h
- decimalFormat.format(temp * 3.6).toFloat()
- }
-
- //切换到UI线程更新界面数据
- runOnUiThread {
- carSpeedView.text = String.format("${speed}Km/h")
- }
- }
- }, 0, 3000)
-
- /**
* TCP初始化
* ***/
SocketManager.instance.connectNetty(
@@ -632,6 +681,8 @@
stopPreview()
BroadcastManager.obtainInstance(this).destroy(LocaleConstant.ACTION_UPDATE_DATA)
mapView.onDestroy()
+ udpClient.release()
+ LocationHelper.get.stopLocation()
}
override fun handleMessage(msg: Message): Boolean {
@@ -716,38 +767,13 @@
uiSettings.isZoomControlsEnabled = true
uiSettings.isTiltGesturesEnabled = false//不许地图随手势倾斜角度
-// val locationStyle = MyLocationStyle()
-// locationStyle.interval(2000)
-// locationStyle.showMyLocation(true)
-// locationStyle.myLocationType(MyLocationStyle.LOCATION_TYPE_LOCATION_ROTATE)
-// aMap.myLocationStyle = locationStyle
-// aMap.isMyLocationEnabled = true
-// aMap.animateCamera(CameraUpdateFactory.zoomTo(13f))
-// aMap.setOnMyLocationChangeListener(this)
+ //显示定位小蓝点
+ val locationStyle = MyLocationStyle()
+ locationStyle.showMyLocation(true)//设置是否显示定位小蓝点
+ aMap.myLocationStyle = locationStyle
+ aMap.isMyLocationEnabled = true
}
-// override fun onMyLocationChange(aMapLocation: Location?) {
-// if (aMapLocation == null) {
-// "当前信号弱,无法定位".show(context)
-// return
-// }
-// val latitude = aMapLocation.latitude
-// val longitude = aMapLocation.longitude
-// latlngs.add(LatLng(latitude, longitude))
-//
-// //绘制线
-// aMap.addPolyline(
-// PolylineOptions().addAll(latlngs).width(15f).color(Color.RED)
-// )
-//
-// if (isStartInspect) {
-// val route = LinkedList()
-// latlngs.forEach {
-// route.add(RouteModel(it.latitude, it.longitude))
-// }
-// }
-// }
-
/***以下是地图生命周期管理************************************************************************/
override fun onResume() {
diff --git a/app/src/main/res/layout/fragment_alarm.xml b/app/src/main/res/layout/fragment_alarm.xml
index a3ebc88..929529f 100644
--- a/app/src/main/res/layout/fragment_alarm.xml
+++ b/app/src/main/res/layout/fragment_alarm.xml
@@ -31,7 +31,7 @@
diff --git a/app/src/main/res/layout/fragment_task.xml b/app/src/main/res/layout/fragment_task.xml
index 35cb1a3..58d852e 100644
--- a/app/src/main/res/layout/fragment_task.xml
+++ b/app/src/main/res/layout/fragment_task.xml
@@ -31,7 +31,7 @@
diff --git a/app/src/main/res/mipmap-hdpi/end.png b/app/src/main/res/mipmap-hdpi/end.png
new file mode 100644
index 0000000..f31385b
--- /dev/null
+++ b/app/src/main/res/mipmap-hdpi/end.png
Binary files differ
diff --git a/app/src/main/res/mipmap-hdpi/start.png b/app/src/main/res/mipmap-hdpi/start.png
new file mode 100644
index 0000000..04839dc
--- /dev/null
+++ b/app/src/main/res/mipmap-hdpi/start.png
Binary files differ
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index e822df6..d72c1a5 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -7,6 +7,9 @@
+
+
+
@@ -46,5 +49,8 @@
+
+
+
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/br/ktd/base/KotlinBaseFragment.kt b/app/src/main/java/com/casic/br/ktd/base/KotlinBaseFragment.kt
new file mode 100644
index 0000000..2dac61c
--- /dev/null
+++ b/app/src/main/java/com/casic/br/ktd/base/KotlinBaseFragment.kt
@@ -0,0 +1,51 @@
+package com.casic.br.ktd.base
+
+import android.os.Bundle
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import androidx.annotation.LayoutRes
+import androidx.fragment.app.Fragment
+
+abstract class KotlinBaseFragment : Fragment() {
+
+ lateinit var bv: View
+
+ override fun onCreateView(
+ inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?
+ ): View? {
+ bv = inflater.inflate(initLayoutRes(), container, false)
+ initView(savedInstanceState)
+ setupTopBarLayout()
+ return bv
+ }
+
+ override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
+ super.onViewCreated(view, savedInstanceState)
+ observeRequestState()
+ initEvent()
+ }
+
+ @LayoutRes
+ abstract fun initLayoutRes(): Int
+
+ /**
+ * 沉浸式状态栏
+ */
+ abstract fun setupTopBarLayout()
+
+ /**
+ * 初始化布局以及控件
+ */
+ abstract fun initView(savedInstanceState: Bundle?)
+
+ /**
+ * 网络请求状态监听
+ */
+ abstract fun observeRequestState()
+
+ /**
+ * 业务逻辑,按钮等事件
+ */
+ abstract fun initEvent()
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/br/ktd/fragment/AlarmPageFragment.kt b/app/src/main/java/com/casic/br/ktd/fragment/AlarmPageFragment.kt
index 6c98a3b..9418169 100644
--- a/app/src/main/java/com/casic/br/ktd/fragment/AlarmPageFragment.kt
+++ b/app/src/main/java/com/casic/br/ktd/fragment/AlarmPageFragment.kt
@@ -2,28 +2,29 @@
import android.os.Bundle
import com.casic.br.ktd.R
+import com.casic.br.ktd.base.KotlinBaseFragment
import com.casic.br.ktd.widgets.DateRangeActionSheet
-import com.pengxh.kt.lite.base.KotlinBaseFragment
import kotlinx.android.synthetic.main.fragment_alarm.view.*
class AlarmPageFragment : KotlinBaseFragment() {
- override fun initData(savedInstanceState: Bundle?) {
+
+ override fun initView(savedInstanceState: Bundle?) {
}
override fun initEvent() {
- baseView.calendarView.setOnClickListener {
+ bv.calendarView.setOnClickListener {
DateRangeActionSheet.Builder().setContext(requireContext())
.setOnActionSheetListener(object :
DateRangeActionSheet.OnDateRangeSelectedListener {
override fun onDateRangeSelected(startDate: String, endDate: String) {
- baseView.selectedDateView.text = "$startDate ~ $endDate"
+ bv.selectedDateView.text = "$startDate ~ $endDate"
}
}).build().show()
}
}
- override fun initLayoutView(): Int = R.layout.fragment_alarm
+ override fun initLayoutRes(): Int = R.layout.fragment_alarm
override fun observeRequestState() {
diff --git a/app/src/main/java/com/casic/br/ktd/fragment/HomePageFragment.kt b/app/src/main/java/com/casic/br/ktd/fragment/HomePageFragment.kt
index 9961935..f3eba5c 100644
--- a/app/src/main/java/com/casic/br/ktd/fragment/HomePageFragment.kt
+++ b/app/src/main/java/com/casic/br/ktd/fragment/HomePageFragment.kt
@@ -1,32 +1,62 @@
package com.casic.br.ktd.fragment
+import android.graphics.Color
import android.os.Bundle
import com.amap.api.maps.AMap
import com.amap.api.maps.AMapOptions
+import com.amap.api.maps.CameraUpdateFactory
+import com.amap.api.maps.model.*
import com.casic.br.ktd.R
-import com.pengxh.kt.lite.base.KotlinBaseFragment
+import com.casic.br.ktd.base.KotlinBaseFragment
import kotlinx.android.synthetic.main.fragment_home.view.*
class HomePageFragment : KotlinBaseFragment() {
private lateinit var aMap: AMap
- override fun initData(savedInstanceState: Bundle?) {
- baseView.mapView.onCreate(savedInstanceState)
- aMap = baseView.mapView.map
+ override fun initView(savedInstanceState: Bundle?) {
+ bv.mapView.onCreate(savedInstanceState)
+ aMap = bv.mapView.map
val uiSettings = aMap.uiSettings
uiSettings.isCompassEnabled = true
- uiSettings.isMyLocationButtonEnabled = true
+ uiSettings.isMyLocationButtonEnabled = false
uiSettings.isScaleControlsEnabled = true
uiSettings.zoomPosition = AMapOptions.ZOOM_POSITION_RIGHT_CENTER
uiSettings.isRotateGesturesEnabled = false//不许地图随手势旋转角度
}
override fun initEvent() {
-
+ //移动到巡检起始经纬度
+ val cameraPosition = CameraPosition(LatLng(39.914199, 116.265785), 16f, 0f, 0f)
+ val cameraUpdate = CameraUpdateFactory.newCameraPosition(cameraPosition)
+ aMap.animateCamera(cameraUpdate, 1500, null)
+ //设置起点
+ addMarker(LatLng(39.914885, 116.272312), R.mipmap.start)
+ //设置终点
+ addMarker(LatLng(39.914716, 116.265097), R.mipmap.end)
+ //瞄点画线
+ val latLngPoints = ArrayList()
+ latLngPoints.add(LatLng(39.914885, 116.272312))
+ latLngPoints.add(LatLng(39.915148, 116.272312))
+ latLngPoints.add(LatLng(39.915399, 116.272302))
+ latLngPoints.add(LatLng(39.915436, 116.271787))
+ latLngPoints.add(LatLng(39.915477, 116.270886))
+ latLngPoints.add(LatLng(39.915477, 116.269968))
+ latLngPoints.add(LatLng(39.915469, 116.269544))
+ latLngPoints.add(LatLng(39.915481, 116.269196))
+ latLngPoints.add(LatLng(39.915452, 116.268472))
+ latLngPoints.add(LatLng(39.915444, 116.267722))
+ latLngPoints.add(LatLng(39.915415, 116.266755))
+ latLngPoints.add(LatLng(39.915403, 116.266165))
+ latLngPoints.add(LatLng(39.915395, 116.265703))
+ latLngPoints.add(LatLng(39.915366, 116.265119))
+ latLngPoints.add(LatLng(39.914716, 116.265097))
+ aMap.addPolyline(
+ PolylineOptions().addAll(latLngPoints).width(10.toFloat()).color(Color.RED)
+ )
}
- override fun initLayoutView(): Int = R.layout.fragment_home
+ override fun initLayoutRes(): Int = R.layout.fragment_home
override fun observeRequestState() {
@@ -36,25 +66,32 @@
}
+ private fun addMarker(point: LatLng, res: Int) {
+ val markerOption = MarkerOptions()
+ markerOption.position(point)
+ markerOption.icon(BitmapDescriptorFactory.fromResource(res))
+ aMap.addMarker(markerOption)
+ }
+
/***以下是地图生命周期管理************************************************************************/
override fun onResume() {
super.onResume()
- baseView.mapView.onResume()
+ bv.mapView.onResume()
}
override fun onPause() {
- baseView.mapView.onPause()
super.onPause()
+ bv.mapView.onPause()
}
override fun onSaveInstanceState(outState: Bundle) {
super.onSaveInstanceState(outState)
- baseView.mapView.onSaveInstanceState(outState)
+ bv.mapView.onSaveInstanceState(outState)
}
override fun onDestroy() {
- baseView.mapView.onDestroy()
super.onDestroy()
+ bv.mapView.onDestroy()
}
}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/br/ktd/fragment/MinePageFragment.kt b/app/src/main/java/com/casic/br/ktd/fragment/MinePageFragment.kt
index 90313ac..3212794 100644
--- a/app/src/main/java/com/casic/br/ktd/fragment/MinePageFragment.kt
+++ b/app/src/main/java/com/casic/br/ktd/fragment/MinePageFragment.kt
@@ -2,10 +2,11 @@
import android.os.Bundle
import com.casic.br.ktd.R
-import com.pengxh.kt.lite.base.KotlinBaseFragment
+import com.casic.br.ktd.base.KotlinBaseFragment
class MinePageFragment : KotlinBaseFragment() {
- override fun initData(savedInstanceState: Bundle?) {
+
+ override fun initView(savedInstanceState: Bundle?) {
}
@@ -13,7 +14,7 @@
}
- override fun initLayoutView(): Int = R.layout.fragment_mine
+ override fun initLayoutRes(): Int = R.layout.fragment_mine
override fun observeRequestState() {
diff --git a/app/src/main/java/com/casic/br/ktd/fragment/TaskPageFragment.kt b/app/src/main/java/com/casic/br/ktd/fragment/TaskPageFragment.kt
index 8f6abf0..6b82a54 100644
--- a/app/src/main/java/com/casic/br/ktd/fragment/TaskPageFragment.kt
+++ b/app/src/main/java/com/casic/br/ktd/fragment/TaskPageFragment.kt
@@ -8,6 +8,7 @@
import androidx.recyclerview.widget.RecyclerView
import com.casic.br.ktd.R
import com.casic.br.ktd.adapter.TaskAdapter
+import com.casic.br.ktd.base.KotlinBaseFragment
import com.casic.br.ktd.holder.SwipeViewHolder
import com.casic.br.ktd.model.TaskListModel
import com.casic.br.ktd.view.InspectionActivity
@@ -15,7 +16,6 @@
import com.casic.br.ktd.widgets.AlertControlDialog
import com.casic.br.ktd.widgets.AlertInputDialog
import com.casic.br.ktd.widgets.DateRangeActionSheet
-import com.pengxh.kt.lite.base.KotlinBaseFragment
import com.pengxh.kt.lite.extensions.navigatePageTo
import com.pengxh.kt.lite.extensions.show
import com.pengxh.kt.lite.utils.WeakReferenceHandler
@@ -36,7 +36,7 @@
private var startTime = ""
private var endTime = ""
- override fun initData(savedInstanceState: Bundle?) {
+ override fun initView(savedInstanceState: Bundle?) {
weakReferenceHandler = WeakReferenceHandler(this)
taskViewModel = ViewModelProvider(this)[TaskViewModel::class.java]
taskViewModel.taskList.observe(this) {
@@ -45,7 +45,7 @@
when {
isRefresh -> {
taskAdapter.setRefreshData(dataRows)
- baseView.taskLayout.finishRefresh()
+ bv.taskLayout.finishRefresh()
isRefresh = false
}
isLoadMore -> {
@@ -53,7 +53,7 @@
"到底了,别拉了".show(requireContext())
}
taskAdapter.setLoadMoreData(dataRows)
- baseView.taskLayout.finishLoadMore()
+ bv.taskLayout.finishLoadMore()
isLoadMore = false
}
else -> {
@@ -76,9 +76,9 @@
when (msg.what) {
2023070501 -> {
if (dataBeans.size == 0) {
- baseView.emptyLayout.visibility = View.VISIBLE
+ bv.emptyLayout.visibility = View.VISIBLE
} else {
- baseView.emptyLayout.visibility = View.GONE
+ bv.emptyLayout.visibility = View.GONE
taskAdapter = object : TaskAdapter(
requireContext(), R.layout.item_task_rv_l, dataBeans
) {
@@ -97,8 +97,8 @@
}
}
//绑定侧滑事件
- swipeAction.attachToRecyclerView(baseView.taskRecyclerView)
- baseView.taskRecyclerView.adapter = taskAdapter
+ swipeAction.attachToRecyclerView(bv.taskRecyclerView)
+ bv.taskRecyclerView.adapter = taskAdapter
taskAdapter.setOnItemCheckedListener(object :
TaskAdapter.OnItemCheckedListener {
override fun onItemChecked(items: ArrayList) {
@@ -168,7 +168,7 @@
override fun initEvent() {
- baseView.calendarView.setOnClickListener {
+ bv.calendarView.setOnClickListener {
DateRangeActionSheet.Builder().setContext(requireContext())
.setOnActionSheetListener(object :
DateRangeActionSheet.OnDateRangeSelectedListener {
@@ -177,12 +177,12 @@
endTime = endDate
//显示
- baseView.selectedDateView.text = "$startDate ~ $endDate"
+ bv.selectedDateView.text = "$startDate ~ $endDate"
}
}).build().show()
}
- baseView.addTaskButton.setOnClickListener {
+ bv.addTaskButton.setOnClickListener {
// AlertInputDialog.Builder()
// .setContext(requireContext())
// .setTitle("新建巡检任务")
@@ -200,11 +200,11 @@
requireContext().navigatePageTo()
}
- baseView.deleteTaskButton.setOnClickListener {
+ bv.deleteTaskButton.setOnClickListener {
selectedItems.size.toString().show(requireContext())
}
- baseView.taskSettingsButton.setOnClickListener {
+ bv.taskSettingsButton.setOnClickListener {
AlertInputDialog.Builder()
.setContext(requireContext())
.setTitle("设置阈值")
@@ -221,14 +221,14 @@
}).build().show()
}
- baseView.taskLayout.setOnRefreshListener {
+ bv.taskLayout.setOnRefreshListener {
isRefresh = true
//刷新之后页码重置
pageIndex = 1
getTaskList()
}
- baseView.taskLayout.setOnLoadMoreListener {
+ bv.taskLayout.setOnLoadMoreListener {
isLoadMore = true
pageIndex++
getTaskList()
@@ -239,13 +239,13 @@
taskViewModel.getTaskList(
startTime,
endTime,
- baseView.taskNameView.text.toString(),
- baseView.taskCodeView.text.toString(),
+ bv.taskNameView.text.toString(),
+ bv.taskCodeView.text.toString(),
pageIndex
)
}
- override fun initLayoutView(): Int = R.layout.fragment_task
+ override fun initLayoutRes(): Int = R.layout.fragment_task
override fun observeRequestState() {
diff --git a/app/src/main/java/com/casic/br/ktd/netty/ISocketListener.kt b/app/src/main/java/com/casic/br/ktd/netty/ISocketListener.kt
deleted file mode 100644
index dab98e1..0000000
--- a/app/src/main/java/com/casic/br/ktd/netty/ISocketListener.kt
+++ /dev/null
@@ -1,19 +0,0 @@
-package com.casic.br.ktd.netty
-
-interface ISocketListener {
- companion object {
- const val STATUS_CONNECT_SUCCESS: Byte = 1 //连接成功
- const val STATUS_CONNECT_CLOSED: Byte = 0 //关闭连接
- const val STATUS_CONNECT_ERROR: Byte = 0 //连接失败
- }
-
- /**
- * 当接收到系统消息
- */
- fun onMessageResponse(data: ByteArray?)
-
- /**
- * 当连接状态发生变化时调用
- */
- fun onServiceStatusConnectChanged(statusCode: Byte)
-}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/br/ktd/netty/SocketChannelHandle.kt b/app/src/main/java/com/casic/br/ktd/netty/SocketChannelHandle.kt
deleted file mode 100644
index 42eb310..0000000
--- a/app/src/main/java/com/casic/br/ktd/netty/SocketChannelHandle.kt
+++ /dev/null
@@ -1,51 +0,0 @@
-package com.casic.br.ktd.netty
-
-import android.util.Log
-import io.netty.channel.ChannelHandlerContext
-import io.netty.channel.SimpleChannelInboundHandler
-import io.netty.handler.timeout.IdleState
-import io.netty.handler.timeout.IdleStateEvent
-import java.nio.charset.StandardCharsets
-
-class SocketChannelHandle(private val listener: ISocketListener?) :
- SimpleChannelInboundHandler() {
-
- private val kTag = "SocketChannelHandle"
-
- override fun channelActive(ctx: ChannelHandlerContext) {
- super.channelActive(ctx)
- Log.d(kTag, "channelActive ===> 连接成功")
- listener?.onServiceStatusConnectChanged(ISocketListener.STATUS_CONNECT_SUCCESS)
- }
-
- override fun channelInactive(ctx: ChannelHandlerContext) {
- super.channelInactive(ctx)
- Log.e(kTag, "channelInactive: 连接断开")
- }
-
- override fun userEventTriggered(ctx: ChannelHandlerContext, evt: Any) {
- super.userEventTriggered(ctx, evt)
- if (evt is IdleStateEvent) {
- if (evt.state() == IdleState.WRITER_IDLE) {
- //写超时,此时可以发送心跳数据给服务器
- val temp = "FF"
- ctx.writeAndFlush(temp.toByteArray(StandardCharsets.UTF_8))
- } else if (evt.state() == IdleState.READER_IDLE) {
- //读超时,此时代表没有收到心跳返回可以关闭当前连接进行重连
- ctx.close()
- }
- }
- }
-
- override fun channelRead0(ctx: ChannelHandlerContext, data: ByteArray?) {
- listener?.onMessageResponse(data)
- }
-
- override fun exceptionCaught(ctx: ChannelHandlerContext, cause: Throwable) {
- super.exceptionCaught(ctx, cause)
- Log.d(kTag, "exceptionCaught ===> $cause")
- listener?.onServiceStatusConnectChanged(ISocketListener.STATUS_CONNECT_ERROR)
- cause.printStackTrace()
- ctx.close()
- }
-}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/br/ktd/netty/SocketClient.kt b/app/src/main/java/com/casic/br/ktd/netty/SocketClient.kt
deleted file mode 100644
index d05d335..0000000
--- a/app/src/main/java/com/casic/br/ktd/netty/SocketClient.kt
+++ /dev/null
@@ -1,153 +0,0 @@
-package com.casic.br.ktd.netty
-
-import android.os.SystemClock
-import android.util.Log
-import io.netty.bootstrap.Bootstrap
-import io.netty.channel.*
-import io.netty.channel.nio.NioEventLoopGroup
-import io.netty.channel.socket.SocketChannel
-import io.netty.channel.socket.nio.NioSocketChannel
-import io.netty.handler.codec.bytes.ByteArrayDecoder
-import io.netty.handler.codec.bytes.ByteArrayEncoder
-import io.netty.handler.timeout.IdleStateHandler
-
-class SocketClient {
-
- private val kTag = "SocketClient"
-
- private var host: String? = null
- private var port = 8000
- private var nioEventLoopGroup: NioEventLoopGroup? = null
- private var channel: Channel? = null
- private var listener: ISocketListener? = null
-
- //现在连接的状态
- var connectStatus = false //判断是否已连接
- private var reconnectNum = Int.MAX_VALUE //定义的重连到时候用
- private var isNeedReconnect = true //是否需要重连
- var isConnecting = false //是否正在连接
- private set
- private var reconnectIntervalTime: Long = 15000 //重连的时间
-
- //重连时间
- fun setReconnectNum(reconnectNum: Int) {
- this.reconnectNum = reconnectNum
- }
-
- fun setReconnectIntervalTime(reconnectIntervalTime: Long) {
- this.reconnectIntervalTime = reconnectIntervalTime
- }
-
- fun setSocketListener(listener: ISocketListener?) {
- this.listener = listener
- }
-
- fun connect(host: String, port: Int) {
- this.host = host
- this.port = port
- Log.d(kTag, "connect ===> 开始连接TCP服务器")
- if (isConnecting) {
- return
- }
- //起个线程
- val clientThread: Thread = object : Thread("client-Netty") {
- override fun run() {
- super.run()
- isNeedReconnect = true
- reconnectNum = Int.MAX_VALUE
- connectServer()
- }
- }
- clientThread.start()
- }
-
- private fun connectServer() {
- synchronized(this@SocketClient) {
- var channelFuture: ChannelFuture? = null //连接管理对象
- if (!connectStatus) {
- isConnecting = true
- nioEventLoopGroup = NioEventLoopGroup() //设置的连接group
- val bootstrap = Bootstrap()
- bootstrap.group(nioEventLoopGroup) //设置的一系列连接参数操作等
- .channel(NioSocketChannel::class.java)
- .option(ChannelOption.TCP_NODELAY, true) //无阻塞
- .option(ChannelOption.SO_KEEPALIVE, true) //长连接
- .option(
- ChannelOption.RCVBUF_ALLOCATOR,
- AdaptiveRecvByteBufAllocator(5000, 5000, 8000)
- ) //接收缓冲区 最小值太小时数据接收不全
- .handler(object : ChannelInitializer() {
- override fun initChannel(channel: SocketChannel) {
- val pipeline = channel.pipeline()
- //参数1:代表读套接字超时的时间,没收到数据会触发读超时回调;
- //参数2:代表写套接字超时时间,没进行写会触发写超时回调;
- //参数3:将在未执行读取或写入时触发超时回调,0代表不处理;
- //读超时尽量设置大于写超时,代表多次写超时时写心跳包,多次写了心跳数据仍然读超时代表当前连接错误,即可断开连接重新连接
- pipeline.addLast(IdleStateHandler(60, 10, 0))
- pipeline.addLast(ByteArrayDecoder())
- pipeline.addLast(ByteArrayEncoder())
- pipeline.addLast(SocketChannelHandle(listener))
- }
- })
- try {
- //连接监听
- channelFuture = bootstrap.connect(host, port)
- .addListener(object : ChannelFutureListener {
- override fun operationComplete(channelFuture: ChannelFuture) {
- if (channelFuture.isSuccess) {
- connectStatus = true
- channel = channelFuture.channel()
- } else {
- Log.e(kTag, "operationComplete: 连接失败")
- connectStatus = false
- }
- isConnecting = false
- }
- }).sync()
- // 等待连接关闭
- channelFuture.channel().closeFuture().sync()
- } catch (e: Exception) {
- e.printStackTrace()
- } finally {
- connectStatus = false
- listener?.onServiceStatusConnectChanged(ISocketListener.STATUS_CONNECT_CLOSED) //STATUS_CONNECT_CLOSED 这我自己定义的 接口标识
- if (null != channelFuture) {
- if (channelFuture.channel() != null && channelFuture.channel().isOpen) {
- channelFuture.channel().close()
- }
- }
- nioEventLoopGroup?.shutdownGracefully()
- reconnect() //重新连接
- }
- }
- }
- }
-
- //断开连接
- fun disconnect() {
- Log.d(kTag, "disconnect ===> 断开连接")
- isNeedReconnect = false
- nioEventLoopGroup?.shutdownGracefully()
- }
-
- //重新连接
- private fun reconnect() {
- if (isNeedReconnect && reconnectNum > 0 && !connectStatus) {
- reconnectNum--
- SystemClock.sleep(reconnectIntervalTime)
- if (isNeedReconnect && reconnectNum > 0 && !connectStatus) {
- Log.d(kTag, "reconnect ===> 重新连接")
- connectServer()
- }
- }
- }
-
- fun sendData(bytes: ByteArray) {
- channel?.writeAndFlush(bytes)?.addListener(ChannelFutureListener { future ->
- if (!future.isSuccess) {
- future.channel().close()
- nioEventLoopGroup!!.shutdownGracefully()
- }
- })
- }
-}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/br/ktd/netty/SocketManager.kt b/app/src/main/java/com/casic/br/ktd/netty/SocketManager.kt
deleted file mode 100644
index 17daf35..0000000
--- a/app/src/main/java/com/casic/br/ktd/netty/SocketManager.kt
+++ /dev/null
@@ -1,113 +0,0 @@
-package com.casic.br.ktd.netty
-
-import android.util.Log
-import com.casic.br.ktd.base.BaseApplication
-import com.casic.br.ktd.extensions.covertAngleValue
-import com.casic.br.ktd.extensions.covertDataValue
-import com.casic.br.ktd.extensions.toUnsignedByteArray
-import com.casic.br.ktd.model.SensorDataModel
-import com.casic.br.ktd.utils.LocaleConstant
-import com.pengxh.kt.lite.extensions.toJson
-import com.pengxh.kt.lite.utils.BroadcastManager
-
-class SocketManager private constructor() : ISocketListener {
-
- private val kTag = "SocketManager"
- private var nettyClient: SocketClient = SocketClient()
-
- companion object {
- val instance: SocketManager by lazy(mode = LazyThreadSafetyMode.SYNCHRONIZED) { SocketManager() }
- }
-
- fun connectNetty(hostname: String, port: Int) {
- Thread {
- if (!nettyClient.connectStatus) {
- nettyClient.setSocketListener(this)
- nettyClient.connect(hostname, port)
- } else {
- nettyClient.disconnect()
- }
- }.start()
- }
-
- override fun onMessageResponse(data: ByteArray?) {
-// Log.d(kTag, "onMessageResponse ===> " + Arrays.toString(data))
- /**
- * 0xFF,0x01,
- * 0x01,0x37,0xE6, 甲烷浓度值(数据码1* 65536 + 数据码2 * 256 + 数据码3)
- * 0x00, 激光甲烷模块工作状态(00表示设备正常,01表示温控故障,02表示设备激光未打开)
- * 0x00,0xB2,0x35, 激光强度值(数据码5* 65536 + 数据码6 * 256 + 数据码7)
- * 0x0A,0x3D, 云台水平角度([数据码8 * 256 + 数据码9]/100,单位为°,精确到0.01)
- * 0x05,0x6F, 云台垂直角度(首先计算Tangle=[数据码10 * 256 + 数据码11]/100,单位为°,精确到0.01。若Tangle在0~90范围内,则垂直角度值=Tangle;若Tangle在-1~-90范围内,则垂直角度值=Tangle-360)
- * 0xC1
- *
- * [-1, 1, 1, 55, -26, 0, 0, -78, 53, 10, 61, 5, 111, -63]
- * 甲烷浓度值为79638,计算为79638=0x01*65536+0x37*256+0xE6[0x01为数据码1,0x37为数据码2,0xE6为数据码3];
- * 激光甲烷设备状态值为0,表示状态正常,[0x00为数据码4];
- * 激光强度值为45621,计算为45621=0x00*65536+0xB2*256+0x35[0x00为数据码5,0xB2为数据码6,0x35为数据码7];
- *
- * =========================================================================================
- * 实际数据(1800-1950左右)
- * [-86, 1, 0, 7, 71, 0, 0, 62, -92, 57, 59, -118, -111, -64]
- * */
-
- if (data == null) {
- return
- }
- val bytes = data.toUnsignedByteArray()
- if (bytes.size == 14) {
- val dataModel = SensorDataModel(0, "激光未打开", 0, 0.0, 0.0)
-
- val methaneBytes = IntArray(3)
- System.arraycopy(bytes, 2, methaneBytes, 0, 3)
- dataModel.methane = methaneBytes.covertDataValue()
-
- dataModel.methaneState = when (bytes[5]) {
- 1 -> "温控故障"
- 2 -> "激光未打开"
- else -> "正常"
- }
-
- val laserBytes = IntArray(3)
- System.arraycopy(bytes, 6, laserBytes, 0, 3)
- dataModel.laser = laserBytes.covertDataValue()
-
- /**
- * 水平角度的实际范围为从水平零点开始,顺时针方向(从上往下看),0~360°
- * 垂直角度的实际范围为从垂直零点开始,以向上为正,-90°~90°,控制精度为0.01°
- * */
- val horizontalBytes = IntArray(2)
- System.arraycopy(bytes, 9, horizontalBytes, 0, 2)
- dataModel.horizontal = horizontalBytes.covertAngleValue()
-
- val verticalBytes = IntArray(2)
- System.arraycopy(bytes, 11, verticalBytes, 0, 2)
- dataModel.vertical = verticalBytes.covertAngleValue()
-
- //{"horizontal":26.21,"laser":45621,"methane":79846,"methaneState":"正常","vertical":13.91}
- BroadcastManager.obtainInstance(BaseApplication.get()).sendBroadcast(
- LocaleConstant.ACTION_UPDATE_DATA, dataModel.toJson()
- )
- }
- }
-
- override fun onServiceStatusConnectChanged(statusCode: Byte) {
- if (statusCode == ISocketListener.STATUS_CONNECT_SUCCESS) {
- if (nettyClient.connectStatus) {
- Log.d(kTag, "连接成功")
- }
- } else {
- if (!nettyClient.connectStatus) {
- Log.e(kTag, "onServiceStatusConnectChanged:$statusCode,连接断开,正在重连")
- }
- }
- }
-
- fun sendData(data: ByteArray) {
- nettyClient.sendData(data)
- }
-
- fun close() {
- nettyClient.disconnect()
- }
-}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/br/ktd/netty/tcp/ISocketListener.kt b/app/src/main/java/com/casic/br/ktd/netty/tcp/ISocketListener.kt
new file mode 100644
index 0000000..13c3084
--- /dev/null
+++ b/app/src/main/java/com/casic/br/ktd/netty/tcp/ISocketListener.kt
@@ -0,0 +1,19 @@
+package com.casic.br.ktd.netty.tcp
+
+interface ISocketListener {
+ companion object {
+ const val STATUS_CONNECT_SUCCESS: Byte = 1 //连接成功
+ const val STATUS_CONNECT_CLOSED: Byte = 0 //关闭连接
+ const val STATUS_CONNECT_ERROR: Byte = 0 //连接失败
+ }
+
+ /**
+ * 当接收到系统消息
+ */
+ fun onMessageResponse(data: ByteArray?)
+
+ /**
+ * 当连接状态发生变化时调用
+ */
+ fun onServiceStatusConnectChanged(statusCode: Byte)
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/br/ktd/netty/tcp/SocketChannelHandle.kt b/app/src/main/java/com/casic/br/ktd/netty/tcp/SocketChannelHandle.kt
new file mode 100644
index 0000000..8e2997f
--- /dev/null
+++ b/app/src/main/java/com/casic/br/ktd/netty/tcp/SocketChannelHandle.kt
@@ -0,0 +1,51 @@
+package com.casic.br.ktd.netty.tcp
+
+import android.util.Log
+import io.netty.channel.ChannelHandlerContext
+import io.netty.channel.SimpleChannelInboundHandler
+import io.netty.handler.timeout.IdleState
+import io.netty.handler.timeout.IdleStateEvent
+import java.nio.charset.StandardCharsets
+
+class SocketChannelHandle(private val listener: ISocketListener?) :
+ SimpleChannelInboundHandler() {
+
+ private val kTag = "SocketChannelHandle"
+
+ override fun channelActive(ctx: ChannelHandlerContext) {
+ super.channelActive(ctx)
+ Log.d(kTag, "channelActive ===> 连接成功")
+ listener?.onServiceStatusConnectChanged(ISocketListener.STATUS_CONNECT_SUCCESS)
+ }
+
+ override fun channelInactive(ctx: ChannelHandlerContext) {
+ super.channelInactive(ctx)
+ Log.e(kTag, "channelInactive: 连接断开")
+ }
+
+ override fun userEventTriggered(ctx: ChannelHandlerContext, evt: Any) {
+ super.userEventTriggered(ctx, evt)
+ if (evt is IdleStateEvent) {
+ if (evt.state() == IdleState.WRITER_IDLE) {
+ //写超时,此时可以发送心跳数据给服务器
+ val temp = "FF"
+ ctx.writeAndFlush(temp.toByteArray(StandardCharsets.UTF_8))
+ } else if (evt.state() == IdleState.READER_IDLE) {
+ //读超时,此时代表没有收到心跳返回可以关闭当前连接进行重连
+ ctx.close()
+ }
+ }
+ }
+
+ override fun channelRead0(ctx: ChannelHandlerContext, data: ByteArray?) {
+ listener?.onMessageResponse(data)
+ }
+
+ override fun exceptionCaught(ctx: ChannelHandlerContext, cause: Throwable) {
+ super.exceptionCaught(ctx, cause)
+ Log.d(kTag, "exceptionCaught ===> $cause")
+ listener?.onServiceStatusConnectChanged(ISocketListener.STATUS_CONNECT_ERROR)
+ cause.printStackTrace()
+ ctx.close()
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/br/ktd/netty/tcp/SocketClient.kt b/app/src/main/java/com/casic/br/ktd/netty/tcp/SocketClient.kt
new file mode 100644
index 0000000..34960a0
--- /dev/null
+++ b/app/src/main/java/com/casic/br/ktd/netty/tcp/SocketClient.kt
@@ -0,0 +1,153 @@
+package com.casic.br.ktd.netty.tcp
+
+import android.os.SystemClock
+import android.util.Log
+import io.netty.bootstrap.Bootstrap
+import io.netty.channel.*
+import io.netty.channel.nio.NioEventLoopGroup
+import io.netty.channel.socket.SocketChannel
+import io.netty.channel.socket.nio.NioSocketChannel
+import io.netty.handler.codec.bytes.ByteArrayDecoder
+import io.netty.handler.codec.bytes.ByteArrayEncoder
+import io.netty.handler.timeout.IdleStateHandler
+
+class SocketClient {
+
+ private val kTag = "SocketClient"
+
+ private var host: String? = null
+ private var port = 8000
+ private var nioEventLoopGroup: NioEventLoopGroup? = null
+ private var channel: Channel? = null
+ private var listener: ISocketListener? = null
+
+ //现在连接的状态
+ var connectStatus = false //判断是否已连接
+ private var reconnectNum = Int.MAX_VALUE //定义的重连到时候用
+ private var isNeedReconnect = true //是否需要重连
+ var isConnecting = false //是否正在连接
+ private set
+ private var reconnectIntervalTime: Long = 15000 //重连的时间
+
+ //重连时间
+ fun setReconnectNum(reconnectNum: Int) {
+ this.reconnectNum = reconnectNum
+ }
+
+ fun setReconnectIntervalTime(reconnectIntervalTime: Long) {
+ this.reconnectIntervalTime = reconnectIntervalTime
+ }
+
+ fun setSocketListener(listener: ISocketListener?) {
+ this.listener = listener
+ }
+
+ fun connect(host: String, port: Int) {
+ this.host = host
+ this.port = port
+ Log.d(kTag, "connect ===> 开始连接TCP服务器")
+ if (isConnecting) {
+ return
+ }
+ //起个线程
+ val clientThread: Thread = object : Thread("client-Netty") {
+ override fun run() {
+ super.run()
+ isNeedReconnect = true
+ reconnectNum = Int.MAX_VALUE
+ connectServer()
+ }
+ }
+ clientThread.start()
+ }
+
+ private fun connectServer() {
+ synchronized(this@SocketClient) {
+ var channelFuture: ChannelFuture? = null //连接管理对象
+ if (!connectStatus) {
+ isConnecting = true
+ nioEventLoopGroup = NioEventLoopGroup() //设置的连接group
+ val bootstrap = Bootstrap()
+ bootstrap.group(nioEventLoopGroup) //设置的一系列连接参数操作等
+ .channel(NioSocketChannel::class.java)
+ .option(ChannelOption.TCP_NODELAY, true) //无阻塞
+ .option(ChannelOption.SO_KEEPALIVE, true) //长连接
+ .option(
+ ChannelOption.RCVBUF_ALLOCATOR,
+ AdaptiveRecvByteBufAllocator(5000, 5000, 8000)
+ ) //接收缓冲区 最小值太小时数据接收不全
+ .handler(object : ChannelInitializer() {
+ override fun initChannel(channel: SocketChannel) {
+ val pipeline = channel.pipeline()
+ //参数1:代表读套接字超时的时间,没收到数据会触发读超时回调;
+ //参数2:代表写套接字超时时间,没进行写会触发写超时回调;
+ //参数3:将在未执行读取或写入时触发超时回调,0代表不处理;
+ //读超时尽量设置大于写超时,代表多次写超时时写心跳包,多次写了心跳数据仍然读超时代表当前连接错误,即可断开连接重新连接
+ pipeline.addLast(IdleStateHandler(60, 10, 0))
+ pipeline.addLast(ByteArrayDecoder())
+ pipeline.addLast(ByteArrayEncoder())
+ pipeline.addLast(SocketChannelHandle(listener))
+ }
+ })
+ try {
+ //连接监听
+ channelFuture = bootstrap.connect(host, port)
+ .addListener(object : ChannelFutureListener {
+ override fun operationComplete(channelFuture: ChannelFuture) {
+ if (channelFuture.isSuccess) {
+ connectStatus = true
+ channel = channelFuture.channel()
+ } else {
+ Log.e(kTag, "operationComplete: 连接失败")
+ connectStatus = false
+ }
+ isConnecting = false
+ }
+ }).sync()
+ // 等待连接关闭
+ channelFuture.channel().closeFuture().sync()
+ } catch (e: Exception) {
+ e.printStackTrace()
+ } finally {
+ connectStatus = false
+ listener?.onServiceStatusConnectChanged(ISocketListener.STATUS_CONNECT_CLOSED) //STATUS_CONNECT_CLOSED 这我自己定义的 接口标识
+ if (null != channelFuture) {
+ if (channelFuture.channel() != null && channelFuture.channel().isOpen) {
+ channelFuture.channel().close()
+ }
+ }
+ nioEventLoopGroup?.shutdownGracefully()
+ reconnect() //重新连接
+ }
+ }
+ }
+ }
+
+ //断开连接
+ fun disconnect() {
+ Log.d(kTag, "disconnect ===> 断开连接")
+ isNeedReconnect = false
+ nioEventLoopGroup?.shutdownGracefully()
+ }
+
+ //重新连接
+ private fun reconnect() {
+ if (isNeedReconnect && reconnectNum > 0 && !connectStatus) {
+ reconnectNum--
+ SystemClock.sleep(reconnectIntervalTime)
+ if (isNeedReconnect && reconnectNum > 0 && !connectStatus) {
+ Log.d(kTag, "reconnect ===> 重新连接")
+ connectServer()
+ }
+ }
+ }
+
+ fun sendData(bytes: ByteArray) {
+ channel?.writeAndFlush(bytes)?.addListener(ChannelFutureListener { future ->
+ if (!future.isSuccess) {
+ future.channel().close()
+ nioEventLoopGroup!!.shutdownGracefully()
+ }
+ })
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/br/ktd/netty/tcp/SocketManager.kt b/app/src/main/java/com/casic/br/ktd/netty/tcp/SocketManager.kt
new file mode 100644
index 0000000..35980b9
--- /dev/null
+++ b/app/src/main/java/com/casic/br/ktd/netty/tcp/SocketManager.kt
@@ -0,0 +1,113 @@
+package com.casic.br.ktd.netty.tcp
+
+import android.util.Log
+import com.casic.br.ktd.base.BaseApplication
+import com.casic.br.ktd.extensions.covertAngleValue
+import com.casic.br.ktd.extensions.covertDataValue
+import com.casic.br.ktd.extensions.toUnsignedByteArray
+import com.casic.br.ktd.model.SensorDataModel
+import com.casic.br.ktd.utils.LocaleConstant
+import com.pengxh.kt.lite.extensions.toJson
+import com.pengxh.kt.lite.utils.BroadcastManager
+
+class SocketManager private constructor() : ISocketListener {
+
+ private val kTag = "SocketManager"
+ private var nettyClient: SocketClient = SocketClient()
+
+ companion object {
+ val instance: SocketManager by lazy(mode = LazyThreadSafetyMode.SYNCHRONIZED) { SocketManager() }
+ }
+
+ fun connectNetty(hostname: String, port: Int) {
+ Thread {
+ if (!nettyClient.connectStatus) {
+ nettyClient.setSocketListener(this)
+ nettyClient.connect(hostname, port)
+ } else {
+ nettyClient.disconnect()
+ }
+ }.start()
+ }
+
+ override fun onMessageResponse(data: ByteArray?) {
+// Log.d(kTag, "onMessageResponse ===> " + Arrays.toString(data))
+ /**
+ * 0xFF,0x01,
+ * 0x01,0x37,0xE6, 甲烷浓度值(数据码1* 65536 + 数据码2 * 256 + 数据码3)
+ * 0x00, 激光甲烷模块工作状态(00表示设备正常,01表示温控故障,02表示设备激光未打开)
+ * 0x00,0xB2,0x35, 激光强度值(数据码5* 65536 + 数据码6 * 256 + 数据码7)
+ * 0x0A,0x3D, 云台水平角度([数据码8 * 256 + 数据码9]/100,单位为°,精确到0.01)
+ * 0x05,0x6F, 云台垂直角度(首先计算Tangle=[数据码10 * 256 + 数据码11]/100,单位为°,精确到0.01。若Tangle在0~90范围内,则垂直角度值=Tangle;若Tangle在-1~-90范围内,则垂直角度值=Tangle-360)
+ * 0xC1
+ *
+ * [-1, 1, 1, 55, -26, 0, 0, -78, 53, 10, 61, 5, 111, -63]
+ * 甲烷浓度值为79638,计算为79638=0x01*65536+0x37*256+0xE6[0x01为数据码1,0x37为数据码2,0xE6为数据码3];
+ * 激光甲烷设备状态值为0,表示状态正常,[0x00为数据码4];
+ * 激光强度值为45621,计算为45621=0x00*65536+0xB2*256+0x35[0x00为数据码5,0xB2为数据码6,0x35为数据码7];
+ *
+ * =========================================================================================
+ * 实际数据(1800-1950左右)
+ * [-86, 1, 0, 7, 71, 0, 0, 62, -92, 57, 59, -118, -111, -64]
+ * */
+
+ if (data == null) {
+ return
+ }
+ val bytes = data.toUnsignedByteArray()
+ if (bytes.size == 14) {
+ val dataModel = SensorDataModel(0, "激光未打开", 0, 0.0, 0.0)
+
+ val methaneBytes = IntArray(3)
+ System.arraycopy(bytes, 2, methaneBytes, 0, 3)
+ dataModel.methane = methaneBytes.covertDataValue()
+
+ dataModel.methaneState = when (bytes[5]) {
+ 1 -> "温控故障"
+ 2 -> "激光未打开"
+ else -> "正常"
+ }
+
+ val laserBytes = IntArray(3)
+ System.arraycopy(bytes, 6, laserBytes, 0, 3)
+ dataModel.laser = laserBytes.covertDataValue()
+
+ /**
+ * 水平角度的实际范围为从水平零点开始,顺时针方向(从上往下看),0~360°
+ * 垂直角度的实际范围为从垂直零点开始,以向上为正,-90°~90°,控制精度为0.01°
+ * */
+ val horizontalBytes = IntArray(2)
+ System.arraycopy(bytes, 9, horizontalBytes, 0, 2)
+ dataModel.horizontal = horizontalBytes.covertAngleValue()
+
+ val verticalBytes = IntArray(2)
+ System.arraycopy(bytes, 11, verticalBytes, 0, 2)
+ dataModel.vertical = verticalBytes.covertAngleValue()
+
+ //{"horizontal":26.21,"laser":45621,"methane":79846,"methaneState":"正常","vertical":13.91}
+ BroadcastManager.obtainInstance(BaseApplication.get()).sendBroadcast(
+ LocaleConstant.ACTION_UPDATE_DATA, dataModel.toJson()
+ )
+ }
+ }
+
+ override fun onServiceStatusConnectChanged(statusCode: Byte) {
+ if (statusCode == ISocketListener.STATUS_CONNECT_SUCCESS) {
+ if (nettyClient.connectStatus) {
+ Log.d(kTag, "连接成功")
+ }
+ } else {
+ if (!nettyClient.connectStatus) {
+ Log.e(kTag, "onServiceStatusConnectChanged:$statusCode,连接断开,正在重连")
+ }
+ }
+ }
+
+ fun sendData(data: ByteArray) {
+ nettyClient.sendData(data)
+ }
+
+ fun close() {
+ nettyClient.disconnect()
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/br/ktd/netty/udp/UdpChannelInboundHandler.kt b/app/src/main/java/com/casic/br/ktd/netty/udp/UdpChannelInboundHandler.kt
new file mode 100644
index 0000000..4d6f97c
--- /dev/null
+++ b/app/src/main/java/com/casic/br/ktd/netty/udp/UdpChannelInboundHandler.kt
@@ -0,0 +1,36 @@
+package com.casic.br.ktd.netty.udp
+
+import io.netty.channel.ChannelHandlerContext
+import io.netty.channel.SimpleChannelInboundHandler
+import io.netty.channel.socket.DatagramPacket
+import io.netty.util.CharsetUtil
+
+
+abstract class UdpChannelInboundHandler : SimpleChannelInboundHandler() {
+
+ private var handlerContext: ChannelHandlerContext? = null
+
+ override fun channelActive(ctx: ChannelHandlerContext?) {
+ super.channelActive(ctx)
+ handlerContext = ctx
+ }
+
+ override fun channelInactive(ctx: ChannelHandlerContext?) {
+ super.channelInactive(ctx)
+ handlerContext?.close()
+ }
+
+ fun sendDatagramPacket(obj: Any) {
+ handlerContext?.writeAndFlush(obj)
+ }
+
+ fun releasePort() {
+ handlerContext?.close()
+ }
+
+ override fun channelRead0(ctx: ChannelHandlerContext, datagramPacket: DatagramPacket) {
+ receivedMessage(datagramPacket.content().toString(CharsetUtil.UTF_8))
+ }
+
+ abstract fun receivedMessage(data: String)
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/br/ktd/netty/udp/UdpChannelInitializer.kt b/app/src/main/java/com/casic/br/ktd/netty/udp/UdpChannelInitializer.kt
new file mode 100644
index 0000000..416c5a1
--- /dev/null
+++ b/app/src/main/java/com/casic/br/ktd/netty/udp/UdpChannelInitializer.kt
@@ -0,0 +1,17 @@
+package com.casic.br.ktd.netty.udp
+
+import io.netty.channel.ChannelInitializer
+import io.netty.channel.socket.DatagramChannel
+import io.netty.handler.timeout.IdleStateHandler
+
+
+open class UdpChannelInitializer(private val handler: UdpChannelInboundHandler) :
+ ChannelInitializer() {
+
+ override fun initChannel(datagramChannel: DatagramChannel) {
+ val pipeline = datagramChannel.pipeline()
+ pipeline.addLast(
+ IdleStateHandler(12, 15, 0)
+ ).addLast(handler)
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/br/ktd/netty/udp/UdpClient.kt b/app/src/main/java/com/casic/br/ktd/netty/udp/UdpClient.kt
new file mode 100644
index 0000000..3893afa
--- /dev/null
+++ b/app/src/main/java/com/casic/br/ktd/netty/udp/UdpClient.kt
@@ -0,0 +1,103 @@
+package com.casic.br.ktd.netty.udp
+
+import com.casic.br.ktd.utils.LocaleConstant
+import com.pengxh.kt.lite.utils.SaveKeyValues
+import io.netty.bootstrap.Bootstrap
+import io.netty.buffer.ByteBuf
+import io.netty.buffer.Unpooled
+import io.netty.channel.ChannelOption
+import io.netty.channel.nio.NioEventLoopGroup
+import io.netty.channel.socket.DatagramPacket
+import io.netty.channel.socket.nio.NioDatagramChannel
+import io.netty.util.CharsetUtil
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.launch
+import kotlinx.coroutines.withContext
+import java.net.InetSocketAddress
+import java.util.concurrent.ExecutorService
+import java.util.concurrent.Executors
+
+
+class UdpClient : UdpChannelInboundHandler(), Runnable {
+
+ private val bootStrap by lazy { Bootstrap() }
+ private val eventLoopGroup by lazy { NioEventLoopGroup() }
+ private val udpChannelInitializer by lazy { UdpChannelInitializer(this) }
+ private var executorService: ExecutorService
+
+ init {
+ bootStrap.group(eventLoopGroup)
+ bootStrap.channel(NioDatagramChannel::class.java)
+ .option(ChannelOption.SO_RCVBUF, 1024)
+ .option(ChannelOption.SO_SNDBUF, 1024)
+ bootStrap.handler(udpChannelInitializer)
+
+ executorService = Executors.newSingleThreadExecutor()
+ executorService.execute(this)
+ }
+
+ override fun run() {
+ try {
+ val channelFuture = bootStrap.bind(LocaleConstant.LOCATION_UDP_PORT).sync()
+ channelFuture.channel().closeFuture().sync()
+ } catch (e: InterruptedException) {
+ e.printStackTrace()
+ } finally {
+ eventLoopGroup.shutdownGracefully()
+ }
+ }
+
+ fun send(value: String) {
+ CoroutineScope(Dispatchers.Main).launch {
+ withContext(Dispatchers.IO) {
+ val host = SaveKeyValues.getValue(
+ LocaleConstant.LOCATION_UDP_SERVER, "192.168.149.213"
+ ).toString()
+ val datagramPacket = DatagramPacket(
+ Unpooled.copiedBuffer(value, CharsetUtil.UTF_8),
+ InetSocketAddress(host, LocaleConstant.LOCATION_UDP_PORT)
+ )
+ sendDatagramPacket(datagramPacket)
+ }
+ }
+ }
+
+ fun send(value: ByteArray) {
+ CoroutineScope(Dispatchers.Main).launch {
+ withContext(Dispatchers.IO) {
+ val host = SaveKeyValues.getValue(
+ LocaleConstant.LOCATION_UDP_SERVER, "192.168.149.213"
+ ).toString()
+ val datagramPacket = DatagramPacket(
+ Unpooled.copiedBuffer(value),
+ InetSocketAddress(host, LocaleConstant.LOCATION_UDP_PORT)
+ )
+ sendDatagramPacket(datagramPacket)
+ }
+ }
+ }
+
+ fun send(value: ByteBuf) {
+ CoroutineScope(Dispatchers.Main).launch {
+ withContext(Dispatchers.IO) {
+ val host = SaveKeyValues.getValue(
+ LocaleConstant.LOCATION_UDP_SERVER, "192.168.149.213"
+ ).toString()
+ val datagramPacket = DatagramPacket(
+ Unpooled.copiedBuffer(value),
+ InetSocketAddress(host, LocaleConstant.LOCATION_UDP_PORT)
+ )
+ sendDatagramPacket(datagramPacket)
+ }
+ }
+ }
+
+ fun release() {
+ releasePort()
+ }
+
+ override fun receivedMessage(data: String) {
+
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/br/ktd/utils/LocaleConstant.kt b/app/src/main/java/com/casic/br/ktd/utils/LocaleConstant.kt
index 0dd119e..4c675df 100644
--- a/app/src/main/java/com/casic/br/ktd/utils/LocaleConstant.kt
+++ b/app/src/main/java/com/casic/br/ktd/utils/LocaleConstant.kt
@@ -50,6 +50,10 @@
const val DEV_NET_IP = "192.168.1.21"
const val DEV_NET_PORT = "8000"
+ //位置信息UDP端口
+ const val LOCATION_UDP_SERVER = "udpServer"
+ const val LOCATION_UDP_PORT = 7777
+
//BroadcastReceiver Action
const val ACTION_UPDATE_DATA = "update"
diff --git a/app/src/main/java/com/casic/br/ktd/utils/LocationHelper.kt b/app/src/main/java/com/casic/br/ktd/utils/LocationHelper.kt
index 8e31d3f..df6adb5 100644
--- a/app/src/main/java/com/casic/br/ktd/utils/LocationHelper.kt
+++ b/app/src/main/java/com/casic/br/ktd/utils/LocationHelper.kt
@@ -7,19 +7,40 @@
import android.location.LocationListener
import android.location.LocationManager
import android.os.Bundle
+import android.util.Log
import androidx.core.app.ActivityCompat
+import com.amap.api.location.AMapLocation
+import com.amap.api.location.AMapLocationClient
+import com.amap.api.location.AMapLocationClientOption
-object LocationHelper {
- fun obtainCurrentLocation(context: Context, listener: ILocationListener) {
+class LocationHelper private constructor() {
+
+ private val kTag = "LocationHelper"
+
+ companion object {
+ //Kotlin委托模式双重锁单例
+ val get: LocationHelper by lazy(mode = LazyThreadSafetyMode.SYNCHRONIZED) {
+ LocationHelper()
+ }
+ }
+
+ private val locationOption = AMapLocationClientOption()
+ private lateinit var locationClient: AMapLocationClient
+
+ init {
+ //设置定位模式为高精度模式,AMapLocationMode.Battery_Saving为低功耗模式,AMapLocationMode.Device_Sensors是仅设备模式
+ locationOption.locationMode = AMapLocationClientOption.AMapLocationMode.Hight_Accuracy
+ locationOption.isNeedAddress = true //设置是否返回地址信息(默认返回地址信息)
+ locationOption.isLocationCacheEnable = true //可选,设置是否使用缓存定位,默认为true
+ }
+
+ fun obtainLocation(context: Context, listener: ILocationListener) {
if (ActivityCompat.checkSelfPermission(
- context,
- Manifest.permission.ACCESS_LOCATION_EXTRA_COMMANDS
+ context, Manifest.permission.ACCESS_LOCATION_EXTRA_COMMANDS
) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(
- context,
- Manifest.permission.ACCESS_FINE_LOCATION
+ context, Manifest.permission.ACCESS_FINE_LOCATION
) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(
- context,
- Manifest.permission.ACCESS_COARSE_LOCATION
+ context, Manifest.permission.ACCESS_COARSE_LOCATION
) != PackageManager.PERMISSION_GRANTED
) {
return
@@ -38,7 +59,37 @@
})
}
+ /**
+ * 高德sdk定位
+ */
+ fun obtainLocationByGD(context: Context?, listener: ILocationListener) {
+ locationClient = AMapLocationClient(context)
+ //给定位客户端对象设置定位参数
+ locationClient.setLocationOption(locationOption)
+ //设置定位回调监听
+ locationClient.setLocationListener { aMapLocation ->
+ if (aMapLocation != null) {
+ if (aMapLocation.errorCode == 0) {
+ listener.onAMapLocationGet(aMapLocation)
+ } else {
+ Log.e(
+ kTag,
+ "ErrCode: ${aMapLocation.errorCode}, errInfo: ${aMapLocation.errorInfo}"
+ )
+ }
+ }
+ }
+ //启动定位
+ locationClient.startLocation()
+ }
+
+ fun stopLocation() {
+ locationClient.stopLocation()//停止定位
+ }
+
interface ILocationListener {
- fun onLocationGet(location: Location?) //高德定位数据
+ fun onLocationGet(location: Location?) //GPS定位数据
+
+ fun onAMapLocationGet(aMapLocation: AMapLocation?) //高德定位数据
}
}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/br/ktd/view/InspectionActivity.kt b/app/src/main/java/com/casic/br/ktd/view/InspectionActivity.kt
index 02c47f8..c893092 100644
--- a/app/src/main/java/com/casic/br/ktd/view/InspectionActivity.kt
+++ b/app/src/main/java/com/casic/br/ktd/view/InspectionActivity.kt
@@ -15,16 +15,21 @@
import android.view.SurfaceHolder
import android.view.View
import android.widget.AdapterView
-import com.amap.api.maps.*
+import com.amap.api.location.AMapLocation
+import com.amap.api.maps.AMap
+import com.amap.api.maps.CameraUpdateFactory
+import com.amap.api.maps.UiSettings
import com.amap.api.maps.model.CameraPosition
import com.amap.api.maps.model.LatLng
+import com.amap.api.maps.model.MyLocationStyle
import com.amap.api.maps.model.PolylineOptions
import com.casic.br.ktd.R
import com.casic.br.ktd.extensions.*
import com.casic.br.ktd.model.ChartPointModel
import com.casic.br.ktd.model.RouteModel
import com.casic.br.ktd.model.SensorDataModel
-import com.casic.br.ktd.netty.SocketManager
+import com.casic.br.ktd.netty.tcp.SocketManager
+import com.casic.br.ktd.netty.udp.UdpClient
import com.casic.br.ktd.utils.LocaleConstant
import com.casic.br.ktd.utils.LocationHelper
import com.casic.br.ktd.widgets.AlertControlDialog
@@ -49,6 +54,10 @@
import hcnetsdk.sdkhub.MessageCodeHub
import hcnetsdk.sdkhub.SDKGuider
import kotlinx.android.synthetic.main.activity_inspection.*
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.launch
+import kotlinx.coroutines.withContext
import java.text.DecimalFormat
import java.text.SimpleDateFormat
import java.util.*
@@ -60,10 +69,10 @@
private val hkSDK by lazy { HCNetSDK.getInstance() }
private val timeFormat by lazy { SimpleDateFormat("yyyyMMddHHmmss", Locale.CHINA) }
private val latlngs = LinkedList()
- private val speedTimer by lazy { Timer() }
private val tcpTimer by lazy { Timer() }
private val decimalFormat by lazy { DecimalFormat("##0.0") }
private val gson by lazy { Gson() }
+ private val udpClient by lazy { UdpClient() }
private var isLoginSuccess = false
private var previewHandle = -1
private var selectChannel = -1
@@ -103,28 +112,32 @@
private lateinit var aMap: AMap
private lateinit var uiSettings: UiSettings
+ /**
+ * 协程配置云台设备,缓解新进页面较卡的问题
+ * */
private fun setDeviceConfig() {
- Log.d(kTag, "setDeviceConfig => 配置设备IP和端口")
- val device = SDKGuider.sdkGuider.devManageGuider.DeviceItem()
- device.m_szDevName = ""
- device.m_struNetInfo = SDKGuider.sdkGuider.devManageGuider.DevNetInfo(
- LocaleConstant.HK_NET_IP,
- LocaleConstant.HK_NET_PORT,
- LocaleConstant.HK_NET_USERNAME,
- LocaleConstant.HK_NET_PASSWORD
- )
- if (device.m_szDevName.isEmpty()) {
- device.m_szDevName = device.m_struNetInfo.m_szIp
- }
- isLoginSuccess = if (
- SDKGuider.sdkGuider.devManageGuider.login_v40_jna(
- device.m_szDevName, device.m_struNetInfo
- )
- ) {
- "设备连接成功".show(this)
- true
- } else {
- false
+ CoroutineScope(Dispatchers.Main).launch {
+ isLoginSuccess = withContext(Dispatchers.IO) {
+ Log.d(kTag, "setDeviceConfig => 配置设备IP和端口")
+ val device = SDKGuider.sdkGuider.devManageGuider.DeviceItem()
+ device.m_szDevName = ""
+ device.m_struNetInfo = SDKGuider.sdkGuider.devManageGuider.DevNetInfo(
+ LocaleConstant.HK_NET_IP,
+ LocaleConstant.HK_NET_PORT,
+ LocaleConstant.HK_NET_USERNAME,
+ LocaleConstant.HK_NET_PASSWORD
+ )
+ if (device.m_szDevName.isEmpty()) {
+ device.m_szDevName = device.m_struNetInfo.m_szIp
+ }
+
+ SDKGuider.sdkGuider.devManageGuider.login_v40_jna(
+ device.m_szDevName, device.m_struNetInfo
+ )
+ }
+ if (isLoginSuccess) {
+ "设备连接成功".show(context)
+ }
}
}
@@ -148,17 +161,74 @@
/**
* 手机GPS定位
* */
- val converter = CoordinateConverter(this)
- LocationHelper.obtainCurrentLocation(this, object : LocationHelper.ILocationListener {
+// val converter = CoordinateConverter(this)
+// LocationHelper.get.obtainLocation(this, object : LocationHelper.ILocationListener {
+// override fun onLocationGet(location: Location?) {
+// if (location == null) {
+// "当前信号弱,无法定位".show(context)
+// return
+// }
+//
+// //发送位置信息给UDP服务端
+// udpClient.send("${location.longitude}, ${location.latitude}")
+// Log.d(kTag, "onLocationGet => 速度:${location.speed}")
+//
+// //WGS-84要转为高德坐标系
+// converter.from(CoordinateConverter.CoordType.GPS)
+// converter.coord(LatLng(location.latitude, location.longitude))
+// val latLng = converter.convert()
+// latlngs.add(latLng)
+//
+// //移动到指定经纬度
+// val cameraPosition = CameraPosition(latLng, 13f, 0f, 0f)
+// val cameraUpdate = CameraUpdateFactory.newCameraPosition(cameraPosition)
+// aMap.animateCamera(cameraUpdate, 1500, null)
+//
+// //绘制线
+// aMap.addPolyline(
+// PolylineOptions().addAll(latlngs).width(12f).color(Color.RED)
+// )
+//
+// if (isStartInspect) {
+// val route = LinkedList()
+// latlngs.forEach {
+// route.add(RouteModel(it.latitude, it.longitude))
+// }
+// }
+// }
+//
+// override fun onAMapLocationGet(aMapLocation: AMapLocation?) {
+//
+// }
+// })
+
+ /**
+ * 高德定位
+ * */
+ LocationHelper.get.obtainLocationByGD(this, object : LocationHelper.ILocationListener {
override fun onLocationGet(location: Location?) {
- if (location == null) {
+
+ }
+
+ override fun onAMapLocationGet(aMapLocation: AMapLocation?) {
+ if (aMapLocation == null) {
"当前信号弱,无法定位".show(context)
return
}
+
+ //发送位置信息给UDP服务端
+ udpClient.send(
+ "${aMapLocation.longitude}, ${aMapLocation.latitude}, ${
+ System.currentTimeMillis().timestampToCompleteDate()
+ }"
+ )
+ //速度 转为 km/h
+ Log.d(kTag, "onLocationGet => 速度:${aMapLocation.speed}")
+ speed = decimalFormat.format(aMapLocation.speed * 3.6).toFloat()
+ carSpeedView.text = String.format("${speed}Km/h")
+
//WGS-84要转为高德坐标系
- converter.from(CoordinateConverter.CoordType.GPS)
- converter.coord(LatLng(location.latitude, location.longitude))
- val latLng = converter.convert()
+ val latLng = LatLng(aMapLocation.latitude, aMapLocation.longitude)
latlngs.add(latLng)
//移动到指定经纬度
@@ -168,7 +238,7 @@
//绘制线
aMap.addPolyline(
- PolylineOptions().addAll(latlngs).width(12f).color(Color.RED)
+ PolylineOptions().addAll(latlngs).width(10f).color(Color.RED)
)
if (isStartInspect) {
@@ -181,27 +251,6 @@
})
/**
- * 计算速度,微分原理,3s计算一次速度
- * */
- speedTimer.schedule(object : TimerTask() {
- override fun run() {
- //经纬度链表数据小于2,无法计算速度,默认为0
- speed = if (latlngs.size < 2) 0.0f else {
- val temp = AMapUtils.calculateLineDistance(
- latlngs.last(), latlngs[latlngs.size - 2]
- ) / 3
- //转为 km/h
- decimalFormat.format(temp * 3.6).toFloat()
- }
-
- //切换到UI线程更新界面数据
- runOnUiThread {
- carSpeedView.text = String.format("${speed}Km/h")
- }
- }
- }, 0, 3000)
-
- /**
* TCP初始化
* ***/
SocketManager.instance.connectNetty(
@@ -632,6 +681,8 @@
stopPreview()
BroadcastManager.obtainInstance(this).destroy(LocaleConstant.ACTION_UPDATE_DATA)
mapView.onDestroy()
+ udpClient.release()
+ LocationHelper.get.stopLocation()
}
override fun handleMessage(msg: Message): Boolean {
@@ -716,38 +767,13 @@
uiSettings.isZoomControlsEnabled = true
uiSettings.isTiltGesturesEnabled = false//不许地图随手势倾斜角度
-// val locationStyle = MyLocationStyle()
-// locationStyle.interval(2000)
-// locationStyle.showMyLocation(true)
-// locationStyle.myLocationType(MyLocationStyle.LOCATION_TYPE_LOCATION_ROTATE)
-// aMap.myLocationStyle = locationStyle
-// aMap.isMyLocationEnabled = true
-// aMap.animateCamera(CameraUpdateFactory.zoomTo(13f))
-// aMap.setOnMyLocationChangeListener(this)
+ //显示定位小蓝点
+ val locationStyle = MyLocationStyle()
+ locationStyle.showMyLocation(true)//设置是否显示定位小蓝点
+ aMap.myLocationStyle = locationStyle
+ aMap.isMyLocationEnabled = true
}
-// override fun onMyLocationChange(aMapLocation: Location?) {
-// if (aMapLocation == null) {
-// "当前信号弱,无法定位".show(context)
-// return
-// }
-// val latitude = aMapLocation.latitude
-// val longitude = aMapLocation.longitude
-// latlngs.add(LatLng(latitude, longitude))
-//
-// //绘制线
-// aMap.addPolyline(
-// PolylineOptions().addAll(latlngs).width(15f).color(Color.RED)
-// )
-//
-// if (isStartInspect) {
-// val route = LinkedList()
-// latlngs.forEach {
-// route.add(RouteModel(it.latitude, it.longitude))
-// }
-// }
-// }
-
/***以下是地图生命周期管理************************************************************************/
override fun onResume() {
diff --git a/app/src/main/res/layout/fragment_alarm.xml b/app/src/main/res/layout/fragment_alarm.xml
index a3ebc88..929529f 100644
--- a/app/src/main/res/layout/fragment_alarm.xml
+++ b/app/src/main/res/layout/fragment_alarm.xml
@@ -31,7 +31,7 @@
diff --git a/app/src/main/res/layout/fragment_task.xml b/app/src/main/res/layout/fragment_task.xml
index 35cb1a3..58d852e 100644
--- a/app/src/main/res/layout/fragment_task.xml
+++ b/app/src/main/res/layout/fragment_task.xml
@@ -31,7 +31,7 @@
diff --git a/app/src/main/res/mipmap-hdpi/end.png b/app/src/main/res/mipmap-hdpi/end.png
new file mode 100644
index 0000000..f31385b
--- /dev/null
+++ b/app/src/main/res/mipmap-hdpi/end.png
Binary files differ
diff --git a/app/src/main/res/mipmap-hdpi/start.png b/app/src/main/res/mipmap-hdpi/start.png
new file mode 100644
index 0000000..04839dc
--- /dev/null
+++ b/app/src/main/res/mipmap-hdpi/start.png
Binary files differ
diff --git a/app/src/main/res/mipmap-mdpi/end.png b/app/src/main/res/mipmap-mdpi/end.png
new file mode 100644
index 0000000..f31385b
--- /dev/null
+++ b/app/src/main/res/mipmap-mdpi/end.png
Binary files differ
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index e822df6..d72c1a5 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -7,6 +7,9 @@
+
+
+
@@ -46,5 +49,8 @@
+
+
+
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/br/ktd/base/KotlinBaseFragment.kt b/app/src/main/java/com/casic/br/ktd/base/KotlinBaseFragment.kt
new file mode 100644
index 0000000..2dac61c
--- /dev/null
+++ b/app/src/main/java/com/casic/br/ktd/base/KotlinBaseFragment.kt
@@ -0,0 +1,51 @@
+package com.casic.br.ktd.base
+
+import android.os.Bundle
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import androidx.annotation.LayoutRes
+import androidx.fragment.app.Fragment
+
+abstract class KotlinBaseFragment : Fragment() {
+
+ lateinit var bv: View
+
+ override fun onCreateView(
+ inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?
+ ): View? {
+ bv = inflater.inflate(initLayoutRes(), container, false)
+ initView(savedInstanceState)
+ setupTopBarLayout()
+ return bv
+ }
+
+ override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
+ super.onViewCreated(view, savedInstanceState)
+ observeRequestState()
+ initEvent()
+ }
+
+ @LayoutRes
+ abstract fun initLayoutRes(): Int
+
+ /**
+ * 沉浸式状态栏
+ */
+ abstract fun setupTopBarLayout()
+
+ /**
+ * 初始化布局以及控件
+ */
+ abstract fun initView(savedInstanceState: Bundle?)
+
+ /**
+ * 网络请求状态监听
+ */
+ abstract fun observeRequestState()
+
+ /**
+ * 业务逻辑,按钮等事件
+ */
+ abstract fun initEvent()
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/br/ktd/fragment/AlarmPageFragment.kt b/app/src/main/java/com/casic/br/ktd/fragment/AlarmPageFragment.kt
index 6c98a3b..9418169 100644
--- a/app/src/main/java/com/casic/br/ktd/fragment/AlarmPageFragment.kt
+++ b/app/src/main/java/com/casic/br/ktd/fragment/AlarmPageFragment.kt
@@ -2,28 +2,29 @@
import android.os.Bundle
import com.casic.br.ktd.R
+import com.casic.br.ktd.base.KotlinBaseFragment
import com.casic.br.ktd.widgets.DateRangeActionSheet
-import com.pengxh.kt.lite.base.KotlinBaseFragment
import kotlinx.android.synthetic.main.fragment_alarm.view.*
class AlarmPageFragment : KotlinBaseFragment() {
- override fun initData(savedInstanceState: Bundle?) {
+
+ override fun initView(savedInstanceState: Bundle?) {
}
override fun initEvent() {
- baseView.calendarView.setOnClickListener {
+ bv.calendarView.setOnClickListener {
DateRangeActionSheet.Builder().setContext(requireContext())
.setOnActionSheetListener(object :
DateRangeActionSheet.OnDateRangeSelectedListener {
override fun onDateRangeSelected(startDate: String, endDate: String) {
- baseView.selectedDateView.text = "$startDate ~ $endDate"
+ bv.selectedDateView.text = "$startDate ~ $endDate"
}
}).build().show()
}
}
- override fun initLayoutView(): Int = R.layout.fragment_alarm
+ override fun initLayoutRes(): Int = R.layout.fragment_alarm
override fun observeRequestState() {
diff --git a/app/src/main/java/com/casic/br/ktd/fragment/HomePageFragment.kt b/app/src/main/java/com/casic/br/ktd/fragment/HomePageFragment.kt
index 9961935..f3eba5c 100644
--- a/app/src/main/java/com/casic/br/ktd/fragment/HomePageFragment.kt
+++ b/app/src/main/java/com/casic/br/ktd/fragment/HomePageFragment.kt
@@ -1,32 +1,62 @@
package com.casic.br.ktd.fragment
+import android.graphics.Color
import android.os.Bundle
import com.amap.api.maps.AMap
import com.amap.api.maps.AMapOptions
+import com.amap.api.maps.CameraUpdateFactory
+import com.amap.api.maps.model.*
import com.casic.br.ktd.R
-import com.pengxh.kt.lite.base.KotlinBaseFragment
+import com.casic.br.ktd.base.KotlinBaseFragment
import kotlinx.android.synthetic.main.fragment_home.view.*
class HomePageFragment : KotlinBaseFragment() {
private lateinit var aMap: AMap
- override fun initData(savedInstanceState: Bundle?) {
- baseView.mapView.onCreate(savedInstanceState)
- aMap = baseView.mapView.map
+ override fun initView(savedInstanceState: Bundle?) {
+ bv.mapView.onCreate(savedInstanceState)
+ aMap = bv.mapView.map
val uiSettings = aMap.uiSettings
uiSettings.isCompassEnabled = true
- uiSettings.isMyLocationButtonEnabled = true
+ uiSettings.isMyLocationButtonEnabled = false
uiSettings.isScaleControlsEnabled = true
uiSettings.zoomPosition = AMapOptions.ZOOM_POSITION_RIGHT_CENTER
uiSettings.isRotateGesturesEnabled = false//不许地图随手势旋转角度
}
override fun initEvent() {
-
+ //移动到巡检起始经纬度
+ val cameraPosition = CameraPosition(LatLng(39.914199, 116.265785), 16f, 0f, 0f)
+ val cameraUpdate = CameraUpdateFactory.newCameraPosition(cameraPosition)
+ aMap.animateCamera(cameraUpdate, 1500, null)
+ //设置起点
+ addMarker(LatLng(39.914885, 116.272312), R.mipmap.start)
+ //设置终点
+ addMarker(LatLng(39.914716, 116.265097), R.mipmap.end)
+ //瞄点画线
+ val latLngPoints = ArrayList()
+ latLngPoints.add(LatLng(39.914885, 116.272312))
+ latLngPoints.add(LatLng(39.915148, 116.272312))
+ latLngPoints.add(LatLng(39.915399, 116.272302))
+ latLngPoints.add(LatLng(39.915436, 116.271787))
+ latLngPoints.add(LatLng(39.915477, 116.270886))
+ latLngPoints.add(LatLng(39.915477, 116.269968))
+ latLngPoints.add(LatLng(39.915469, 116.269544))
+ latLngPoints.add(LatLng(39.915481, 116.269196))
+ latLngPoints.add(LatLng(39.915452, 116.268472))
+ latLngPoints.add(LatLng(39.915444, 116.267722))
+ latLngPoints.add(LatLng(39.915415, 116.266755))
+ latLngPoints.add(LatLng(39.915403, 116.266165))
+ latLngPoints.add(LatLng(39.915395, 116.265703))
+ latLngPoints.add(LatLng(39.915366, 116.265119))
+ latLngPoints.add(LatLng(39.914716, 116.265097))
+ aMap.addPolyline(
+ PolylineOptions().addAll(latLngPoints).width(10.toFloat()).color(Color.RED)
+ )
}
- override fun initLayoutView(): Int = R.layout.fragment_home
+ override fun initLayoutRes(): Int = R.layout.fragment_home
override fun observeRequestState() {
@@ -36,25 +66,32 @@
}
+ private fun addMarker(point: LatLng, res: Int) {
+ val markerOption = MarkerOptions()
+ markerOption.position(point)
+ markerOption.icon(BitmapDescriptorFactory.fromResource(res))
+ aMap.addMarker(markerOption)
+ }
+
/***以下是地图生命周期管理************************************************************************/
override fun onResume() {
super.onResume()
- baseView.mapView.onResume()
+ bv.mapView.onResume()
}
override fun onPause() {
- baseView.mapView.onPause()
super.onPause()
+ bv.mapView.onPause()
}
override fun onSaveInstanceState(outState: Bundle) {
super.onSaveInstanceState(outState)
- baseView.mapView.onSaveInstanceState(outState)
+ bv.mapView.onSaveInstanceState(outState)
}
override fun onDestroy() {
- baseView.mapView.onDestroy()
super.onDestroy()
+ bv.mapView.onDestroy()
}
}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/br/ktd/fragment/MinePageFragment.kt b/app/src/main/java/com/casic/br/ktd/fragment/MinePageFragment.kt
index 90313ac..3212794 100644
--- a/app/src/main/java/com/casic/br/ktd/fragment/MinePageFragment.kt
+++ b/app/src/main/java/com/casic/br/ktd/fragment/MinePageFragment.kt
@@ -2,10 +2,11 @@
import android.os.Bundle
import com.casic.br.ktd.R
-import com.pengxh.kt.lite.base.KotlinBaseFragment
+import com.casic.br.ktd.base.KotlinBaseFragment
class MinePageFragment : KotlinBaseFragment() {
- override fun initData(savedInstanceState: Bundle?) {
+
+ override fun initView(savedInstanceState: Bundle?) {
}
@@ -13,7 +14,7 @@
}
- override fun initLayoutView(): Int = R.layout.fragment_mine
+ override fun initLayoutRes(): Int = R.layout.fragment_mine
override fun observeRequestState() {
diff --git a/app/src/main/java/com/casic/br/ktd/fragment/TaskPageFragment.kt b/app/src/main/java/com/casic/br/ktd/fragment/TaskPageFragment.kt
index 8f6abf0..6b82a54 100644
--- a/app/src/main/java/com/casic/br/ktd/fragment/TaskPageFragment.kt
+++ b/app/src/main/java/com/casic/br/ktd/fragment/TaskPageFragment.kt
@@ -8,6 +8,7 @@
import androidx.recyclerview.widget.RecyclerView
import com.casic.br.ktd.R
import com.casic.br.ktd.adapter.TaskAdapter
+import com.casic.br.ktd.base.KotlinBaseFragment
import com.casic.br.ktd.holder.SwipeViewHolder
import com.casic.br.ktd.model.TaskListModel
import com.casic.br.ktd.view.InspectionActivity
@@ -15,7 +16,6 @@
import com.casic.br.ktd.widgets.AlertControlDialog
import com.casic.br.ktd.widgets.AlertInputDialog
import com.casic.br.ktd.widgets.DateRangeActionSheet
-import com.pengxh.kt.lite.base.KotlinBaseFragment
import com.pengxh.kt.lite.extensions.navigatePageTo
import com.pengxh.kt.lite.extensions.show
import com.pengxh.kt.lite.utils.WeakReferenceHandler
@@ -36,7 +36,7 @@
private var startTime = ""
private var endTime = ""
- override fun initData(savedInstanceState: Bundle?) {
+ override fun initView(savedInstanceState: Bundle?) {
weakReferenceHandler = WeakReferenceHandler(this)
taskViewModel = ViewModelProvider(this)[TaskViewModel::class.java]
taskViewModel.taskList.observe(this) {
@@ -45,7 +45,7 @@
when {
isRefresh -> {
taskAdapter.setRefreshData(dataRows)
- baseView.taskLayout.finishRefresh()
+ bv.taskLayout.finishRefresh()
isRefresh = false
}
isLoadMore -> {
@@ -53,7 +53,7 @@
"到底了,别拉了".show(requireContext())
}
taskAdapter.setLoadMoreData(dataRows)
- baseView.taskLayout.finishLoadMore()
+ bv.taskLayout.finishLoadMore()
isLoadMore = false
}
else -> {
@@ -76,9 +76,9 @@
when (msg.what) {
2023070501 -> {
if (dataBeans.size == 0) {
- baseView.emptyLayout.visibility = View.VISIBLE
+ bv.emptyLayout.visibility = View.VISIBLE
} else {
- baseView.emptyLayout.visibility = View.GONE
+ bv.emptyLayout.visibility = View.GONE
taskAdapter = object : TaskAdapter(
requireContext(), R.layout.item_task_rv_l, dataBeans
) {
@@ -97,8 +97,8 @@
}
}
//绑定侧滑事件
- swipeAction.attachToRecyclerView(baseView.taskRecyclerView)
- baseView.taskRecyclerView.adapter = taskAdapter
+ swipeAction.attachToRecyclerView(bv.taskRecyclerView)
+ bv.taskRecyclerView.adapter = taskAdapter
taskAdapter.setOnItemCheckedListener(object :
TaskAdapter.OnItemCheckedListener {
override fun onItemChecked(items: ArrayList) {
@@ -168,7 +168,7 @@
override fun initEvent() {
- baseView.calendarView.setOnClickListener {
+ bv.calendarView.setOnClickListener {
DateRangeActionSheet.Builder().setContext(requireContext())
.setOnActionSheetListener(object :
DateRangeActionSheet.OnDateRangeSelectedListener {
@@ -177,12 +177,12 @@
endTime = endDate
//显示
- baseView.selectedDateView.text = "$startDate ~ $endDate"
+ bv.selectedDateView.text = "$startDate ~ $endDate"
}
}).build().show()
}
- baseView.addTaskButton.setOnClickListener {
+ bv.addTaskButton.setOnClickListener {
// AlertInputDialog.Builder()
// .setContext(requireContext())
// .setTitle("新建巡检任务")
@@ -200,11 +200,11 @@
requireContext().navigatePageTo()
}
- baseView.deleteTaskButton.setOnClickListener {
+ bv.deleteTaskButton.setOnClickListener {
selectedItems.size.toString().show(requireContext())
}
- baseView.taskSettingsButton.setOnClickListener {
+ bv.taskSettingsButton.setOnClickListener {
AlertInputDialog.Builder()
.setContext(requireContext())
.setTitle("设置阈值")
@@ -221,14 +221,14 @@
}).build().show()
}
- baseView.taskLayout.setOnRefreshListener {
+ bv.taskLayout.setOnRefreshListener {
isRefresh = true
//刷新之后页码重置
pageIndex = 1
getTaskList()
}
- baseView.taskLayout.setOnLoadMoreListener {
+ bv.taskLayout.setOnLoadMoreListener {
isLoadMore = true
pageIndex++
getTaskList()
@@ -239,13 +239,13 @@
taskViewModel.getTaskList(
startTime,
endTime,
- baseView.taskNameView.text.toString(),
- baseView.taskCodeView.text.toString(),
+ bv.taskNameView.text.toString(),
+ bv.taskCodeView.text.toString(),
pageIndex
)
}
- override fun initLayoutView(): Int = R.layout.fragment_task
+ override fun initLayoutRes(): Int = R.layout.fragment_task
override fun observeRequestState() {
diff --git a/app/src/main/java/com/casic/br/ktd/netty/ISocketListener.kt b/app/src/main/java/com/casic/br/ktd/netty/ISocketListener.kt
deleted file mode 100644
index dab98e1..0000000
--- a/app/src/main/java/com/casic/br/ktd/netty/ISocketListener.kt
+++ /dev/null
@@ -1,19 +0,0 @@
-package com.casic.br.ktd.netty
-
-interface ISocketListener {
- companion object {
- const val STATUS_CONNECT_SUCCESS: Byte = 1 //连接成功
- const val STATUS_CONNECT_CLOSED: Byte = 0 //关闭连接
- const val STATUS_CONNECT_ERROR: Byte = 0 //连接失败
- }
-
- /**
- * 当接收到系统消息
- */
- fun onMessageResponse(data: ByteArray?)
-
- /**
- * 当连接状态发生变化时调用
- */
- fun onServiceStatusConnectChanged(statusCode: Byte)
-}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/br/ktd/netty/SocketChannelHandle.kt b/app/src/main/java/com/casic/br/ktd/netty/SocketChannelHandle.kt
deleted file mode 100644
index 42eb310..0000000
--- a/app/src/main/java/com/casic/br/ktd/netty/SocketChannelHandle.kt
+++ /dev/null
@@ -1,51 +0,0 @@
-package com.casic.br.ktd.netty
-
-import android.util.Log
-import io.netty.channel.ChannelHandlerContext
-import io.netty.channel.SimpleChannelInboundHandler
-import io.netty.handler.timeout.IdleState
-import io.netty.handler.timeout.IdleStateEvent
-import java.nio.charset.StandardCharsets
-
-class SocketChannelHandle(private val listener: ISocketListener?) :
- SimpleChannelInboundHandler() {
-
- private val kTag = "SocketChannelHandle"
-
- override fun channelActive(ctx: ChannelHandlerContext) {
- super.channelActive(ctx)
- Log.d(kTag, "channelActive ===> 连接成功")
- listener?.onServiceStatusConnectChanged(ISocketListener.STATUS_CONNECT_SUCCESS)
- }
-
- override fun channelInactive(ctx: ChannelHandlerContext) {
- super.channelInactive(ctx)
- Log.e(kTag, "channelInactive: 连接断开")
- }
-
- override fun userEventTriggered(ctx: ChannelHandlerContext, evt: Any) {
- super.userEventTriggered(ctx, evt)
- if (evt is IdleStateEvent) {
- if (evt.state() == IdleState.WRITER_IDLE) {
- //写超时,此时可以发送心跳数据给服务器
- val temp = "FF"
- ctx.writeAndFlush(temp.toByteArray(StandardCharsets.UTF_8))
- } else if (evt.state() == IdleState.READER_IDLE) {
- //读超时,此时代表没有收到心跳返回可以关闭当前连接进行重连
- ctx.close()
- }
- }
- }
-
- override fun channelRead0(ctx: ChannelHandlerContext, data: ByteArray?) {
- listener?.onMessageResponse(data)
- }
-
- override fun exceptionCaught(ctx: ChannelHandlerContext, cause: Throwable) {
- super.exceptionCaught(ctx, cause)
- Log.d(kTag, "exceptionCaught ===> $cause")
- listener?.onServiceStatusConnectChanged(ISocketListener.STATUS_CONNECT_ERROR)
- cause.printStackTrace()
- ctx.close()
- }
-}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/br/ktd/netty/SocketClient.kt b/app/src/main/java/com/casic/br/ktd/netty/SocketClient.kt
deleted file mode 100644
index d05d335..0000000
--- a/app/src/main/java/com/casic/br/ktd/netty/SocketClient.kt
+++ /dev/null
@@ -1,153 +0,0 @@
-package com.casic.br.ktd.netty
-
-import android.os.SystemClock
-import android.util.Log
-import io.netty.bootstrap.Bootstrap
-import io.netty.channel.*
-import io.netty.channel.nio.NioEventLoopGroup
-import io.netty.channel.socket.SocketChannel
-import io.netty.channel.socket.nio.NioSocketChannel
-import io.netty.handler.codec.bytes.ByteArrayDecoder
-import io.netty.handler.codec.bytes.ByteArrayEncoder
-import io.netty.handler.timeout.IdleStateHandler
-
-class SocketClient {
-
- private val kTag = "SocketClient"
-
- private var host: String? = null
- private var port = 8000
- private var nioEventLoopGroup: NioEventLoopGroup? = null
- private var channel: Channel? = null
- private var listener: ISocketListener? = null
-
- //现在连接的状态
- var connectStatus = false //判断是否已连接
- private var reconnectNum = Int.MAX_VALUE //定义的重连到时候用
- private var isNeedReconnect = true //是否需要重连
- var isConnecting = false //是否正在连接
- private set
- private var reconnectIntervalTime: Long = 15000 //重连的时间
-
- //重连时间
- fun setReconnectNum(reconnectNum: Int) {
- this.reconnectNum = reconnectNum
- }
-
- fun setReconnectIntervalTime(reconnectIntervalTime: Long) {
- this.reconnectIntervalTime = reconnectIntervalTime
- }
-
- fun setSocketListener(listener: ISocketListener?) {
- this.listener = listener
- }
-
- fun connect(host: String, port: Int) {
- this.host = host
- this.port = port
- Log.d(kTag, "connect ===> 开始连接TCP服务器")
- if (isConnecting) {
- return
- }
- //起个线程
- val clientThread: Thread = object : Thread("client-Netty") {
- override fun run() {
- super.run()
- isNeedReconnect = true
- reconnectNum = Int.MAX_VALUE
- connectServer()
- }
- }
- clientThread.start()
- }
-
- private fun connectServer() {
- synchronized(this@SocketClient) {
- var channelFuture: ChannelFuture? = null //连接管理对象
- if (!connectStatus) {
- isConnecting = true
- nioEventLoopGroup = NioEventLoopGroup() //设置的连接group
- val bootstrap = Bootstrap()
- bootstrap.group(nioEventLoopGroup) //设置的一系列连接参数操作等
- .channel(NioSocketChannel::class.java)
- .option(ChannelOption.TCP_NODELAY, true) //无阻塞
- .option(ChannelOption.SO_KEEPALIVE, true) //长连接
- .option(
- ChannelOption.RCVBUF_ALLOCATOR,
- AdaptiveRecvByteBufAllocator(5000, 5000, 8000)
- ) //接收缓冲区 最小值太小时数据接收不全
- .handler(object : ChannelInitializer() {
- override fun initChannel(channel: SocketChannel) {
- val pipeline = channel.pipeline()
- //参数1:代表读套接字超时的时间,没收到数据会触发读超时回调;
- //参数2:代表写套接字超时时间,没进行写会触发写超时回调;
- //参数3:将在未执行读取或写入时触发超时回调,0代表不处理;
- //读超时尽量设置大于写超时,代表多次写超时时写心跳包,多次写了心跳数据仍然读超时代表当前连接错误,即可断开连接重新连接
- pipeline.addLast(IdleStateHandler(60, 10, 0))
- pipeline.addLast(ByteArrayDecoder())
- pipeline.addLast(ByteArrayEncoder())
- pipeline.addLast(SocketChannelHandle(listener))
- }
- })
- try {
- //连接监听
- channelFuture = bootstrap.connect(host, port)
- .addListener(object : ChannelFutureListener {
- override fun operationComplete(channelFuture: ChannelFuture) {
- if (channelFuture.isSuccess) {
- connectStatus = true
- channel = channelFuture.channel()
- } else {
- Log.e(kTag, "operationComplete: 连接失败")
- connectStatus = false
- }
- isConnecting = false
- }
- }).sync()
- // 等待连接关闭
- channelFuture.channel().closeFuture().sync()
- } catch (e: Exception) {
- e.printStackTrace()
- } finally {
- connectStatus = false
- listener?.onServiceStatusConnectChanged(ISocketListener.STATUS_CONNECT_CLOSED) //STATUS_CONNECT_CLOSED 这我自己定义的 接口标识
- if (null != channelFuture) {
- if (channelFuture.channel() != null && channelFuture.channel().isOpen) {
- channelFuture.channel().close()
- }
- }
- nioEventLoopGroup?.shutdownGracefully()
- reconnect() //重新连接
- }
- }
- }
- }
-
- //断开连接
- fun disconnect() {
- Log.d(kTag, "disconnect ===> 断开连接")
- isNeedReconnect = false
- nioEventLoopGroup?.shutdownGracefully()
- }
-
- //重新连接
- private fun reconnect() {
- if (isNeedReconnect && reconnectNum > 0 && !connectStatus) {
- reconnectNum--
- SystemClock.sleep(reconnectIntervalTime)
- if (isNeedReconnect && reconnectNum > 0 && !connectStatus) {
- Log.d(kTag, "reconnect ===> 重新连接")
- connectServer()
- }
- }
- }
-
- fun sendData(bytes: ByteArray) {
- channel?.writeAndFlush(bytes)?.addListener(ChannelFutureListener { future ->
- if (!future.isSuccess) {
- future.channel().close()
- nioEventLoopGroup!!.shutdownGracefully()
- }
- })
- }
-}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/br/ktd/netty/SocketManager.kt b/app/src/main/java/com/casic/br/ktd/netty/SocketManager.kt
deleted file mode 100644
index 17daf35..0000000
--- a/app/src/main/java/com/casic/br/ktd/netty/SocketManager.kt
+++ /dev/null
@@ -1,113 +0,0 @@
-package com.casic.br.ktd.netty
-
-import android.util.Log
-import com.casic.br.ktd.base.BaseApplication
-import com.casic.br.ktd.extensions.covertAngleValue
-import com.casic.br.ktd.extensions.covertDataValue
-import com.casic.br.ktd.extensions.toUnsignedByteArray
-import com.casic.br.ktd.model.SensorDataModel
-import com.casic.br.ktd.utils.LocaleConstant
-import com.pengxh.kt.lite.extensions.toJson
-import com.pengxh.kt.lite.utils.BroadcastManager
-
-class SocketManager private constructor() : ISocketListener {
-
- private val kTag = "SocketManager"
- private var nettyClient: SocketClient = SocketClient()
-
- companion object {
- val instance: SocketManager by lazy(mode = LazyThreadSafetyMode.SYNCHRONIZED) { SocketManager() }
- }
-
- fun connectNetty(hostname: String, port: Int) {
- Thread {
- if (!nettyClient.connectStatus) {
- nettyClient.setSocketListener(this)
- nettyClient.connect(hostname, port)
- } else {
- nettyClient.disconnect()
- }
- }.start()
- }
-
- override fun onMessageResponse(data: ByteArray?) {
-// Log.d(kTag, "onMessageResponse ===> " + Arrays.toString(data))
- /**
- * 0xFF,0x01,
- * 0x01,0x37,0xE6, 甲烷浓度值(数据码1* 65536 + 数据码2 * 256 + 数据码3)
- * 0x00, 激光甲烷模块工作状态(00表示设备正常,01表示温控故障,02表示设备激光未打开)
- * 0x00,0xB2,0x35, 激光强度值(数据码5* 65536 + 数据码6 * 256 + 数据码7)
- * 0x0A,0x3D, 云台水平角度([数据码8 * 256 + 数据码9]/100,单位为°,精确到0.01)
- * 0x05,0x6F, 云台垂直角度(首先计算Tangle=[数据码10 * 256 + 数据码11]/100,单位为°,精确到0.01。若Tangle在0~90范围内,则垂直角度值=Tangle;若Tangle在-1~-90范围内,则垂直角度值=Tangle-360)
- * 0xC1
- *
- * [-1, 1, 1, 55, -26, 0, 0, -78, 53, 10, 61, 5, 111, -63]
- * 甲烷浓度值为79638,计算为79638=0x01*65536+0x37*256+0xE6[0x01为数据码1,0x37为数据码2,0xE6为数据码3];
- * 激光甲烷设备状态值为0,表示状态正常,[0x00为数据码4];
- * 激光强度值为45621,计算为45621=0x00*65536+0xB2*256+0x35[0x00为数据码5,0xB2为数据码6,0x35为数据码7];
- *
- * =========================================================================================
- * 实际数据(1800-1950左右)
- * [-86, 1, 0, 7, 71, 0, 0, 62, -92, 57, 59, -118, -111, -64]
- * */
-
- if (data == null) {
- return
- }
- val bytes = data.toUnsignedByteArray()
- if (bytes.size == 14) {
- val dataModel = SensorDataModel(0, "激光未打开", 0, 0.0, 0.0)
-
- val methaneBytes = IntArray(3)
- System.arraycopy(bytes, 2, methaneBytes, 0, 3)
- dataModel.methane = methaneBytes.covertDataValue()
-
- dataModel.methaneState = when (bytes[5]) {
- 1 -> "温控故障"
- 2 -> "激光未打开"
- else -> "正常"
- }
-
- val laserBytes = IntArray(3)
- System.arraycopy(bytes, 6, laserBytes, 0, 3)
- dataModel.laser = laserBytes.covertDataValue()
-
- /**
- * 水平角度的实际范围为从水平零点开始,顺时针方向(从上往下看),0~360°
- * 垂直角度的实际范围为从垂直零点开始,以向上为正,-90°~90°,控制精度为0.01°
- * */
- val horizontalBytes = IntArray(2)
- System.arraycopy(bytes, 9, horizontalBytes, 0, 2)
- dataModel.horizontal = horizontalBytes.covertAngleValue()
-
- val verticalBytes = IntArray(2)
- System.arraycopy(bytes, 11, verticalBytes, 0, 2)
- dataModel.vertical = verticalBytes.covertAngleValue()
-
- //{"horizontal":26.21,"laser":45621,"methane":79846,"methaneState":"正常","vertical":13.91}
- BroadcastManager.obtainInstance(BaseApplication.get()).sendBroadcast(
- LocaleConstant.ACTION_UPDATE_DATA, dataModel.toJson()
- )
- }
- }
-
- override fun onServiceStatusConnectChanged(statusCode: Byte) {
- if (statusCode == ISocketListener.STATUS_CONNECT_SUCCESS) {
- if (nettyClient.connectStatus) {
- Log.d(kTag, "连接成功")
- }
- } else {
- if (!nettyClient.connectStatus) {
- Log.e(kTag, "onServiceStatusConnectChanged:$statusCode,连接断开,正在重连")
- }
- }
- }
-
- fun sendData(data: ByteArray) {
- nettyClient.sendData(data)
- }
-
- fun close() {
- nettyClient.disconnect()
- }
-}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/br/ktd/netty/tcp/ISocketListener.kt b/app/src/main/java/com/casic/br/ktd/netty/tcp/ISocketListener.kt
new file mode 100644
index 0000000..13c3084
--- /dev/null
+++ b/app/src/main/java/com/casic/br/ktd/netty/tcp/ISocketListener.kt
@@ -0,0 +1,19 @@
+package com.casic.br.ktd.netty.tcp
+
+interface ISocketListener {
+ companion object {
+ const val STATUS_CONNECT_SUCCESS: Byte = 1 //连接成功
+ const val STATUS_CONNECT_CLOSED: Byte = 0 //关闭连接
+ const val STATUS_CONNECT_ERROR: Byte = 0 //连接失败
+ }
+
+ /**
+ * 当接收到系统消息
+ */
+ fun onMessageResponse(data: ByteArray?)
+
+ /**
+ * 当连接状态发生变化时调用
+ */
+ fun onServiceStatusConnectChanged(statusCode: Byte)
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/br/ktd/netty/tcp/SocketChannelHandle.kt b/app/src/main/java/com/casic/br/ktd/netty/tcp/SocketChannelHandle.kt
new file mode 100644
index 0000000..8e2997f
--- /dev/null
+++ b/app/src/main/java/com/casic/br/ktd/netty/tcp/SocketChannelHandle.kt
@@ -0,0 +1,51 @@
+package com.casic.br.ktd.netty.tcp
+
+import android.util.Log
+import io.netty.channel.ChannelHandlerContext
+import io.netty.channel.SimpleChannelInboundHandler
+import io.netty.handler.timeout.IdleState
+import io.netty.handler.timeout.IdleStateEvent
+import java.nio.charset.StandardCharsets
+
+class SocketChannelHandle(private val listener: ISocketListener?) :
+ SimpleChannelInboundHandler() {
+
+ private val kTag = "SocketChannelHandle"
+
+ override fun channelActive(ctx: ChannelHandlerContext) {
+ super.channelActive(ctx)
+ Log.d(kTag, "channelActive ===> 连接成功")
+ listener?.onServiceStatusConnectChanged(ISocketListener.STATUS_CONNECT_SUCCESS)
+ }
+
+ override fun channelInactive(ctx: ChannelHandlerContext) {
+ super.channelInactive(ctx)
+ Log.e(kTag, "channelInactive: 连接断开")
+ }
+
+ override fun userEventTriggered(ctx: ChannelHandlerContext, evt: Any) {
+ super.userEventTriggered(ctx, evt)
+ if (evt is IdleStateEvent) {
+ if (evt.state() == IdleState.WRITER_IDLE) {
+ //写超时,此时可以发送心跳数据给服务器
+ val temp = "FF"
+ ctx.writeAndFlush(temp.toByteArray(StandardCharsets.UTF_8))
+ } else if (evt.state() == IdleState.READER_IDLE) {
+ //读超时,此时代表没有收到心跳返回可以关闭当前连接进行重连
+ ctx.close()
+ }
+ }
+ }
+
+ override fun channelRead0(ctx: ChannelHandlerContext, data: ByteArray?) {
+ listener?.onMessageResponse(data)
+ }
+
+ override fun exceptionCaught(ctx: ChannelHandlerContext, cause: Throwable) {
+ super.exceptionCaught(ctx, cause)
+ Log.d(kTag, "exceptionCaught ===> $cause")
+ listener?.onServiceStatusConnectChanged(ISocketListener.STATUS_CONNECT_ERROR)
+ cause.printStackTrace()
+ ctx.close()
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/br/ktd/netty/tcp/SocketClient.kt b/app/src/main/java/com/casic/br/ktd/netty/tcp/SocketClient.kt
new file mode 100644
index 0000000..34960a0
--- /dev/null
+++ b/app/src/main/java/com/casic/br/ktd/netty/tcp/SocketClient.kt
@@ -0,0 +1,153 @@
+package com.casic.br.ktd.netty.tcp
+
+import android.os.SystemClock
+import android.util.Log
+import io.netty.bootstrap.Bootstrap
+import io.netty.channel.*
+import io.netty.channel.nio.NioEventLoopGroup
+import io.netty.channel.socket.SocketChannel
+import io.netty.channel.socket.nio.NioSocketChannel
+import io.netty.handler.codec.bytes.ByteArrayDecoder
+import io.netty.handler.codec.bytes.ByteArrayEncoder
+import io.netty.handler.timeout.IdleStateHandler
+
+class SocketClient {
+
+ private val kTag = "SocketClient"
+
+ private var host: String? = null
+ private var port = 8000
+ private var nioEventLoopGroup: NioEventLoopGroup? = null
+ private var channel: Channel? = null
+ private var listener: ISocketListener? = null
+
+ //现在连接的状态
+ var connectStatus = false //判断是否已连接
+ private var reconnectNum = Int.MAX_VALUE //定义的重连到时候用
+ private var isNeedReconnect = true //是否需要重连
+ var isConnecting = false //是否正在连接
+ private set
+ private var reconnectIntervalTime: Long = 15000 //重连的时间
+
+ //重连时间
+ fun setReconnectNum(reconnectNum: Int) {
+ this.reconnectNum = reconnectNum
+ }
+
+ fun setReconnectIntervalTime(reconnectIntervalTime: Long) {
+ this.reconnectIntervalTime = reconnectIntervalTime
+ }
+
+ fun setSocketListener(listener: ISocketListener?) {
+ this.listener = listener
+ }
+
+ fun connect(host: String, port: Int) {
+ this.host = host
+ this.port = port
+ Log.d(kTag, "connect ===> 开始连接TCP服务器")
+ if (isConnecting) {
+ return
+ }
+ //起个线程
+ val clientThread: Thread = object : Thread("client-Netty") {
+ override fun run() {
+ super.run()
+ isNeedReconnect = true
+ reconnectNum = Int.MAX_VALUE
+ connectServer()
+ }
+ }
+ clientThread.start()
+ }
+
+ private fun connectServer() {
+ synchronized(this@SocketClient) {
+ var channelFuture: ChannelFuture? = null //连接管理对象
+ if (!connectStatus) {
+ isConnecting = true
+ nioEventLoopGroup = NioEventLoopGroup() //设置的连接group
+ val bootstrap = Bootstrap()
+ bootstrap.group(nioEventLoopGroup) //设置的一系列连接参数操作等
+ .channel(NioSocketChannel::class.java)
+ .option(ChannelOption.TCP_NODELAY, true) //无阻塞
+ .option(ChannelOption.SO_KEEPALIVE, true) //长连接
+ .option(
+ ChannelOption.RCVBUF_ALLOCATOR,
+ AdaptiveRecvByteBufAllocator(5000, 5000, 8000)
+ ) //接收缓冲区 最小值太小时数据接收不全
+ .handler(object : ChannelInitializer() {
+ override fun initChannel(channel: SocketChannel) {
+ val pipeline = channel.pipeline()
+ //参数1:代表读套接字超时的时间,没收到数据会触发读超时回调;
+ //参数2:代表写套接字超时时间,没进行写会触发写超时回调;
+ //参数3:将在未执行读取或写入时触发超时回调,0代表不处理;
+ //读超时尽量设置大于写超时,代表多次写超时时写心跳包,多次写了心跳数据仍然读超时代表当前连接错误,即可断开连接重新连接
+ pipeline.addLast(IdleStateHandler(60, 10, 0))
+ pipeline.addLast(ByteArrayDecoder())
+ pipeline.addLast(ByteArrayEncoder())
+ pipeline.addLast(SocketChannelHandle(listener))
+ }
+ })
+ try {
+ //连接监听
+ channelFuture = bootstrap.connect(host, port)
+ .addListener(object : ChannelFutureListener {
+ override fun operationComplete(channelFuture: ChannelFuture) {
+ if (channelFuture.isSuccess) {
+ connectStatus = true
+ channel = channelFuture.channel()
+ } else {
+ Log.e(kTag, "operationComplete: 连接失败")
+ connectStatus = false
+ }
+ isConnecting = false
+ }
+ }).sync()
+ // 等待连接关闭
+ channelFuture.channel().closeFuture().sync()
+ } catch (e: Exception) {
+ e.printStackTrace()
+ } finally {
+ connectStatus = false
+ listener?.onServiceStatusConnectChanged(ISocketListener.STATUS_CONNECT_CLOSED) //STATUS_CONNECT_CLOSED 这我自己定义的 接口标识
+ if (null != channelFuture) {
+ if (channelFuture.channel() != null && channelFuture.channel().isOpen) {
+ channelFuture.channel().close()
+ }
+ }
+ nioEventLoopGroup?.shutdownGracefully()
+ reconnect() //重新连接
+ }
+ }
+ }
+ }
+
+ //断开连接
+ fun disconnect() {
+ Log.d(kTag, "disconnect ===> 断开连接")
+ isNeedReconnect = false
+ nioEventLoopGroup?.shutdownGracefully()
+ }
+
+ //重新连接
+ private fun reconnect() {
+ if (isNeedReconnect && reconnectNum > 0 && !connectStatus) {
+ reconnectNum--
+ SystemClock.sleep(reconnectIntervalTime)
+ if (isNeedReconnect && reconnectNum > 0 && !connectStatus) {
+ Log.d(kTag, "reconnect ===> 重新连接")
+ connectServer()
+ }
+ }
+ }
+
+ fun sendData(bytes: ByteArray) {
+ channel?.writeAndFlush(bytes)?.addListener(ChannelFutureListener { future ->
+ if (!future.isSuccess) {
+ future.channel().close()
+ nioEventLoopGroup!!.shutdownGracefully()
+ }
+ })
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/br/ktd/netty/tcp/SocketManager.kt b/app/src/main/java/com/casic/br/ktd/netty/tcp/SocketManager.kt
new file mode 100644
index 0000000..35980b9
--- /dev/null
+++ b/app/src/main/java/com/casic/br/ktd/netty/tcp/SocketManager.kt
@@ -0,0 +1,113 @@
+package com.casic.br.ktd.netty.tcp
+
+import android.util.Log
+import com.casic.br.ktd.base.BaseApplication
+import com.casic.br.ktd.extensions.covertAngleValue
+import com.casic.br.ktd.extensions.covertDataValue
+import com.casic.br.ktd.extensions.toUnsignedByteArray
+import com.casic.br.ktd.model.SensorDataModel
+import com.casic.br.ktd.utils.LocaleConstant
+import com.pengxh.kt.lite.extensions.toJson
+import com.pengxh.kt.lite.utils.BroadcastManager
+
+class SocketManager private constructor() : ISocketListener {
+
+ private val kTag = "SocketManager"
+ private var nettyClient: SocketClient = SocketClient()
+
+ companion object {
+ val instance: SocketManager by lazy(mode = LazyThreadSafetyMode.SYNCHRONIZED) { SocketManager() }
+ }
+
+ fun connectNetty(hostname: String, port: Int) {
+ Thread {
+ if (!nettyClient.connectStatus) {
+ nettyClient.setSocketListener(this)
+ nettyClient.connect(hostname, port)
+ } else {
+ nettyClient.disconnect()
+ }
+ }.start()
+ }
+
+ override fun onMessageResponse(data: ByteArray?) {
+// Log.d(kTag, "onMessageResponse ===> " + Arrays.toString(data))
+ /**
+ * 0xFF,0x01,
+ * 0x01,0x37,0xE6, 甲烷浓度值(数据码1* 65536 + 数据码2 * 256 + 数据码3)
+ * 0x00, 激光甲烷模块工作状态(00表示设备正常,01表示温控故障,02表示设备激光未打开)
+ * 0x00,0xB2,0x35, 激光强度值(数据码5* 65536 + 数据码6 * 256 + 数据码7)
+ * 0x0A,0x3D, 云台水平角度([数据码8 * 256 + 数据码9]/100,单位为°,精确到0.01)
+ * 0x05,0x6F, 云台垂直角度(首先计算Tangle=[数据码10 * 256 + 数据码11]/100,单位为°,精确到0.01。若Tangle在0~90范围内,则垂直角度值=Tangle;若Tangle在-1~-90范围内,则垂直角度值=Tangle-360)
+ * 0xC1
+ *
+ * [-1, 1, 1, 55, -26, 0, 0, -78, 53, 10, 61, 5, 111, -63]
+ * 甲烷浓度值为79638,计算为79638=0x01*65536+0x37*256+0xE6[0x01为数据码1,0x37为数据码2,0xE6为数据码3];
+ * 激光甲烷设备状态值为0,表示状态正常,[0x00为数据码4];
+ * 激光强度值为45621,计算为45621=0x00*65536+0xB2*256+0x35[0x00为数据码5,0xB2为数据码6,0x35为数据码7];
+ *
+ * =========================================================================================
+ * 实际数据(1800-1950左右)
+ * [-86, 1, 0, 7, 71, 0, 0, 62, -92, 57, 59, -118, -111, -64]
+ * */
+
+ if (data == null) {
+ return
+ }
+ val bytes = data.toUnsignedByteArray()
+ if (bytes.size == 14) {
+ val dataModel = SensorDataModel(0, "激光未打开", 0, 0.0, 0.0)
+
+ val methaneBytes = IntArray(3)
+ System.arraycopy(bytes, 2, methaneBytes, 0, 3)
+ dataModel.methane = methaneBytes.covertDataValue()
+
+ dataModel.methaneState = when (bytes[5]) {
+ 1 -> "温控故障"
+ 2 -> "激光未打开"
+ else -> "正常"
+ }
+
+ val laserBytes = IntArray(3)
+ System.arraycopy(bytes, 6, laserBytes, 0, 3)
+ dataModel.laser = laserBytes.covertDataValue()
+
+ /**
+ * 水平角度的实际范围为从水平零点开始,顺时针方向(从上往下看),0~360°
+ * 垂直角度的实际范围为从垂直零点开始,以向上为正,-90°~90°,控制精度为0.01°
+ * */
+ val horizontalBytes = IntArray(2)
+ System.arraycopy(bytes, 9, horizontalBytes, 0, 2)
+ dataModel.horizontal = horizontalBytes.covertAngleValue()
+
+ val verticalBytes = IntArray(2)
+ System.arraycopy(bytes, 11, verticalBytes, 0, 2)
+ dataModel.vertical = verticalBytes.covertAngleValue()
+
+ //{"horizontal":26.21,"laser":45621,"methane":79846,"methaneState":"正常","vertical":13.91}
+ BroadcastManager.obtainInstance(BaseApplication.get()).sendBroadcast(
+ LocaleConstant.ACTION_UPDATE_DATA, dataModel.toJson()
+ )
+ }
+ }
+
+ override fun onServiceStatusConnectChanged(statusCode: Byte) {
+ if (statusCode == ISocketListener.STATUS_CONNECT_SUCCESS) {
+ if (nettyClient.connectStatus) {
+ Log.d(kTag, "连接成功")
+ }
+ } else {
+ if (!nettyClient.connectStatus) {
+ Log.e(kTag, "onServiceStatusConnectChanged:$statusCode,连接断开,正在重连")
+ }
+ }
+ }
+
+ fun sendData(data: ByteArray) {
+ nettyClient.sendData(data)
+ }
+
+ fun close() {
+ nettyClient.disconnect()
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/br/ktd/netty/udp/UdpChannelInboundHandler.kt b/app/src/main/java/com/casic/br/ktd/netty/udp/UdpChannelInboundHandler.kt
new file mode 100644
index 0000000..4d6f97c
--- /dev/null
+++ b/app/src/main/java/com/casic/br/ktd/netty/udp/UdpChannelInboundHandler.kt
@@ -0,0 +1,36 @@
+package com.casic.br.ktd.netty.udp
+
+import io.netty.channel.ChannelHandlerContext
+import io.netty.channel.SimpleChannelInboundHandler
+import io.netty.channel.socket.DatagramPacket
+import io.netty.util.CharsetUtil
+
+
+abstract class UdpChannelInboundHandler : SimpleChannelInboundHandler() {
+
+ private var handlerContext: ChannelHandlerContext? = null
+
+ override fun channelActive(ctx: ChannelHandlerContext?) {
+ super.channelActive(ctx)
+ handlerContext = ctx
+ }
+
+ override fun channelInactive(ctx: ChannelHandlerContext?) {
+ super.channelInactive(ctx)
+ handlerContext?.close()
+ }
+
+ fun sendDatagramPacket(obj: Any) {
+ handlerContext?.writeAndFlush(obj)
+ }
+
+ fun releasePort() {
+ handlerContext?.close()
+ }
+
+ override fun channelRead0(ctx: ChannelHandlerContext, datagramPacket: DatagramPacket) {
+ receivedMessage(datagramPacket.content().toString(CharsetUtil.UTF_8))
+ }
+
+ abstract fun receivedMessage(data: String)
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/br/ktd/netty/udp/UdpChannelInitializer.kt b/app/src/main/java/com/casic/br/ktd/netty/udp/UdpChannelInitializer.kt
new file mode 100644
index 0000000..416c5a1
--- /dev/null
+++ b/app/src/main/java/com/casic/br/ktd/netty/udp/UdpChannelInitializer.kt
@@ -0,0 +1,17 @@
+package com.casic.br.ktd.netty.udp
+
+import io.netty.channel.ChannelInitializer
+import io.netty.channel.socket.DatagramChannel
+import io.netty.handler.timeout.IdleStateHandler
+
+
+open class UdpChannelInitializer(private val handler: UdpChannelInboundHandler) :
+ ChannelInitializer() {
+
+ override fun initChannel(datagramChannel: DatagramChannel) {
+ val pipeline = datagramChannel.pipeline()
+ pipeline.addLast(
+ IdleStateHandler(12, 15, 0)
+ ).addLast(handler)
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/br/ktd/netty/udp/UdpClient.kt b/app/src/main/java/com/casic/br/ktd/netty/udp/UdpClient.kt
new file mode 100644
index 0000000..3893afa
--- /dev/null
+++ b/app/src/main/java/com/casic/br/ktd/netty/udp/UdpClient.kt
@@ -0,0 +1,103 @@
+package com.casic.br.ktd.netty.udp
+
+import com.casic.br.ktd.utils.LocaleConstant
+import com.pengxh.kt.lite.utils.SaveKeyValues
+import io.netty.bootstrap.Bootstrap
+import io.netty.buffer.ByteBuf
+import io.netty.buffer.Unpooled
+import io.netty.channel.ChannelOption
+import io.netty.channel.nio.NioEventLoopGroup
+import io.netty.channel.socket.DatagramPacket
+import io.netty.channel.socket.nio.NioDatagramChannel
+import io.netty.util.CharsetUtil
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.launch
+import kotlinx.coroutines.withContext
+import java.net.InetSocketAddress
+import java.util.concurrent.ExecutorService
+import java.util.concurrent.Executors
+
+
+class UdpClient : UdpChannelInboundHandler(), Runnable {
+
+ private val bootStrap by lazy { Bootstrap() }
+ private val eventLoopGroup by lazy { NioEventLoopGroup() }
+ private val udpChannelInitializer by lazy { UdpChannelInitializer(this) }
+ private var executorService: ExecutorService
+
+ init {
+ bootStrap.group(eventLoopGroup)
+ bootStrap.channel(NioDatagramChannel::class.java)
+ .option(ChannelOption.SO_RCVBUF, 1024)
+ .option(ChannelOption.SO_SNDBUF, 1024)
+ bootStrap.handler(udpChannelInitializer)
+
+ executorService = Executors.newSingleThreadExecutor()
+ executorService.execute(this)
+ }
+
+ override fun run() {
+ try {
+ val channelFuture = bootStrap.bind(LocaleConstant.LOCATION_UDP_PORT).sync()
+ channelFuture.channel().closeFuture().sync()
+ } catch (e: InterruptedException) {
+ e.printStackTrace()
+ } finally {
+ eventLoopGroup.shutdownGracefully()
+ }
+ }
+
+ fun send(value: String) {
+ CoroutineScope(Dispatchers.Main).launch {
+ withContext(Dispatchers.IO) {
+ val host = SaveKeyValues.getValue(
+ LocaleConstant.LOCATION_UDP_SERVER, "192.168.149.213"
+ ).toString()
+ val datagramPacket = DatagramPacket(
+ Unpooled.copiedBuffer(value, CharsetUtil.UTF_8),
+ InetSocketAddress(host, LocaleConstant.LOCATION_UDP_PORT)
+ )
+ sendDatagramPacket(datagramPacket)
+ }
+ }
+ }
+
+ fun send(value: ByteArray) {
+ CoroutineScope(Dispatchers.Main).launch {
+ withContext(Dispatchers.IO) {
+ val host = SaveKeyValues.getValue(
+ LocaleConstant.LOCATION_UDP_SERVER, "192.168.149.213"
+ ).toString()
+ val datagramPacket = DatagramPacket(
+ Unpooled.copiedBuffer(value),
+ InetSocketAddress(host, LocaleConstant.LOCATION_UDP_PORT)
+ )
+ sendDatagramPacket(datagramPacket)
+ }
+ }
+ }
+
+ fun send(value: ByteBuf) {
+ CoroutineScope(Dispatchers.Main).launch {
+ withContext(Dispatchers.IO) {
+ val host = SaveKeyValues.getValue(
+ LocaleConstant.LOCATION_UDP_SERVER, "192.168.149.213"
+ ).toString()
+ val datagramPacket = DatagramPacket(
+ Unpooled.copiedBuffer(value),
+ InetSocketAddress(host, LocaleConstant.LOCATION_UDP_PORT)
+ )
+ sendDatagramPacket(datagramPacket)
+ }
+ }
+ }
+
+ fun release() {
+ releasePort()
+ }
+
+ override fun receivedMessage(data: String) {
+
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/br/ktd/utils/LocaleConstant.kt b/app/src/main/java/com/casic/br/ktd/utils/LocaleConstant.kt
index 0dd119e..4c675df 100644
--- a/app/src/main/java/com/casic/br/ktd/utils/LocaleConstant.kt
+++ b/app/src/main/java/com/casic/br/ktd/utils/LocaleConstant.kt
@@ -50,6 +50,10 @@
const val DEV_NET_IP = "192.168.1.21"
const val DEV_NET_PORT = "8000"
+ //位置信息UDP端口
+ const val LOCATION_UDP_SERVER = "udpServer"
+ const val LOCATION_UDP_PORT = 7777
+
//BroadcastReceiver Action
const val ACTION_UPDATE_DATA = "update"
diff --git a/app/src/main/java/com/casic/br/ktd/utils/LocationHelper.kt b/app/src/main/java/com/casic/br/ktd/utils/LocationHelper.kt
index 8e31d3f..df6adb5 100644
--- a/app/src/main/java/com/casic/br/ktd/utils/LocationHelper.kt
+++ b/app/src/main/java/com/casic/br/ktd/utils/LocationHelper.kt
@@ -7,19 +7,40 @@
import android.location.LocationListener
import android.location.LocationManager
import android.os.Bundle
+import android.util.Log
import androidx.core.app.ActivityCompat
+import com.amap.api.location.AMapLocation
+import com.amap.api.location.AMapLocationClient
+import com.amap.api.location.AMapLocationClientOption
-object LocationHelper {
- fun obtainCurrentLocation(context: Context, listener: ILocationListener) {
+class LocationHelper private constructor() {
+
+ private val kTag = "LocationHelper"
+
+ companion object {
+ //Kotlin委托模式双重锁单例
+ val get: LocationHelper by lazy(mode = LazyThreadSafetyMode.SYNCHRONIZED) {
+ LocationHelper()
+ }
+ }
+
+ private val locationOption = AMapLocationClientOption()
+ private lateinit var locationClient: AMapLocationClient
+
+ init {
+ //设置定位模式为高精度模式,AMapLocationMode.Battery_Saving为低功耗模式,AMapLocationMode.Device_Sensors是仅设备模式
+ locationOption.locationMode = AMapLocationClientOption.AMapLocationMode.Hight_Accuracy
+ locationOption.isNeedAddress = true //设置是否返回地址信息(默认返回地址信息)
+ locationOption.isLocationCacheEnable = true //可选,设置是否使用缓存定位,默认为true
+ }
+
+ fun obtainLocation(context: Context, listener: ILocationListener) {
if (ActivityCompat.checkSelfPermission(
- context,
- Manifest.permission.ACCESS_LOCATION_EXTRA_COMMANDS
+ context, Manifest.permission.ACCESS_LOCATION_EXTRA_COMMANDS
) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(
- context,
- Manifest.permission.ACCESS_FINE_LOCATION
+ context, Manifest.permission.ACCESS_FINE_LOCATION
) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(
- context,
- Manifest.permission.ACCESS_COARSE_LOCATION
+ context, Manifest.permission.ACCESS_COARSE_LOCATION
) != PackageManager.PERMISSION_GRANTED
) {
return
@@ -38,7 +59,37 @@
})
}
+ /**
+ * 高德sdk定位
+ */
+ fun obtainLocationByGD(context: Context?, listener: ILocationListener) {
+ locationClient = AMapLocationClient(context)
+ //给定位客户端对象设置定位参数
+ locationClient.setLocationOption(locationOption)
+ //设置定位回调监听
+ locationClient.setLocationListener { aMapLocation ->
+ if (aMapLocation != null) {
+ if (aMapLocation.errorCode == 0) {
+ listener.onAMapLocationGet(aMapLocation)
+ } else {
+ Log.e(
+ kTag,
+ "ErrCode: ${aMapLocation.errorCode}, errInfo: ${aMapLocation.errorInfo}"
+ )
+ }
+ }
+ }
+ //启动定位
+ locationClient.startLocation()
+ }
+
+ fun stopLocation() {
+ locationClient.stopLocation()//停止定位
+ }
+
interface ILocationListener {
- fun onLocationGet(location: Location?) //高德定位数据
+ fun onLocationGet(location: Location?) //GPS定位数据
+
+ fun onAMapLocationGet(aMapLocation: AMapLocation?) //高德定位数据
}
}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/br/ktd/view/InspectionActivity.kt b/app/src/main/java/com/casic/br/ktd/view/InspectionActivity.kt
index 02c47f8..c893092 100644
--- a/app/src/main/java/com/casic/br/ktd/view/InspectionActivity.kt
+++ b/app/src/main/java/com/casic/br/ktd/view/InspectionActivity.kt
@@ -15,16 +15,21 @@
import android.view.SurfaceHolder
import android.view.View
import android.widget.AdapterView
-import com.amap.api.maps.*
+import com.amap.api.location.AMapLocation
+import com.amap.api.maps.AMap
+import com.amap.api.maps.CameraUpdateFactory
+import com.amap.api.maps.UiSettings
import com.amap.api.maps.model.CameraPosition
import com.amap.api.maps.model.LatLng
+import com.amap.api.maps.model.MyLocationStyle
import com.amap.api.maps.model.PolylineOptions
import com.casic.br.ktd.R
import com.casic.br.ktd.extensions.*
import com.casic.br.ktd.model.ChartPointModel
import com.casic.br.ktd.model.RouteModel
import com.casic.br.ktd.model.SensorDataModel
-import com.casic.br.ktd.netty.SocketManager
+import com.casic.br.ktd.netty.tcp.SocketManager
+import com.casic.br.ktd.netty.udp.UdpClient
import com.casic.br.ktd.utils.LocaleConstant
import com.casic.br.ktd.utils.LocationHelper
import com.casic.br.ktd.widgets.AlertControlDialog
@@ -49,6 +54,10 @@
import hcnetsdk.sdkhub.MessageCodeHub
import hcnetsdk.sdkhub.SDKGuider
import kotlinx.android.synthetic.main.activity_inspection.*
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.launch
+import kotlinx.coroutines.withContext
import java.text.DecimalFormat
import java.text.SimpleDateFormat
import java.util.*
@@ -60,10 +69,10 @@
private val hkSDK by lazy { HCNetSDK.getInstance() }
private val timeFormat by lazy { SimpleDateFormat("yyyyMMddHHmmss", Locale.CHINA) }
private val latlngs = LinkedList()
- private val speedTimer by lazy { Timer() }
private val tcpTimer by lazy { Timer() }
private val decimalFormat by lazy { DecimalFormat("##0.0") }
private val gson by lazy { Gson() }
+ private val udpClient by lazy { UdpClient() }
private var isLoginSuccess = false
private var previewHandle = -1
private var selectChannel = -1
@@ -103,28 +112,32 @@
private lateinit var aMap: AMap
private lateinit var uiSettings: UiSettings
+ /**
+ * 协程配置云台设备,缓解新进页面较卡的问题
+ * */
private fun setDeviceConfig() {
- Log.d(kTag, "setDeviceConfig => 配置设备IP和端口")
- val device = SDKGuider.sdkGuider.devManageGuider.DeviceItem()
- device.m_szDevName = ""
- device.m_struNetInfo = SDKGuider.sdkGuider.devManageGuider.DevNetInfo(
- LocaleConstant.HK_NET_IP,
- LocaleConstant.HK_NET_PORT,
- LocaleConstant.HK_NET_USERNAME,
- LocaleConstant.HK_NET_PASSWORD
- )
- if (device.m_szDevName.isEmpty()) {
- device.m_szDevName = device.m_struNetInfo.m_szIp
- }
- isLoginSuccess = if (
- SDKGuider.sdkGuider.devManageGuider.login_v40_jna(
- device.m_szDevName, device.m_struNetInfo
- )
- ) {
- "设备连接成功".show(this)
- true
- } else {
- false
+ CoroutineScope(Dispatchers.Main).launch {
+ isLoginSuccess = withContext(Dispatchers.IO) {
+ Log.d(kTag, "setDeviceConfig => 配置设备IP和端口")
+ val device = SDKGuider.sdkGuider.devManageGuider.DeviceItem()
+ device.m_szDevName = ""
+ device.m_struNetInfo = SDKGuider.sdkGuider.devManageGuider.DevNetInfo(
+ LocaleConstant.HK_NET_IP,
+ LocaleConstant.HK_NET_PORT,
+ LocaleConstant.HK_NET_USERNAME,
+ LocaleConstant.HK_NET_PASSWORD
+ )
+ if (device.m_szDevName.isEmpty()) {
+ device.m_szDevName = device.m_struNetInfo.m_szIp
+ }
+
+ SDKGuider.sdkGuider.devManageGuider.login_v40_jna(
+ device.m_szDevName, device.m_struNetInfo
+ )
+ }
+ if (isLoginSuccess) {
+ "设备连接成功".show(context)
+ }
}
}
@@ -148,17 +161,74 @@
/**
* 手机GPS定位
* */
- val converter = CoordinateConverter(this)
- LocationHelper.obtainCurrentLocation(this, object : LocationHelper.ILocationListener {
+// val converter = CoordinateConverter(this)
+// LocationHelper.get.obtainLocation(this, object : LocationHelper.ILocationListener {
+// override fun onLocationGet(location: Location?) {
+// if (location == null) {
+// "当前信号弱,无法定位".show(context)
+// return
+// }
+//
+// //发送位置信息给UDP服务端
+// udpClient.send("${location.longitude}, ${location.latitude}")
+// Log.d(kTag, "onLocationGet => 速度:${location.speed}")
+//
+// //WGS-84要转为高德坐标系
+// converter.from(CoordinateConverter.CoordType.GPS)
+// converter.coord(LatLng(location.latitude, location.longitude))
+// val latLng = converter.convert()
+// latlngs.add(latLng)
+//
+// //移动到指定经纬度
+// val cameraPosition = CameraPosition(latLng, 13f, 0f, 0f)
+// val cameraUpdate = CameraUpdateFactory.newCameraPosition(cameraPosition)
+// aMap.animateCamera(cameraUpdate, 1500, null)
+//
+// //绘制线
+// aMap.addPolyline(
+// PolylineOptions().addAll(latlngs).width(12f).color(Color.RED)
+// )
+//
+// if (isStartInspect) {
+// val route = LinkedList()
+// latlngs.forEach {
+// route.add(RouteModel(it.latitude, it.longitude))
+// }
+// }
+// }
+//
+// override fun onAMapLocationGet(aMapLocation: AMapLocation?) {
+//
+// }
+// })
+
+ /**
+ * 高德定位
+ * */
+ LocationHelper.get.obtainLocationByGD(this, object : LocationHelper.ILocationListener {
override fun onLocationGet(location: Location?) {
- if (location == null) {
+
+ }
+
+ override fun onAMapLocationGet(aMapLocation: AMapLocation?) {
+ if (aMapLocation == null) {
"当前信号弱,无法定位".show(context)
return
}
+
+ //发送位置信息给UDP服务端
+ udpClient.send(
+ "${aMapLocation.longitude}, ${aMapLocation.latitude}, ${
+ System.currentTimeMillis().timestampToCompleteDate()
+ }"
+ )
+ //速度 转为 km/h
+ Log.d(kTag, "onLocationGet => 速度:${aMapLocation.speed}")
+ speed = decimalFormat.format(aMapLocation.speed * 3.6).toFloat()
+ carSpeedView.text = String.format("${speed}Km/h")
+
//WGS-84要转为高德坐标系
- converter.from(CoordinateConverter.CoordType.GPS)
- converter.coord(LatLng(location.latitude, location.longitude))
- val latLng = converter.convert()
+ val latLng = LatLng(aMapLocation.latitude, aMapLocation.longitude)
latlngs.add(latLng)
//移动到指定经纬度
@@ -168,7 +238,7 @@
//绘制线
aMap.addPolyline(
- PolylineOptions().addAll(latlngs).width(12f).color(Color.RED)
+ PolylineOptions().addAll(latlngs).width(10f).color(Color.RED)
)
if (isStartInspect) {
@@ -181,27 +251,6 @@
})
/**
- * 计算速度,微分原理,3s计算一次速度
- * */
- speedTimer.schedule(object : TimerTask() {
- override fun run() {
- //经纬度链表数据小于2,无法计算速度,默认为0
- speed = if (latlngs.size < 2) 0.0f else {
- val temp = AMapUtils.calculateLineDistance(
- latlngs.last(), latlngs[latlngs.size - 2]
- ) / 3
- //转为 km/h
- decimalFormat.format(temp * 3.6).toFloat()
- }
-
- //切换到UI线程更新界面数据
- runOnUiThread {
- carSpeedView.text = String.format("${speed}Km/h")
- }
- }
- }, 0, 3000)
-
- /**
* TCP初始化
* ***/
SocketManager.instance.connectNetty(
@@ -632,6 +681,8 @@
stopPreview()
BroadcastManager.obtainInstance(this).destroy(LocaleConstant.ACTION_UPDATE_DATA)
mapView.onDestroy()
+ udpClient.release()
+ LocationHelper.get.stopLocation()
}
override fun handleMessage(msg: Message): Boolean {
@@ -716,38 +767,13 @@
uiSettings.isZoomControlsEnabled = true
uiSettings.isTiltGesturesEnabled = false//不许地图随手势倾斜角度
-// val locationStyle = MyLocationStyle()
-// locationStyle.interval(2000)
-// locationStyle.showMyLocation(true)
-// locationStyle.myLocationType(MyLocationStyle.LOCATION_TYPE_LOCATION_ROTATE)
-// aMap.myLocationStyle = locationStyle
-// aMap.isMyLocationEnabled = true
-// aMap.animateCamera(CameraUpdateFactory.zoomTo(13f))
-// aMap.setOnMyLocationChangeListener(this)
+ //显示定位小蓝点
+ val locationStyle = MyLocationStyle()
+ locationStyle.showMyLocation(true)//设置是否显示定位小蓝点
+ aMap.myLocationStyle = locationStyle
+ aMap.isMyLocationEnabled = true
}
-// override fun onMyLocationChange(aMapLocation: Location?) {
-// if (aMapLocation == null) {
-// "当前信号弱,无法定位".show(context)
-// return
-// }
-// val latitude = aMapLocation.latitude
-// val longitude = aMapLocation.longitude
-// latlngs.add(LatLng(latitude, longitude))
-//
-// //绘制线
-// aMap.addPolyline(
-// PolylineOptions().addAll(latlngs).width(15f).color(Color.RED)
-// )
-//
-// if (isStartInspect) {
-// val route = LinkedList()
-// latlngs.forEach {
-// route.add(RouteModel(it.latitude, it.longitude))
-// }
-// }
-// }
-
/***以下是地图生命周期管理************************************************************************/
override fun onResume() {
diff --git a/app/src/main/res/layout/fragment_alarm.xml b/app/src/main/res/layout/fragment_alarm.xml
index a3ebc88..929529f 100644
--- a/app/src/main/res/layout/fragment_alarm.xml
+++ b/app/src/main/res/layout/fragment_alarm.xml
@@ -31,7 +31,7 @@
diff --git a/app/src/main/res/layout/fragment_task.xml b/app/src/main/res/layout/fragment_task.xml
index 35cb1a3..58d852e 100644
--- a/app/src/main/res/layout/fragment_task.xml
+++ b/app/src/main/res/layout/fragment_task.xml
@@ -31,7 +31,7 @@
diff --git a/app/src/main/res/mipmap-hdpi/end.png b/app/src/main/res/mipmap-hdpi/end.png
new file mode 100644
index 0000000..f31385b
--- /dev/null
+++ b/app/src/main/res/mipmap-hdpi/end.png
Binary files differ
diff --git a/app/src/main/res/mipmap-hdpi/start.png b/app/src/main/res/mipmap-hdpi/start.png
new file mode 100644
index 0000000..04839dc
--- /dev/null
+++ b/app/src/main/res/mipmap-hdpi/start.png
Binary files differ
diff --git a/app/src/main/res/mipmap-mdpi/end.png b/app/src/main/res/mipmap-mdpi/end.png
new file mode 100644
index 0000000..f31385b
--- /dev/null
+++ b/app/src/main/res/mipmap-mdpi/end.png
Binary files differ
diff --git a/app/src/main/res/mipmap-mdpi/start.png b/app/src/main/res/mipmap-mdpi/start.png
new file mode 100644
index 0000000..04839dc
--- /dev/null
+++ b/app/src/main/res/mipmap-mdpi/start.png
Binary files differ
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index e822df6..d72c1a5 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -7,6 +7,9 @@
+
+
+
@@ -46,5 +49,8 @@
+
+
+
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/br/ktd/base/KotlinBaseFragment.kt b/app/src/main/java/com/casic/br/ktd/base/KotlinBaseFragment.kt
new file mode 100644
index 0000000..2dac61c
--- /dev/null
+++ b/app/src/main/java/com/casic/br/ktd/base/KotlinBaseFragment.kt
@@ -0,0 +1,51 @@
+package com.casic.br.ktd.base
+
+import android.os.Bundle
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import androidx.annotation.LayoutRes
+import androidx.fragment.app.Fragment
+
+abstract class KotlinBaseFragment : Fragment() {
+
+ lateinit var bv: View
+
+ override fun onCreateView(
+ inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?
+ ): View? {
+ bv = inflater.inflate(initLayoutRes(), container, false)
+ initView(savedInstanceState)
+ setupTopBarLayout()
+ return bv
+ }
+
+ override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
+ super.onViewCreated(view, savedInstanceState)
+ observeRequestState()
+ initEvent()
+ }
+
+ @LayoutRes
+ abstract fun initLayoutRes(): Int
+
+ /**
+ * 沉浸式状态栏
+ */
+ abstract fun setupTopBarLayout()
+
+ /**
+ * 初始化布局以及控件
+ */
+ abstract fun initView(savedInstanceState: Bundle?)
+
+ /**
+ * 网络请求状态监听
+ */
+ abstract fun observeRequestState()
+
+ /**
+ * 业务逻辑,按钮等事件
+ */
+ abstract fun initEvent()
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/br/ktd/fragment/AlarmPageFragment.kt b/app/src/main/java/com/casic/br/ktd/fragment/AlarmPageFragment.kt
index 6c98a3b..9418169 100644
--- a/app/src/main/java/com/casic/br/ktd/fragment/AlarmPageFragment.kt
+++ b/app/src/main/java/com/casic/br/ktd/fragment/AlarmPageFragment.kt
@@ -2,28 +2,29 @@
import android.os.Bundle
import com.casic.br.ktd.R
+import com.casic.br.ktd.base.KotlinBaseFragment
import com.casic.br.ktd.widgets.DateRangeActionSheet
-import com.pengxh.kt.lite.base.KotlinBaseFragment
import kotlinx.android.synthetic.main.fragment_alarm.view.*
class AlarmPageFragment : KotlinBaseFragment() {
- override fun initData(savedInstanceState: Bundle?) {
+
+ override fun initView(savedInstanceState: Bundle?) {
}
override fun initEvent() {
- baseView.calendarView.setOnClickListener {
+ bv.calendarView.setOnClickListener {
DateRangeActionSheet.Builder().setContext(requireContext())
.setOnActionSheetListener(object :
DateRangeActionSheet.OnDateRangeSelectedListener {
override fun onDateRangeSelected(startDate: String, endDate: String) {
- baseView.selectedDateView.text = "$startDate ~ $endDate"
+ bv.selectedDateView.text = "$startDate ~ $endDate"
}
}).build().show()
}
}
- override fun initLayoutView(): Int = R.layout.fragment_alarm
+ override fun initLayoutRes(): Int = R.layout.fragment_alarm
override fun observeRequestState() {
diff --git a/app/src/main/java/com/casic/br/ktd/fragment/HomePageFragment.kt b/app/src/main/java/com/casic/br/ktd/fragment/HomePageFragment.kt
index 9961935..f3eba5c 100644
--- a/app/src/main/java/com/casic/br/ktd/fragment/HomePageFragment.kt
+++ b/app/src/main/java/com/casic/br/ktd/fragment/HomePageFragment.kt
@@ -1,32 +1,62 @@
package com.casic.br.ktd.fragment
+import android.graphics.Color
import android.os.Bundle
import com.amap.api.maps.AMap
import com.amap.api.maps.AMapOptions
+import com.amap.api.maps.CameraUpdateFactory
+import com.amap.api.maps.model.*
import com.casic.br.ktd.R
-import com.pengxh.kt.lite.base.KotlinBaseFragment
+import com.casic.br.ktd.base.KotlinBaseFragment
import kotlinx.android.synthetic.main.fragment_home.view.*
class HomePageFragment : KotlinBaseFragment() {
private lateinit var aMap: AMap
- override fun initData(savedInstanceState: Bundle?) {
- baseView.mapView.onCreate(savedInstanceState)
- aMap = baseView.mapView.map
+ override fun initView(savedInstanceState: Bundle?) {
+ bv.mapView.onCreate(savedInstanceState)
+ aMap = bv.mapView.map
val uiSettings = aMap.uiSettings
uiSettings.isCompassEnabled = true
- uiSettings.isMyLocationButtonEnabled = true
+ uiSettings.isMyLocationButtonEnabled = false
uiSettings.isScaleControlsEnabled = true
uiSettings.zoomPosition = AMapOptions.ZOOM_POSITION_RIGHT_CENTER
uiSettings.isRotateGesturesEnabled = false//不许地图随手势旋转角度
}
override fun initEvent() {
-
+ //移动到巡检起始经纬度
+ val cameraPosition = CameraPosition(LatLng(39.914199, 116.265785), 16f, 0f, 0f)
+ val cameraUpdate = CameraUpdateFactory.newCameraPosition(cameraPosition)
+ aMap.animateCamera(cameraUpdate, 1500, null)
+ //设置起点
+ addMarker(LatLng(39.914885, 116.272312), R.mipmap.start)
+ //设置终点
+ addMarker(LatLng(39.914716, 116.265097), R.mipmap.end)
+ //瞄点画线
+ val latLngPoints = ArrayList()
+ latLngPoints.add(LatLng(39.914885, 116.272312))
+ latLngPoints.add(LatLng(39.915148, 116.272312))
+ latLngPoints.add(LatLng(39.915399, 116.272302))
+ latLngPoints.add(LatLng(39.915436, 116.271787))
+ latLngPoints.add(LatLng(39.915477, 116.270886))
+ latLngPoints.add(LatLng(39.915477, 116.269968))
+ latLngPoints.add(LatLng(39.915469, 116.269544))
+ latLngPoints.add(LatLng(39.915481, 116.269196))
+ latLngPoints.add(LatLng(39.915452, 116.268472))
+ latLngPoints.add(LatLng(39.915444, 116.267722))
+ latLngPoints.add(LatLng(39.915415, 116.266755))
+ latLngPoints.add(LatLng(39.915403, 116.266165))
+ latLngPoints.add(LatLng(39.915395, 116.265703))
+ latLngPoints.add(LatLng(39.915366, 116.265119))
+ latLngPoints.add(LatLng(39.914716, 116.265097))
+ aMap.addPolyline(
+ PolylineOptions().addAll(latLngPoints).width(10.toFloat()).color(Color.RED)
+ )
}
- override fun initLayoutView(): Int = R.layout.fragment_home
+ override fun initLayoutRes(): Int = R.layout.fragment_home
override fun observeRequestState() {
@@ -36,25 +66,32 @@
}
+ private fun addMarker(point: LatLng, res: Int) {
+ val markerOption = MarkerOptions()
+ markerOption.position(point)
+ markerOption.icon(BitmapDescriptorFactory.fromResource(res))
+ aMap.addMarker(markerOption)
+ }
+
/***以下是地图生命周期管理************************************************************************/
override fun onResume() {
super.onResume()
- baseView.mapView.onResume()
+ bv.mapView.onResume()
}
override fun onPause() {
- baseView.mapView.onPause()
super.onPause()
+ bv.mapView.onPause()
}
override fun onSaveInstanceState(outState: Bundle) {
super.onSaveInstanceState(outState)
- baseView.mapView.onSaveInstanceState(outState)
+ bv.mapView.onSaveInstanceState(outState)
}
override fun onDestroy() {
- baseView.mapView.onDestroy()
super.onDestroy()
+ bv.mapView.onDestroy()
}
}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/br/ktd/fragment/MinePageFragment.kt b/app/src/main/java/com/casic/br/ktd/fragment/MinePageFragment.kt
index 90313ac..3212794 100644
--- a/app/src/main/java/com/casic/br/ktd/fragment/MinePageFragment.kt
+++ b/app/src/main/java/com/casic/br/ktd/fragment/MinePageFragment.kt
@@ -2,10 +2,11 @@
import android.os.Bundle
import com.casic.br.ktd.R
-import com.pengxh.kt.lite.base.KotlinBaseFragment
+import com.casic.br.ktd.base.KotlinBaseFragment
class MinePageFragment : KotlinBaseFragment() {
- override fun initData(savedInstanceState: Bundle?) {
+
+ override fun initView(savedInstanceState: Bundle?) {
}
@@ -13,7 +14,7 @@
}
- override fun initLayoutView(): Int = R.layout.fragment_mine
+ override fun initLayoutRes(): Int = R.layout.fragment_mine
override fun observeRequestState() {
diff --git a/app/src/main/java/com/casic/br/ktd/fragment/TaskPageFragment.kt b/app/src/main/java/com/casic/br/ktd/fragment/TaskPageFragment.kt
index 8f6abf0..6b82a54 100644
--- a/app/src/main/java/com/casic/br/ktd/fragment/TaskPageFragment.kt
+++ b/app/src/main/java/com/casic/br/ktd/fragment/TaskPageFragment.kt
@@ -8,6 +8,7 @@
import androidx.recyclerview.widget.RecyclerView
import com.casic.br.ktd.R
import com.casic.br.ktd.adapter.TaskAdapter
+import com.casic.br.ktd.base.KotlinBaseFragment
import com.casic.br.ktd.holder.SwipeViewHolder
import com.casic.br.ktd.model.TaskListModel
import com.casic.br.ktd.view.InspectionActivity
@@ -15,7 +16,6 @@
import com.casic.br.ktd.widgets.AlertControlDialog
import com.casic.br.ktd.widgets.AlertInputDialog
import com.casic.br.ktd.widgets.DateRangeActionSheet
-import com.pengxh.kt.lite.base.KotlinBaseFragment
import com.pengxh.kt.lite.extensions.navigatePageTo
import com.pengxh.kt.lite.extensions.show
import com.pengxh.kt.lite.utils.WeakReferenceHandler
@@ -36,7 +36,7 @@
private var startTime = ""
private var endTime = ""
- override fun initData(savedInstanceState: Bundle?) {
+ override fun initView(savedInstanceState: Bundle?) {
weakReferenceHandler = WeakReferenceHandler(this)
taskViewModel = ViewModelProvider(this)[TaskViewModel::class.java]
taskViewModel.taskList.observe(this) {
@@ -45,7 +45,7 @@
when {
isRefresh -> {
taskAdapter.setRefreshData(dataRows)
- baseView.taskLayout.finishRefresh()
+ bv.taskLayout.finishRefresh()
isRefresh = false
}
isLoadMore -> {
@@ -53,7 +53,7 @@
"到底了,别拉了".show(requireContext())
}
taskAdapter.setLoadMoreData(dataRows)
- baseView.taskLayout.finishLoadMore()
+ bv.taskLayout.finishLoadMore()
isLoadMore = false
}
else -> {
@@ -76,9 +76,9 @@
when (msg.what) {
2023070501 -> {
if (dataBeans.size == 0) {
- baseView.emptyLayout.visibility = View.VISIBLE
+ bv.emptyLayout.visibility = View.VISIBLE
} else {
- baseView.emptyLayout.visibility = View.GONE
+ bv.emptyLayout.visibility = View.GONE
taskAdapter = object : TaskAdapter(
requireContext(), R.layout.item_task_rv_l, dataBeans
) {
@@ -97,8 +97,8 @@
}
}
//绑定侧滑事件
- swipeAction.attachToRecyclerView(baseView.taskRecyclerView)
- baseView.taskRecyclerView.adapter = taskAdapter
+ swipeAction.attachToRecyclerView(bv.taskRecyclerView)
+ bv.taskRecyclerView.adapter = taskAdapter
taskAdapter.setOnItemCheckedListener(object :
TaskAdapter.OnItemCheckedListener {
override fun onItemChecked(items: ArrayList) {
@@ -168,7 +168,7 @@
override fun initEvent() {
- baseView.calendarView.setOnClickListener {
+ bv.calendarView.setOnClickListener {
DateRangeActionSheet.Builder().setContext(requireContext())
.setOnActionSheetListener(object :
DateRangeActionSheet.OnDateRangeSelectedListener {
@@ -177,12 +177,12 @@
endTime = endDate
//显示
- baseView.selectedDateView.text = "$startDate ~ $endDate"
+ bv.selectedDateView.text = "$startDate ~ $endDate"
}
}).build().show()
}
- baseView.addTaskButton.setOnClickListener {
+ bv.addTaskButton.setOnClickListener {
// AlertInputDialog.Builder()
// .setContext(requireContext())
// .setTitle("新建巡检任务")
@@ -200,11 +200,11 @@
requireContext().navigatePageTo()
}
- baseView.deleteTaskButton.setOnClickListener {
+ bv.deleteTaskButton.setOnClickListener {
selectedItems.size.toString().show(requireContext())
}
- baseView.taskSettingsButton.setOnClickListener {
+ bv.taskSettingsButton.setOnClickListener {
AlertInputDialog.Builder()
.setContext(requireContext())
.setTitle("设置阈值")
@@ -221,14 +221,14 @@
}).build().show()
}
- baseView.taskLayout.setOnRefreshListener {
+ bv.taskLayout.setOnRefreshListener {
isRefresh = true
//刷新之后页码重置
pageIndex = 1
getTaskList()
}
- baseView.taskLayout.setOnLoadMoreListener {
+ bv.taskLayout.setOnLoadMoreListener {
isLoadMore = true
pageIndex++
getTaskList()
@@ -239,13 +239,13 @@
taskViewModel.getTaskList(
startTime,
endTime,
- baseView.taskNameView.text.toString(),
- baseView.taskCodeView.text.toString(),
+ bv.taskNameView.text.toString(),
+ bv.taskCodeView.text.toString(),
pageIndex
)
}
- override fun initLayoutView(): Int = R.layout.fragment_task
+ override fun initLayoutRes(): Int = R.layout.fragment_task
override fun observeRequestState() {
diff --git a/app/src/main/java/com/casic/br/ktd/netty/ISocketListener.kt b/app/src/main/java/com/casic/br/ktd/netty/ISocketListener.kt
deleted file mode 100644
index dab98e1..0000000
--- a/app/src/main/java/com/casic/br/ktd/netty/ISocketListener.kt
+++ /dev/null
@@ -1,19 +0,0 @@
-package com.casic.br.ktd.netty
-
-interface ISocketListener {
- companion object {
- const val STATUS_CONNECT_SUCCESS: Byte = 1 //连接成功
- const val STATUS_CONNECT_CLOSED: Byte = 0 //关闭连接
- const val STATUS_CONNECT_ERROR: Byte = 0 //连接失败
- }
-
- /**
- * 当接收到系统消息
- */
- fun onMessageResponse(data: ByteArray?)
-
- /**
- * 当连接状态发生变化时调用
- */
- fun onServiceStatusConnectChanged(statusCode: Byte)
-}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/br/ktd/netty/SocketChannelHandle.kt b/app/src/main/java/com/casic/br/ktd/netty/SocketChannelHandle.kt
deleted file mode 100644
index 42eb310..0000000
--- a/app/src/main/java/com/casic/br/ktd/netty/SocketChannelHandle.kt
+++ /dev/null
@@ -1,51 +0,0 @@
-package com.casic.br.ktd.netty
-
-import android.util.Log
-import io.netty.channel.ChannelHandlerContext
-import io.netty.channel.SimpleChannelInboundHandler
-import io.netty.handler.timeout.IdleState
-import io.netty.handler.timeout.IdleStateEvent
-import java.nio.charset.StandardCharsets
-
-class SocketChannelHandle(private val listener: ISocketListener?) :
- SimpleChannelInboundHandler() {
-
- private val kTag = "SocketChannelHandle"
-
- override fun channelActive(ctx: ChannelHandlerContext) {
- super.channelActive(ctx)
- Log.d(kTag, "channelActive ===> 连接成功")
- listener?.onServiceStatusConnectChanged(ISocketListener.STATUS_CONNECT_SUCCESS)
- }
-
- override fun channelInactive(ctx: ChannelHandlerContext) {
- super.channelInactive(ctx)
- Log.e(kTag, "channelInactive: 连接断开")
- }
-
- override fun userEventTriggered(ctx: ChannelHandlerContext, evt: Any) {
- super.userEventTriggered(ctx, evt)
- if (evt is IdleStateEvent) {
- if (evt.state() == IdleState.WRITER_IDLE) {
- //写超时,此时可以发送心跳数据给服务器
- val temp = "FF"
- ctx.writeAndFlush(temp.toByteArray(StandardCharsets.UTF_8))
- } else if (evt.state() == IdleState.READER_IDLE) {
- //读超时,此时代表没有收到心跳返回可以关闭当前连接进行重连
- ctx.close()
- }
- }
- }
-
- override fun channelRead0(ctx: ChannelHandlerContext, data: ByteArray?) {
- listener?.onMessageResponse(data)
- }
-
- override fun exceptionCaught(ctx: ChannelHandlerContext, cause: Throwable) {
- super.exceptionCaught(ctx, cause)
- Log.d(kTag, "exceptionCaught ===> $cause")
- listener?.onServiceStatusConnectChanged(ISocketListener.STATUS_CONNECT_ERROR)
- cause.printStackTrace()
- ctx.close()
- }
-}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/br/ktd/netty/SocketClient.kt b/app/src/main/java/com/casic/br/ktd/netty/SocketClient.kt
deleted file mode 100644
index d05d335..0000000
--- a/app/src/main/java/com/casic/br/ktd/netty/SocketClient.kt
+++ /dev/null
@@ -1,153 +0,0 @@
-package com.casic.br.ktd.netty
-
-import android.os.SystemClock
-import android.util.Log
-import io.netty.bootstrap.Bootstrap
-import io.netty.channel.*
-import io.netty.channel.nio.NioEventLoopGroup
-import io.netty.channel.socket.SocketChannel
-import io.netty.channel.socket.nio.NioSocketChannel
-import io.netty.handler.codec.bytes.ByteArrayDecoder
-import io.netty.handler.codec.bytes.ByteArrayEncoder
-import io.netty.handler.timeout.IdleStateHandler
-
-class SocketClient {
-
- private val kTag = "SocketClient"
-
- private var host: String? = null
- private var port = 8000
- private var nioEventLoopGroup: NioEventLoopGroup? = null
- private var channel: Channel? = null
- private var listener: ISocketListener? = null
-
- //现在连接的状态
- var connectStatus = false //判断是否已连接
- private var reconnectNum = Int.MAX_VALUE //定义的重连到时候用
- private var isNeedReconnect = true //是否需要重连
- var isConnecting = false //是否正在连接
- private set
- private var reconnectIntervalTime: Long = 15000 //重连的时间
-
- //重连时间
- fun setReconnectNum(reconnectNum: Int) {
- this.reconnectNum = reconnectNum
- }
-
- fun setReconnectIntervalTime(reconnectIntervalTime: Long) {
- this.reconnectIntervalTime = reconnectIntervalTime
- }
-
- fun setSocketListener(listener: ISocketListener?) {
- this.listener = listener
- }
-
- fun connect(host: String, port: Int) {
- this.host = host
- this.port = port
- Log.d(kTag, "connect ===> 开始连接TCP服务器")
- if (isConnecting) {
- return
- }
- //起个线程
- val clientThread: Thread = object : Thread("client-Netty") {
- override fun run() {
- super.run()
- isNeedReconnect = true
- reconnectNum = Int.MAX_VALUE
- connectServer()
- }
- }
- clientThread.start()
- }
-
- private fun connectServer() {
- synchronized(this@SocketClient) {
- var channelFuture: ChannelFuture? = null //连接管理对象
- if (!connectStatus) {
- isConnecting = true
- nioEventLoopGroup = NioEventLoopGroup() //设置的连接group
- val bootstrap = Bootstrap()
- bootstrap.group(nioEventLoopGroup) //设置的一系列连接参数操作等
- .channel(NioSocketChannel::class.java)
- .option(ChannelOption.TCP_NODELAY, true) //无阻塞
- .option(ChannelOption.SO_KEEPALIVE, true) //长连接
- .option(
- ChannelOption.RCVBUF_ALLOCATOR,
- AdaptiveRecvByteBufAllocator(5000, 5000, 8000)
- ) //接收缓冲区 最小值太小时数据接收不全
- .handler(object : ChannelInitializer() {
- override fun initChannel(channel: SocketChannel) {
- val pipeline = channel.pipeline()
- //参数1:代表读套接字超时的时间,没收到数据会触发读超时回调;
- //参数2:代表写套接字超时时间,没进行写会触发写超时回调;
- //参数3:将在未执行读取或写入时触发超时回调,0代表不处理;
- //读超时尽量设置大于写超时,代表多次写超时时写心跳包,多次写了心跳数据仍然读超时代表当前连接错误,即可断开连接重新连接
- pipeline.addLast(IdleStateHandler(60, 10, 0))
- pipeline.addLast(ByteArrayDecoder())
- pipeline.addLast(ByteArrayEncoder())
- pipeline.addLast(SocketChannelHandle(listener))
- }
- })
- try {
- //连接监听
- channelFuture = bootstrap.connect(host, port)
- .addListener(object : ChannelFutureListener {
- override fun operationComplete(channelFuture: ChannelFuture) {
- if (channelFuture.isSuccess) {
- connectStatus = true
- channel = channelFuture.channel()
- } else {
- Log.e(kTag, "operationComplete: 连接失败")
- connectStatus = false
- }
- isConnecting = false
- }
- }).sync()
- // 等待连接关闭
- channelFuture.channel().closeFuture().sync()
- } catch (e: Exception) {
- e.printStackTrace()
- } finally {
- connectStatus = false
- listener?.onServiceStatusConnectChanged(ISocketListener.STATUS_CONNECT_CLOSED) //STATUS_CONNECT_CLOSED 这我自己定义的 接口标识
- if (null != channelFuture) {
- if (channelFuture.channel() != null && channelFuture.channel().isOpen) {
- channelFuture.channel().close()
- }
- }
- nioEventLoopGroup?.shutdownGracefully()
- reconnect() //重新连接
- }
- }
- }
- }
-
- //断开连接
- fun disconnect() {
- Log.d(kTag, "disconnect ===> 断开连接")
- isNeedReconnect = false
- nioEventLoopGroup?.shutdownGracefully()
- }
-
- //重新连接
- private fun reconnect() {
- if (isNeedReconnect && reconnectNum > 0 && !connectStatus) {
- reconnectNum--
- SystemClock.sleep(reconnectIntervalTime)
- if (isNeedReconnect && reconnectNum > 0 && !connectStatus) {
- Log.d(kTag, "reconnect ===> 重新连接")
- connectServer()
- }
- }
- }
-
- fun sendData(bytes: ByteArray) {
- channel?.writeAndFlush(bytes)?.addListener(ChannelFutureListener { future ->
- if (!future.isSuccess) {
- future.channel().close()
- nioEventLoopGroup!!.shutdownGracefully()
- }
- })
- }
-}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/br/ktd/netty/SocketManager.kt b/app/src/main/java/com/casic/br/ktd/netty/SocketManager.kt
deleted file mode 100644
index 17daf35..0000000
--- a/app/src/main/java/com/casic/br/ktd/netty/SocketManager.kt
+++ /dev/null
@@ -1,113 +0,0 @@
-package com.casic.br.ktd.netty
-
-import android.util.Log
-import com.casic.br.ktd.base.BaseApplication
-import com.casic.br.ktd.extensions.covertAngleValue
-import com.casic.br.ktd.extensions.covertDataValue
-import com.casic.br.ktd.extensions.toUnsignedByteArray
-import com.casic.br.ktd.model.SensorDataModel
-import com.casic.br.ktd.utils.LocaleConstant
-import com.pengxh.kt.lite.extensions.toJson
-import com.pengxh.kt.lite.utils.BroadcastManager
-
-class SocketManager private constructor() : ISocketListener {
-
- private val kTag = "SocketManager"
- private var nettyClient: SocketClient = SocketClient()
-
- companion object {
- val instance: SocketManager by lazy(mode = LazyThreadSafetyMode.SYNCHRONIZED) { SocketManager() }
- }
-
- fun connectNetty(hostname: String, port: Int) {
- Thread {
- if (!nettyClient.connectStatus) {
- nettyClient.setSocketListener(this)
- nettyClient.connect(hostname, port)
- } else {
- nettyClient.disconnect()
- }
- }.start()
- }
-
- override fun onMessageResponse(data: ByteArray?) {
-// Log.d(kTag, "onMessageResponse ===> " + Arrays.toString(data))
- /**
- * 0xFF,0x01,
- * 0x01,0x37,0xE6, 甲烷浓度值(数据码1* 65536 + 数据码2 * 256 + 数据码3)
- * 0x00, 激光甲烷模块工作状态(00表示设备正常,01表示温控故障,02表示设备激光未打开)
- * 0x00,0xB2,0x35, 激光强度值(数据码5* 65536 + 数据码6 * 256 + 数据码7)
- * 0x0A,0x3D, 云台水平角度([数据码8 * 256 + 数据码9]/100,单位为°,精确到0.01)
- * 0x05,0x6F, 云台垂直角度(首先计算Tangle=[数据码10 * 256 + 数据码11]/100,单位为°,精确到0.01。若Tangle在0~90范围内,则垂直角度值=Tangle;若Tangle在-1~-90范围内,则垂直角度值=Tangle-360)
- * 0xC1
- *
- * [-1, 1, 1, 55, -26, 0, 0, -78, 53, 10, 61, 5, 111, -63]
- * 甲烷浓度值为79638,计算为79638=0x01*65536+0x37*256+0xE6[0x01为数据码1,0x37为数据码2,0xE6为数据码3];
- * 激光甲烷设备状态值为0,表示状态正常,[0x00为数据码4];
- * 激光强度值为45621,计算为45621=0x00*65536+0xB2*256+0x35[0x00为数据码5,0xB2为数据码6,0x35为数据码7];
- *
- * =========================================================================================
- * 实际数据(1800-1950左右)
- * [-86, 1, 0, 7, 71, 0, 0, 62, -92, 57, 59, -118, -111, -64]
- * */
-
- if (data == null) {
- return
- }
- val bytes = data.toUnsignedByteArray()
- if (bytes.size == 14) {
- val dataModel = SensorDataModel(0, "激光未打开", 0, 0.0, 0.0)
-
- val methaneBytes = IntArray(3)
- System.arraycopy(bytes, 2, methaneBytes, 0, 3)
- dataModel.methane = methaneBytes.covertDataValue()
-
- dataModel.methaneState = when (bytes[5]) {
- 1 -> "温控故障"
- 2 -> "激光未打开"
- else -> "正常"
- }
-
- val laserBytes = IntArray(3)
- System.arraycopy(bytes, 6, laserBytes, 0, 3)
- dataModel.laser = laserBytes.covertDataValue()
-
- /**
- * 水平角度的实际范围为从水平零点开始,顺时针方向(从上往下看),0~360°
- * 垂直角度的实际范围为从垂直零点开始,以向上为正,-90°~90°,控制精度为0.01°
- * */
- val horizontalBytes = IntArray(2)
- System.arraycopy(bytes, 9, horizontalBytes, 0, 2)
- dataModel.horizontal = horizontalBytes.covertAngleValue()
-
- val verticalBytes = IntArray(2)
- System.arraycopy(bytes, 11, verticalBytes, 0, 2)
- dataModel.vertical = verticalBytes.covertAngleValue()
-
- //{"horizontal":26.21,"laser":45621,"methane":79846,"methaneState":"正常","vertical":13.91}
- BroadcastManager.obtainInstance(BaseApplication.get()).sendBroadcast(
- LocaleConstant.ACTION_UPDATE_DATA, dataModel.toJson()
- )
- }
- }
-
- override fun onServiceStatusConnectChanged(statusCode: Byte) {
- if (statusCode == ISocketListener.STATUS_CONNECT_SUCCESS) {
- if (nettyClient.connectStatus) {
- Log.d(kTag, "连接成功")
- }
- } else {
- if (!nettyClient.connectStatus) {
- Log.e(kTag, "onServiceStatusConnectChanged:$statusCode,连接断开,正在重连")
- }
- }
- }
-
- fun sendData(data: ByteArray) {
- nettyClient.sendData(data)
- }
-
- fun close() {
- nettyClient.disconnect()
- }
-}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/br/ktd/netty/tcp/ISocketListener.kt b/app/src/main/java/com/casic/br/ktd/netty/tcp/ISocketListener.kt
new file mode 100644
index 0000000..13c3084
--- /dev/null
+++ b/app/src/main/java/com/casic/br/ktd/netty/tcp/ISocketListener.kt
@@ -0,0 +1,19 @@
+package com.casic.br.ktd.netty.tcp
+
+interface ISocketListener {
+ companion object {
+ const val STATUS_CONNECT_SUCCESS: Byte = 1 //连接成功
+ const val STATUS_CONNECT_CLOSED: Byte = 0 //关闭连接
+ const val STATUS_CONNECT_ERROR: Byte = 0 //连接失败
+ }
+
+ /**
+ * 当接收到系统消息
+ */
+ fun onMessageResponse(data: ByteArray?)
+
+ /**
+ * 当连接状态发生变化时调用
+ */
+ fun onServiceStatusConnectChanged(statusCode: Byte)
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/br/ktd/netty/tcp/SocketChannelHandle.kt b/app/src/main/java/com/casic/br/ktd/netty/tcp/SocketChannelHandle.kt
new file mode 100644
index 0000000..8e2997f
--- /dev/null
+++ b/app/src/main/java/com/casic/br/ktd/netty/tcp/SocketChannelHandle.kt
@@ -0,0 +1,51 @@
+package com.casic.br.ktd.netty.tcp
+
+import android.util.Log
+import io.netty.channel.ChannelHandlerContext
+import io.netty.channel.SimpleChannelInboundHandler
+import io.netty.handler.timeout.IdleState
+import io.netty.handler.timeout.IdleStateEvent
+import java.nio.charset.StandardCharsets
+
+class SocketChannelHandle(private val listener: ISocketListener?) :
+ SimpleChannelInboundHandler() {
+
+ private val kTag = "SocketChannelHandle"
+
+ override fun channelActive(ctx: ChannelHandlerContext) {
+ super.channelActive(ctx)
+ Log.d(kTag, "channelActive ===> 连接成功")
+ listener?.onServiceStatusConnectChanged(ISocketListener.STATUS_CONNECT_SUCCESS)
+ }
+
+ override fun channelInactive(ctx: ChannelHandlerContext) {
+ super.channelInactive(ctx)
+ Log.e(kTag, "channelInactive: 连接断开")
+ }
+
+ override fun userEventTriggered(ctx: ChannelHandlerContext, evt: Any) {
+ super.userEventTriggered(ctx, evt)
+ if (evt is IdleStateEvent) {
+ if (evt.state() == IdleState.WRITER_IDLE) {
+ //写超时,此时可以发送心跳数据给服务器
+ val temp = "FF"
+ ctx.writeAndFlush(temp.toByteArray(StandardCharsets.UTF_8))
+ } else if (evt.state() == IdleState.READER_IDLE) {
+ //读超时,此时代表没有收到心跳返回可以关闭当前连接进行重连
+ ctx.close()
+ }
+ }
+ }
+
+ override fun channelRead0(ctx: ChannelHandlerContext, data: ByteArray?) {
+ listener?.onMessageResponse(data)
+ }
+
+ override fun exceptionCaught(ctx: ChannelHandlerContext, cause: Throwable) {
+ super.exceptionCaught(ctx, cause)
+ Log.d(kTag, "exceptionCaught ===> $cause")
+ listener?.onServiceStatusConnectChanged(ISocketListener.STATUS_CONNECT_ERROR)
+ cause.printStackTrace()
+ ctx.close()
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/br/ktd/netty/tcp/SocketClient.kt b/app/src/main/java/com/casic/br/ktd/netty/tcp/SocketClient.kt
new file mode 100644
index 0000000..34960a0
--- /dev/null
+++ b/app/src/main/java/com/casic/br/ktd/netty/tcp/SocketClient.kt
@@ -0,0 +1,153 @@
+package com.casic.br.ktd.netty.tcp
+
+import android.os.SystemClock
+import android.util.Log
+import io.netty.bootstrap.Bootstrap
+import io.netty.channel.*
+import io.netty.channel.nio.NioEventLoopGroup
+import io.netty.channel.socket.SocketChannel
+import io.netty.channel.socket.nio.NioSocketChannel
+import io.netty.handler.codec.bytes.ByteArrayDecoder
+import io.netty.handler.codec.bytes.ByteArrayEncoder
+import io.netty.handler.timeout.IdleStateHandler
+
+class SocketClient {
+
+ private val kTag = "SocketClient"
+
+ private var host: String? = null
+ private var port = 8000
+ private var nioEventLoopGroup: NioEventLoopGroup? = null
+ private var channel: Channel? = null
+ private var listener: ISocketListener? = null
+
+ //现在连接的状态
+ var connectStatus = false //判断是否已连接
+ private var reconnectNum = Int.MAX_VALUE //定义的重连到时候用
+ private var isNeedReconnect = true //是否需要重连
+ var isConnecting = false //是否正在连接
+ private set
+ private var reconnectIntervalTime: Long = 15000 //重连的时间
+
+ //重连时间
+ fun setReconnectNum(reconnectNum: Int) {
+ this.reconnectNum = reconnectNum
+ }
+
+ fun setReconnectIntervalTime(reconnectIntervalTime: Long) {
+ this.reconnectIntervalTime = reconnectIntervalTime
+ }
+
+ fun setSocketListener(listener: ISocketListener?) {
+ this.listener = listener
+ }
+
+ fun connect(host: String, port: Int) {
+ this.host = host
+ this.port = port
+ Log.d(kTag, "connect ===> 开始连接TCP服务器")
+ if (isConnecting) {
+ return
+ }
+ //起个线程
+ val clientThread: Thread = object : Thread("client-Netty") {
+ override fun run() {
+ super.run()
+ isNeedReconnect = true
+ reconnectNum = Int.MAX_VALUE
+ connectServer()
+ }
+ }
+ clientThread.start()
+ }
+
+ private fun connectServer() {
+ synchronized(this@SocketClient) {
+ var channelFuture: ChannelFuture? = null //连接管理对象
+ if (!connectStatus) {
+ isConnecting = true
+ nioEventLoopGroup = NioEventLoopGroup() //设置的连接group
+ val bootstrap = Bootstrap()
+ bootstrap.group(nioEventLoopGroup) //设置的一系列连接参数操作等
+ .channel(NioSocketChannel::class.java)
+ .option(ChannelOption.TCP_NODELAY, true) //无阻塞
+ .option(ChannelOption.SO_KEEPALIVE, true) //长连接
+ .option(
+ ChannelOption.RCVBUF_ALLOCATOR,
+ AdaptiveRecvByteBufAllocator(5000, 5000, 8000)
+ ) //接收缓冲区 最小值太小时数据接收不全
+ .handler(object : ChannelInitializer() {
+ override fun initChannel(channel: SocketChannel) {
+ val pipeline = channel.pipeline()
+ //参数1:代表读套接字超时的时间,没收到数据会触发读超时回调;
+ //参数2:代表写套接字超时时间,没进行写会触发写超时回调;
+ //参数3:将在未执行读取或写入时触发超时回调,0代表不处理;
+ //读超时尽量设置大于写超时,代表多次写超时时写心跳包,多次写了心跳数据仍然读超时代表当前连接错误,即可断开连接重新连接
+ pipeline.addLast(IdleStateHandler(60, 10, 0))
+ pipeline.addLast(ByteArrayDecoder())
+ pipeline.addLast(ByteArrayEncoder())
+ pipeline.addLast(SocketChannelHandle(listener))
+ }
+ })
+ try {
+ //连接监听
+ channelFuture = bootstrap.connect(host, port)
+ .addListener(object : ChannelFutureListener {
+ override fun operationComplete(channelFuture: ChannelFuture) {
+ if (channelFuture.isSuccess) {
+ connectStatus = true
+ channel = channelFuture.channel()
+ } else {
+ Log.e(kTag, "operationComplete: 连接失败")
+ connectStatus = false
+ }
+ isConnecting = false
+ }
+ }).sync()
+ // 等待连接关闭
+ channelFuture.channel().closeFuture().sync()
+ } catch (e: Exception) {
+ e.printStackTrace()
+ } finally {
+ connectStatus = false
+ listener?.onServiceStatusConnectChanged(ISocketListener.STATUS_CONNECT_CLOSED) //STATUS_CONNECT_CLOSED 这我自己定义的 接口标识
+ if (null != channelFuture) {
+ if (channelFuture.channel() != null && channelFuture.channel().isOpen) {
+ channelFuture.channel().close()
+ }
+ }
+ nioEventLoopGroup?.shutdownGracefully()
+ reconnect() //重新连接
+ }
+ }
+ }
+ }
+
+ //断开连接
+ fun disconnect() {
+ Log.d(kTag, "disconnect ===> 断开连接")
+ isNeedReconnect = false
+ nioEventLoopGroup?.shutdownGracefully()
+ }
+
+ //重新连接
+ private fun reconnect() {
+ if (isNeedReconnect && reconnectNum > 0 && !connectStatus) {
+ reconnectNum--
+ SystemClock.sleep(reconnectIntervalTime)
+ if (isNeedReconnect && reconnectNum > 0 && !connectStatus) {
+ Log.d(kTag, "reconnect ===> 重新连接")
+ connectServer()
+ }
+ }
+ }
+
+ fun sendData(bytes: ByteArray) {
+ channel?.writeAndFlush(bytes)?.addListener(ChannelFutureListener { future ->
+ if (!future.isSuccess) {
+ future.channel().close()
+ nioEventLoopGroup!!.shutdownGracefully()
+ }
+ })
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/br/ktd/netty/tcp/SocketManager.kt b/app/src/main/java/com/casic/br/ktd/netty/tcp/SocketManager.kt
new file mode 100644
index 0000000..35980b9
--- /dev/null
+++ b/app/src/main/java/com/casic/br/ktd/netty/tcp/SocketManager.kt
@@ -0,0 +1,113 @@
+package com.casic.br.ktd.netty.tcp
+
+import android.util.Log
+import com.casic.br.ktd.base.BaseApplication
+import com.casic.br.ktd.extensions.covertAngleValue
+import com.casic.br.ktd.extensions.covertDataValue
+import com.casic.br.ktd.extensions.toUnsignedByteArray
+import com.casic.br.ktd.model.SensorDataModel
+import com.casic.br.ktd.utils.LocaleConstant
+import com.pengxh.kt.lite.extensions.toJson
+import com.pengxh.kt.lite.utils.BroadcastManager
+
+class SocketManager private constructor() : ISocketListener {
+
+ private val kTag = "SocketManager"
+ private var nettyClient: SocketClient = SocketClient()
+
+ companion object {
+ val instance: SocketManager by lazy(mode = LazyThreadSafetyMode.SYNCHRONIZED) { SocketManager() }
+ }
+
+ fun connectNetty(hostname: String, port: Int) {
+ Thread {
+ if (!nettyClient.connectStatus) {
+ nettyClient.setSocketListener(this)
+ nettyClient.connect(hostname, port)
+ } else {
+ nettyClient.disconnect()
+ }
+ }.start()
+ }
+
+ override fun onMessageResponse(data: ByteArray?) {
+// Log.d(kTag, "onMessageResponse ===> " + Arrays.toString(data))
+ /**
+ * 0xFF,0x01,
+ * 0x01,0x37,0xE6, 甲烷浓度值(数据码1* 65536 + 数据码2 * 256 + 数据码3)
+ * 0x00, 激光甲烷模块工作状态(00表示设备正常,01表示温控故障,02表示设备激光未打开)
+ * 0x00,0xB2,0x35, 激光强度值(数据码5* 65536 + 数据码6 * 256 + 数据码7)
+ * 0x0A,0x3D, 云台水平角度([数据码8 * 256 + 数据码9]/100,单位为°,精确到0.01)
+ * 0x05,0x6F, 云台垂直角度(首先计算Tangle=[数据码10 * 256 + 数据码11]/100,单位为°,精确到0.01。若Tangle在0~90范围内,则垂直角度值=Tangle;若Tangle在-1~-90范围内,则垂直角度值=Tangle-360)
+ * 0xC1
+ *
+ * [-1, 1, 1, 55, -26, 0, 0, -78, 53, 10, 61, 5, 111, -63]
+ * 甲烷浓度值为79638,计算为79638=0x01*65536+0x37*256+0xE6[0x01为数据码1,0x37为数据码2,0xE6为数据码3];
+ * 激光甲烷设备状态值为0,表示状态正常,[0x00为数据码4];
+ * 激光强度值为45621,计算为45621=0x00*65536+0xB2*256+0x35[0x00为数据码5,0xB2为数据码6,0x35为数据码7];
+ *
+ * =========================================================================================
+ * 实际数据(1800-1950左右)
+ * [-86, 1, 0, 7, 71, 0, 0, 62, -92, 57, 59, -118, -111, -64]
+ * */
+
+ if (data == null) {
+ return
+ }
+ val bytes = data.toUnsignedByteArray()
+ if (bytes.size == 14) {
+ val dataModel = SensorDataModel(0, "激光未打开", 0, 0.0, 0.0)
+
+ val methaneBytes = IntArray(3)
+ System.arraycopy(bytes, 2, methaneBytes, 0, 3)
+ dataModel.methane = methaneBytes.covertDataValue()
+
+ dataModel.methaneState = when (bytes[5]) {
+ 1 -> "温控故障"
+ 2 -> "激光未打开"
+ else -> "正常"
+ }
+
+ val laserBytes = IntArray(3)
+ System.arraycopy(bytes, 6, laserBytes, 0, 3)
+ dataModel.laser = laserBytes.covertDataValue()
+
+ /**
+ * 水平角度的实际范围为从水平零点开始,顺时针方向(从上往下看),0~360°
+ * 垂直角度的实际范围为从垂直零点开始,以向上为正,-90°~90°,控制精度为0.01°
+ * */
+ val horizontalBytes = IntArray(2)
+ System.arraycopy(bytes, 9, horizontalBytes, 0, 2)
+ dataModel.horizontal = horizontalBytes.covertAngleValue()
+
+ val verticalBytes = IntArray(2)
+ System.arraycopy(bytes, 11, verticalBytes, 0, 2)
+ dataModel.vertical = verticalBytes.covertAngleValue()
+
+ //{"horizontal":26.21,"laser":45621,"methane":79846,"methaneState":"正常","vertical":13.91}
+ BroadcastManager.obtainInstance(BaseApplication.get()).sendBroadcast(
+ LocaleConstant.ACTION_UPDATE_DATA, dataModel.toJson()
+ )
+ }
+ }
+
+ override fun onServiceStatusConnectChanged(statusCode: Byte) {
+ if (statusCode == ISocketListener.STATUS_CONNECT_SUCCESS) {
+ if (nettyClient.connectStatus) {
+ Log.d(kTag, "连接成功")
+ }
+ } else {
+ if (!nettyClient.connectStatus) {
+ Log.e(kTag, "onServiceStatusConnectChanged:$statusCode,连接断开,正在重连")
+ }
+ }
+ }
+
+ fun sendData(data: ByteArray) {
+ nettyClient.sendData(data)
+ }
+
+ fun close() {
+ nettyClient.disconnect()
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/br/ktd/netty/udp/UdpChannelInboundHandler.kt b/app/src/main/java/com/casic/br/ktd/netty/udp/UdpChannelInboundHandler.kt
new file mode 100644
index 0000000..4d6f97c
--- /dev/null
+++ b/app/src/main/java/com/casic/br/ktd/netty/udp/UdpChannelInboundHandler.kt
@@ -0,0 +1,36 @@
+package com.casic.br.ktd.netty.udp
+
+import io.netty.channel.ChannelHandlerContext
+import io.netty.channel.SimpleChannelInboundHandler
+import io.netty.channel.socket.DatagramPacket
+import io.netty.util.CharsetUtil
+
+
+abstract class UdpChannelInboundHandler : SimpleChannelInboundHandler() {
+
+ private var handlerContext: ChannelHandlerContext? = null
+
+ override fun channelActive(ctx: ChannelHandlerContext?) {
+ super.channelActive(ctx)
+ handlerContext = ctx
+ }
+
+ override fun channelInactive(ctx: ChannelHandlerContext?) {
+ super.channelInactive(ctx)
+ handlerContext?.close()
+ }
+
+ fun sendDatagramPacket(obj: Any) {
+ handlerContext?.writeAndFlush(obj)
+ }
+
+ fun releasePort() {
+ handlerContext?.close()
+ }
+
+ override fun channelRead0(ctx: ChannelHandlerContext, datagramPacket: DatagramPacket) {
+ receivedMessage(datagramPacket.content().toString(CharsetUtil.UTF_8))
+ }
+
+ abstract fun receivedMessage(data: String)
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/br/ktd/netty/udp/UdpChannelInitializer.kt b/app/src/main/java/com/casic/br/ktd/netty/udp/UdpChannelInitializer.kt
new file mode 100644
index 0000000..416c5a1
--- /dev/null
+++ b/app/src/main/java/com/casic/br/ktd/netty/udp/UdpChannelInitializer.kt
@@ -0,0 +1,17 @@
+package com.casic.br.ktd.netty.udp
+
+import io.netty.channel.ChannelInitializer
+import io.netty.channel.socket.DatagramChannel
+import io.netty.handler.timeout.IdleStateHandler
+
+
+open class UdpChannelInitializer(private val handler: UdpChannelInboundHandler) :
+ ChannelInitializer() {
+
+ override fun initChannel(datagramChannel: DatagramChannel) {
+ val pipeline = datagramChannel.pipeline()
+ pipeline.addLast(
+ IdleStateHandler(12, 15, 0)
+ ).addLast(handler)
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/br/ktd/netty/udp/UdpClient.kt b/app/src/main/java/com/casic/br/ktd/netty/udp/UdpClient.kt
new file mode 100644
index 0000000..3893afa
--- /dev/null
+++ b/app/src/main/java/com/casic/br/ktd/netty/udp/UdpClient.kt
@@ -0,0 +1,103 @@
+package com.casic.br.ktd.netty.udp
+
+import com.casic.br.ktd.utils.LocaleConstant
+import com.pengxh.kt.lite.utils.SaveKeyValues
+import io.netty.bootstrap.Bootstrap
+import io.netty.buffer.ByteBuf
+import io.netty.buffer.Unpooled
+import io.netty.channel.ChannelOption
+import io.netty.channel.nio.NioEventLoopGroup
+import io.netty.channel.socket.DatagramPacket
+import io.netty.channel.socket.nio.NioDatagramChannel
+import io.netty.util.CharsetUtil
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.launch
+import kotlinx.coroutines.withContext
+import java.net.InetSocketAddress
+import java.util.concurrent.ExecutorService
+import java.util.concurrent.Executors
+
+
+class UdpClient : UdpChannelInboundHandler(), Runnable {
+
+ private val bootStrap by lazy { Bootstrap() }
+ private val eventLoopGroup by lazy { NioEventLoopGroup() }
+ private val udpChannelInitializer by lazy { UdpChannelInitializer(this) }
+ private var executorService: ExecutorService
+
+ init {
+ bootStrap.group(eventLoopGroup)
+ bootStrap.channel(NioDatagramChannel::class.java)
+ .option(ChannelOption.SO_RCVBUF, 1024)
+ .option(ChannelOption.SO_SNDBUF, 1024)
+ bootStrap.handler(udpChannelInitializer)
+
+ executorService = Executors.newSingleThreadExecutor()
+ executorService.execute(this)
+ }
+
+ override fun run() {
+ try {
+ val channelFuture = bootStrap.bind(LocaleConstant.LOCATION_UDP_PORT).sync()
+ channelFuture.channel().closeFuture().sync()
+ } catch (e: InterruptedException) {
+ e.printStackTrace()
+ } finally {
+ eventLoopGroup.shutdownGracefully()
+ }
+ }
+
+ fun send(value: String) {
+ CoroutineScope(Dispatchers.Main).launch {
+ withContext(Dispatchers.IO) {
+ val host = SaveKeyValues.getValue(
+ LocaleConstant.LOCATION_UDP_SERVER, "192.168.149.213"
+ ).toString()
+ val datagramPacket = DatagramPacket(
+ Unpooled.copiedBuffer(value, CharsetUtil.UTF_8),
+ InetSocketAddress(host, LocaleConstant.LOCATION_UDP_PORT)
+ )
+ sendDatagramPacket(datagramPacket)
+ }
+ }
+ }
+
+ fun send(value: ByteArray) {
+ CoroutineScope(Dispatchers.Main).launch {
+ withContext(Dispatchers.IO) {
+ val host = SaveKeyValues.getValue(
+ LocaleConstant.LOCATION_UDP_SERVER, "192.168.149.213"
+ ).toString()
+ val datagramPacket = DatagramPacket(
+ Unpooled.copiedBuffer(value),
+ InetSocketAddress(host, LocaleConstant.LOCATION_UDP_PORT)
+ )
+ sendDatagramPacket(datagramPacket)
+ }
+ }
+ }
+
+ fun send(value: ByteBuf) {
+ CoroutineScope(Dispatchers.Main).launch {
+ withContext(Dispatchers.IO) {
+ val host = SaveKeyValues.getValue(
+ LocaleConstant.LOCATION_UDP_SERVER, "192.168.149.213"
+ ).toString()
+ val datagramPacket = DatagramPacket(
+ Unpooled.copiedBuffer(value),
+ InetSocketAddress(host, LocaleConstant.LOCATION_UDP_PORT)
+ )
+ sendDatagramPacket(datagramPacket)
+ }
+ }
+ }
+
+ fun release() {
+ releasePort()
+ }
+
+ override fun receivedMessage(data: String) {
+
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/br/ktd/utils/LocaleConstant.kt b/app/src/main/java/com/casic/br/ktd/utils/LocaleConstant.kt
index 0dd119e..4c675df 100644
--- a/app/src/main/java/com/casic/br/ktd/utils/LocaleConstant.kt
+++ b/app/src/main/java/com/casic/br/ktd/utils/LocaleConstant.kt
@@ -50,6 +50,10 @@
const val DEV_NET_IP = "192.168.1.21"
const val DEV_NET_PORT = "8000"
+ //位置信息UDP端口
+ const val LOCATION_UDP_SERVER = "udpServer"
+ const val LOCATION_UDP_PORT = 7777
+
//BroadcastReceiver Action
const val ACTION_UPDATE_DATA = "update"
diff --git a/app/src/main/java/com/casic/br/ktd/utils/LocationHelper.kt b/app/src/main/java/com/casic/br/ktd/utils/LocationHelper.kt
index 8e31d3f..df6adb5 100644
--- a/app/src/main/java/com/casic/br/ktd/utils/LocationHelper.kt
+++ b/app/src/main/java/com/casic/br/ktd/utils/LocationHelper.kt
@@ -7,19 +7,40 @@
import android.location.LocationListener
import android.location.LocationManager
import android.os.Bundle
+import android.util.Log
import androidx.core.app.ActivityCompat
+import com.amap.api.location.AMapLocation
+import com.amap.api.location.AMapLocationClient
+import com.amap.api.location.AMapLocationClientOption
-object LocationHelper {
- fun obtainCurrentLocation(context: Context, listener: ILocationListener) {
+class LocationHelper private constructor() {
+
+ private val kTag = "LocationHelper"
+
+ companion object {
+ //Kotlin委托模式双重锁单例
+ val get: LocationHelper by lazy(mode = LazyThreadSafetyMode.SYNCHRONIZED) {
+ LocationHelper()
+ }
+ }
+
+ private val locationOption = AMapLocationClientOption()
+ private lateinit var locationClient: AMapLocationClient
+
+ init {
+ //设置定位模式为高精度模式,AMapLocationMode.Battery_Saving为低功耗模式,AMapLocationMode.Device_Sensors是仅设备模式
+ locationOption.locationMode = AMapLocationClientOption.AMapLocationMode.Hight_Accuracy
+ locationOption.isNeedAddress = true //设置是否返回地址信息(默认返回地址信息)
+ locationOption.isLocationCacheEnable = true //可选,设置是否使用缓存定位,默认为true
+ }
+
+ fun obtainLocation(context: Context, listener: ILocationListener) {
if (ActivityCompat.checkSelfPermission(
- context,
- Manifest.permission.ACCESS_LOCATION_EXTRA_COMMANDS
+ context, Manifest.permission.ACCESS_LOCATION_EXTRA_COMMANDS
) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(
- context,
- Manifest.permission.ACCESS_FINE_LOCATION
+ context, Manifest.permission.ACCESS_FINE_LOCATION
) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(
- context,
- Manifest.permission.ACCESS_COARSE_LOCATION
+ context, Manifest.permission.ACCESS_COARSE_LOCATION
) != PackageManager.PERMISSION_GRANTED
) {
return
@@ -38,7 +59,37 @@
})
}
+ /**
+ * 高德sdk定位
+ */
+ fun obtainLocationByGD(context: Context?, listener: ILocationListener) {
+ locationClient = AMapLocationClient(context)
+ //给定位客户端对象设置定位参数
+ locationClient.setLocationOption(locationOption)
+ //设置定位回调监听
+ locationClient.setLocationListener { aMapLocation ->
+ if (aMapLocation != null) {
+ if (aMapLocation.errorCode == 0) {
+ listener.onAMapLocationGet(aMapLocation)
+ } else {
+ Log.e(
+ kTag,
+ "ErrCode: ${aMapLocation.errorCode}, errInfo: ${aMapLocation.errorInfo}"
+ )
+ }
+ }
+ }
+ //启动定位
+ locationClient.startLocation()
+ }
+
+ fun stopLocation() {
+ locationClient.stopLocation()//停止定位
+ }
+
interface ILocationListener {
- fun onLocationGet(location: Location?) //高德定位数据
+ fun onLocationGet(location: Location?) //GPS定位数据
+
+ fun onAMapLocationGet(aMapLocation: AMapLocation?) //高德定位数据
}
}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/br/ktd/view/InspectionActivity.kt b/app/src/main/java/com/casic/br/ktd/view/InspectionActivity.kt
index 02c47f8..c893092 100644
--- a/app/src/main/java/com/casic/br/ktd/view/InspectionActivity.kt
+++ b/app/src/main/java/com/casic/br/ktd/view/InspectionActivity.kt
@@ -15,16 +15,21 @@
import android.view.SurfaceHolder
import android.view.View
import android.widget.AdapterView
-import com.amap.api.maps.*
+import com.amap.api.location.AMapLocation
+import com.amap.api.maps.AMap
+import com.amap.api.maps.CameraUpdateFactory
+import com.amap.api.maps.UiSettings
import com.amap.api.maps.model.CameraPosition
import com.amap.api.maps.model.LatLng
+import com.amap.api.maps.model.MyLocationStyle
import com.amap.api.maps.model.PolylineOptions
import com.casic.br.ktd.R
import com.casic.br.ktd.extensions.*
import com.casic.br.ktd.model.ChartPointModel
import com.casic.br.ktd.model.RouteModel
import com.casic.br.ktd.model.SensorDataModel
-import com.casic.br.ktd.netty.SocketManager
+import com.casic.br.ktd.netty.tcp.SocketManager
+import com.casic.br.ktd.netty.udp.UdpClient
import com.casic.br.ktd.utils.LocaleConstant
import com.casic.br.ktd.utils.LocationHelper
import com.casic.br.ktd.widgets.AlertControlDialog
@@ -49,6 +54,10 @@
import hcnetsdk.sdkhub.MessageCodeHub
import hcnetsdk.sdkhub.SDKGuider
import kotlinx.android.synthetic.main.activity_inspection.*
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.launch
+import kotlinx.coroutines.withContext
import java.text.DecimalFormat
import java.text.SimpleDateFormat
import java.util.*
@@ -60,10 +69,10 @@
private val hkSDK by lazy { HCNetSDK.getInstance() }
private val timeFormat by lazy { SimpleDateFormat("yyyyMMddHHmmss", Locale.CHINA) }
private val latlngs = LinkedList()
- private val speedTimer by lazy { Timer() }
private val tcpTimer by lazy { Timer() }
private val decimalFormat by lazy { DecimalFormat("##0.0") }
private val gson by lazy { Gson() }
+ private val udpClient by lazy { UdpClient() }
private var isLoginSuccess = false
private var previewHandle = -1
private var selectChannel = -1
@@ -103,28 +112,32 @@
private lateinit var aMap: AMap
private lateinit var uiSettings: UiSettings
+ /**
+ * 协程配置云台设备,缓解新进页面较卡的问题
+ * */
private fun setDeviceConfig() {
- Log.d(kTag, "setDeviceConfig => 配置设备IP和端口")
- val device = SDKGuider.sdkGuider.devManageGuider.DeviceItem()
- device.m_szDevName = ""
- device.m_struNetInfo = SDKGuider.sdkGuider.devManageGuider.DevNetInfo(
- LocaleConstant.HK_NET_IP,
- LocaleConstant.HK_NET_PORT,
- LocaleConstant.HK_NET_USERNAME,
- LocaleConstant.HK_NET_PASSWORD
- )
- if (device.m_szDevName.isEmpty()) {
- device.m_szDevName = device.m_struNetInfo.m_szIp
- }
- isLoginSuccess = if (
- SDKGuider.sdkGuider.devManageGuider.login_v40_jna(
- device.m_szDevName, device.m_struNetInfo
- )
- ) {
- "设备连接成功".show(this)
- true
- } else {
- false
+ CoroutineScope(Dispatchers.Main).launch {
+ isLoginSuccess = withContext(Dispatchers.IO) {
+ Log.d(kTag, "setDeviceConfig => 配置设备IP和端口")
+ val device = SDKGuider.sdkGuider.devManageGuider.DeviceItem()
+ device.m_szDevName = ""
+ device.m_struNetInfo = SDKGuider.sdkGuider.devManageGuider.DevNetInfo(
+ LocaleConstant.HK_NET_IP,
+ LocaleConstant.HK_NET_PORT,
+ LocaleConstant.HK_NET_USERNAME,
+ LocaleConstant.HK_NET_PASSWORD
+ )
+ if (device.m_szDevName.isEmpty()) {
+ device.m_szDevName = device.m_struNetInfo.m_szIp
+ }
+
+ SDKGuider.sdkGuider.devManageGuider.login_v40_jna(
+ device.m_szDevName, device.m_struNetInfo
+ )
+ }
+ if (isLoginSuccess) {
+ "设备连接成功".show(context)
+ }
}
}
@@ -148,17 +161,74 @@
/**
* 手机GPS定位
* */
- val converter = CoordinateConverter(this)
- LocationHelper.obtainCurrentLocation(this, object : LocationHelper.ILocationListener {
+// val converter = CoordinateConverter(this)
+// LocationHelper.get.obtainLocation(this, object : LocationHelper.ILocationListener {
+// override fun onLocationGet(location: Location?) {
+// if (location == null) {
+// "当前信号弱,无法定位".show(context)
+// return
+// }
+//
+// //发送位置信息给UDP服务端
+// udpClient.send("${location.longitude}, ${location.latitude}")
+// Log.d(kTag, "onLocationGet => 速度:${location.speed}")
+//
+// //WGS-84要转为高德坐标系
+// converter.from(CoordinateConverter.CoordType.GPS)
+// converter.coord(LatLng(location.latitude, location.longitude))
+// val latLng = converter.convert()
+// latlngs.add(latLng)
+//
+// //移动到指定经纬度
+// val cameraPosition = CameraPosition(latLng, 13f, 0f, 0f)
+// val cameraUpdate = CameraUpdateFactory.newCameraPosition(cameraPosition)
+// aMap.animateCamera(cameraUpdate, 1500, null)
+//
+// //绘制线
+// aMap.addPolyline(
+// PolylineOptions().addAll(latlngs).width(12f).color(Color.RED)
+// )
+//
+// if (isStartInspect) {
+// val route = LinkedList()
+// latlngs.forEach {
+// route.add(RouteModel(it.latitude, it.longitude))
+// }
+// }
+// }
+//
+// override fun onAMapLocationGet(aMapLocation: AMapLocation?) {
+//
+// }
+// })
+
+ /**
+ * 高德定位
+ * */
+ LocationHelper.get.obtainLocationByGD(this, object : LocationHelper.ILocationListener {
override fun onLocationGet(location: Location?) {
- if (location == null) {
+
+ }
+
+ override fun onAMapLocationGet(aMapLocation: AMapLocation?) {
+ if (aMapLocation == null) {
"当前信号弱,无法定位".show(context)
return
}
+
+ //发送位置信息给UDP服务端
+ udpClient.send(
+ "${aMapLocation.longitude}, ${aMapLocation.latitude}, ${
+ System.currentTimeMillis().timestampToCompleteDate()
+ }"
+ )
+ //速度 转为 km/h
+ Log.d(kTag, "onLocationGet => 速度:${aMapLocation.speed}")
+ speed = decimalFormat.format(aMapLocation.speed * 3.6).toFloat()
+ carSpeedView.text = String.format("${speed}Km/h")
+
//WGS-84要转为高德坐标系
- converter.from(CoordinateConverter.CoordType.GPS)
- converter.coord(LatLng(location.latitude, location.longitude))
- val latLng = converter.convert()
+ val latLng = LatLng(aMapLocation.latitude, aMapLocation.longitude)
latlngs.add(latLng)
//移动到指定经纬度
@@ -168,7 +238,7 @@
//绘制线
aMap.addPolyline(
- PolylineOptions().addAll(latlngs).width(12f).color(Color.RED)
+ PolylineOptions().addAll(latlngs).width(10f).color(Color.RED)
)
if (isStartInspect) {
@@ -181,27 +251,6 @@
})
/**
- * 计算速度,微分原理,3s计算一次速度
- * */
- speedTimer.schedule(object : TimerTask() {
- override fun run() {
- //经纬度链表数据小于2,无法计算速度,默认为0
- speed = if (latlngs.size < 2) 0.0f else {
- val temp = AMapUtils.calculateLineDistance(
- latlngs.last(), latlngs[latlngs.size - 2]
- ) / 3
- //转为 km/h
- decimalFormat.format(temp * 3.6).toFloat()
- }
-
- //切换到UI线程更新界面数据
- runOnUiThread {
- carSpeedView.text = String.format("${speed}Km/h")
- }
- }
- }, 0, 3000)
-
- /**
* TCP初始化
* ***/
SocketManager.instance.connectNetty(
@@ -632,6 +681,8 @@
stopPreview()
BroadcastManager.obtainInstance(this).destroy(LocaleConstant.ACTION_UPDATE_DATA)
mapView.onDestroy()
+ udpClient.release()
+ LocationHelper.get.stopLocation()
}
override fun handleMessage(msg: Message): Boolean {
@@ -716,38 +767,13 @@
uiSettings.isZoomControlsEnabled = true
uiSettings.isTiltGesturesEnabled = false//不许地图随手势倾斜角度
-// val locationStyle = MyLocationStyle()
-// locationStyle.interval(2000)
-// locationStyle.showMyLocation(true)
-// locationStyle.myLocationType(MyLocationStyle.LOCATION_TYPE_LOCATION_ROTATE)
-// aMap.myLocationStyle = locationStyle
-// aMap.isMyLocationEnabled = true
-// aMap.animateCamera(CameraUpdateFactory.zoomTo(13f))
-// aMap.setOnMyLocationChangeListener(this)
+ //显示定位小蓝点
+ val locationStyle = MyLocationStyle()
+ locationStyle.showMyLocation(true)//设置是否显示定位小蓝点
+ aMap.myLocationStyle = locationStyle
+ aMap.isMyLocationEnabled = true
}
-// override fun onMyLocationChange(aMapLocation: Location?) {
-// if (aMapLocation == null) {
-// "当前信号弱,无法定位".show(context)
-// return
-// }
-// val latitude = aMapLocation.latitude
-// val longitude = aMapLocation.longitude
-// latlngs.add(LatLng(latitude, longitude))
-//
-// //绘制线
-// aMap.addPolyline(
-// PolylineOptions().addAll(latlngs).width(15f).color(Color.RED)
-// )
-//
-// if (isStartInspect) {
-// val route = LinkedList()
-// latlngs.forEach {
-// route.add(RouteModel(it.latitude, it.longitude))
-// }
-// }
-// }
-
/***以下是地图生命周期管理************************************************************************/
override fun onResume() {
diff --git a/app/src/main/res/layout/fragment_alarm.xml b/app/src/main/res/layout/fragment_alarm.xml
index a3ebc88..929529f 100644
--- a/app/src/main/res/layout/fragment_alarm.xml
+++ b/app/src/main/res/layout/fragment_alarm.xml
@@ -31,7 +31,7 @@
diff --git a/app/src/main/res/layout/fragment_task.xml b/app/src/main/res/layout/fragment_task.xml
index 35cb1a3..58d852e 100644
--- a/app/src/main/res/layout/fragment_task.xml
+++ b/app/src/main/res/layout/fragment_task.xml
@@ -31,7 +31,7 @@
diff --git a/app/src/main/res/mipmap-hdpi/end.png b/app/src/main/res/mipmap-hdpi/end.png
new file mode 100644
index 0000000..f31385b
--- /dev/null
+++ b/app/src/main/res/mipmap-hdpi/end.png
Binary files differ
diff --git a/app/src/main/res/mipmap-hdpi/start.png b/app/src/main/res/mipmap-hdpi/start.png
new file mode 100644
index 0000000..04839dc
--- /dev/null
+++ b/app/src/main/res/mipmap-hdpi/start.png
Binary files differ
diff --git a/app/src/main/res/mipmap-mdpi/end.png b/app/src/main/res/mipmap-mdpi/end.png
new file mode 100644
index 0000000..f31385b
--- /dev/null
+++ b/app/src/main/res/mipmap-mdpi/end.png
Binary files differ
diff --git a/app/src/main/res/mipmap-mdpi/start.png b/app/src/main/res/mipmap-mdpi/start.png
new file mode 100644
index 0000000..04839dc
--- /dev/null
+++ b/app/src/main/res/mipmap-mdpi/start.png
Binary files differ
diff --git a/app/src/main/res/mipmap-xhdpi/end.png b/app/src/main/res/mipmap-xhdpi/end.png
new file mode 100644
index 0000000..f31385b
--- /dev/null
+++ b/app/src/main/res/mipmap-xhdpi/end.png
Binary files differ
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index e822df6..d72c1a5 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -7,6 +7,9 @@
+
+
+
@@ -46,5 +49,8 @@
+
+
+
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/br/ktd/base/KotlinBaseFragment.kt b/app/src/main/java/com/casic/br/ktd/base/KotlinBaseFragment.kt
new file mode 100644
index 0000000..2dac61c
--- /dev/null
+++ b/app/src/main/java/com/casic/br/ktd/base/KotlinBaseFragment.kt
@@ -0,0 +1,51 @@
+package com.casic.br.ktd.base
+
+import android.os.Bundle
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import androidx.annotation.LayoutRes
+import androidx.fragment.app.Fragment
+
+abstract class KotlinBaseFragment : Fragment() {
+
+ lateinit var bv: View
+
+ override fun onCreateView(
+ inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?
+ ): View? {
+ bv = inflater.inflate(initLayoutRes(), container, false)
+ initView(savedInstanceState)
+ setupTopBarLayout()
+ return bv
+ }
+
+ override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
+ super.onViewCreated(view, savedInstanceState)
+ observeRequestState()
+ initEvent()
+ }
+
+ @LayoutRes
+ abstract fun initLayoutRes(): Int
+
+ /**
+ * 沉浸式状态栏
+ */
+ abstract fun setupTopBarLayout()
+
+ /**
+ * 初始化布局以及控件
+ */
+ abstract fun initView(savedInstanceState: Bundle?)
+
+ /**
+ * 网络请求状态监听
+ */
+ abstract fun observeRequestState()
+
+ /**
+ * 业务逻辑,按钮等事件
+ */
+ abstract fun initEvent()
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/br/ktd/fragment/AlarmPageFragment.kt b/app/src/main/java/com/casic/br/ktd/fragment/AlarmPageFragment.kt
index 6c98a3b..9418169 100644
--- a/app/src/main/java/com/casic/br/ktd/fragment/AlarmPageFragment.kt
+++ b/app/src/main/java/com/casic/br/ktd/fragment/AlarmPageFragment.kt
@@ -2,28 +2,29 @@
import android.os.Bundle
import com.casic.br.ktd.R
+import com.casic.br.ktd.base.KotlinBaseFragment
import com.casic.br.ktd.widgets.DateRangeActionSheet
-import com.pengxh.kt.lite.base.KotlinBaseFragment
import kotlinx.android.synthetic.main.fragment_alarm.view.*
class AlarmPageFragment : KotlinBaseFragment() {
- override fun initData(savedInstanceState: Bundle?) {
+
+ override fun initView(savedInstanceState: Bundle?) {
}
override fun initEvent() {
- baseView.calendarView.setOnClickListener {
+ bv.calendarView.setOnClickListener {
DateRangeActionSheet.Builder().setContext(requireContext())
.setOnActionSheetListener(object :
DateRangeActionSheet.OnDateRangeSelectedListener {
override fun onDateRangeSelected(startDate: String, endDate: String) {
- baseView.selectedDateView.text = "$startDate ~ $endDate"
+ bv.selectedDateView.text = "$startDate ~ $endDate"
}
}).build().show()
}
}
- override fun initLayoutView(): Int = R.layout.fragment_alarm
+ override fun initLayoutRes(): Int = R.layout.fragment_alarm
override fun observeRequestState() {
diff --git a/app/src/main/java/com/casic/br/ktd/fragment/HomePageFragment.kt b/app/src/main/java/com/casic/br/ktd/fragment/HomePageFragment.kt
index 9961935..f3eba5c 100644
--- a/app/src/main/java/com/casic/br/ktd/fragment/HomePageFragment.kt
+++ b/app/src/main/java/com/casic/br/ktd/fragment/HomePageFragment.kt
@@ -1,32 +1,62 @@
package com.casic.br.ktd.fragment
+import android.graphics.Color
import android.os.Bundle
import com.amap.api.maps.AMap
import com.amap.api.maps.AMapOptions
+import com.amap.api.maps.CameraUpdateFactory
+import com.amap.api.maps.model.*
import com.casic.br.ktd.R
-import com.pengxh.kt.lite.base.KotlinBaseFragment
+import com.casic.br.ktd.base.KotlinBaseFragment
import kotlinx.android.synthetic.main.fragment_home.view.*
class HomePageFragment : KotlinBaseFragment() {
private lateinit var aMap: AMap
- override fun initData(savedInstanceState: Bundle?) {
- baseView.mapView.onCreate(savedInstanceState)
- aMap = baseView.mapView.map
+ override fun initView(savedInstanceState: Bundle?) {
+ bv.mapView.onCreate(savedInstanceState)
+ aMap = bv.mapView.map
val uiSettings = aMap.uiSettings
uiSettings.isCompassEnabled = true
- uiSettings.isMyLocationButtonEnabled = true
+ uiSettings.isMyLocationButtonEnabled = false
uiSettings.isScaleControlsEnabled = true
uiSettings.zoomPosition = AMapOptions.ZOOM_POSITION_RIGHT_CENTER
uiSettings.isRotateGesturesEnabled = false//不许地图随手势旋转角度
}
override fun initEvent() {
-
+ //移动到巡检起始经纬度
+ val cameraPosition = CameraPosition(LatLng(39.914199, 116.265785), 16f, 0f, 0f)
+ val cameraUpdate = CameraUpdateFactory.newCameraPosition(cameraPosition)
+ aMap.animateCamera(cameraUpdate, 1500, null)
+ //设置起点
+ addMarker(LatLng(39.914885, 116.272312), R.mipmap.start)
+ //设置终点
+ addMarker(LatLng(39.914716, 116.265097), R.mipmap.end)
+ //瞄点画线
+ val latLngPoints = ArrayList()
+ latLngPoints.add(LatLng(39.914885, 116.272312))
+ latLngPoints.add(LatLng(39.915148, 116.272312))
+ latLngPoints.add(LatLng(39.915399, 116.272302))
+ latLngPoints.add(LatLng(39.915436, 116.271787))
+ latLngPoints.add(LatLng(39.915477, 116.270886))
+ latLngPoints.add(LatLng(39.915477, 116.269968))
+ latLngPoints.add(LatLng(39.915469, 116.269544))
+ latLngPoints.add(LatLng(39.915481, 116.269196))
+ latLngPoints.add(LatLng(39.915452, 116.268472))
+ latLngPoints.add(LatLng(39.915444, 116.267722))
+ latLngPoints.add(LatLng(39.915415, 116.266755))
+ latLngPoints.add(LatLng(39.915403, 116.266165))
+ latLngPoints.add(LatLng(39.915395, 116.265703))
+ latLngPoints.add(LatLng(39.915366, 116.265119))
+ latLngPoints.add(LatLng(39.914716, 116.265097))
+ aMap.addPolyline(
+ PolylineOptions().addAll(latLngPoints).width(10.toFloat()).color(Color.RED)
+ )
}
- override fun initLayoutView(): Int = R.layout.fragment_home
+ override fun initLayoutRes(): Int = R.layout.fragment_home
override fun observeRequestState() {
@@ -36,25 +66,32 @@
}
+ private fun addMarker(point: LatLng, res: Int) {
+ val markerOption = MarkerOptions()
+ markerOption.position(point)
+ markerOption.icon(BitmapDescriptorFactory.fromResource(res))
+ aMap.addMarker(markerOption)
+ }
+
/***以下是地图生命周期管理************************************************************************/
override fun onResume() {
super.onResume()
- baseView.mapView.onResume()
+ bv.mapView.onResume()
}
override fun onPause() {
- baseView.mapView.onPause()
super.onPause()
+ bv.mapView.onPause()
}
override fun onSaveInstanceState(outState: Bundle) {
super.onSaveInstanceState(outState)
- baseView.mapView.onSaveInstanceState(outState)
+ bv.mapView.onSaveInstanceState(outState)
}
override fun onDestroy() {
- baseView.mapView.onDestroy()
super.onDestroy()
+ bv.mapView.onDestroy()
}
}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/br/ktd/fragment/MinePageFragment.kt b/app/src/main/java/com/casic/br/ktd/fragment/MinePageFragment.kt
index 90313ac..3212794 100644
--- a/app/src/main/java/com/casic/br/ktd/fragment/MinePageFragment.kt
+++ b/app/src/main/java/com/casic/br/ktd/fragment/MinePageFragment.kt
@@ -2,10 +2,11 @@
import android.os.Bundle
import com.casic.br.ktd.R
-import com.pengxh.kt.lite.base.KotlinBaseFragment
+import com.casic.br.ktd.base.KotlinBaseFragment
class MinePageFragment : KotlinBaseFragment() {
- override fun initData(savedInstanceState: Bundle?) {
+
+ override fun initView(savedInstanceState: Bundle?) {
}
@@ -13,7 +14,7 @@
}
- override fun initLayoutView(): Int = R.layout.fragment_mine
+ override fun initLayoutRes(): Int = R.layout.fragment_mine
override fun observeRequestState() {
diff --git a/app/src/main/java/com/casic/br/ktd/fragment/TaskPageFragment.kt b/app/src/main/java/com/casic/br/ktd/fragment/TaskPageFragment.kt
index 8f6abf0..6b82a54 100644
--- a/app/src/main/java/com/casic/br/ktd/fragment/TaskPageFragment.kt
+++ b/app/src/main/java/com/casic/br/ktd/fragment/TaskPageFragment.kt
@@ -8,6 +8,7 @@
import androidx.recyclerview.widget.RecyclerView
import com.casic.br.ktd.R
import com.casic.br.ktd.adapter.TaskAdapter
+import com.casic.br.ktd.base.KotlinBaseFragment
import com.casic.br.ktd.holder.SwipeViewHolder
import com.casic.br.ktd.model.TaskListModel
import com.casic.br.ktd.view.InspectionActivity
@@ -15,7 +16,6 @@
import com.casic.br.ktd.widgets.AlertControlDialog
import com.casic.br.ktd.widgets.AlertInputDialog
import com.casic.br.ktd.widgets.DateRangeActionSheet
-import com.pengxh.kt.lite.base.KotlinBaseFragment
import com.pengxh.kt.lite.extensions.navigatePageTo
import com.pengxh.kt.lite.extensions.show
import com.pengxh.kt.lite.utils.WeakReferenceHandler
@@ -36,7 +36,7 @@
private var startTime = ""
private var endTime = ""
- override fun initData(savedInstanceState: Bundle?) {
+ override fun initView(savedInstanceState: Bundle?) {
weakReferenceHandler = WeakReferenceHandler(this)
taskViewModel = ViewModelProvider(this)[TaskViewModel::class.java]
taskViewModel.taskList.observe(this) {
@@ -45,7 +45,7 @@
when {
isRefresh -> {
taskAdapter.setRefreshData(dataRows)
- baseView.taskLayout.finishRefresh()
+ bv.taskLayout.finishRefresh()
isRefresh = false
}
isLoadMore -> {
@@ -53,7 +53,7 @@
"到底了,别拉了".show(requireContext())
}
taskAdapter.setLoadMoreData(dataRows)
- baseView.taskLayout.finishLoadMore()
+ bv.taskLayout.finishLoadMore()
isLoadMore = false
}
else -> {
@@ -76,9 +76,9 @@
when (msg.what) {
2023070501 -> {
if (dataBeans.size == 0) {
- baseView.emptyLayout.visibility = View.VISIBLE
+ bv.emptyLayout.visibility = View.VISIBLE
} else {
- baseView.emptyLayout.visibility = View.GONE
+ bv.emptyLayout.visibility = View.GONE
taskAdapter = object : TaskAdapter(
requireContext(), R.layout.item_task_rv_l, dataBeans
) {
@@ -97,8 +97,8 @@
}
}
//绑定侧滑事件
- swipeAction.attachToRecyclerView(baseView.taskRecyclerView)
- baseView.taskRecyclerView.adapter = taskAdapter
+ swipeAction.attachToRecyclerView(bv.taskRecyclerView)
+ bv.taskRecyclerView.adapter = taskAdapter
taskAdapter.setOnItemCheckedListener(object :
TaskAdapter.OnItemCheckedListener {
override fun onItemChecked(items: ArrayList) {
@@ -168,7 +168,7 @@
override fun initEvent() {
- baseView.calendarView.setOnClickListener {
+ bv.calendarView.setOnClickListener {
DateRangeActionSheet.Builder().setContext(requireContext())
.setOnActionSheetListener(object :
DateRangeActionSheet.OnDateRangeSelectedListener {
@@ -177,12 +177,12 @@
endTime = endDate
//显示
- baseView.selectedDateView.text = "$startDate ~ $endDate"
+ bv.selectedDateView.text = "$startDate ~ $endDate"
}
}).build().show()
}
- baseView.addTaskButton.setOnClickListener {
+ bv.addTaskButton.setOnClickListener {
// AlertInputDialog.Builder()
// .setContext(requireContext())
// .setTitle("新建巡检任务")
@@ -200,11 +200,11 @@
requireContext().navigatePageTo()
}
- baseView.deleteTaskButton.setOnClickListener {
+ bv.deleteTaskButton.setOnClickListener {
selectedItems.size.toString().show(requireContext())
}
- baseView.taskSettingsButton.setOnClickListener {
+ bv.taskSettingsButton.setOnClickListener {
AlertInputDialog.Builder()
.setContext(requireContext())
.setTitle("设置阈值")
@@ -221,14 +221,14 @@
}).build().show()
}
- baseView.taskLayout.setOnRefreshListener {
+ bv.taskLayout.setOnRefreshListener {
isRefresh = true
//刷新之后页码重置
pageIndex = 1
getTaskList()
}
- baseView.taskLayout.setOnLoadMoreListener {
+ bv.taskLayout.setOnLoadMoreListener {
isLoadMore = true
pageIndex++
getTaskList()
@@ -239,13 +239,13 @@
taskViewModel.getTaskList(
startTime,
endTime,
- baseView.taskNameView.text.toString(),
- baseView.taskCodeView.text.toString(),
+ bv.taskNameView.text.toString(),
+ bv.taskCodeView.text.toString(),
pageIndex
)
}
- override fun initLayoutView(): Int = R.layout.fragment_task
+ override fun initLayoutRes(): Int = R.layout.fragment_task
override fun observeRequestState() {
diff --git a/app/src/main/java/com/casic/br/ktd/netty/ISocketListener.kt b/app/src/main/java/com/casic/br/ktd/netty/ISocketListener.kt
deleted file mode 100644
index dab98e1..0000000
--- a/app/src/main/java/com/casic/br/ktd/netty/ISocketListener.kt
+++ /dev/null
@@ -1,19 +0,0 @@
-package com.casic.br.ktd.netty
-
-interface ISocketListener {
- companion object {
- const val STATUS_CONNECT_SUCCESS: Byte = 1 //连接成功
- const val STATUS_CONNECT_CLOSED: Byte = 0 //关闭连接
- const val STATUS_CONNECT_ERROR: Byte = 0 //连接失败
- }
-
- /**
- * 当接收到系统消息
- */
- fun onMessageResponse(data: ByteArray?)
-
- /**
- * 当连接状态发生变化时调用
- */
- fun onServiceStatusConnectChanged(statusCode: Byte)
-}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/br/ktd/netty/SocketChannelHandle.kt b/app/src/main/java/com/casic/br/ktd/netty/SocketChannelHandle.kt
deleted file mode 100644
index 42eb310..0000000
--- a/app/src/main/java/com/casic/br/ktd/netty/SocketChannelHandle.kt
+++ /dev/null
@@ -1,51 +0,0 @@
-package com.casic.br.ktd.netty
-
-import android.util.Log
-import io.netty.channel.ChannelHandlerContext
-import io.netty.channel.SimpleChannelInboundHandler
-import io.netty.handler.timeout.IdleState
-import io.netty.handler.timeout.IdleStateEvent
-import java.nio.charset.StandardCharsets
-
-class SocketChannelHandle(private val listener: ISocketListener?) :
- SimpleChannelInboundHandler() {
-
- private val kTag = "SocketChannelHandle"
-
- override fun channelActive(ctx: ChannelHandlerContext) {
- super.channelActive(ctx)
- Log.d(kTag, "channelActive ===> 连接成功")
- listener?.onServiceStatusConnectChanged(ISocketListener.STATUS_CONNECT_SUCCESS)
- }
-
- override fun channelInactive(ctx: ChannelHandlerContext) {
- super.channelInactive(ctx)
- Log.e(kTag, "channelInactive: 连接断开")
- }
-
- override fun userEventTriggered(ctx: ChannelHandlerContext, evt: Any) {
- super.userEventTriggered(ctx, evt)
- if (evt is IdleStateEvent) {
- if (evt.state() == IdleState.WRITER_IDLE) {
- //写超时,此时可以发送心跳数据给服务器
- val temp = "FF"
- ctx.writeAndFlush(temp.toByteArray(StandardCharsets.UTF_8))
- } else if (evt.state() == IdleState.READER_IDLE) {
- //读超时,此时代表没有收到心跳返回可以关闭当前连接进行重连
- ctx.close()
- }
- }
- }
-
- override fun channelRead0(ctx: ChannelHandlerContext, data: ByteArray?) {
- listener?.onMessageResponse(data)
- }
-
- override fun exceptionCaught(ctx: ChannelHandlerContext, cause: Throwable) {
- super.exceptionCaught(ctx, cause)
- Log.d(kTag, "exceptionCaught ===> $cause")
- listener?.onServiceStatusConnectChanged(ISocketListener.STATUS_CONNECT_ERROR)
- cause.printStackTrace()
- ctx.close()
- }
-}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/br/ktd/netty/SocketClient.kt b/app/src/main/java/com/casic/br/ktd/netty/SocketClient.kt
deleted file mode 100644
index d05d335..0000000
--- a/app/src/main/java/com/casic/br/ktd/netty/SocketClient.kt
+++ /dev/null
@@ -1,153 +0,0 @@
-package com.casic.br.ktd.netty
-
-import android.os.SystemClock
-import android.util.Log
-import io.netty.bootstrap.Bootstrap
-import io.netty.channel.*
-import io.netty.channel.nio.NioEventLoopGroup
-import io.netty.channel.socket.SocketChannel
-import io.netty.channel.socket.nio.NioSocketChannel
-import io.netty.handler.codec.bytes.ByteArrayDecoder
-import io.netty.handler.codec.bytes.ByteArrayEncoder
-import io.netty.handler.timeout.IdleStateHandler
-
-class SocketClient {
-
- private val kTag = "SocketClient"
-
- private var host: String? = null
- private var port = 8000
- private var nioEventLoopGroup: NioEventLoopGroup? = null
- private var channel: Channel? = null
- private var listener: ISocketListener? = null
-
- //现在连接的状态
- var connectStatus = false //判断是否已连接
- private var reconnectNum = Int.MAX_VALUE //定义的重连到时候用
- private var isNeedReconnect = true //是否需要重连
- var isConnecting = false //是否正在连接
- private set
- private var reconnectIntervalTime: Long = 15000 //重连的时间
-
- //重连时间
- fun setReconnectNum(reconnectNum: Int) {
- this.reconnectNum = reconnectNum
- }
-
- fun setReconnectIntervalTime(reconnectIntervalTime: Long) {
- this.reconnectIntervalTime = reconnectIntervalTime
- }
-
- fun setSocketListener(listener: ISocketListener?) {
- this.listener = listener
- }
-
- fun connect(host: String, port: Int) {
- this.host = host
- this.port = port
- Log.d(kTag, "connect ===> 开始连接TCP服务器")
- if (isConnecting) {
- return
- }
- //起个线程
- val clientThread: Thread = object : Thread("client-Netty") {
- override fun run() {
- super.run()
- isNeedReconnect = true
- reconnectNum = Int.MAX_VALUE
- connectServer()
- }
- }
- clientThread.start()
- }
-
- private fun connectServer() {
- synchronized(this@SocketClient) {
- var channelFuture: ChannelFuture? = null //连接管理对象
- if (!connectStatus) {
- isConnecting = true
- nioEventLoopGroup = NioEventLoopGroup() //设置的连接group
- val bootstrap = Bootstrap()
- bootstrap.group(nioEventLoopGroup) //设置的一系列连接参数操作等
- .channel(NioSocketChannel::class.java)
- .option(ChannelOption.TCP_NODELAY, true) //无阻塞
- .option(ChannelOption.SO_KEEPALIVE, true) //长连接
- .option(
- ChannelOption.RCVBUF_ALLOCATOR,
- AdaptiveRecvByteBufAllocator(5000, 5000, 8000)
- ) //接收缓冲区 最小值太小时数据接收不全
- .handler(object : ChannelInitializer() {
- override fun initChannel(channel: SocketChannel) {
- val pipeline = channel.pipeline()
- //参数1:代表读套接字超时的时间,没收到数据会触发读超时回调;
- //参数2:代表写套接字超时时间,没进行写会触发写超时回调;
- //参数3:将在未执行读取或写入时触发超时回调,0代表不处理;
- //读超时尽量设置大于写超时,代表多次写超时时写心跳包,多次写了心跳数据仍然读超时代表当前连接错误,即可断开连接重新连接
- pipeline.addLast(IdleStateHandler(60, 10, 0))
- pipeline.addLast(ByteArrayDecoder())
- pipeline.addLast(ByteArrayEncoder())
- pipeline.addLast(SocketChannelHandle(listener))
- }
- })
- try {
- //连接监听
- channelFuture = bootstrap.connect(host, port)
- .addListener(object : ChannelFutureListener {
- override fun operationComplete(channelFuture: ChannelFuture) {
- if (channelFuture.isSuccess) {
- connectStatus = true
- channel = channelFuture.channel()
- } else {
- Log.e(kTag, "operationComplete: 连接失败")
- connectStatus = false
- }
- isConnecting = false
- }
- }).sync()
- // 等待连接关闭
- channelFuture.channel().closeFuture().sync()
- } catch (e: Exception) {
- e.printStackTrace()
- } finally {
- connectStatus = false
- listener?.onServiceStatusConnectChanged(ISocketListener.STATUS_CONNECT_CLOSED) //STATUS_CONNECT_CLOSED 这我自己定义的 接口标识
- if (null != channelFuture) {
- if (channelFuture.channel() != null && channelFuture.channel().isOpen) {
- channelFuture.channel().close()
- }
- }
- nioEventLoopGroup?.shutdownGracefully()
- reconnect() //重新连接
- }
- }
- }
- }
-
- //断开连接
- fun disconnect() {
- Log.d(kTag, "disconnect ===> 断开连接")
- isNeedReconnect = false
- nioEventLoopGroup?.shutdownGracefully()
- }
-
- //重新连接
- private fun reconnect() {
- if (isNeedReconnect && reconnectNum > 0 && !connectStatus) {
- reconnectNum--
- SystemClock.sleep(reconnectIntervalTime)
- if (isNeedReconnect && reconnectNum > 0 && !connectStatus) {
- Log.d(kTag, "reconnect ===> 重新连接")
- connectServer()
- }
- }
- }
-
- fun sendData(bytes: ByteArray) {
- channel?.writeAndFlush(bytes)?.addListener(ChannelFutureListener { future ->
- if (!future.isSuccess) {
- future.channel().close()
- nioEventLoopGroup!!.shutdownGracefully()
- }
- })
- }
-}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/br/ktd/netty/SocketManager.kt b/app/src/main/java/com/casic/br/ktd/netty/SocketManager.kt
deleted file mode 100644
index 17daf35..0000000
--- a/app/src/main/java/com/casic/br/ktd/netty/SocketManager.kt
+++ /dev/null
@@ -1,113 +0,0 @@
-package com.casic.br.ktd.netty
-
-import android.util.Log
-import com.casic.br.ktd.base.BaseApplication
-import com.casic.br.ktd.extensions.covertAngleValue
-import com.casic.br.ktd.extensions.covertDataValue
-import com.casic.br.ktd.extensions.toUnsignedByteArray
-import com.casic.br.ktd.model.SensorDataModel
-import com.casic.br.ktd.utils.LocaleConstant
-import com.pengxh.kt.lite.extensions.toJson
-import com.pengxh.kt.lite.utils.BroadcastManager
-
-class SocketManager private constructor() : ISocketListener {
-
- private val kTag = "SocketManager"
- private var nettyClient: SocketClient = SocketClient()
-
- companion object {
- val instance: SocketManager by lazy(mode = LazyThreadSafetyMode.SYNCHRONIZED) { SocketManager() }
- }
-
- fun connectNetty(hostname: String, port: Int) {
- Thread {
- if (!nettyClient.connectStatus) {
- nettyClient.setSocketListener(this)
- nettyClient.connect(hostname, port)
- } else {
- nettyClient.disconnect()
- }
- }.start()
- }
-
- override fun onMessageResponse(data: ByteArray?) {
-// Log.d(kTag, "onMessageResponse ===> " + Arrays.toString(data))
- /**
- * 0xFF,0x01,
- * 0x01,0x37,0xE6, 甲烷浓度值(数据码1* 65536 + 数据码2 * 256 + 数据码3)
- * 0x00, 激光甲烷模块工作状态(00表示设备正常,01表示温控故障,02表示设备激光未打开)
- * 0x00,0xB2,0x35, 激光强度值(数据码5* 65536 + 数据码6 * 256 + 数据码7)
- * 0x0A,0x3D, 云台水平角度([数据码8 * 256 + 数据码9]/100,单位为°,精确到0.01)
- * 0x05,0x6F, 云台垂直角度(首先计算Tangle=[数据码10 * 256 + 数据码11]/100,单位为°,精确到0.01。若Tangle在0~90范围内,则垂直角度值=Tangle;若Tangle在-1~-90范围内,则垂直角度值=Tangle-360)
- * 0xC1
- *
- * [-1, 1, 1, 55, -26, 0, 0, -78, 53, 10, 61, 5, 111, -63]
- * 甲烷浓度值为79638,计算为79638=0x01*65536+0x37*256+0xE6[0x01为数据码1,0x37为数据码2,0xE6为数据码3];
- * 激光甲烷设备状态值为0,表示状态正常,[0x00为数据码4];
- * 激光强度值为45621,计算为45621=0x00*65536+0xB2*256+0x35[0x00为数据码5,0xB2为数据码6,0x35为数据码7];
- *
- * =========================================================================================
- * 实际数据(1800-1950左右)
- * [-86, 1, 0, 7, 71, 0, 0, 62, -92, 57, 59, -118, -111, -64]
- * */
-
- if (data == null) {
- return
- }
- val bytes = data.toUnsignedByteArray()
- if (bytes.size == 14) {
- val dataModel = SensorDataModel(0, "激光未打开", 0, 0.0, 0.0)
-
- val methaneBytes = IntArray(3)
- System.arraycopy(bytes, 2, methaneBytes, 0, 3)
- dataModel.methane = methaneBytes.covertDataValue()
-
- dataModel.methaneState = when (bytes[5]) {
- 1 -> "温控故障"
- 2 -> "激光未打开"
- else -> "正常"
- }
-
- val laserBytes = IntArray(3)
- System.arraycopy(bytes, 6, laserBytes, 0, 3)
- dataModel.laser = laserBytes.covertDataValue()
-
- /**
- * 水平角度的实际范围为从水平零点开始,顺时针方向(从上往下看),0~360°
- * 垂直角度的实际范围为从垂直零点开始,以向上为正,-90°~90°,控制精度为0.01°
- * */
- val horizontalBytes = IntArray(2)
- System.arraycopy(bytes, 9, horizontalBytes, 0, 2)
- dataModel.horizontal = horizontalBytes.covertAngleValue()
-
- val verticalBytes = IntArray(2)
- System.arraycopy(bytes, 11, verticalBytes, 0, 2)
- dataModel.vertical = verticalBytes.covertAngleValue()
-
- //{"horizontal":26.21,"laser":45621,"methane":79846,"methaneState":"正常","vertical":13.91}
- BroadcastManager.obtainInstance(BaseApplication.get()).sendBroadcast(
- LocaleConstant.ACTION_UPDATE_DATA, dataModel.toJson()
- )
- }
- }
-
- override fun onServiceStatusConnectChanged(statusCode: Byte) {
- if (statusCode == ISocketListener.STATUS_CONNECT_SUCCESS) {
- if (nettyClient.connectStatus) {
- Log.d(kTag, "连接成功")
- }
- } else {
- if (!nettyClient.connectStatus) {
- Log.e(kTag, "onServiceStatusConnectChanged:$statusCode,连接断开,正在重连")
- }
- }
- }
-
- fun sendData(data: ByteArray) {
- nettyClient.sendData(data)
- }
-
- fun close() {
- nettyClient.disconnect()
- }
-}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/br/ktd/netty/tcp/ISocketListener.kt b/app/src/main/java/com/casic/br/ktd/netty/tcp/ISocketListener.kt
new file mode 100644
index 0000000..13c3084
--- /dev/null
+++ b/app/src/main/java/com/casic/br/ktd/netty/tcp/ISocketListener.kt
@@ -0,0 +1,19 @@
+package com.casic.br.ktd.netty.tcp
+
+interface ISocketListener {
+ companion object {
+ const val STATUS_CONNECT_SUCCESS: Byte = 1 //连接成功
+ const val STATUS_CONNECT_CLOSED: Byte = 0 //关闭连接
+ const val STATUS_CONNECT_ERROR: Byte = 0 //连接失败
+ }
+
+ /**
+ * 当接收到系统消息
+ */
+ fun onMessageResponse(data: ByteArray?)
+
+ /**
+ * 当连接状态发生变化时调用
+ */
+ fun onServiceStatusConnectChanged(statusCode: Byte)
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/br/ktd/netty/tcp/SocketChannelHandle.kt b/app/src/main/java/com/casic/br/ktd/netty/tcp/SocketChannelHandle.kt
new file mode 100644
index 0000000..8e2997f
--- /dev/null
+++ b/app/src/main/java/com/casic/br/ktd/netty/tcp/SocketChannelHandle.kt
@@ -0,0 +1,51 @@
+package com.casic.br.ktd.netty.tcp
+
+import android.util.Log
+import io.netty.channel.ChannelHandlerContext
+import io.netty.channel.SimpleChannelInboundHandler
+import io.netty.handler.timeout.IdleState
+import io.netty.handler.timeout.IdleStateEvent
+import java.nio.charset.StandardCharsets
+
+class SocketChannelHandle(private val listener: ISocketListener?) :
+ SimpleChannelInboundHandler() {
+
+ private val kTag = "SocketChannelHandle"
+
+ override fun channelActive(ctx: ChannelHandlerContext) {
+ super.channelActive(ctx)
+ Log.d(kTag, "channelActive ===> 连接成功")
+ listener?.onServiceStatusConnectChanged(ISocketListener.STATUS_CONNECT_SUCCESS)
+ }
+
+ override fun channelInactive(ctx: ChannelHandlerContext) {
+ super.channelInactive(ctx)
+ Log.e(kTag, "channelInactive: 连接断开")
+ }
+
+ override fun userEventTriggered(ctx: ChannelHandlerContext, evt: Any) {
+ super.userEventTriggered(ctx, evt)
+ if (evt is IdleStateEvent) {
+ if (evt.state() == IdleState.WRITER_IDLE) {
+ //写超时,此时可以发送心跳数据给服务器
+ val temp = "FF"
+ ctx.writeAndFlush(temp.toByteArray(StandardCharsets.UTF_8))
+ } else if (evt.state() == IdleState.READER_IDLE) {
+ //读超时,此时代表没有收到心跳返回可以关闭当前连接进行重连
+ ctx.close()
+ }
+ }
+ }
+
+ override fun channelRead0(ctx: ChannelHandlerContext, data: ByteArray?) {
+ listener?.onMessageResponse(data)
+ }
+
+ override fun exceptionCaught(ctx: ChannelHandlerContext, cause: Throwable) {
+ super.exceptionCaught(ctx, cause)
+ Log.d(kTag, "exceptionCaught ===> $cause")
+ listener?.onServiceStatusConnectChanged(ISocketListener.STATUS_CONNECT_ERROR)
+ cause.printStackTrace()
+ ctx.close()
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/br/ktd/netty/tcp/SocketClient.kt b/app/src/main/java/com/casic/br/ktd/netty/tcp/SocketClient.kt
new file mode 100644
index 0000000..34960a0
--- /dev/null
+++ b/app/src/main/java/com/casic/br/ktd/netty/tcp/SocketClient.kt
@@ -0,0 +1,153 @@
+package com.casic.br.ktd.netty.tcp
+
+import android.os.SystemClock
+import android.util.Log
+import io.netty.bootstrap.Bootstrap
+import io.netty.channel.*
+import io.netty.channel.nio.NioEventLoopGroup
+import io.netty.channel.socket.SocketChannel
+import io.netty.channel.socket.nio.NioSocketChannel
+import io.netty.handler.codec.bytes.ByteArrayDecoder
+import io.netty.handler.codec.bytes.ByteArrayEncoder
+import io.netty.handler.timeout.IdleStateHandler
+
+class SocketClient {
+
+ private val kTag = "SocketClient"
+
+ private var host: String? = null
+ private var port = 8000
+ private var nioEventLoopGroup: NioEventLoopGroup? = null
+ private var channel: Channel? = null
+ private var listener: ISocketListener? = null
+
+ //现在连接的状态
+ var connectStatus = false //判断是否已连接
+ private var reconnectNum = Int.MAX_VALUE //定义的重连到时候用
+ private var isNeedReconnect = true //是否需要重连
+ var isConnecting = false //是否正在连接
+ private set
+ private var reconnectIntervalTime: Long = 15000 //重连的时间
+
+ //重连时间
+ fun setReconnectNum(reconnectNum: Int) {
+ this.reconnectNum = reconnectNum
+ }
+
+ fun setReconnectIntervalTime(reconnectIntervalTime: Long) {
+ this.reconnectIntervalTime = reconnectIntervalTime
+ }
+
+ fun setSocketListener(listener: ISocketListener?) {
+ this.listener = listener
+ }
+
+ fun connect(host: String, port: Int) {
+ this.host = host
+ this.port = port
+ Log.d(kTag, "connect ===> 开始连接TCP服务器")
+ if (isConnecting) {
+ return
+ }
+ //起个线程
+ val clientThread: Thread = object : Thread("client-Netty") {
+ override fun run() {
+ super.run()
+ isNeedReconnect = true
+ reconnectNum = Int.MAX_VALUE
+ connectServer()
+ }
+ }
+ clientThread.start()
+ }
+
+ private fun connectServer() {
+ synchronized(this@SocketClient) {
+ var channelFuture: ChannelFuture? = null //连接管理对象
+ if (!connectStatus) {
+ isConnecting = true
+ nioEventLoopGroup = NioEventLoopGroup() //设置的连接group
+ val bootstrap = Bootstrap()
+ bootstrap.group(nioEventLoopGroup) //设置的一系列连接参数操作等
+ .channel(NioSocketChannel::class.java)
+ .option(ChannelOption.TCP_NODELAY, true) //无阻塞
+ .option(ChannelOption.SO_KEEPALIVE, true) //长连接
+ .option(
+ ChannelOption.RCVBUF_ALLOCATOR,
+ AdaptiveRecvByteBufAllocator(5000, 5000, 8000)
+ ) //接收缓冲区 最小值太小时数据接收不全
+ .handler(object : ChannelInitializer() {
+ override fun initChannel(channel: SocketChannel) {
+ val pipeline = channel.pipeline()
+ //参数1:代表读套接字超时的时间,没收到数据会触发读超时回调;
+ //参数2:代表写套接字超时时间,没进行写会触发写超时回调;
+ //参数3:将在未执行读取或写入时触发超时回调,0代表不处理;
+ //读超时尽量设置大于写超时,代表多次写超时时写心跳包,多次写了心跳数据仍然读超时代表当前连接错误,即可断开连接重新连接
+ pipeline.addLast(IdleStateHandler(60, 10, 0))
+ pipeline.addLast(ByteArrayDecoder())
+ pipeline.addLast(ByteArrayEncoder())
+ pipeline.addLast(SocketChannelHandle(listener))
+ }
+ })
+ try {
+ //连接监听
+ channelFuture = bootstrap.connect(host, port)
+ .addListener(object : ChannelFutureListener {
+ override fun operationComplete(channelFuture: ChannelFuture) {
+ if (channelFuture.isSuccess) {
+ connectStatus = true
+ channel = channelFuture.channel()
+ } else {
+ Log.e(kTag, "operationComplete: 连接失败")
+ connectStatus = false
+ }
+ isConnecting = false
+ }
+ }).sync()
+ // 等待连接关闭
+ channelFuture.channel().closeFuture().sync()
+ } catch (e: Exception) {
+ e.printStackTrace()
+ } finally {
+ connectStatus = false
+ listener?.onServiceStatusConnectChanged(ISocketListener.STATUS_CONNECT_CLOSED) //STATUS_CONNECT_CLOSED 这我自己定义的 接口标识
+ if (null != channelFuture) {
+ if (channelFuture.channel() != null && channelFuture.channel().isOpen) {
+ channelFuture.channel().close()
+ }
+ }
+ nioEventLoopGroup?.shutdownGracefully()
+ reconnect() //重新连接
+ }
+ }
+ }
+ }
+
+ //断开连接
+ fun disconnect() {
+ Log.d(kTag, "disconnect ===> 断开连接")
+ isNeedReconnect = false
+ nioEventLoopGroup?.shutdownGracefully()
+ }
+
+ //重新连接
+ private fun reconnect() {
+ if (isNeedReconnect && reconnectNum > 0 && !connectStatus) {
+ reconnectNum--
+ SystemClock.sleep(reconnectIntervalTime)
+ if (isNeedReconnect && reconnectNum > 0 && !connectStatus) {
+ Log.d(kTag, "reconnect ===> 重新连接")
+ connectServer()
+ }
+ }
+ }
+
+ fun sendData(bytes: ByteArray) {
+ channel?.writeAndFlush(bytes)?.addListener(ChannelFutureListener { future ->
+ if (!future.isSuccess) {
+ future.channel().close()
+ nioEventLoopGroup!!.shutdownGracefully()
+ }
+ })
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/br/ktd/netty/tcp/SocketManager.kt b/app/src/main/java/com/casic/br/ktd/netty/tcp/SocketManager.kt
new file mode 100644
index 0000000..35980b9
--- /dev/null
+++ b/app/src/main/java/com/casic/br/ktd/netty/tcp/SocketManager.kt
@@ -0,0 +1,113 @@
+package com.casic.br.ktd.netty.tcp
+
+import android.util.Log
+import com.casic.br.ktd.base.BaseApplication
+import com.casic.br.ktd.extensions.covertAngleValue
+import com.casic.br.ktd.extensions.covertDataValue
+import com.casic.br.ktd.extensions.toUnsignedByteArray
+import com.casic.br.ktd.model.SensorDataModel
+import com.casic.br.ktd.utils.LocaleConstant
+import com.pengxh.kt.lite.extensions.toJson
+import com.pengxh.kt.lite.utils.BroadcastManager
+
+class SocketManager private constructor() : ISocketListener {
+
+ private val kTag = "SocketManager"
+ private var nettyClient: SocketClient = SocketClient()
+
+ companion object {
+ val instance: SocketManager by lazy(mode = LazyThreadSafetyMode.SYNCHRONIZED) { SocketManager() }
+ }
+
+ fun connectNetty(hostname: String, port: Int) {
+ Thread {
+ if (!nettyClient.connectStatus) {
+ nettyClient.setSocketListener(this)
+ nettyClient.connect(hostname, port)
+ } else {
+ nettyClient.disconnect()
+ }
+ }.start()
+ }
+
+ override fun onMessageResponse(data: ByteArray?) {
+// Log.d(kTag, "onMessageResponse ===> " + Arrays.toString(data))
+ /**
+ * 0xFF,0x01,
+ * 0x01,0x37,0xE6, 甲烷浓度值(数据码1* 65536 + 数据码2 * 256 + 数据码3)
+ * 0x00, 激光甲烷模块工作状态(00表示设备正常,01表示温控故障,02表示设备激光未打开)
+ * 0x00,0xB2,0x35, 激光强度值(数据码5* 65536 + 数据码6 * 256 + 数据码7)
+ * 0x0A,0x3D, 云台水平角度([数据码8 * 256 + 数据码9]/100,单位为°,精确到0.01)
+ * 0x05,0x6F, 云台垂直角度(首先计算Tangle=[数据码10 * 256 + 数据码11]/100,单位为°,精确到0.01。若Tangle在0~90范围内,则垂直角度值=Tangle;若Tangle在-1~-90范围内,则垂直角度值=Tangle-360)
+ * 0xC1
+ *
+ * [-1, 1, 1, 55, -26, 0, 0, -78, 53, 10, 61, 5, 111, -63]
+ * 甲烷浓度值为79638,计算为79638=0x01*65536+0x37*256+0xE6[0x01为数据码1,0x37为数据码2,0xE6为数据码3];
+ * 激光甲烷设备状态值为0,表示状态正常,[0x00为数据码4];
+ * 激光强度值为45621,计算为45621=0x00*65536+0xB2*256+0x35[0x00为数据码5,0xB2为数据码6,0x35为数据码7];
+ *
+ * =========================================================================================
+ * 实际数据(1800-1950左右)
+ * [-86, 1, 0, 7, 71, 0, 0, 62, -92, 57, 59, -118, -111, -64]
+ * */
+
+ if (data == null) {
+ return
+ }
+ val bytes = data.toUnsignedByteArray()
+ if (bytes.size == 14) {
+ val dataModel = SensorDataModel(0, "激光未打开", 0, 0.0, 0.0)
+
+ val methaneBytes = IntArray(3)
+ System.arraycopy(bytes, 2, methaneBytes, 0, 3)
+ dataModel.methane = methaneBytes.covertDataValue()
+
+ dataModel.methaneState = when (bytes[5]) {
+ 1 -> "温控故障"
+ 2 -> "激光未打开"
+ else -> "正常"
+ }
+
+ val laserBytes = IntArray(3)
+ System.arraycopy(bytes, 6, laserBytes, 0, 3)
+ dataModel.laser = laserBytes.covertDataValue()
+
+ /**
+ * 水平角度的实际范围为从水平零点开始,顺时针方向(从上往下看),0~360°
+ * 垂直角度的实际范围为从垂直零点开始,以向上为正,-90°~90°,控制精度为0.01°
+ * */
+ val horizontalBytes = IntArray(2)
+ System.arraycopy(bytes, 9, horizontalBytes, 0, 2)
+ dataModel.horizontal = horizontalBytes.covertAngleValue()
+
+ val verticalBytes = IntArray(2)
+ System.arraycopy(bytes, 11, verticalBytes, 0, 2)
+ dataModel.vertical = verticalBytes.covertAngleValue()
+
+ //{"horizontal":26.21,"laser":45621,"methane":79846,"methaneState":"正常","vertical":13.91}
+ BroadcastManager.obtainInstance(BaseApplication.get()).sendBroadcast(
+ LocaleConstant.ACTION_UPDATE_DATA, dataModel.toJson()
+ )
+ }
+ }
+
+ override fun onServiceStatusConnectChanged(statusCode: Byte) {
+ if (statusCode == ISocketListener.STATUS_CONNECT_SUCCESS) {
+ if (nettyClient.connectStatus) {
+ Log.d(kTag, "连接成功")
+ }
+ } else {
+ if (!nettyClient.connectStatus) {
+ Log.e(kTag, "onServiceStatusConnectChanged:$statusCode,连接断开,正在重连")
+ }
+ }
+ }
+
+ fun sendData(data: ByteArray) {
+ nettyClient.sendData(data)
+ }
+
+ fun close() {
+ nettyClient.disconnect()
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/br/ktd/netty/udp/UdpChannelInboundHandler.kt b/app/src/main/java/com/casic/br/ktd/netty/udp/UdpChannelInboundHandler.kt
new file mode 100644
index 0000000..4d6f97c
--- /dev/null
+++ b/app/src/main/java/com/casic/br/ktd/netty/udp/UdpChannelInboundHandler.kt
@@ -0,0 +1,36 @@
+package com.casic.br.ktd.netty.udp
+
+import io.netty.channel.ChannelHandlerContext
+import io.netty.channel.SimpleChannelInboundHandler
+import io.netty.channel.socket.DatagramPacket
+import io.netty.util.CharsetUtil
+
+
+abstract class UdpChannelInboundHandler : SimpleChannelInboundHandler() {
+
+ private var handlerContext: ChannelHandlerContext? = null
+
+ override fun channelActive(ctx: ChannelHandlerContext?) {
+ super.channelActive(ctx)
+ handlerContext = ctx
+ }
+
+ override fun channelInactive(ctx: ChannelHandlerContext?) {
+ super.channelInactive(ctx)
+ handlerContext?.close()
+ }
+
+ fun sendDatagramPacket(obj: Any) {
+ handlerContext?.writeAndFlush(obj)
+ }
+
+ fun releasePort() {
+ handlerContext?.close()
+ }
+
+ override fun channelRead0(ctx: ChannelHandlerContext, datagramPacket: DatagramPacket) {
+ receivedMessage(datagramPacket.content().toString(CharsetUtil.UTF_8))
+ }
+
+ abstract fun receivedMessage(data: String)
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/br/ktd/netty/udp/UdpChannelInitializer.kt b/app/src/main/java/com/casic/br/ktd/netty/udp/UdpChannelInitializer.kt
new file mode 100644
index 0000000..416c5a1
--- /dev/null
+++ b/app/src/main/java/com/casic/br/ktd/netty/udp/UdpChannelInitializer.kt
@@ -0,0 +1,17 @@
+package com.casic.br.ktd.netty.udp
+
+import io.netty.channel.ChannelInitializer
+import io.netty.channel.socket.DatagramChannel
+import io.netty.handler.timeout.IdleStateHandler
+
+
+open class UdpChannelInitializer(private val handler: UdpChannelInboundHandler) :
+ ChannelInitializer() {
+
+ override fun initChannel(datagramChannel: DatagramChannel) {
+ val pipeline = datagramChannel.pipeline()
+ pipeline.addLast(
+ IdleStateHandler(12, 15, 0)
+ ).addLast(handler)
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/br/ktd/netty/udp/UdpClient.kt b/app/src/main/java/com/casic/br/ktd/netty/udp/UdpClient.kt
new file mode 100644
index 0000000..3893afa
--- /dev/null
+++ b/app/src/main/java/com/casic/br/ktd/netty/udp/UdpClient.kt
@@ -0,0 +1,103 @@
+package com.casic.br.ktd.netty.udp
+
+import com.casic.br.ktd.utils.LocaleConstant
+import com.pengxh.kt.lite.utils.SaveKeyValues
+import io.netty.bootstrap.Bootstrap
+import io.netty.buffer.ByteBuf
+import io.netty.buffer.Unpooled
+import io.netty.channel.ChannelOption
+import io.netty.channel.nio.NioEventLoopGroup
+import io.netty.channel.socket.DatagramPacket
+import io.netty.channel.socket.nio.NioDatagramChannel
+import io.netty.util.CharsetUtil
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.launch
+import kotlinx.coroutines.withContext
+import java.net.InetSocketAddress
+import java.util.concurrent.ExecutorService
+import java.util.concurrent.Executors
+
+
+class UdpClient : UdpChannelInboundHandler(), Runnable {
+
+ private val bootStrap by lazy { Bootstrap() }
+ private val eventLoopGroup by lazy { NioEventLoopGroup() }
+ private val udpChannelInitializer by lazy { UdpChannelInitializer(this) }
+ private var executorService: ExecutorService
+
+ init {
+ bootStrap.group(eventLoopGroup)
+ bootStrap.channel(NioDatagramChannel::class.java)
+ .option(ChannelOption.SO_RCVBUF, 1024)
+ .option(ChannelOption.SO_SNDBUF, 1024)
+ bootStrap.handler(udpChannelInitializer)
+
+ executorService = Executors.newSingleThreadExecutor()
+ executorService.execute(this)
+ }
+
+ override fun run() {
+ try {
+ val channelFuture = bootStrap.bind(LocaleConstant.LOCATION_UDP_PORT).sync()
+ channelFuture.channel().closeFuture().sync()
+ } catch (e: InterruptedException) {
+ e.printStackTrace()
+ } finally {
+ eventLoopGroup.shutdownGracefully()
+ }
+ }
+
+ fun send(value: String) {
+ CoroutineScope(Dispatchers.Main).launch {
+ withContext(Dispatchers.IO) {
+ val host = SaveKeyValues.getValue(
+ LocaleConstant.LOCATION_UDP_SERVER, "192.168.149.213"
+ ).toString()
+ val datagramPacket = DatagramPacket(
+ Unpooled.copiedBuffer(value, CharsetUtil.UTF_8),
+ InetSocketAddress(host, LocaleConstant.LOCATION_UDP_PORT)
+ )
+ sendDatagramPacket(datagramPacket)
+ }
+ }
+ }
+
+ fun send(value: ByteArray) {
+ CoroutineScope(Dispatchers.Main).launch {
+ withContext(Dispatchers.IO) {
+ val host = SaveKeyValues.getValue(
+ LocaleConstant.LOCATION_UDP_SERVER, "192.168.149.213"
+ ).toString()
+ val datagramPacket = DatagramPacket(
+ Unpooled.copiedBuffer(value),
+ InetSocketAddress(host, LocaleConstant.LOCATION_UDP_PORT)
+ )
+ sendDatagramPacket(datagramPacket)
+ }
+ }
+ }
+
+ fun send(value: ByteBuf) {
+ CoroutineScope(Dispatchers.Main).launch {
+ withContext(Dispatchers.IO) {
+ val host = SaveKeyValues.getValue(
+ LocaleConstant.LOCATION_UDP_SERVER, "192.168.149.213"
+ ).toString()
+ val datagramPacket = DatagramPacket(
+ Unpooled.copiedBuffer(value),
+ InetSocketAddress(host, LocaleConstant.LOCATION_UDP_PORT)
+ )
+ sendDatagramPacket(datagramPacket)
+ }
+ }
+ }
+
+ fun release() {
+ releasePort()
+ }
+
+ override fun receivedMessage(data: String) {
+
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/br/ktd/utils/LocaleConstant.kt b/app/src/main/java/com/casic/br/ktd/utils/LocaleConstant.kt
index 0dd119e..4c675df 100644
--- a/app/src/main/java/com/casic/br/ktd/utils/LocaleConstant.kt
+++ b/app/src/main/java/com/casic/br/ktd/utils/LocaleConstant.kt
@@ -50,6 +50,10 @@
const val DEV_NET_IP = "192.168.1.21"
const val DEV_NET_PORT = "8000"
+ //位置信息UDP端口
+ const val LOCATION_UDP_SERVER = "udpServer"
+ const val LOCATION_UDP_PORT = 7777
+
//BroadcastReceiver Action
const val ACTION_UPDATE_DATA = "update"
diff --git a/app/src/main/java/com/casic/br/ktd/utils/LocationHelper.kt b/app/src/main/java/com/casic/br/ktd/utils/LocationHelper.kt
index 8e31d3f..df6adb5 100644
--- a/app/src/main/java/com/casic/br/ktd/utils/LocationHelper.kt
+++ b/app/src/main/java/com/casic/br/ktd/utils/LocationHelper.kt
@@ -7,19 +7,40 @@
import android.location.LocationListener
import android.location.LocationManager
import android.os.Bundle
+import android.util.Log
import androidx.core.app.ActivityCompat
+import com.amap.api.location.AMapLocation
+import com.amap.api.location.AMapLocationClient
+import com.amap.api.location.AMapLocationClientOption
-object LocationHelper {
- fun obtainCurrentLocation(context: Context, listener: ILocationListener) {
+class LocationHelper private constructor() {
+
+ private val kTag = "LocationHelper"
+
+ companion object {
+ //Kotlin委托模式双重锁单例
+ val get: LocationHelper by lazy(mode = LazyThreadSafetyMode.SYNCHRONIZED) {
+ LocationHelper()
+ }
+ }
+
+ private val locationOption = AMapLocationClientOption()
+ private lateinit var locationClient: AMapLocationClient
+
+ init {
+ //设置定位模式为高精度模式,AMapLocationMode.Battery_Saving为低功耗模式,AMapLocationMode.Device_Sensors是仅设备模式
+ locationOption.locationMode = AMapLocationClientOption.AMapLocationMode.Hight_Accuracy
+ locationOption.isNeedAddress = true //设置是否返回地址信息(默认返回地址信息)
+ locationOption.isLocationCacheEnable = true //可选,设置是否使用缓存定位,默认为true
+ }
+
+ fun obtainLocation(context: Context, listener: ILocationListener) {
if (ActivityCompat.checkSelfPermission(
- context,
- Manifest.permission.ACCESS_LOCATION_EXTRA_COMMANDS
+ context, Manifest.permission.ACCESS_LOCATION_EXTRA_COMMANDS
) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(
- context,
- Manifest.permission.ACCESS_FINE_LOCATION
+ context, Manifest.permission.ACCESS_FINE_LOCATION
) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(
- context,
- Manifest.permission.ACCESS_COARSE_LOCATION
+ context, Manifest.permission.ACCESS_COARSE_LOCATION
) != PackageManager.PERMISSION_GRANTED
) {
return
@@ -38,7 +59,37 @@
})
}
+ /**
+ * 高德sdk定位
+ */
+ fun obtainLocationByGD(context: Context?, listener: ILocationListener) {
+ locationClient = AMapLocationClient(context)
+ //给定位客户端对象设置定位参数
+ locationClient.setLocationOption(locationOption)
+ //设置定位回调监听
+ locationClient.setLocationListener { aMapLocation ->
+ if (aMapLocation != null) {
+ if (aMapLocation.errorCode == 0) {
+ listener.onAMapLocationGet(aMapLocation)
+ } else {
+ Log.e(
+ kTag,
+ "ErrCode: ${aMapLocation.errorCode}, errInfo: ${aMapLocation.errorInfo}"
+ )
+ }
+ }
+ }
+ //启动定位
+ locationClient.startLocation()
+ }
+
+ fun stopLocation() {
+ locationClient.stopLocation()//停止定位
+ }
+
interface ILocationListener {
- fun onLocationGet(location: Location?) //高德定位数据
+ fun onLocationGet(location: Location?) //GPS定位数据
+
+ fun onAMapLocationGet(aMapLocation: AMapLocation?) //高德定位数据
}
}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/br/ktd/view/InspectionActivity.kt b/app/src/main/java/com/casic/br/ktd/view/InspectionActivity.kt
index 02c47f8..c893092 100644
--- a/app/src/main/java/com/casic/br/ktd/view/InspectionActivity.kt
+++ b/app/src/main/java/com/casic/br/ktd/view/InspectionActivity.kt
@@ -15,16 +15,21 @@
import android.view.SurfaceHolder
import android.view.View
import android.widget.AdapterView
-import com.amap.api.maps.*
+import com.amap.api.location.AMapLocation
+import com.amap.api.maps.AMap
+import com.amap.api.maps.CameraUpdateFactory
+import com.amap.api.maps.UiSettings
import com.amap.api.maps.model.CameraPosition
import com.amap.api.maps.model.LatLng
+import com.amap.api.maps.model.MyLocationStyle
import com.amap.api.maps.model.PolylineOptions
import com.casic.br.ktd.R
import com.casic.br.ktd.extensions.*
import com.casic.br.ktd.model.ChartPointModel
import com.casic.br.ktd.model.RouteModel
import com.casic.br.ktd.model.SensorDataModel
-import com.casic.br.ktd.netty.SocketManager
+import com.casic.br.ktd.netty.tcp.SocketManager
+import com.casic.br.ktd.netty.udp.UdpClient
import com.casic.br.ktd.utils.LocaleConstant
import com.casic.br.ktd.utils.LocationHelper
import com.casic.br.ktd.widgets.AlertControlDialog
@@ -49,6 +54,10 @@
import hcnetsdk.sdkhub.MessageCodeHub
import hcnetsdk.sdkhub.SDKGuider
import kotlinx.android.synthetic.main.activity_inspection.*
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.launch
+import kotlinx.coroutines.withContext
import java.text.DecimalFormat
import java.text.SimpleDateFormat
import java.util.*
@@ -60,10 +69,10 @@
private val hkSDK by lazy { HCNetSDK.getInstance() }
private val timeFormat by lazy { SimpleDateFormat("yyyyMMddHHmmss", Locale.CHINA) }
private val latlngs = LinkedList()
- private val speedTimer by lazy { Timer() }
private val tcpTimer by lazy { Timer() }
private val decimalFormat by lazy { DecimalFormat("##0.0") }
private val gson by lazy { Gson() }
+ private val udpClient by lazy { UdpClient() }
private var isLoginSuccess = false
private var previewHandle = -1
private var selectChannel = -1
@@ -103,28 +112,32 @@
private lateinit var aMap: AMap
private lateinit var uiSettings: UiSettings
+ /**
+ * 协程配置云台设备,缓解新进页面较卡的问题
+ * */
private fun setDeviceConfig() {
- Log.d(kTag, "setDeviceConfig => 配置设备IP和端口")
- val device = SDKGuider.sdkGuider.devManageGuider.DeviceItem()
- device.m_szDevName = ""
- device.m_struNetInfo = SDKGuider.sdkGuider.devManageGuider.DevNetInfo(
- LocaleConstant.HK_NET_IP,
- LocaleConstant.HK_NET_PORT,
- LocaleConstant.HK_NET_USERNAME,
- LocaleConstant.HK_NET_PASSWORD
- )
- if (device.m_szDevName.isEmpty()) {
- device.m_szDevName = device.m_struNetInfo.m_szIp
- }
- isLoginSuccess = if (
- SDKGuider.sdkGuider.devManageGuider.login_v40_jna(
- device.m_szDevName, device.m_struNetInfo
- )
- ) {
- "设备连接成功".show(this)
- true
- } else {
- false
+ CoroutineScope(Dispatchers.Main).launch {
+ isLoginSuccess = withContext(Dispatchers.IO) {
+ Log.d(kTag, "setDeviceConfig => 配置设备IP和端口")
+ val device = SDKGuider.sdkGuider.devManageGuider.DeviceItem()
+ device.m_szDevName = ""
+ device.m_struNetInfo = SDKGuider.sdkGuider.devManageGuider.DevNetInfo(
+ LocaleConstant.HK_NET_IP,
+ LocaleConstant.HK_NET_PORT,
+ LocaleConstant.HK_NET_USERNAME,
+ LocaleConstant.HK_NET_PASSWORD
+ )
+ if (device.m_szDevName.isEmpty()) {
+ device.m_szDevName = device.m_struNetInfo.m_szIp
+ }
+
+ SDKGuider.sdkGuider.devManageGuider.login_v40_jna(
+ device.m_szDevName, device.m_struNetInfo
+ )
+ }
+ if (isLoginSuccess) {
+ "设备连接成功".show(context)
+ }
}
}
@@ -148,17 +161,74 @@
/**
* 手机GPS定位
* */
- val converter = CoordinateConverter(this)
- LocationHelper.obtainCurrentLocation(this, object : LocationHelper.ILocationListener {
+// val converter = CoordinateConverter(this)
+// LocationHelper.get.obtainLocation(this, object : LocationHelper.ILocationListener {
+// override fun onLocationGet(location: Location?) {
+// if (location == null) {
+// "当前信号弱,无法定位".show(context)
+// return
+// }
+//
+// //发送位置信息给UDP服务端
+// udpClient.send("${location.longitude}, ${location.latitude}")
+// Log.d(kTag, "onLocationGet => 速度:${location.speed}")
+//
+// //WGS-84要转为高德坐标系
+// converter.from(CoordinateConverter.CoordType.GPS)
+// converter.coord(LatLng(location.latitude, location.longitude))
+// val latLng = converter.convert()
+// latlngs.add(latLng)
+//
+// //移动到指定经纬度
+// val cameraPosition = CameraPosition(latLng, 13f, 0f, 0f)
+// val cameraUpdate = CameraUpdateFactory.newCameraPosition(cameraPosition)
+// aMap.animateCamera(cameraUpdate, 1500, null)
+//
+// //绘制线
+// aMap.addPolyline(
+// PolylineOptions().addAll(latlngs).width(12f).color(Color.RED)
+// )
+//
+// if (isStartInspect) {
+// val route = LinkedList()
+// latlngs.forEach {
+// route.add(RouteModel(it.latitude, it.longitude))
+// }
+// }
+// }
+//
+// override fun onAMapLocationGet(aMapLocation: AMapLocation?) {
+//
+// }
+// })
+
+ /**
+ * 高德定位
+ * */
+ LocationHelper.get.obtainLocationByGD(this, object : LocationHelper.ILocationListener {
override fun onLocationGet(location: Location?) {
- if (location == null) {
+
+ }
+
+ override fun onAMapLocationGet(aMapLocation: AMapLocation?) {
+ if (aMapLocation == null) {
"当前信号弱,无法定位".show(context)
return
}
+
+ //发送位置信息给UDP服务端
+ udpClient.send(
+ "${aMapLocation.longitude}, ${aMapLocation.latitude}, ${
+ System.currentTimeMillis().timestampToCompleteDate()
+ }"
+ )
+ //速度 转为 km/h
+ Log.d(kTag, "onLocationGet => 速度:${aMapLocation.speed}")
+ speed = decimalFormat.format(aMapLocation.speed * 3.6).toFloat()
+ carSpeedView.text = String.format("${speed}Km/h")
+
//WGS-84要转为高德坐标系
- converter.from(CoordinateConverter.CoordType.GPS)
- converter.coord(LatLng(location.latitude, location.longitude))
- val latLng = converter.convert()
+ val latLng = LatLng(aMapLocation.latitude, aMapLocation.longitude)
latlngs.add(latLng)
//移动到指定经纬度
@@ -168,7 +238,7 @@
//绘制线
aMap.addPolyline(
- PolylineOptions().addAll(latlngs).width(12f).color(Color.RED)
+ PolylineOptions().addAll(latlngs).width(10f).color(Color.RED)
)
if (isStartInspect) {
@@ -181,27 +251,6 @@
})
/**
- * 计算速度,微分原理,3s计算一次速度
- * */
- speedTimer.schedule(object : TimerTask() {
- override fun run() {
- //经纬度链表数据小于2,无法计算速度,默认为0
- speed = if (latlngs.size < 2) 0.0f else {
- val temp = AMapUtils.calculateLineDistance(
- latlngs.last(), latlngs[latlngs.size - 2]
- ) / 3
- //转为 km/h
- decimalFormat.format(temp * 3.6).toFloat()
- }
-
- //切换到UI线程更新界面数据
- runOnUiThread {
- carSpeedView.text = String.format("${speed}Km/h")
- }
- }
- }, 0, 3000)
-
- /**
* TCP初始化
* ***/
SocketManager.instance.connectNetty(
@@ -632,6 +681,8 @@
stopPreview()
BroadcastManager.obtainInstance(this).destroy(LocaleConstant.ACTION_UPDATE_DATA)
mapView.onDestroy()
+ udpClient.release()
+ LocationHelper.get.stopLocation()
}
override fun handleMessage(msg: Message): Boolean {
@@ -716,38 +767,13 @@
uiSettings.isZoomControlsEnabled = true
uiSettings.isTiltGesturesEnabled = false//不许地图随手势倾斜角度
-// val locationStyle = MyLocationStyle()
-// locationStyle.interval(2000)
-// locationStyle.showMyLocation(true)
-// locationStyle.myLocationType(MyLocationStyle.LOCATION_TYPE_LOCATION_ROTATE)
-// aMap.myLocationStyle = locationStyle
-// aMap.isMyLocationEnabled = true
-// aMap.animateCamera(CameraUpdateFactory.zoomTo(13f))
-// aMap.setOnMyLocationChangeListener(this)
+ //显示定位小蓝点
+ val locationStyle = MyLocationStyle()
+ locationStyle.showMyLocation(true)//设置是否显示定位小蓝点
+ aMap.myLocationStyle = locationStyle
+ aMap.isMyLocationEnabled = true
}
-// override fun onMyLocationChange(aMapLocation: Location?) {
-// if (aMapLocation == null) {
-// "当前信号弱,无法定位".show(context)
-// return
-// }
-// val latitude = aMapLocation.latitude
-// val longitude = aMapLocation.longitude
-// latlngs.add(LatLng(latitude, longitude))
-//
-// //绘制线
-// aMap.addPolyline(
-// PolylineOptions().addAll(latlngs).width(15f).color(Color.RED)
-// )
-//
-// if (isStartInspect) {
-// val route = LinkedList()
-// latlngs.forEach {
-// route.add(RouteModel(it.latitude, it.longitude))
-// }
-// }
-// }
-
/***以下是地图生命周期管理************************************************************************/
override fun onResume() {
diff --git a/app/src/main/res/layout/fragment_alarm.xml b/app/src/main/res/layout/fragment_alarm.xml
index a3ebc88..929529f 100644
--- a/app/src/main/res/layout/fragment_alarm.xml
+++ b/app/src/main/res/layout/fragment_alarm.xml
@@ -31,7 +31,7 @@
diff --git a/app/src/main/res/layout/fragment_task.xml b/app/src/main/res/layout/fragment_task.xml
index 35cb1a3..58d852e 100644
--- a/app/src/main/res/layout/fragment_task.xml
+++ b/app/src/main/res/layout/fragment_task.xml
@@ -31,7 +31,7 @@
diff --git a/app/src/main/res/mipmap-hdpi/end.png b/app/src/main/res/mipmap-hdpi/end.png
new file mode 100644
index 0000000..f31385b
--- /dev/null
+++ b/app/src/main/res/mipmap-hdpi/end.png
Binary files differ
diff --git a/app/src/main/res/mipmap-hdpi/start.png b/app/src/main/res/mipmap-hdpi/start.png
new file mode 100644
index 0000000..04839dc
--- /dev/null
+++ b/app/src/main/res/mipmap-hdpi/start.png
Binary files differ
diff --git a/app/src/main/res/mipmap-mdpi/end.png b/app/src/main/res/mipmap-mdpi/end.png
new file mode 100644
index 0000000..f31385b
--- /dev/null
+++ b/app/src/main/res/mipmap-mdpi/end.png
Binary files differ
diff --git a/app/src/main/res/mipmap-mdpi/start.png b/app/src/main/res/mipmap-mdpi/start.png
new file mode 100644
index 0000000..04839dc
--- /dev/null
+++ b/app/src/main/res/mipmap-mdpi/start.png
Binary files differ
diff --git a/app/src/main/res/mipmap-xhdpi/end.png b/app/src/main/res/mipmap-xhdpi/end.png
new file mode 100644
index 0000000..f31385b
--- /dev/null
+++ b/app/src/main/res/mipmap-xhdpi/end.png
Binary files differ
diff --git a/app/src/main/res/mipmap-xhdpi/start.png b/app/src/main/res/mipmap-xhdpi/start.png
new file mode 100644
index 0000000..04839dc
--- /dev/null
+++ b/app/src/main/res/mipmap-xhdpi/start.png
Binary files differ
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index e822df6..d72c1a5 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -7,6 +7,9 @@
+
+
+
@@ -46,5 +49,8 @@
+
+
+
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/br/ktd/base/KotlinBaseFragment.kt b/app/src/main/java/com/casic/br/ktd/base/KotlinBaseFragment.kt
new file mode 100644
index 0000000..2dac61c
--- /dev/null
+++ b/app/src/main/java/com/casic/br/ktd/base/KotlinBaseFragment.kt
@@ -0,0 +1,51 @@
+package com.casic.br.ktd.base
+
+import android.os.Bundle
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import androidx.annotation.LayoutRes
+import androidx.fragment.app.Fragment
+
+abstract class KotlinBaseFragment : Fragment() {
+
+ lateinit var bv: View
+
+ override fun onCreateView(
+ inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?
+ ): View? {
+ bv = inflater.inflate(initLayoutRes(), container, false)
+ initView(savedInstanceState)
+ setupTopBarLayout()
+ return bv
+ }
+
+ override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
+ super.onViewCreated(view, savedInstanceState)
+ observeRequestState()
+ initEvent()
+ }
+
+ @LayoutRes
+ abstract fun initLayoutRes(): Int
+
+ /**
+ * 沉浸式状态栏
+ */
+ abstract fun setupTopBarLayout()
+
+ /**
+ * 初始化布局以及控件
+ */
+ abstract fun initView(savedInstanceState: Bundle?)
+
+ /**
+ * 网络请求状态监听
+ */
+ abstract fun observeRequestState()
+
+ /**
+ * 业务逻辑,按钮等事件
+ */
+ abstract fun initEvent()
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/br/ktd/fragment/AlarmPageFragment.kt b/app/src/main/java/com/casic/br/ktd/fragment/AlarmPageFragment.kt
index 6c98a3b..9418169 100644
--- a/app/src/main/java/com/casic/br/ktd/fragment/AlarmPageFragment.kt
+++ b/app/src/main/java/com/casic/br/ktd/fragment/AlarmPageFragment.kt
@@ -2,28 +2,29 @@
import android.os.Bundle
import com.casic.br.ktd.R
+import com.casic.br.ktd.base.KotlinBaseFragment
import com.casic.br.ktd.widgets.DateRangeActionSheet
-import com.pengxh.kt.lite.base.KotlinBaseFragment
import kotlinx.android.synthetic.main.fragment_alarm.view.*
class AlarmPageFragment : KotlinBaseFragment() {
- override fun initData(savedInstanceState: Bundle?) {
+
+ override fun initView(savedInstanceState: Bundle?) {
}
override fun initEvent() {
- baseView.calendarView.setOnClickListener {
+ bv.calendarView.setOnClickListener {
DateRangeActionSheet.Builder().setContext(requireContext())
.setOnActionSheetListener(object :
DateRangeActionSheet.OnDateRangeSelectedListener {
override fun onDateRangeSelected(startDate: String, endDate: String) {
- baseView.selectedDateView.text = "$startDate ~ $endDate"
+ bv.selectedDateView.text = "$startDate ~ $endDate"
}
}).build().show()
}
}
- override fun initLayoutView(): Int = R.layout.fragment_alarm
+ override fun initLayoutRes(): Int = R.layout.fragment_alarm
override fun observeRequestState() {
diff --git a/app/src/main/java/com/casic/br/ktd/fragment/HomePageFragment.kt b/app/src/main/java/com/casic/br/ktd/fragment/HomePageFragment.kt
index 9961935..f3eba5c 100644
--- a/app/src/main/java/com/casic/br/ktd/fragment/HomePageFragment.kt
+++ b/app/src/main/java/com/casic/br/ktd/fragment/HomePageFragment.kt
@@ -1,32 +1,62 @@
package com.casic.br.ktd.fragment
+import android.graphics.Color
import android.os.Bundle
import com.amap.api.maps.AMap
import com.amap.api.maps.AMapOptions
+import com.amap.api.maps.CameraUpdateFactory
+import com.amap.api.maps.model.*
import com.casic.br.ktd.R
-import com.pengxh.kt.lite.base.KotlinBaseFragment
+import com.casic.br.ktd.base.KotlinBaseFragment
import kotlinx.android.synthetic.main.fragment_home.view.*
class HomePageFragment : KotlinBaseFragment() {
private lateinit var aMap: AMap
- override fun initData(savedInstanceState: Bundle?) {
- baseView.mapView.onCreate(savedInstanceState)
- aMap = baseView.mapView.map
+ override fun initView(savedInstanceState: Bundle?) {
+ bv.mapView.onCreate(savedInstanceState)
+ aMap = bv.mapView.map
val uiSettings = aMap.uiSettings
uiSettings.isCompassEnabled = true
- uiSettings.isMyLocationButtonEnabled = true
+ uiSettings.isMyLocationButtonEnabled = false
uiSettings.isScaleControlsEnabled = true
uiSettings.zoomPosition = AMapOptions.ZOOM_POSITION_RIGHT_CENTER
uiSettings.isRotateGesturesEnabled = false//不许地图随手势旋转角度
}
override fun initEvent() {
-
+ //移动到巡检起始经纬度
+ val cameraPosition = CameraPosition(LatLng(39.914199, 116.265785), 16f, 0f, 0f)
+ val cameraUpdate = CameraUpdateFactory.newCameraPosition(cameraPosition)
+ aMap.animateCamera(cameraUpdate, 1500, null)
+ //设置起点
+ addMarker(LatLng(39.914885, 116.272312), R.mipmap.start)
+ //设置终点
+ addMarker(LatLng(39.914716, 116.265097), R.mipmap.end)
+ //瞄点画线
+ val latLngPoints = ArrayList()
+ latLngPoints.add(LatLng(39.914885, 116.272312))
+ latLngPoints.add(LatLng(39.915148, 116.272312))
+ latLngPoints.add(LatLng(39.915399, 116.272302))
+ latLngPoints.add(LatLng(39.915436, 116.271787))
+ latLngPoints.add(LatLng(39.915477, 116.270886))
+ latLngPoints.add(LatLng(39.915477, 116.269968))
+ latLngPoints.add(LatLng(39.915469, 116.269544))
+ latLngPoints.add(LatLng(39.915481, 116.269196))
+ latLngPoints.add(LatLng(39.915452, 116.268472))
+ latLngPoints.add(LatLng(39.915444, 116.267722))
+ latLngPoints.add(LatLng(39.915415, 116.266755))
+ latLngPoints.add(LatLng(39.915403, 116.266165))
+ latLngPoints.add(LatLng(39.915395, 116.265703))
+ latLngPoints.add(LatLng(39.915366, 116.265119))
+ latLngPoints.add(LatLng(39.914716, 116.265097))
+ aMap.addPolyline(
+ PolylineOptions().addAll(latLngPoints).width(10.toFloat()).color(Color.RED)
+ )
}
- override fun initLayoutView(): Int = R.layout.fragment_home
+ override fun initLayoutRes(): Int = R.layout.fragment_home
override fun observeRequestState() {
@@ -36,25 +66,32 @@
}
+ private fun addMarker(point: LatLng, res: Int) {
+ val markerOption = MarkerOptions()
+ markerOption.position(point)
+ markerOption.icon(BitmapDescriptorFactory.fromResource(res))
+ aMap.addMarker(markerOption)
+ }
+
/***以下是地图生命周期管理************************************************************************/
override fun onResume() {
super.onResume()
- baseView.mapView.onResume()
+ bv.mapView.onResume()
}
override fun onPause() {
- baseView.mapView.onPause()
super.onPause()
+ bv.mapView.onPause()
}
override fun onSaveInstanceState(outState: Bundle) {
super.onSaveInstanceState(outState)
- baseView.mapView.onSaveInstanceState(outState)
+ bv.mapView.onSaveInstanceState(outState)
}
override fun onDestroy() {
- baseView.mapView.onDestroy()
super.onDestroy()
+ bv.mapView.onDestroy()
}
}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/br/ktd/fragment/MinePageFragment.kt b/app/src/main/java/com/casic/br/ktd/fragment/MinePageFragment.kt
index 90313ac..3212794 100644
--- a/app/src/main/java/com/casic/br/ktd/fragment/MinePageFragment.kt
+++ b/app/src/main/java/com/casic/br/ktd/fragment/MinePageFragment.kt
@@ -2,10 +2,11 @@
import android.os.Bundle
import com.casic.br.ktd.R
-import com.pengxh.kt.lite.base.KotlinBaseFragment
+import com.casic.br.ktd.base.KotlinBaseFragment
class MinePageFragment : KotlinBaseFragment() {
- override fun initData(savedInstanceState: Bundle?) {
+
+ override fun initView(savedInstanceState: Bundle?) {
}
@@ -13,7 +14,7 @@
}
- override fun initLayoutView(): Int = R.layout.fragment_mine
+ override fun initLayoutRes(): Int = R.layout.fragment_mine
override fun observeRequestState() {
diff --git a/app/src/main/java/com/casic/br/ktd/fragment/TaskPageFragment.kt b/app/src/main/java/com/casic/br/ktd/fragment/TaskPageFragment.kt
index 8f6abf0..6b82a54 100644
--- a/app/src/main/java/com/casic/br/ktd/fragment/TaskPageFragment.kt
+++ b/app/src/main/java/com/casic/br/ktd/fragment/TaskPageFragment.kt
@@ -8,6 +8,7 @@
import androidx.recyclerview.widget.RecyclerView
import com.casic.br.ktd.R
import com.casic.br.ktd.adapter.TaskAdapter
+import com.casic.br.ktd.base.KotlinBaseFragment
import com.casic.br.ktd.holder.SwipeViewHolder
import com.casic.br.ktd.model.TaskListModel
import com.casic.br.ktd.view.InspectionActivity
@@ -15,7 +16,6 @@
import com.casic.br.ktd.widgets.AlertControlDialog
import com.casic.br.ktd.widgets.AlertInputDialog
import com.casic.br.ktd.widgets.DateRangeActionSheet
-import com.pengxh.kt.lite.base.KotlinBaseFragment
import com.pengxh.kt.lite.extensions.navigatePageTo
import com.pengxh.kt.lite.extensions.show
import com.pengxh.kt.lite.utils.WeakReferenceHandler
@@ -36,7 +36,7 @@
private var startTime = ""
private var endTime = ""
- override fun initData(savedInstanceState: Bundle?) {
+ override fun initView(savedInstanceState: Bundle?) {
weakReferenceHandler = WeakReferenceHandler(this)
taskViewModel = ViewModelProvider(this)[TaskViewModel::class.java]
taskViewModel.taskList.observe(this) {
@@ -45,7 +45,7 @@
when {
isRefresh -> {
taskAdapter.setRefreshData(dataRows)
- baseView.taskLayout.finishRefresh()
+ bv.taskLayout.finishRefresh()
isRefresh = false
}
isLoadMore -> {
@@ -53,7 +53,7 @@
"到底了,别拉了".show(requireContext())
}
taskAdapter.setLoadMoreData(dataRows)
- baseView.taskLayout.finishLoadMore()
+ bv.taskLayout.finishLoadMore()
isLoadMore = false
}
else -> {
@@ -76,9 +76,9 @@
when (msg.what) {
2023070501 -> {
if (dataBeans.size == 0) {
- baseView.emptyLayout.visibility = View.VISIBLE
+ bv.emptyLayout.visibility = View.VISIBLE
} else {
- baseView.emptyLayout.visibility = View.GONE
+ bv.emptyLayout.visibility = View.GONE
taskAdapter = object : TaskAdapter(
requireContext(), R.layout.item_task_rv_l, dataBeans
) {
@@ -97,8 +97,8 @@
}
}
//绑定侧滑事件
- swipeAction.attachToRecyclerView(baseView.taskRecyclerView)
- baseView.taskRecyclerView.adapter = taskAdapter
+ swipeAction.attachToRecyclerView(bv.taskRecyclerView)
+ bv.taskRecyclerView.adapter = taskAdapter
taskAdapter.setOnItemCheckedListener(object :
TaskAdapter.OnItemCheckedListener {
override fun onItemChecked(items: ArrayList) {
@@ -168,7 +168,7 @@
override fun initEvent() {
- baseView.calendarView.setOnClickListener {
+ bv.calendarView.setOnClickListener {
DateRangeActionSheet.Builder().setContext(requireContext())
.setOnActionSheetListener(object :
DateRangeActionSheet.OnDateRangeSelectedListener {
@@ -177,12 +177,12 @@
endTime = endDate
//显示
- baseView.selectedDateView.text = "$startDate ~ $endDate"
+ bv.selectedDateView.text = "$startDate ~ $endDate"
}
}).build().show()
}
- baseView.addTaskButton.setOnClickListener {
+ bv.addTaskButton.setOnClickListener {
// AlertInputDialog.Builder()
// .setContext(requireContext())
// .setTitle("新建巡检任务")
@@ -200,11 +200,11 @@
requireContext().navigatePageTo()
}
- baseView.deleteTaskButton.setOnClickListener {
+ bv.deleteTaskButton.setOnClickListener {
selectedItems.size.toString().show(requireContext())
}
- baseView.taskSettingsButton.setOnClickListener {
+ bv.taskSettingsButton.setOnClickListener {
AlertInputDialog.Builder()
.setContext(requireContext())
.setTitle("设置阈值")
@@ -221,14 +221,14 @@
}).build().show()
}
- baseView.taskLayout.setOnRefreshListener {
+ bv.taskLayout.setOnRefreshListener {
isRefresh = true
//刷新之后页码重置
pageIndex = 1
getTaskList()
}
- baseView.taskLayout.setOnLoadMoreListener {
+ bv.taskLayout.setOnLoadMoreListener {
isLoadMore = true
pageIndex++
getTaskList()
@@ -239,13 +239,13 @@
taskViewModel.getTaskList(
startTime,
endTime,
- baseView.taskNameView.text.toString(),
- baseView.taskCodeView.text.toString(),
+ bv.taskNameView.text.toString(),
+ bv.taskCodeView.text.toString(),
pageIndex
)
}
- override fun initLayoutView(): Int = R.layout.fragment_task
+ override fun initLayoutRes(): Int = R.layout.fragment_task
override fun observeRequestState() {
diff --git a/app/src/main/java/com/casic/br/ktd/netty/ISocketListener.kt b/app/src/main/java/com/casic/br/ktd/netty/ISocketListener.kt
deleted file mode 100644
index dab98e1..0000000
--- a/app/src/main/java/com/casic/br/ktd/netty/ISocketListener.kt
+++ /dev/null
@@ -1,19 +0,0 @@
-package com.casic.br.ktd.netty
-
-interface ISocketListener {
- companion object {
- const val STATUS_CONNECT_SUCCESS: Byte = 1 //连接成功
- const val STATUS_CONNECT_CLOSED: Byte = 0 //关闭连接
- const val STATUS_CONNECT_ERROR: Byte = 0 //连接失败
- }
-
- /**
- * 当接收到系统消息
- */
- fun onMessageResponse(data: ByteArray?)
-
- /**
- * 当连接状态发生变化时调用
- */
- fun onServiceStatusConnectChanged(statusCode: Byte)
-}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/br/ktd/netty/SocketChannelHandle.kt b/app/src/main/java/com/casic/br/ktd/netty/SocketChannelHandle.kt
deleted file mode 100644
index 42eb310..0000000
--- a/app/src/main/java/com/casic/br/ktd/netty/SocketChannelHandle.kt
+++ /dev/null
@@ -1,51 +0,0 @@
-package com.casic.br.ktd.netty
-
-import android.util.Log
-import io.netty.channel.ChannelHandlerContext
-import io.netty.channel.SimpleChannelInboundHandler
-import io.netty.handler.timeout.IdleState
-import io.netty.handler.timeout.IdleStateEvent
-import java.nio.charset.StandardCharsets
-
-class SocketChannelHandle(private val listener: ISocketListener?) :
- SimpleChannelInboundHandler() {
-
- private val kTag = "SocketChannelHandle"
-
- override fun channelActive(ctx: ChannelHandlerContext) {
- super.channelActive(ctx)
- Log.d(kTag, "channelActive ===> 连接成功")
- listener?.onServiceStatusConnectChanged(ISocketListener.STATUS_CONNECT_SUCCESS)
- }
-
- override fun channelInactive(ctx: ChannelHandlerContext) {
- super.channelInactive(ctx)
- Log.e(kTag, "channelInactive: 连接断开")
- }
-
- override fun userEventTriggered(ctx: ChannelHandlerContext, evt: Any) {
- super.userEventTriggered(ctx, evt)
- if (evt is IdleStateEvent) {
- if (evt.state() == IdleState.WRITER_IDLE) {
- //写超时,此时可以发送心跳数据给服务器
- val temp = "FF"
- ctx.writeAndFlush(temp.toByteArray(StandardCharsets.UTF_8))
- } else if (evt.state() == IdleState.READER_IDLE) {
- //读超时,此时代表没有收到心跳返回可以关闭当前连接进行重连
- ctx.close()
- }
- }
- }
-
- override fun channelRead0(ctx: ChannelHandlerContext, data: ByteArray?) {
- listener?.onMessageResponse(data)
- }
-
- override fun exceptionCaught(ctx: ChannelHandlerContext, cause: Throwable) {
- super.exceptionCaught(ctx, cause)
- Log.d(kTag, "exceptionCaught ===> $cause")
- listener?.onServiceStatusConnectChanged(ISocketListener.STATUS_CONNECT_ERROR)
- cause.printStackTrace()
- ctx.close()
- }
-}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/br/ktd/netty/SocketClient.kt b/app/src/main/java/com/casic/br/ktd/netty/SocketClient.kt
deleted file mode 100644
index d05d335..0000000
--- a/app/src/main/java/com/casic/br/ktd/netty/SocketClient.kt
+++ /dev/null
@@ -1,153 +0,0 @@
-package com.casic.br.ktd.netty
-
-import android.os.SystemClock
-import android.util.Log
-import io.netty.bootstrap.Bootstrap
-import io.netty.channel.*
-import io.netty.channel.nio.NioEventLoopGroup
-import io.netty.channel.socket.SocketChannel
-import io.netty.channel.socket.nio.NioSocketChannel
-import io.netty.handler.codec.bytes.ByteArrayDecoder
-import io.netty.handler.codec.bytes.ByteArrayEncoder
-import io.netty.handler.timeout.IdleStateHandler
-
-class SocketClient {
-
- private val kTag = "SocketClient"
-
- private var host: String? = null
- private var port = 8000
- private var nioEventLoopGroup: NioEventLoopGroup? = null
- private var channel: Channel? = null
- private var listener: ISocketListener? = null
-
- //现在连接的状态
- var connectStatus = false //判断是否已连接
- private var reconnectNum = Int.MAX_VALUE //定义的重连到时候用
- private var isNeedReconnect = true //是否需要重连
- var isConnecting = false //是否正在连接
- private set
- private var reconnectIntervalTime: Long = 15000 //重连的时间
-
- //重连时间
- fun setReconnectNum(reconnectNum: Int) {
- this.reconnectNum = reconnectNum
- }
-
- fun setReconnectIntervalTime(reconnectIntervalTime: Long) {
- this.reconnectIntervalTime = reconnectIntervalTime
- }
-
- fun setSocketListener(listener: ISocketListener?) {
- this.listener = listener
- }
-
- fun connect(host: String, port: Int) {
- this.host = host
- this.port = port
- Log.d(kTag, "connect ===> 开始连接TCP服务器")
- if (isConnecting) {
- return
- }
- //起个线程
- val clientThread: Thread = object : Thread("client-Netty") {
- override fun run() {
- super.run()
- isNeedReconnect = true
- reconnectNum = Int.MAX_VALUE
- connectServer()
- }
- }
- clientThread.start()
- }
-
- private fun connectServer() {
- synchronized(this@SocketClient) {
- var channelFuture: ChannelFuture? = null //连接管理对象
- if (!connectStatus) {
- isConnecting = true
- nioEventLoopGroup = NioEventLoopGroup() //设置的连接group
- val bootstrap = Bootstrap()
- bootstrap.group(nioEventLoopGroup) //设置的一系列连接参数操作等
- .channel(NioSocketChannel::class.java)
- .option(ChannelOption.TCP_NODELAY, true) //无阻塞
- .option(ChannelOption.SO_KEEPALIVE, true) //长连接
- .option(
- ChannelOption.RCVBUF_ALLOCATOR,
- AdaptiveRecvByteBufAllocator(5000, 5000, 8000)
- ) //接收缓冲区 最小值太小时数据接收不全
- .handler(object : ChannelInitializer() {
- override fun initChannel(channel: SocketChannel) {
- val pipeline = channel.pipeline()
- //参数1:代表读套接字超时的时间,没收到数据会触发读超时回调;
- //参数2:代表写套接字超时时间,没进行写会触发写超时回调;
- //参数3:将在未执行读取或写入时触发超时回调,0代表不处理;
- //读超时尽量设置大于写超时,代表多次写超时时写心跳包,多次写了心跳数据仍然读超时代表当前连接错误,即可断开连接重新连接
- pipeline.addLast(IdleStateHandler(60, 10, 0))
- pipeline.addLast(ByteArrayDecoder())
- pipeline.addLast(ByteArrayEncoder())
- pipeline.addLast(SocketChannelHandle(listener))
- }
- })
- try {
- //连接监听
- channelFuture = bootstrap.connect(host, port)
- .addListener(object : ChannelFutureListener {
- override fun operationComplete(channelFuture: ChannelFuture) {
- if (channelFuture.isSuccess) {
- connectStatus = true
- channel = channelFuture.channel()
- } else {
- Log.e(kTag, "operationComplete: 连接失败")
- connectStatus = false
- }
- isConnecting = false
- }
- }).sync()
- // 等待连接关闭
- channelFuture.channel().closeFuture().sync()
- } catch (e: Exception) {
- e.printStackTrace()
- } finally {
- connectStatus = false
- listener?.onServiceStatusConnectChanged(ISocketListener.STATUS_CONNECT_CLOSED) //STATUS_CONNECT_CLOSED 这我自己定义的 接口标识
- if (null != channelFuture) {
- if (channelFuture.channel() != null && channelFuture.channel().isOpen) {
- channelFuture.channel().close()
- }
- }
- nioEventLoopGroup?.shutdownGracefully()
- reconnect() //重新连接
- }
- }
- }
- }
-
- //断开连接
- fun disconnect() {
- Log.d(kTag, "disconnect ===> 断开连接")
- isNeedReconnect = false
- nioEventLoopGroup?.shutdownGracefully()
- }
-
- //重新连接
- private fun reconnect() {
- if (isNeedReconnect && reconnectNum > 0 && !connectStatus) {
- reconnectNum--
- SystemClock.sleep(reconnectIntervalTime)
- if (isNeedReconnect && reconnectNum > 0 && !connectStatus) {
- Log.d(kTag, "reconnect ===> 重新连接")
- connectServer()
- }
- }
- }
-
- fun sendData(bytes: ByteArray) {
- channel?.writeAndFlush(bytes)?.addListener(ChannelFutureListener { future ->
- if (!future.isSuccess) {
- future.channel().close()
- nioEventLoopGroup!!.shutdownGracefully()
- }
- })
- }
-}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/br/ktd/netty/SocketManager.kt b/app/src/main/java/com/casic/br/ktd/netty/SocketManager.kt
deleted file mode 100644
index 17daf35..0000000
--- a/app/src/main/java/com/casic/br/ktd/netty/SocketManager.kt
+++ /dev/null
@@ -1,113 +0,0 @@
-package com.casic.br.ktd.netty
-
-import android.util.Log
-import com.casic.br.ktd.base.BaseApplication
-import com.casic.br.ktd.extensions.covertAngleValue
-import com.casic.br.ktd.extensions.covertDataValue
-import com.casic.br.ktd.extensions.toUnsignedByteArray
-import com.casic.br.ktd.model.SensorDataModel
-import com.casic.br.ktd.utils.LocaleConstant
-import com.pengxh.kt.lite.extensions.toJson
-import com.pengxh.kt.lite.utils.BroadcastManager
-
-class SocketManager private constructor() : ISocketListener {
-
- private val kTag = "SocketManager"
- private var nettyClient: SocketClient = SocketClient()
-
- companion object {
- val instance: SocketManager by lazy(mode = LazyThreadSafetyMode.SYNCHRONIZED) { SocketManager() }
- }
-
- fun connectNetty(hostname: String, port: Int) {
- Thread {
- if (!nettyClient.connectStatus) {
- nettyClient.setSocketListener(this)
- nettyClient.connect(hostname, port)
- } else {
- nettyClient.disconnect()
- }
- }.start()
- }
-
- override fun onMessageResponse(data: ByteArray?) {
-// Log.d(kTag, "onMessageResponse ===> " + Arrays.toString(data))
- /**
- * 0xFF,0x01,
- * 0x01,0x37,0xE6, 甲烷浓度值(数据码1* 65536 + 数据码2 * 256 + 数据码3)
- * 0x00, 激光甲烷模块工作状态(00表示设备正常,01表示温控故障,02表示设备激光未打开)
- * 0x00,0xB2,0x35, 激光强度值(数据码5* 65536 + 数据码6 * 256 + 数据码7)
- * 0x0A,0x3D, 云台水平角度([数据码8 * 256 + 数据码9]/100,单位为°,精确到0.01)
- * 0x05,0x6F, 云台垂直角度(首先计算Tangle=[数据码10 * 256 + 数据码11]/100,单位为°,精确到0.01。若Tangle在0~90范围内,则垂直角度值=Tangle;若Tangle在-1~-90范围内,则垂直角度值=Tangle-360)
- * 0xC1
- *
- * [-1, 1, 1, 55, -26, 0, 0, -78, 53, 10, 61, 5, 111, -63]
- * 甲烷浓度值为79638,计算为79638=0x01*65536+0x37*256+0xE6[0x01为数据码1,0x37为数据码2,0xE6为数据码3];
- * 激光甲烷设备状态值为0,表示状态正常,[0x00为数据码4];
- * 激光强度值为45621,计算为45621=0x00*65536+0xB2*256+0x35[0x00为数据码5,0xB2为数据码6,0x35为数据码7];
- *
- * =========================================================================================
- * 实际数据(1800-1950左右)
- * [-86, 1, 0, 7, 71, 0, 0, 62, -92, 57, 59, -118, -111, -64]
- * */
-
- if (data == null) {
- return
- }
- val bytes = data.toUnsignedByteArray()
- if (bytes.size == 14) {
- val dataModel = SensorDataModel(0, "激光未打开", 0, 0.0, 0.0)
-
- val methaneBytes = IntArray(3)
- System.arraycopy(bytes, 2, methaneBytes, 0, 3)
- dataModel.methane = methaneBytes.covertDataValue()
-
- dataModel.methaneState = when (bytes[5]) {
- 1 -> "温控故障"
- 2 -> "激光未打开"
- else -> "正常"
- }
-
- val laserBytes = IntArray(3)
- System.arraycopy(bytes, 6, laserBytes, 0, 3)
- dataModel.laser = laserBytes.covertDataValue()
-
- /**
- * 水平角度的实际范围为从水平零点开始,顺时针方向(从上往下看),0~360°
- * 垂直角度的实际范围为从垂直零点开始,以向上为正,-90°~90°,控制精度为0.01°
- * */
- val horizontalBytes = IntArray(2)
- System.arraycopy(bytes, 9, horizontalBytes, 0, 2)
- dataModel.horizontal = horizontalBytes.covertAngleValue()
-
- val verticalBytes = IntArray(2)
- System.arraycopy(bytes, 11, verticalBytes, 0, 2)
- dataModel.vertical = verticalBytes.covertAngleValue()
-
- //{"horizontal":26.21,"laser":45621,"methane":79846,"methaneState":"正常","vertical":13.91}
- BroadcastManager.obtainInstance(BaseApplication.get()).sendBroadcast(
- LocaleConstant.ACTION_UPDATE_DATA, dataModel.toJson()
- )
- }
- }
-
- override fun onServiceStatusConnectChanged(statusCode: Byte) {
- if (statusCode == ISocketListener.STATUS_CONNECT_SUCCESS) {
- if (nettyClient.connectStatus) {
- Log.d(kTag, "连接成功")
- }
- } else {
- if (!nettyClient.connectStatus) {
- Log.e(kTag, "onServiceStatusConnectChanged:$statusCode,连接断开,正在重连")
- }
- }
- }
-
- fun sendData(data: ByteArray) {
- nettyClient.sendData(data)
- }
-
- fun close() {
- nettyClient.disconnect()
- }
-}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/br/ktd/netty/tcp/ISocketListener.kt b/app/src/main/java/com/casic/br/ktd/netty/tcp/ISocketListener.kt
new file mode 100644
index 0000000..13c3084
--- /dev/null
+++ b/app/src/main/java/com/casic/br/ktd/netty/tcp/ISocketListener.kt
@@ -0,0 +1,19 @@
+package com.casic.br.ktd.netty.tcp
+
+interface ISocketListener {
+ companion object {
+ const val STATUS_CONNECT_SUCCESS: Byte = 1 //连接成功
+ const val STATUS_CONNECT_CLOSED: Byte = 0 //关闭连接
+ const val STATUS_CONNECT_ERROR: Byte = 0 //连接失败
+ }
+
+ /**
+ * 当接收到系统消息
+ */
+ fun onMessageResponse(data: ByteArray?)
+
+ /**
+ * 当连接状态发生变化时调用
+ */
+ fun onServiceStatusConnectChanged(statusCode: Byte)
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/br/ktd/netty/tcp/SocketChannelHandle.kt b/app/src/main/java/com/casic/br/ktd/netty/tcp/SocketChannelHandle.kt
new file mode 100644
index 0000000..8e2997f
--- /dev/null
+++ b/app/src/main/java/com/casic/br/ktd/netty/tcp/SocketChannelHandle.kt
@@ -0,0 +1,51 @@
+package com.casic.br.ktd.netty.tcp
+
+import android.util.Log
+import io.netty.channel.ChannelHandlerContext
+import io.netty.channel.SimpleChannelInboundHandler
+import io.netty.handler.timeout.IdleState
+import io.netty.handler.timeout.IdleStateEvent
+import java.nio.charset.StandardCharsets
+
+class SocketChannelHandle(private val listener: ISocketListener?) :
+ SimpleChannelInboundHandler() {
+
+ private val kTag = "SocketChannelHandle"
+
+ override fun channelActive(ctx: ChannelHandlerContext) {
+ super.channelActive(ctx)
+ Log.d(kTag, "channelActive ===> 连接成功")
+ listener?.onServiceStatusConnectChanged(ISocketListener.STATUS_CONNECT_SUCCESS)
+ }
+
+ override fun channelInactive(ctx: ChannelHandlerContext) {
+ super.channelInactive(ctx)
+ Log.e(kTag, "channelInactive: 连接断开")
+ }
+
+ override fun userEventTriggered(ctx: ChannelHandlerContext, evt: Any) {
+ super.userEventTriggered(ctx, evt)
+ if (evt is IdleStateEvent) {
+ if (evt.state() == IdleState.WRITER_IDLE) {
+ //写超时,此时可以发送心跳数据给服务器
+ val temp = "FF"
+ ctx.writeAndFlush(temp.toByteArray(StandardCharsets.UTF_8))
+ } else if (evt.state() == IdleState.READER_IDLE) {
+ //读超时,此时代表没有收到心跳返回可以关闭当前连接进行重连
+ ctx.close()
+ }
+ }
+ }
+
+ override fun channelRead0(ctx: ChannelHandlerContext, data: ByteArray?) {
+ listener?.onMessageResponse(data)
+ }
+
+ override fun exceptionCaught(ctx: ChannelHandlerContext, cause: Throwable) {
+ super.exceptionCaught(ctx, cause)
+ Log.d(kTag, "exceptionCaught ===> $cause")
+ listener?.onServiceStatusConnectChanged(ISocketListener.STATUS_CONNECT_ERROR)
+ cause.printStackTrace()
+ ctx.close()
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/br/ktd/netty/tcp/SocketClient.kt b/app/src/main/java/com/casic/br/ktd/netty/tcp/SocketClient.kt
new file mode 100644
index 0000000..34960a0
--- /dev/null
+++ b/app/src/main/java/com/casic/br/ktd/netty/tcp/SocketClient.kt
@@ -0,0 +1,153 @@
+package com.casic.br.ktd.netty.tcp
+
+import android.os.SystemClock
+import android.util.Log
+import io.netty.bootstrap.Bootstrap
+import io.netty.channel.*
+import io.netty.channel.nio.NioEventLoopGroup
+import io.netty.channel.socket.SocketChannel
+import io.netty.channel.socket.nio.NioSocketChannel
+import io.netty.handler.codec.bytes.ByteArrayDecoder
+import io.netty.handler.codec.bytes.ByteArrayEncoder
+import io.netty.handler.timeout.IdleStateHandler
+
+class SocketClient {
+
+ private val kTag = "SocketClient"
+
+ private var host: String? = null
+ private var port = 8000
+ private var nioEventLoopGroup: NioEventLoopGroup? = null
+ private var channel: Channel? = null
+ private var listener: ISocketListener? = null
+
+ //现在连接的状态
+ var connectStatus = false //判断是否已连接
+ private var reconnectNum = Int.MAX_VALUE //定义的重连到时候用
+ private var isNeedReconnect = true //是否需要重连
+ var isConnecting = false //是否正在连接
+ private set
+ private var reconnectIntervalTime: Long = 15000 //重连的时间
+
+ //重连时间
+ fun setReconnectNum(reconnectNum: Int) {
+ this.reconnectNum = reconnectNum
+ }
+
+ fun setReconnectIntervalTime(reconnectIntervalTime: Long) {
+ this.reconnectIntervalTime = reconnectIntervalTime
+ }
+
+ fun setSocketListener(listener: ISocketListener?) {
+ this.listener = listener
+ }
+
+ fun connect(host: String, port: Int) {
+ this.host = host
+ this.port = port
+ Log.d(kTag, "connect ===> 开始连接TCP服务器")
+ if (isConnecting) {
+ return
+ }
+ //起个线程
+ val clientThread: Thread = object : Thread("client-Netty") {
+ override fun run() {
+ super.run()
+ isNeedReconnect = true
+ reconnectNum = Int.MAX_VALUE
+ connectServer()
+ }
+ }
+ clientThread.start()
+ }
+
+ private fun connectServer() {
+ synchronized(this@SocketClient) {
+ var channelFuture: ChannelFuture? = null //连接管理对象
+ if (!connectStatus) {
+ isConnecting = true
+ nioEventLoopGroup = NioEventLoopGroup() //设置的连接group
+ val bootstrap = Bootstrap()
+ bootstrap.group(nioEventLoopGroup) //设置的一系列连接参数操作等
+ .channel(NioSocketChannel::class.java)
+ .option(ChannelOption.TCP_NODELAY, true) //无阻塞
+ .option(ChannelOption.SO_KEEPALIVE, true) //长连接
+ .option(
+ ChannelOption.RCVBUF_ALLOCATOR,
+ AdaptiveRecvByteBufAllocator(5000, 5000, 8000)
+ ) //接收缓冲区 最小值太小时数据接收不全
+ .handler(object : ChannelInitializer() {
+ override fun initChannel(channel: SocketChannel) {
+ val pipeline = channel.pipeline()
+ //参数1:代表读套接字超时的时间,没收到数据会触发读超时回调;
+ //参数2:代表写套接字超时时间,没进行写会触发写超时回调;
+ //参数3:将在未执行读取或写入时触发超时回调,0代表不处理;
+ //读超时尽量设置大于写超时,代表多次写超时时写心跳包,多次写了心跳数据仍然读超时代表当前连接错误,即可断开连接重新连接
+ pipeline.addLast(IdleStateHandler(60, 10, 0))
+ pipeline.addLast(ByteArrayDecoder())
+ pipeline.addLast(ByteArrayEncoder())
+ pipeline.addLast(SocketChannelHandle(listener))
+ }
+ })
+ try {
+ //连接监听
+ channelFuture = bootstrap.connect(host, port)
+ .addListener(object : ChannelFutureListener {
+ override fun operationComplete(channelFuture: ChannelFuture) {
+ if (channelFuture.isSuccess) {
+ connectStatus = true
+ channel = channelFuture.channel()
+ } else {
+ Log.e(kTag, "operationComplete: 连接失败")
+ connectStatus = false
+ }
+ isConnecting = false
+ }
+ }).sync()
+ // 等待连接关闭
+ channelFuture.channel().closeFuture().sync()
+ } catch (e: Exception) {
+ e.printStackTrace()
+ } finally {
+ connectStatus = false
+ listener?.onServiceStatusConnectChanged(ISocketListener.STATUS_CONNECT_CLOSED) //STATUS_CONNECT_CLOSED 这我自己定义的 接口标识
+ if (null != channelFuture) {
+ if (channelFuture.channel() != null && channelFuture.channel().isOpen) {
+ channelFuture.channel().close()
+ }
+ }
+ nioEventLoopGroup?.shutdownGracefully()
+ reconnect() //重新连接
+ }
+ }
+ }
+ }
+
+ //断开连接
+ fun disconnect() {
+ Log.d(kTag, "disconnect ===> 断开连接")
+ isNeedReconnect = false
+ nioEventLoopGroup?.shutdownGracefully()
+ }
+
+ //重新连接
+ private fun reconnect() {
+ if (isNeedReconnect && reconnectNum > 0 && !connectStatus) {
+ reconnectNum--
+ SystemClock.sleep(reconnectIntervalTime)
+ if (isNeedReconnect && reconnectNum > 0 && !connectStatus) {
+ Log.d(kTag, "reconnect ===> 重新连接")
+ connectServer()
+ }
+ }
+ }
+
+ fun sendData(bytes: ByteArray) {
+ channel?.writeAndFlush(bytes)?.addListener(ChannelFutureListener { future ->
+ if (!future.isSuccess) {
+ future.channel().close()
+ nioEventLoopGroup!!.shutdownGracefully()
+ }
+ })
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/br/ktd/netty/tcp/SocketManager.kt b/app/src/main/java/com/casic/br/ktd/netty/tcp/SocketManager.kt
new file mode 100644
index 0000000..35980b9
--- /dev/null
+++ b/app/src/main/java/com/casic/br/ktd/netty/tcp/SocketManager.kt
@@ -0,0 +1,113 @@
+package com.casic.br.ktd.netty.tcp
+
+import android.util.Log
+import com.casic.br.ktd.base.BaseApplication
+import com.casic.br.ktd.extensions.covertAngleValue
+import com.casic.br.ktd.extensions.covertDataValue
+import com.casic.br.ktd.extensions.toUnsignedByteArray
+import com.casic.br.ktd.model.SensorDataModel
+import com.casic.br.ktd.utils.LocaleConstant
+import com.pengxh.kt.lite.extensions.toJson
+import com.pengxh.kt.lite.utils.BroadcastManager
+
+class SocketManager private constructor() : ISocketListener {
+
+ private val kTag = "SocketManager"
+ private var nettyClient: SocketClient = SocketClient()
+
+ companion object {
+ val instance: SocketManager by lazy(mode = LazyThreadSafetyMode.SYNCHRONIZED) { SocketManager() }
+ }
+
+ fun connectNetty(hostname: String, port: Int) {
+ Thread {
+ if (!nettyClient.connectStatus) {
+ nettyClient.setSocketListener(this)
+ nettyClient.connect(hostname, port)
+ } else {
+ nettyClient.disconnect()
+ }
+ }.start()
+ }
+
+ override fun onMessageResponse(data: ByteArray?) {
+// Log.d(kTag, "onMessageResponse ===> " + Arrays.toString(data))
+ /**
+ * 0xFF,0x01,
+ * 0x01,0x37,0xE6, 甲烷浓度值(数据码1* 65536 + 数据码2 * 256 + 数据码3)
+ * 0x00, 激光甲烷模块工作状态(00表示设备正常,01表示温控故障,02表示设备激光未打开)
+ * 0x00,0xB2,0x35, 激光强度值(数据码5* 65536 + 数据码6 * 256 + 数据码7)
+ * 0x0A,0x3D, 云台水平角度([数据码8 * 256 + 数据码9]/100,单位为°,精确到0.01)
+ * 0x05,0x6F, 云台垂直角度(首先计算Tangle=[数据码10 * 256 + 数据码11]/100,单位为°,精确到0.01。若Tangle在0~90范围内,则垂直角度值=Tangle;若Tangle在-1~-90范围内,则垂直角度值=Tangle-360)
+ * 0xC1
+ *
+ * [-1, 1, 1, 55, -26, 0, 0, -78, 53, 10, 61, 5, 111, -63]
+ * 甲烷浓度值为79638,计算为79638=0x01*65536+0x37*256+0xE6[0x01为数据码1,0x37为数据码2,0xE6为数据码3];
+ * 激光甲烷设备状态值为0,表示状态正常,[0x00为数据码4];
+ * 激光强度值为45621,计算为45621=0x00*65536+0xB2*256+0x35[0x00为数据码5,0xB2为数据码6,0x35为数据码7];
+ *
+ * =========================================================================================
+ * 实际数据(1800-1950左右)
+ * [-86, 1, 0, 7, 71, 0, 0, 62, -92, 57, 59, -118, -111, -64]
+ * */
+
+ if (data == null) {
+ return
+ }
+ val bytes = data.toUnsignedByteArray()
+ if (bytes.size == 14) {
+ val dataModel = SensorDataModel(0, "激光未打开", 0, 0.0, 0.0)
+
+ val methaneBytes = IntArray(3)
+ System.arraycopy(bytes, 2, methaneBytes, 0, 3)
+ dataModel.methane = methaneBytes.covertDataValue()
+
+ dataModel.methaneState = when (bytes[5]) {
+ 1 -> "温控故障"
+ 2 -> "激光未打开"
+ else -> "正常"
+ }
+
+ val laserBytes = IntArray(3)
+ System.arraycopy(bytes, 6, laserBytes, 0, 3)
+ dataModel.laser = laserBytes.covertDataValue()
+
+ /**
+ * 水平角度的实际范围为从水平零点开始,顺时针方向(从上往下看),0~360°
+ * 垂直角度的实际范围为从垂直零点开始,以向上为正,-90°~90°,控制精度为0.01°
+ * */
+ val horizontalBytes = IntArray(2)
+ System.arraycopy(bytes, 9, horizontalBytes, 0, 2)
+ dataModel.horizontal = horizontalBytes.covertAngleValue()
+
+ val verticalBytes = IntArray(2)
+ System.arraycopy(bytes, 11, verticalBytes, 0, 2)
+ dataModel.vertical = verticalBytes.covertAngleValue()
+
+ //{"horizontal":26.21,"laser":45621,"methane":79846,"methaneState":"正常","vertical":13.91}
+ BroadcastManager.obtainInstance(BaseApplication.get()).sendBroadcast(
+ LocaleConstant.ACTION_UPDATE_DATA, dataModel.toJson()
+ )
+ }
+ }
+
+ override fun onServiceStatusConnectChanged(statusCode: Byte) {
+ if (statusCode == ISocketListener.STATUS_CONNECT_SUCCESS) {
+ if (nettyClient.connectStatus) {
+ Log.d(kTag, "连接成功")
+ }
+ } else {
+ if (!nettyClient.connectStatus) {
+ Log.e(kTag, "onServiceStatusConnectChanged:$statusCode,连接断开,正在重连")
+ }
+ }
+ }
+
+ fun sendData(data: ByteArray) {
+ nettyClient.sendData(data)
+ }
+
+ fun close() {
+ nettyClient.disconnect()
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/br/ktd/netty/udp/UdpChannelInboundHandler.kt b/app/src/main/java/com/casic/br/ktd/netty/udp/UdpChannelInboundHandler.kt
new file mode 100644
index 0000000..4d6f97c
--- /dev/null
+++ b/app/src/main/java/com/casic/br/ktd/netty/udp/UdpChannelInboundHandler.kt
@@ -0,0 +1,36 @@
+package com.casic.br.ktd.netty.udp
+
+import io.netty.channel.ChannelHandlerContext
+import io.netty.channel.SimpleChannelInboundHandler
+import io.netty.channel.socket.DatagramPacket
+import io.netty.util.CharsetUtil
+
+
+abstract class UdpChannelInboundHandler : SimpleChannelInboundHandler