Отчёт по курсовой работе
по дисциплине
«Разработка информационно - управляющих систем»
на тему:
«Разработка приложения для Android «Track tracking»»
ПОЯСНИТЕЛЬНАЯ ЗАПИСКА
Студент группы ПИМ-19 Головкин Д. М.
Студент группы ПИМ-19 Соколов Д. С.
Руководитель Ломанов А.Н.
Рыбинск 2020
Содержание
1 Постановка задачи. 3
2 Используемые инструменты и технологии. 4
3 Назначение приложения и функциональные требования. 5
4 Заключение. 6
5 Литература. 7
Приложения. 8
Приложение А – примеры программного кода. 8
Приложение Б - Интерфейс программы……………………………………………………....14
Постановка задачи
Целью курсовой работы является написание программы, способной обрабатывать потом данных и на его основе давать результат. Входными данным являются GPS координаты устройства, с которого выполняется программа. Координаты приходят несколько раз в секунду, что позволяет на их основе строить карту маршрутов и определять местонахождение пользователя.
|
|
Используемые инструменты и технологии
В качестве языка разработки программного продукта, был выбран Kotlin, так как он предоставляет все необходимые компоненты и библиотеки для создания и стабильной работы в Android.
Kotlin – статически типизированный, объектно-ориентированный язык программирования, работающий поверх Java Virtual Machine и разрабатываемый компанией JetBrains. Благодаря его преимуществам, он был выбран приоритетным языком для создания Android-приложения компанией Google. Вот некоторые из плюсов языка:
1) Простые функции и структуры можно объявить одной строкой.
2) Геттеры и сеттеры задаются за кулисами для интероперабельности с Java-кодом.
3) Kotlin не допускает возникновения NullPointerException, выдавая ошибку компиляции.
4) В Kotlin содержатся специальные классы, предназначенные специально для хранения данных. Они генерируют различные шаблоны: equals(), hashCode(), toString(), геттеры и сеттеры и т.д.
5) Так же Kotlin позволяет расширять функциональность существующих классов, не прибегая к наследованию. Это делается при помощи функций-расширений. Для объявления такой функции к её имени нужно приписать префикс в виде расширяемого типа.
6) Kotlin — это следующий этап развития Java, с которой он полностью совместим. Это делает его отличным инструментом для мобильных и энтерпрайз-приложений.
Назначение приложения и функциональные требования
|
|
Мобильные устройства часто используются для решения различных задач связанных с определением географических координат. Транспорт, строительство, путешественники, так или иначе, нуждаются в определении своего местоположения или других объектов. Реализация данного приложения поможет людям избегать плутания на местности и возвращаться в точку начала движения.
Функциональные требования
· Определения сторон света
· Отображение компаса на экране устройства
· Отображение карты на экране устройства
· Установка на карте отметок пройденного пути
Этапы реализации
Задачу реализации программы можно разбить на 3 этапа:
1. получение GPS координат и их обработка
2. симуляция компаса на экране
3. отображение данных на карте
1. Получение gps координат и их обработка:
В Android SDK весь функционал по работе с навигационными системами объединён в пакет android.location. Ключевые компоненты данного пакета:
· LocationManager – (класс) обеспечивает доступ к системной службе определения местоположения Android;
· LocationListener — (интерфейс) регламентирует обработку приложение событий службы определения местоположения Android;
· Location – (класс) представляет географические координаты полученные от навигационной системы.
Первым делом необходимо предоставить приложению необходимые разрешения в файле манифеста. Определяем поставщика данных о местоположении. В данном случае используется GPS. Определяется минимальный интервал обновления данных о местоположения в миллисекундах (Значение «0» соответствует использованию минимально возможного интервала времени для данного устройства). Определяется м инимальное расстояние для обновления данных о местоположении в метрах ( Значение «0» соответствует использованию минимально возможного расстояния для данного устройства). Полученные координаты за 5 метров или за 30 секунд усредняются и впоследствии будут добавлены на карту.
2. Симуляция компаса на экране:
Для определения направления компаса необходимо рассчитать азимут из полученных координат и получить угол направления движения. После этого загружаем картинку и поворачиваем ее ориентируясь на север.
3. Отображение данных на карте:
Полученные и обработанные координаты отмечаются на карте устройства. Так пользователь сможет определить свой путь, тем самым вернувшись в исходную точку не заблудившись.
Заключение
В ходе выполнения курсовой работы был получен опыт в обработке большого потока данных поступающих на устройство. Обработка GPS координат (вычисление средних значений, полученных за определенный интервал времени) и отображение их на Google карте. Также получен опыт в разработке программ под устройства Android с помощью языка программирования Kotlin.
Литература
1. STARTANDROID. [Электронный ресурс] URL: https://startandroid.ru/ru/uroki/vse-uroki-spiskom/132-urok-69-peredaem-parcelable-obekty-s-pomoschju-intent.
2. Хабр. Пишем на Kotlin под Android. [Электронный ресурс] URL: https://habr.com/ru/company/JetBrains/blog/231525/
3. Developers. Location. [Электронный ресурс] URL: https://developer.android.com/reference/kotlin/android/location/Location 4. Официальное руководство по Kotlin. [Электронный ресурс] URL: https://kotlinlang.org/.
Приложения
Приложение А – примеры программного кода
Класс MainActivity:
class MainActivity: AppCompatActivity(), LocationListener, SensorEventListener {
private val REQUEST_LOCATION = 2 private var sensorManager: SensorManager? = null
/***************/ lateinit var mapFragment: SupportMapFragment lateinit var googleMap: GoogleMap /***************/
override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.main_activity) setLocation() sensorManager = getSystemService(Context.SENSOR_SERVICE) as SensorManager startCompass() }
private fun setLocation() { if (ActivityCompat.checkSelfPermission(this, android.Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(this,
android.Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED){ ActivityCompat.requestPermissions(this, arrayOf(android.Manifest.permission.ACCESS_FINE_LOCATION, android.Manifest.permission.ACCESS_COARSE_LOCATION), REQUEST_LOCATION) }else{
var locationManager = getSystemService(Context.LOCATION_SERVICE) as LocationManager val criteria = Criteria() val provider = locationManager.getProviders(criteria, false) val location = locationManager.getLastKnownLocation(provider[1])
locationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER,1000,0f, this) if (location!= null) { text_view_location.text = convertLocationToString(location.latitude, location.longitude) /***************/ mapFragment = supportFragmentManager.findFragmentById(R.id.mapView) as SupportMapFragment mapFragment.getMapAsync(OnMapReadyCallback { googleMap = it
val location1 = LatLng(location.latitude, location.longitude) googleMap.addMarker(MarkerOptions().position(location1).title("Это Я.")) googleMap!!.addPolyline(PolylineOptions().add(LatLng(location.latitude, location.longitude)).color(Color.RED)) /*googleMap.addPolyline(PolylineOptions() .add(LatLng(location.latitude, location.longitude)) .width(0f) .color(Color.RED))*/ googleMap.animateCamera(CameraUpdateFactory.newLatLngZoom(location1, 10f)) }) /***************/ }else{ Toast.makeText(this,"Location not available!",Toast.LENGTH_SHORT).show() } } }
override fun onRequestPermissionsResult( requestCode: Int, permissions: Array<out String>, grantResults: IntArray ) { if(requestCode == REQUEST_LOCATION) setLocation() }
private fun convertLocationToString(latitude: Double, longitude: Double): String {
val builder = StringBuilder() if (latitude < 0) builder.append("S ") else builder.append("N ")
val latitudeDegrees = Location.convert(Math.abs(latitude), Location.FORMAT_SECONDS) val latitudeSplit = latitudeDegrees.split((":").toRegex()).dropLastWhile({it.isEmpty()}).toTypedArray() builder.append(latitudeSplit[0]) builder.append("*") builder.append(latitudeSplit[1]) builder.append("'") builder.append(latitudeSplit[2]) builder.append("\"") builder.append("\n")
if (longitude < 0) builder.append("W ") else builder.append("E ") val longlatitudeDegrees = Location.convert(Math.abs(longitude),Location.FORMAT_SECONDS) val longitudeSplit = longlatitudeDegrees.split((":")).dropLastWhile({it.isEmpty()}).toTypedArray() builder.append(longitudeSplit[0]) builder.append("*") builder.append(longitudeSplit[1]) builder.append("'") builder.append(longitudeSplit[2]) builder.append("\"") return builder.toString() }
override fun onLocationChanged(location: Location?) { setLocation()
}
override fun onStatusChanged(provider: String?, status: Int, extras: Bundle?) {
}
override fun onProviderEnabled(provider: String?) {
}
override fun onProviderDisabled(provider: String?) {
}
override fun onAccuracyChanged(sensor: Sensor?, accuracy: Int) {
}
private var rotationMatrix = FloatArray(9) private var orientation = FloatArray(3) private var azimuth:Int = 0 private var lastAccelerometer = FloatArray(3) private var lastAccelerometerSet = false private var lastMagnetometer = FloatArray(3) private var lastMagnetometerSet = false
override fun onSensorChanged(event: SensorEvent?) { if (event!!.sensor.type == Sensor.TYPE_ROTATION_VECTOR){ SensorManager.getRotationMatrixFromVector(rotationMatrix, event!!.values) azimuth = (Math.toDegrees(SensorManager.getOrientation(rotationMatrix, orientation)[0].toDouble())+360).toInt()%360 }
if (event!!.sensor.type == Sensor.TYPE_ACCELEROMETER){ System.arraycopy(event!!.values, 0, lastAccelerometer,0,event.values.size) lastAccelerometerSet = true }else if(event.sensor.type == Sensor.TYPE_MAGNETIC_FIELD){ System.arraycopy(event.values,0, lastMagnetometer,0,event.values.size) lastMagnetometerSet = true } if (lastAccelerometerSet && lastMagnetometerSet) { SensorManager.getRotationMatrix(rotationMatrix,null,lastAccelerometer, lastMagnetometer) SensorManager.getOrientation(rotationMatrix, orientation) azimuth = (Math.toDegrees(SensorManager.getOrientation(rotationMatrix,orientation)[0].toDouble())+360).toInt()%360 } azimuth = Math.round(azimuth.toFloat()) compass_image.rotation = (-azimuth).toFloat() val where = when(azimuth){ in 281..349 -> "NW" in 261..280 -> "W" in 191..260 -> "SW" in 171..190 -> "S" in 101..170 -> "SE" in 81..100 -> "E" in 11..80 -> "NE" else -> "N" } text_view_degree.text = "$azimuth*$where" }
private var accelerometer: Sensor? = null private var magnetometer: Sensor? = null private var haveSensorAccelerometer = false private var haveSensorMagnetometer = false private var rotationVector: Sensor? = null private var haveSensorRotationVector = false
private fun startCompass(){ if (sensorManager!!.getDefaultSensor(Sensor.TYPE_ROTATION_VECTOR) == null) { if (sensorManager!!.getDefaultSensor(Sensor.TYPE_ACCELEROMETER) == null || sensorManager!!.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD)==null){ noSensorAlert() } else { accelerometer = sensorManager!!.getDefaultSensor(Sensor.TYPE_ACCELEROMETER) magnetometer = sensorManager!!.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD)
haveSensorAccelerometer = sensorManager!!.registerListener(this, accelerometer, SensorManager.SENSOR_DELAY_UI) haveSensorMagnetometer = sensorManager!!.registerListener(this, magnetometer, SensorManager.SENSOR_DELAY_UI) } }else { rotationVector = sensorManager!!.getDefaultSensor(Sensor.TYPE_ROTATION_VECTOR) haveSensorRotationVector = sensorManager!!.registerListener(this, rotationVector, SensorManager.SENSOR_DELAY_UI) } }
private fun stopCompass(){ if (haveSensorRotationVector) sensorManager!!.unregisterListener(this, rotationVector) if (haveSensorAccelerometer) sensorManager!!.unregisterListener(this, accelerometer) if (haveSensorMagnetometer) sensorManager!!.unregisterListener(this, magnetometer) }
private fun noSensorAlert() { val alertDialog = AlertDialog.Builder(this) alertDialog.setMessage("Not support a compass!").setCancelable(false).setNegativeButton("Close"){_,_->finish()} alertDialog.show() }
override fun onResume() { super.onResume() startCompass() } override fun onPause() { super.onPause() stopCompass() } } | |||||
|
| ||||
Приложение Б