Advertisement
tuomasvaltanen

Untitled

Feb 16th, 2023 (edited)
146
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 13.41 KB | None | 0 0
  1. // Edistynyt mobiiliohjelmointi, 16.2.2023
  2.  
  3. // current weather API OpenWeatherMap
  4. https://openweathermap.org/current
  5.  
  6. // rajapinnasta dataa esim näin:
  7. https://api.openweathermap.org/data/2.5/weather?lat=66.50336579596632&lon=25.727513206740678&appid=OMA_API_KEY_TÄHÄN&units=metric
  8.  
  9. // esimerkki-dataa:
  10.  
  11. {"coord":{"lon":25.7275,"lat":66.5034},"weather":[{"id":803,"main":"Clouds","description":"broken clouds","icon":"04d"}],"base":"stations","main":{"temp":-1.29,"feels_like":-7.89,"temp_min":-1.29,"temp_max":-1.29,"pressure":1005,"humidity":100},"visibility":10000,"wind":{"speed":7.72,"deg":180},"clouds":{"all":75},"dt":1676543953,"sys":{"type":1,"id":1354,"country":"FI","sunrise":1676528625,"sunset":1676558334},"timezone":7200,"id":638936,"name":"Rovaniemi","cod":200}
  12.  
  13. // Tehdään seuraava osio, eli haetaan säätiedot kaupungin koordinaattien perusteella:
  14.  
  15. Google Maps -> OpenStreetMap -ohjeet:
  16.  
  17. 1. MapsFragment -> onMarkerClick:
  18. Tarvitsemme markerin koordinaatit seuraavia vaiheita varten (esim. p0.position.latitude jne.)
  19.  
  20. 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).
  21.  
  22. 3. Navigoi onMarkerClickistä CityWeatherFragmentiin käyttämällä navController -> navigate
  23.  
  24. 4. CityWeatherFragmentissa – ota vastaan argumentit, ja luo uusi JSON_URL -muuttuja (ks. esimerkki alta).
  25. 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:
  26.  
  27. val API_KEY : String = BuildConfig.OPENWEATHER_API_KEY
  28.  
  29. HUOM! BuildConfig päivittyy vain silloin kun ohjelmaa ajetaan emulaattorissa (play-nappi), pelkkä rebuild ei riitä!
  30.  
  31. val JSON_URL : String = “https://api.openweathermap.org/data/2.5/weather?lat=${args.latitude}&long=${args.longitude}&units=metric&appid=${API_KEY}”
  32.  
  33. 5. Käytä Volleyta, ja lataa JSON_URLin avulla JSON-data (response)
  34.  
  35. 6. Luo säädatan pohjalta CityWeather-niminen luokka käyttämällä json2kt.com -palvelua, ja lataa se Android-projektiisi. aseta OpenWeatherMapista tuleva JSON esim. Rovaniemen säätilanteesta esimerkkidataksi
  36.  
  37. 7. Muunna JSON-data (response) GSONin avulla CityWeather-olioksi. Käytä oikeaa versiota GSON-koodista, eli tässä tapauksessa dataa tulee vain yksi objekti!
  38.  
  39. 8. Tulosta CityWeather -olion avulla tämän hetkinen lämpötila LogCatiin ja esim. ulkoasussa olevaan TextViewiin
  40.  
  41. -----------------------------
  42.  
  43. Tehdään ensin uusi fragment -> CityWeatherFragment, ja sille kaksi parametria, latitude ja longitude (float)
  44. Lisäksi action MapsFragmentista -> CityWeatherFragment
  45.  
  46. MapsFragment.kt, onMarkerClick():
  47.  
  48. // OnMarkerClickiä kutsutaan jos mitä tahansa markeria kartalla klikataan
  49. override fun onMarkerClick(p0: Marker): Boolean {
  50.  
  51. Log.d("TESTI", "MARKKERI CLICK! JES!")
  52.  
  53. // kaivetaan marker-oliosta klikatun markkerin nimi ja koordinaatit
  54. Log.d("TESTI", p0.tag.toString())
  55.  
  56. Log.d("TESTI", p0.position.latitude.toString())
  57. Log.d("TESTI", p0.position.longitude.toString())
  58.  
  59. val latitude : Float = p0.position.latitude.toFloat()
  60. val longitude : Float = p0.position.longitude.toFloat()
  61.  
  62. // tähän action ja navigate, parametreiksi ylläolevat latitude ja longitude -muuttujat
  63. val action = MapsFragmentDirections.actionMapsFragmentToCityWeatherFragment(latitude, longitude)
  64. findNavController().navigate(action)
  65.  
  66. // OnMarkerClick vaatii että lopuksi palautetaan Boolean
  67. return false
  68. }
  69.  
  70. // CItyWeatherFragment:
  71.  
  72. class CityWeatherFragment : Fragment() {
  73. // change this to match your fragment name
  74. private var _binding: FragmentCityWeatherBinding? = null
  75.  
  76. val args: CityWeatherFragmentArgs by navArgs()
  77. // This property is only valid between onCreateView and
  78. // onDestroyView.
  79. private val binding get() = _binding!!
  80.  
  81. override fun onCreateView(
  82. inflater: LayoutInflater,
  83. container: ViewGroup?,
  84. savedInstanceState: Bundle?
  85. ): View? {
  86. _binding = FragmentCityWeatherBinding.inflate(inflater, container, false)
  87. val root: View = binding.root
  88.  
  89. Log.d("TESTI", args.latitude.toString())
  90. Log.d("TESTI", args.longitude.toString())
  91.  
  92. getWeather()
  93.  
  94. // the binding -object allows you to access views in the layout, textviews etc.
  95.  
  96. return root
  97. }
  98.  
  99. fun getWeather() {
  100. val API_KEY = BuildConfig.OPENWEATHER_API_KEY
  101.  
  102. val JSON_URL : String = "https://api.openweathermap.org/data/2.5/weather?lat=${args.latitude}&lon=${args.longitude}&units=metric&appid=${API_KEY}"
  103.  
  104. val gson = GsonBuilder().setPrettyPrinting().create()
  105.  
  106. // Request a string response from the provided URL.
  107. val stringRequest: StringRequest = object : StringRequest(
  108. Request.Method.GET, JSON_URL,
  109. Response.Listener { response ->
  110.  
  111. // print the response as a whole
  112. // we can use GSON to modify this response into something more usable
  113. Log.d("TESTI", response)
  114.  
  115. var item : CityWeather = gson.fromJson(response, CityWeather::class.java)
  116.  
  117. Log.d("TESTI", "Lämpötila: ${item.main?.temp} C")
  118.  
  119. // asetetaan lämpötila esim. TextViewiin, tässä tapauksessa TextViewin
  120. // id = textView_city_temperature
  121. // binding.textViewCityTemperature.text = item.main?.temp.toString() + " C"
  122.  
  123. },
  124. Response.ErrorListener {
  125. // typically this is a connection error
  126. Log.d("TESTI", it.toString())
  127. })
  128. {
  129. @Throws(AuthFailureError::class)
  130. override fun getHeaders(): Map<String, String> {
  131.  
  132. // basic headers for the data
  133. val headers = HashMap<String, String>()
  134. headers["Accept"] = "application/json"
  135. headers["Content-Type"] = "application/json; charset=utf-8"
  136. return headers
  137. }
  138. }
  139.  
  140. // Add the request to the RequestQueue. This has to be done in both getting and sending new data.
  141. // if using this in an activity, use "this" instead of "context"
  142. val requestQueue = Volley.newRequestQueue(context)
  143. requestQueue.add(stringRequest)
  144.  
  145. }
  146.  
  147. override fun onDestroyView() {
  148. super.onDestroyView()
  149. _binding = null
  150. }
  151. }
  152.  
  153.  
  154. #######################################
  155.  
  156. Muutetaan permissionit Manifestiin OpenStreetMapia varten, eli:
  157.  
  158. <uses-permission android:name="android.permission.INTERNET" />
  159. <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
  160. <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
  161. <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
  162.  
  163. huom, jos pyydät permissioneita koodila, samat permissionit pitää löytyä myös manifestissa.
  164.  
  165. MainActivity.kt:
  166.  
  167. import alkuun ylös:
  168.  
  169. import android.Manifest
  170.  
  171. onCreaten loppuun:
  172.  
  173. // in Activity onCreate:
  174. val PERMISSION_ALL = 123
  175. val PERMISSIONS = arrayOf(
  176. Manifest.permission.ACCESS_FINE_LOCATION,
  177. Manifest.permission.ACCESS_COARSE_LOCATION,
  178. Manifest.permission.ACCESS_NETWORK_STATE,
  179. Manifest.permission.INTERNET
  180. )
  181.  
  182. if (!hasPermissions(this, *PERMISSIONS)) {
  183. ActivityCompat.requestPermissions(this, PERMISSIONS, PERMISSION_ALL)
  184. }
  185.  
  186.  
  187. omaksi funktioksi MainActivityyn:
  188. fun hasPermissions(context: Context, vararg permissions: String): Boolean = permissions.all {
  189. ActivityCompat.checkSelfPermission(context, it) == PackageManager.PERMISSION_GRANTED
  190. }
  191.  
  192.  
  193. eli kokonaisuus, esim:
  194.  
  195. class MainActivity : AppCompatActivity() {
  196.  
  197. private lateinit var appBarConfiguration: AppBarConfiguration
  198. private lateinit var binding: ActivityMainBinding
  199.  
  200. override fun onCreate(savedInstanceState: Bundle?) {
  201. super.onCreate(savedInstanceState)
  202.  
  203. binding = ActivityMainBinding.inflate(layoutInflater)
  204. setContentView(binding.root)
  205.  
  206. setSupportActionBar(binding.appBarMain.toolbar)
  207.  
  208. binding.appBarMain.fab.setOnClickListener { view ->
  209. Snackbar.make(view, "Replace with your own action", Snackbar.LENGTH_LONG)
  210. .setAction("Action", null).show()
  211. }
  212. val drawerLayout: DrawerLayout = binding.drawerLayout
  213. val navView: NavigationView = binding.navView
  214. val navController = findNavController(R.id.nav_host_fragment_content_main)
  215. // Passing each menu ID as a set of Idds because each
  216. // menu should be considered as top level destinations.
  217. appBarConfiguration = AppBarConfiguration(setOf(
  218. R.id.nav_home, R.id.nav_gallery, R.id.nav_slideshow, R.id.dataReadFragment,
  219. R.id.commentApiFragment, R.id.mapsFragment), drawerLayout)
  220.  
  221. setupActionBarWithNavController(navController, appBarConfiguration)
  222. navView.setupWithNavController(navController)
  223.  
  224. // in Activity onCreate:
  225. val PERMISSION_ALL = 123
  226. val PERMISSIONS = arrayOf(
  227. Manifest.permission.ACCESS_FINE_LOCATION,
  228. Manifest.permission.ACCESS_COARSE_LOCATION,
  229. Manifest.permission.ACCESS_NETWORK_STATE,
  230. Manifest.permission.INTERNET
  231. )
  232.  
  233. if (!hasPermissions(this, *PERMISSIONS)) {
  234. ActivityCompat.requestPermissions(this, PERMISSIONS, PERMISSION_ALL)
  235. }
  236. }
  237.  
  238. // add a new function to ACTIVITY
  239. fun hasPermissions(context: Context, vararg permissions: String): Boolean = permissions.all {
  240. ActivityCompat.checkSelfPermission(context, it) == PackageManager.PERMISSION_GRANTED
  241. }
  242.  
  243. override fun onCreateOptionsMenu(menu: Menu): Boolean {
  244. // Inflate the menu; this adds items to the action bar if it is present.
  245. menuInflater.inflate(R.menu.main, menu)
  246. return true
  247. }
  248.  
  249. override fun onSupportNavigateUp(): Boolean {
  250. val navController = findNavController(R.id.nav_host_fragment_content_main)
  251. return navController.navigateUp(appBarConfiguration) || super.onSupportNavigateUp()
  252. }
  253. }
  254.  
  255. ####################################
  256.  
  257. OpenStreetMap Androidille:
  258.  
  259. https://github.com/osmdroid/osmdroid
  260.  
  261. Käyttöohje:
  262. https://github.com/osmdroid/osmdroid/wiki
  263.  
  264. Tarvittavat gradle-dependencyt:
  265.  
  266. implementation 'org.osmdroid:osmdroid-android:6.1.14'
  267. implementation 'androidx.preference:preference:1.2.0'
  268.  
  269. Tehdään oma fragment OpenStreetMapFragment, ja lisätään päävalikkoon.
  270.  
  271. OpenStreetMapFragmentin ulkoasuksi:
  272.  
  273. <?xml version="1.0" encoding="utf-8"?>
  274. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
  275. android:orientation="vertical"
  276. android:layout_width="fill_parent"
  277. android:layout_height="fill_parent">
  278. <org.osmdroid.views.MapView android:id="@+id/map"
  279. android:layout_width="fill_parent"
  280. android:layout_height="fill_parent" />
  281. </LinearLayout>
  282.  
  283. OpenStreetFragment.kt:
  284.  
  285. import androidx.preference.PreferenceManager
  286. import org.osmdroid.config.Configuration.*
  287. import org.osmdroid.tileprovider.tilesource.TileSourceFactory
  288. import org.osmdroid.util.GeoPoint
  289. import org.osmdroid.views.overlay.Marker
  290.  
  291. class OpenStreetMapFragment : Fragment() {
  292. // change this to match your fragment name
  293. private var _binding: FragmentOpenStreetMapBinding? = null
  294.  
  295. // This property is only valid between onCreateView and
  296. // onDestroyView.
  297. private val binding get() = _binding!!
  298.  
  299. override fun onCreateView(
  300. inflater: LayoutInflater,
  301. container: ViewGroup?,
  302. savedInstanceState: Bundle?
  303. ): View? {
  304. _binding = FragmentOpenStreetMapBinding.inflate(inflater, container, false)
  305. val root: View = binding.root
  306.  
  307. // haetaan viittaus Androidin sisäiseen SharedPreferences-ominaisuuteen
  308. // jonne OpenStreetMap voi tallentaa tarvittaessa dataa (esim. kartta-tile-kuvat)
  309. getInstance().load(context, PreferenceManager.getDefaultSharedPreferences(context as Context))
  310.  
  311. // the binding -object allows you to access views in the layout, textviews etc.
  312.  
  313. // asetetaan TileSource, oletus MAPNIK
  314. binding.map.setTileSource(TileSourceFactory.MAPNIK)
  315.  
  316. // asetetaan zoom-taso ja koordinatit Rovaniemelle
  317. // huom, setZoom olettaa floatin!
  318. val mapController = binding.map.controller
  319. mapController.setZoom(16.0)
  320. val startPoint = GeoPoint(66.50336579596632, 25.727513206740678);
  321. mapController.setCenter(startPoint);
  322.  
  323. // lisätään marker Rovaniemielle
  324. val marker = Marker(binding.map)
  325. marker.position = startPoint
  326. marker.title = "Rovaniemi marker!"
  327. marker.setAnchor(Marker.ANCHOR_CENTER, Marker.ANCHOR_CENTER)
  328. binding.map.overlays.add(marker)
  329. binding.map.invalidate()
  330.  
  331. // markeria jos klikataan, ajetaan tämä
  332. marker.setOnMarkerClickListener { marker, mapView ->
  333.  
  334. Log.d("TESTI", "Markeria klikattu!")
  335.  
  336. return@setOnMarkerClickListener false
  337. }
  338.  
  339. return root
  340. }
  341.  
  342. override fun onDestroyView() {
  343. super.onDestroyView()
  344. _binding = null
  345. }
  346. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement