Advertisement
tuomasvaltanen

Untitled

Feb 14th, 2023 (edited)
185
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 11.71 KB | None | 0 0
  1. // Edistynyt mobiiliohjelmointi, 14.2.2023
  2.  
  3. // OpenWeatherMapin API:
  4. // https://openweathermap.org/current
  5.  
  6. // esim. Rantavitikan kampus, Lapin AMK:
  7. https://api.openweathermap.org/data/2.5/weather?lat=66.48130266083665&lon=25.723290728723306&appid=OMA_API_KEY_TÄHÄN
  8.  
  9. // data on esim:
  10.  
  11. {"coord":{"lon":25.7233,"lat":66.4813},"weather":[{"id":600,"main":"Snow","description":"light snow","icon":"13n"}],"base":"stations","main":{"temp":269.94,"feels_like":265.71,"temp_min":269.94,"temp_max":269.94,"pressure":1020,"humidity":86},"visibility":10000,"wind":{"speed":3.09,"deg":210},"snow":{"1h":0.12},"clouds":{"all":20},"dt":1676355896,"sys":{"type":1,"id":1354,"country":"FI","sunrise":1676356275,"sunset":1676385095},"timezone":7200,"id":638936,"name":"Rovaniemi","cod":200}
  12.  
  13. // muutetaan yksiköt metriseen järjestelmään (oletuksena lämpötila on näemmä Kelvineitä)
  14. https://api.openweathermap.org/data/2.5/weather?lat=66.48130266083665&lon=25.723290728723306&appid=OMA_API_KEY_TÄHÄN&units=metric
  15.  
  16. // nyt data on:
  17. {"coord":{"lon":25.7233,"lat":66.4813},"weather":[{"id":600,"main":"Snow","description":"light snow","icon":"13n"}],"base":"stations","main":{"temp":-3.21,"feels_like":-7.44,"temp_min":-3.21,"temp_max":-3.21,"pressure":1020,"humidity":86},"visibility":10000,"wind":{"speed":3.09,"deg":210},"snow":{"1h":0.1},"clouds":{"all":20},"dt":1676356259,"sys":{"type":1,"id":1354,"country":"FI","sunrise":1676356275,"sunset":1676385095},"timezone":7200,"id":638936,"name":"Rovaniemi","cod":200}
  18.  
  19. Google Maps -> OpenStreetMap -ohjeet:
  20. 1. MapsFragment -> onMarkerClick:
  21. Tarvitsemme markerin koordinaatit seuraavia vaiheita varten (esim. p0.position.latitude jne.)
  22.  
  23. 2. Luo uusi fragment navigation editorin avulla: CityWeatherFragment (ota käyttöön myös binding layer) ja tee action MapsFragmentista CityWeatherFragmentiin. CityWeatherFragmentille kaksi argumenttia: latitude ja longitude (molemmat Float).
  24.  
  25. 3. Navigoi onMarkerClickistä CityWeatherFragmentiin käyttämällä navController -> navigate
  26.  
  27. 4. CityWeatherFragment – ota vastaan argumentit, ja luo uusi JSON_URL -muuttuja.
  28.  
  29. Tee ensin muuttuja API_KEY, johon tallennat oman OpenWeatherMapin API keyn. Jos tallensit API key:n local.properties-tiedostoon, voit hakea sen koodissa näin:
  30.  
  31. val API_KEY : String = BuildConfig.OPENWEATHER_API_KEY
  32.  
  33. HUOM! BuildConfig päivittyy vain silloin kun ohjelmaa ajetaan emulaattorissa (play-nappi), pelkkä rebuild ei riitä!
  34.  
  35. val JSON_URL : String = https://api.openweathermap.org/data/2.5/weather?lat=${args.latitude}&long=${args.longitude}&units=metric&appid=${API_KEY}
  36.  
  37. 5. Käytä Volleyta, ja lataa JSON_URLin avulla JSON-data
  38.  
  39. 6. Luo säädatan pohjalta CityWeather-niminen luokka käyttämällä json2kt.com -palvelua, ja lataa se Android-projektiisi
  40.  
  41. 7. Muunna JSON-data (response) GSONin avulla CityWeather-olioksi. Käytä oikeaa versiota GSON-koodista, eli tässä tapauksessa dataa tulee vain yksi objekti!
  42.  
  43. 8. Tulosta CityWeather -olion avulla tämän hetkinen lämpötila
  44. LogCatiin ja esim. ulkoasussa olevaan TextViewiin
  45.  
  46. ------------------------------------------------------
  47.  
  48. Muista luoda tarvittavat data-luokat json2kt.com-palvelussa! Lopputuloksena tulee 8 luokkatiedostoa (kannattaa tehdä oma paketti projektiin, esim. datatypes -> cityweather, ettei projektin kansio ole sekaisin fragmentteja ja dataluokkia.)
  49.  
  50. Jos Snow-luokkaan tulee virhe, ota muuttujan nimestä 1 pois (eli pelkkä h)
  51.  
  52. Ohjaajan versio (täydennetään myöhemmin):
  53.  
  54. MapsFragment.kt, onMarkerClick():
  55.  
  56. // jos mitä tahansa markeria klikataan, ajetaan tämä funktio
  57. override fun onMarkerClick(p0: Marker): Boolean {
  58. Log.d("ADVTECH", "MARKKERI!")
  59.  
  60. // lokitetaan/tulostetaan markeriin liitetyt koordinaatit sekä
  61. // tagi, jossa pitäisi olla kaupungin nimi
  62. Log.d("ADVTECH", p0.position.latitude.toString())
  63. Log.d("ADVTECH", p0.position.longitude.toString())
  64. Log.d("ADVTECH", p0.tag.toString())
  65.  
  66. // navigoidaan CityWeatherFragmentiin, ja laitetaan koordinaatit parametreiksi
  67. val action = MapsFragmentDirections.actionMapsFragmentToCityWeatherFragment(p0.position.latitude.toFloat(), p0.position.longitude.toFloat())
  68. findNavController().navigate(action)
  69.  
  70. // onMarkerClick vaatii lopussa että palautetaan boolean
  71. return false
  72. }
  73.  
  74. CityWeatherFragment.kt:
  75.  
  76. class CityWeatherFragment : Fragment() {
  77. private var _binding: FragmentCityWeatherBinding? = null
  78.  
  79. // get fragment parameters from previous fragment
  80. val args: CityWeatherFragmentArgs by navArgs()
  81.  
  82. // This property is only valid between onCreateView and
  83. // onDestroyView.
  84. private val binding get() = _binding!!
  85. override fun onCreateView(
  86. inflater: LayoutInflater,
  87. container: ViewGroup?,
  88. savedInstanceState: Bundle?
  89. ): View? {
  90. _binding = FragmentCityWeatherBinding.inflate(inflater, container, false)
  91. val root: View = binding.root
  92.  
  93. // print out the given parameter into logs
  94.  
  95. getWeather()
  96.  
  97. return root
  98. }
  99.  
  100. fun getWeather() {
  101. // haetaan API-key local.properties-tiedostosta, muista käyttää projektia päällä play-napista että tiedosto päivittyy
  102. // voit myös asettaa API keyn suoraan muuttujaan tekstinä, mutta se ei ole optimaalinen ratkaisu
  103. val API_KEY : String = BuildConfig.OPENWEATHERMAP_API_KEY
  104.  
  105. // rakennetaan URL rajapintaan muuttujien avulla
  106. val JSON_URL : String = "https://api.openweathermap.org/data/2.5/weather?lat=${args.latitude}&lon=${args.longitude}&appid=${API_KEY}&units=metric"
  107.  
  108. val gson = GsonBuilder().setPrettyPrinting().create()
  109.  
  110. // Request a string response from the provided URL.
  111. val stringRequest: StringRequest = object : StringRequest(
  112. Request.Method.GET, JSON_URL,
  113. Response.Listener { response ->
  114. // print the response as a whole
  115. // we can use GSON to modify this response into something more usable
  116. Log.d("ADVTECH", response)
  117.  
  118. // muunnetaan data CityWeather-olioksi
  119. var item : CityWeather = gson.fromJson(response, CityWeather::class.java)
  120.  
  121. // haetaan pelkkä lämpötila
  122. Log.d("ADVTECH", item.main?.temp.toString() + " C")
  123.  
  124. // jos halutaan näyttää esim. TextViewissä ja sen id on textView_temperature:
  125. // binding.textViewTemperature.text = item.main?.temp.toString() + " C"
  126. },
  127. Response.ErrorListener {
  128. // typically this is a connection error
  129. Log.d("ADVTECH", it.toString())
  130. })
  131. {
  132. @Throws(AuthFailureError::class)
  133. override fun getHeaders(): Map<String, String> {
  134.  
  135. // basic headers for the data
  136. val headers = HashMap<String, String>()
  137. headers["Accept"] = "application/json"
  138. headers["Content-Type"] = "application/json; charset=utf-8"
  139. return headers
  140. }
  141. }
  142.  
  143. // Add the request to the RequestQueue. This has to be done in both getting and sending new data.
  144. // if using this in an activity, use "this" instead of "context"
  145. val requestQueue = Volley.newRequestQueue(context)
  146. requestQueue.add(stringRequest)
  147.  
  148.  
  149. Log.d("ADVTECH", JSON_URL)
  150. }
  151.  
  152. override fun onDestroyView() {
  153. super.onDestroyView()
  154. _binding = null
  155. }
  156. }
  157.  
  158. EXTRA:
  159.  
  160. Stylen asettaminen TextViewiin koodissa:
  161.  
  162. textViewTitle.setTextAppearance(this, R.style.RedHUGEText);
  163.  
  164. TextViewin värin muuttaminen koodissa:
  165.  
  166. textView.setTextColor(Color.parseColor("#FF0000"))
  167.  
  168. // Permissionit tulee aina kysyä myös koodissa, jotta käyttäjä voi antaa suostumuksensa
  169. // uusissa Androideissa tämä on vaadittua
  170.  
  171.  
  172.  
  173.  
  174. // AndroidManifest:
  175.  
  176. <uses-permission android:name="android.permission.INTERNET" />
  177. <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
  178. <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
  179. <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
  180.  
  181. Lisätään MainActivityyn funktio:
  182.  
  183. fun hasPermissions(context: Context, vararg permissions: String): Boolean = permissions.all {
  184. ActivityCompat.checkSelfPermission(context, it) == PackageManager.PERMISSION_GRANTED
  185. }
  186.  
  187. // lisätään MainActivityn onCreaten loppuun:
  188.  
  189. // in Activity onCreate:
  190. val PERMISSION_ALL = 123
  191.  
  192. // näiden permissioneiden pitää olla myös AndroidManifestissa
  193. val PERMISSIONS = arrayOf(
  194. Manifest.permission.INTERNET,
  195. Manifest.permission.ACCESS_FINE_LOCATION,
  196. Manifest.permission.ACCESS_COARSE_LOCATION,
  197. Manifest.permission.ACCESS_NETWORK_STATE
  198. )
  199.  
  200. if (!hasPermissions(this, *PERMISSIONS)) {
  201. ActivityCompat.requestPermissions(this, PERMISSIONS, PERMISSION_ALL)
  202. }
  203.  
  204.  
  205. // OpenStreetMap
  206. https://github.com/osmdroid/osmdroid/wiki/How-to-use-the-osmdroid-library-(Kotlin)
  207.  
  208. // Uusi fragment, OpenStreetMapFragment.kt:
  209.  
  210. import org.osmdroid.views.MapView
  211. import org.osmdroid.config.Configuration.*
  212. import org.osmdroid.tileprovider.tilesource.TileSourceFactory
  213. import org.osmdroid.util.GeoPoint
  214. import org.osmdroid.views.overlay.Marker
  215.  
  216. /**
  217. * A simple [Fragment] subclass.
  218. * Use the [OpenStreetMapFragment.newInstance] factory method to
  219. * create an instance of this fragment.
  220. */
  221. class OpenStreetMapFragment : Fragment() {
  222. // change this to match your fragment name
  223. private var _binding: FragmentOpenStreetMapBinding? = null
  224.  
  225. // This property is only valid between onCreateView and
  226. // onDestroyView.
  227. private val binding get() = _binding!!
  228.  
  229. override fun onCreateView(
  230. inflater: LayoutInflater,
  231. container: ViewGroup?,
  232. savedInstanceState: Bundle?
  233. ): View? {
  234. _binding = FragmentOpenStreetMapBinding.inflate(inflater, container, false)
  235. val root: View = binding.root
  236.  
  237. // tarvittavat gradle-importit:
  238. // implementation 'org.osmdroid:osmdroid-android:6.1.14'
  239. // implementation 'androidx.preference:preference:1.2.0'
  240.  
  241. // käytetään tätä versiota PreferenceMananagerista ettei ole deprecated Android 10:stä eteenpäin
  242. // huom: import ylhäällä: import androidx.preference.PreferenceManager
  243. getInstance().load(context, PreferenceManager.getDefaultSharedPreferences(context as Context))
  244.  
  245. // binding-layerin kautta mapViewiin pääsy, ks. osm-droidin ohje miten lisätään ulkoasu tälle fragmentille
  246. // https://github.com/osmdroid/osmdroid/wiki/How-to-use-the-osmdroid-library-(Kotlin)
  247. binding.map.setTileSource(TileSourceFactory.MAPNIK)
  248.  
  249. // asetetaan alkupiste + zoomaus
  250. val mapController = binding.map.controller
  251. mapController.setZoom(18.0)
  252. val startPoint = GeoPoint(66.50352001528042, 25.727189822733095);
  253. mapController.setCenter(startPoint);
  254.  
  255. // lisätään marker Rovaniemelle
  256. val marker = Marker(binding.map)
  257. marker.position = startPoint
  258. marker.title = "Rovaniemi marker!"
  259. marker.setAnchor(Marker.ANCHOR_CENTER, Marker.ANCHOR_CENTER)
  260. binding.map.overlays.add(marker)
  261. binding.map.invalidate()
  262.  
  263. // onClick onnistuu mm. näin
  264. marker.setOnMarkerClickListener { marker, mapView ->
  265.  
  266. Log.d("ADVTECH", "MARKKKERIIIII!")
  267.  
  268. return@setOnMarkerClickListener false
  269. }
  270.  
  271. return root
  272. }
  273.  
  274. override fun onDestroyView() {
  275. super.onDestroyView()
  276. _binding = null
  277.  
  278. }
  279. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement