MyPlaces – znajdź mnie!

Zgłosiłam się do udziału w bootcampie androidowym. Warunkiem wzięcia udziału było napisanie dwóch aplikacji do końca sierpnia. Niestety końcówkę sierpnia spędziłam z Małym w szpitalu, więc się nie załapałam, ale coś tam z tej aplikacji powstało 😉 Nie chcę żeby się zmarnowało, więc dokończyłam implementację i będę mieć do portfolio ;D

Mały w żłobku, więc zaczynamy 🙂

Jedna z aplikacji, które były wymagane miała używać GPS-a i pozwalać na zapisywanie położenia w „sposób trwały”. Dodatkowo mogła też wyświetlać je na mapie. Stworzyłam sobie taką aplikację w Kotlinie. I tak bardziej wygląda to na koślawą aplikację javową, ale może jeszcze kiedyś do niej usiądę i będzie bardziej kotlinowa 😉 cały kod -> tu

Troszkę kodu? proszę 😉


package com.projects.jezinka.myplaces
import android.provider.BaseColumns
object MyPlacesContract {
data class MyPlace(val id: Long,
val longitude: String,
val latitude: String,
val note: String,
val order: Int)
class MyPlaceEntry : BaseColumns {
companion object {
val TABLE_NAME = "my_place"
val _ID = "_id"
val COLUMN_NAME_LONGITUDE = "longitude"
val COLUMN_NAME_LATITUDE = "latitude"
val COLUMN_NAME_NOTE = "note"
val COLUMN_NAME_ORDER = "order_no"
}
}
}

Kotlin nie oferuje statycznych obiektów, właściwości, etc. Zamiast tego mamy tzw. companion object, którego możemy użyć w odwołaniach:


package com.projects.jezinka.myplaces
import android.content.Context
import android.database.sqlite.SQLiteDatabase
import android.database.sqlite.SQLiteOpenHelper
class MyPlacesDBHelper(context: Context) : SQLiteOpenHelper(context, DATABASE_NAME, null, DATABASE_VERSION) {
private val SQL_CREATE_ENTRIES =
"""CREATE TABLE ${MyPlacesContract.MyPlaceEntry.Companion.TABLE_NAME}
(${MyPlacesContract.MyPlaceEntry.Companion._ID} INTEGER PRIMARY KEY,
${MyPlacesContract.MyPlaceEntry.Companion.COLUMN_NAME_NOTE} TEXT,
${MyPlacesContract.MyPlaceEntry.Companion.COLUMN_NAME_LONGITUDE} TEXT,
${MyPlacesContract.MyPlaceEntry.Companion.COLUMN_NAME_LATITUDE} TEXT,
${MyPlacesContract.MyPlaceEntry.Companion.COLUMN_NAME_ORDER} INTEGER)"""
private val SQL_DELETE_ENTRIES = "DROP TABLE IF EXISTS ${MyPlacesContract.MyPlaceEntry.Companion.TABLE_NAME}"
override fun onCreate(db: SQLiteDatabase) {
db.execSQL(SQL_CREATE_ENTRIES)
}
override fun onOpen(db: SQLiteDatabase) {
super.onOpen(db)
db.execSQL("PRAGMA foreign_keys=ON")
}
override fun onUpgrade(db: SQLiteDatabase, oldVersion: Int, newVersion: Int) {
// This database is only a cache for online data, so its upgrade policy is
// to simply to discard the data and start over
db.execSQL(SQL_DELETE_ENTRIES)
onCreate(db)
}
override fun onDowngrade(db: SQLiteDatabase, oldVersion: Int, newVersion: Int) {
onUpgrade(db, oldVersion, newVersion)
}
companion object {
// If you change the database schema, you must increment the database version.
val DATABASE_VERSION = 5
val DATABASE_NAME = "myPlaces.db"
}
}

Baza jest dość prosta. Jedna tabelka, 5 kolumn (id, długość, szerokość, notka, kolejność). Zbyt wielkiej filozofii tu nie ma 😉

Pod guzikiem „znajdź mnie”, wywołuję funkcję, która pobiera położenie telefonu na podstawie GPS-a:


fun findMeButtonClick(view: View) {
val locationManager = applicationContext.getSystemService(Context.LOCATION_SERVICE) as LocationManager
val bestProvider = locationManager.getBestProvider(Criteria(), false)
val location = locationManager.getLastKnownLocation(bestProvider)
if (location != null) {
longitude.text = location.longitude.toString()
latitude.text = location.latitude.toString()
}
}

view raw

MainActivity.kt

hosted with ❤ by GitHub

Całą robotę robi: getLastKnownLocation, bo przecież nie muszę sama oprogramowywać całego modułu obliczającego moją lokalizację 😀

Przycisk z mapką obsługuję na poziomie adaptera podłączonego do ListView na głównym ekranie:


(holder.mapButton as ImageButton).setOnClickListener({ (context as MainActivity).showOnMap(myPlace.longitude.toDouble(), myPlace.latitude.toDouble(), myPlace.note) })

Żeby wyświetlić wybrany punkt na mapce, trzeba załadować odpowiednie parametry w nowo tworzone activity:


fun showOnMap(mLong: Double, mLat: Double, mTitle: String) {
val activityIntent = Intent(this, MapsActivity::class.java)
activityIntent.putExtra("long", mLong)
activityIntent.putExtra("lat", mLat)
activityIntent.putExtra("title", mTitle)
this.startActivity(activityIntent)
}

view raw

MainActivity.kt

hosted with ❤ by GitHub

Activity do obsługi mapki:


package com.projects.jezinka.myplaces
import android.os.Bundle
import android.support.v4.app.FragmentActivity
import com.google.android.gms.maps.CameraUpdateFactory
import com.google.android.gms.maps.GoogleMap
import com.google.android.gms.maps.OnMapReadyCallback
import com.google.android.gms.maps.SupportMapFragment
import com.google.android.gms.maps.model.LatLng
import com.google.android.gms.maps.model.MarkerOptions
class MapsActivity : FragmentActivity(), OnMapReadyCallback {
private var mMap: GoogleMap? = null
private var mlong: Double = -34.0
private var mlat: Double = 151.0
private var mTitle: String = getString(R.string.here)
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_maps)
mlong = intent.getDoubleExtra("long", mlong)
mlat = intent.getDoubleExtra("lat", mlat)
mTitle = intent.getStringExtra("title")
val mapFragment = supportFragmentManager.findFragmentById(R.id.map) as SupportMapFragment
mapFragment.getMapAsync(this)
}
override fun onMapReady(googleMap: GoogleMap) {
mMap = googleMap
val myPlace = LatLng(mlat, mlong)
mMap!!.addMarker(MarkerOptions().position(myPlace).title(mTitle))
mMap!!.moveCamera(CameraUpdateFactory.newLatLng(myPlace))
mMap!!.animateCamera(CameraUpdateFactory.zoomTo(15f))
}
}

view raw

MapsActivity.kt

hosted with ❤ by GitHub

Reszta kodu na GitHubie – oczywiście bez kluczy do API 😉

Dodaj komentarz

Twój adres e-mail nie zostanie opublikowany. Wymagane pola są oznaczone *

This site uses Akismet to reduce spam. Learn how your comment data is processed.