Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- Edistynyt mobiiliohjelmointi, 24.3.2023, B243, AAMULUENTO
- ---------------------------------------------------
- Tehdään tänään oma MQTT-klusteri HiveMQ-palveluun, testataan yhteydet MQTTX:llä, ja ohjelmoidaan sitten Androidiin fragment, joka osaa lähettää ja vastaanottaa tekstidataa.
- Vaiheet:
- 1. Tee Harjoitus 4 ohjeen mukaisesti HiveMQ-palveluun oma klusteri, tee käyttäjätunnus, ja
- testaa datan liikkuminen (lähetys ja vastaanotto) molempiin suuntiin ohjeen mukaisella topicilla MQTTX-ohjelmalle
- 2. Tee mobile_navigation -työkalulla uusi Fragment Android-projektiin nimeltä RemoteMessageFragment. Lisää tämä fragment päävalikkoon, ja ota fragmentissa binding-layer käyttöön
- 3. Tee local.properties-tiedostoon tarvittavat muuttujat HiveMQ:ta varten (ei lainausmerkkejä mihinkään arvoon):
- HIVEMQ_BROKER=oman_klusterin_osoite
- HIVEMQ_USERNAME=oman_klusterin_käyttäjänimi
- HIVEMQ_PASSWORD=oman_klusterin_salasana
- HIVEMQ_TOPIC=koodin_käyttämä_topic
- 4. Jatketaan tästä vaiheesta yhdessä klo 9:20
- -----------
- RemoteMessageFragmentin ulkoasu, TextView ja Button, esim.
- <?xml version="1.0" encoding="utf-8"?>
- <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:tools="http://schemas.android.com/tools"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:layout_margin="10dp"
- android:orientation="vertical"
- tools:context=".RemoteMessageFragment">
- <TextView
- android:id="@+id/textView_remote_message"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:textSize="22sp"
- android:textStyle="bold" />
- <Button
- android:id="@+id/button_send_remote_message"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_marginTop="10dp"
- android:text="Button" />
- </LinearLayout>
- RemoteMessageFragment.kt, viestin vastaanottaminen:
- class RemoteMessageFragment : Fragment() {
- // change this to match your fragment name
- private var _binding: FragmentRemoteMessageBinding? = null
- // This property is only valid between onCreateView and
- // onDestroyView.
- private val binding get() = _binding!!
- // HiveMQ MQTT ver 3 -client
- private lateinit var client: Mqtt3AsyncClient
- override fun onCreateView(
- inflater: LayoutInflater,
- container: ViewGroup?,
- savedInstanceState: Bundle?
- ): View? {
- _binding = FragmentRemoteMessageBinding.inflate(inflater, container, false)
- val root: View = binding.root
- // version 3, IBM Cloud, weather station
- // identifier => lisätään local.propertiesissa olevaan alkuosaan satunnainen teksti
- // jotta saadaan uniikki osa myös mukaan (vaadittu IBM Cloudissa)
- client = MqttClient.builder()
- .useMqttVersion3()
- .sslWithDefaultConfig()
- .identifier("And23B243TVtest1")
- .serverHost(BuildConfig.HIVEMQ_BROKER)
- .serverPort(8883)
- .buildAsync()
- client.connectWith()
- .simpleAuth()
- .username(BuildConfig.HIVEMQ_USERNAME)
- .password(BuildConfig.HIVEMQ_PASSWORD.toByteArray())
- .applySimpleAuth()
- .send()
- .whenComplete { connAck: Mqtt3ConnAck?, throwable: Throwable? ->
- if (throwable != null) {
- Log.d("ADVTECH", "Connection failure.")
- Log.d("ADVTECH", throwable.message.toString())
- } else {
- // Setup subscribes or start publishing
- subscribeToTopic()
- }
- }
- return root
- }
- // subscribe apufunktio
- fun subscribeToTopic()
- {
- client.subscribeWith()
- .topicFilter("test/topic")
- .callback { publish ->
- // this callback runs everytime your code receives new data payload
- var result = String(publish.getPayloadAsBytes())
- Log.d("ADVTECH", result)
- activity?.runOnUiThread{
- binding.textViewRemoteMessage.text = result
- }
- }
- .send()
- .whenComplete { subAck, throwable ->
- if (throwable != null) {
- // Handle failure to subscribe
- Log.d("ADVTECH", "Subscribe failed.")
- } else {
- // Handle successful subscription, e.g. logging or incrementing a metric
- Log.d("ADVTECH", "Subscribed!")
- }
- }
- }
- override fun onDestroyView() {
- super.onDestroyView()
- _binding = null
- // kannattaa myös katkaista MQTT-yhteys kun fragment suljetaan
- client.disconnect()
- }
- }
- // jos halutaan lähettää dataa napin kautta, esim. jos Buttonin id on button_send_remote_message, voidaan asettaa tämä onCreateViewiin:
- // kun nappia painetaan, generoidaan satunnainen viesti ja
- // lähetetään samaan topiciin. tässä tapauksessa esim. test/topic
- binding.buttonSendRemoteMessage.setOnClickListener {
- var randomNumber = Random.nextInt(0, 100)
- var stringPayload = "Hello world! " + randomNumber.toString()
- client.publishWith()
- .topic(BuildConfig.HIVEMQ_TOPIC)
- .payload(stringPayload.toByteArray())
- .send()
- }
- // Kolmannen osapuolen Custom Viewit:
- // kokeillaan
- https://github.com/ybq/Android-SpinKit
- // osa kolmannen osapuolen liitännöistä vaatii jitpack.io -repositoryyn yhteyden.
- Avaa settings.gradle, ja lisää
- maven { url "https://jitpack.io" }
- molempiin repositories-kohtaan, eli kaikkinensa:
- pluginManagement {
- repositories {
- google()
- mavenCentral()
- gradlePluginPortal()
- maven { url "https://jitpack.io" }
- }
- }
- dependencyResolutionManagement {
- repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
- repositories {
- google()
- mavenCentral()
- maven { url "https://jitpack.io" }
- }
- }
- esim fragment_homen ulkoasuun:
- <com.github.ybq.android.spinkit.SpinKitView
- android:id="@+id/spin_kit"
- style="@style/SpinKitView.Large.Wave"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_gravity="center"
- app:SpinKit_Color="@color/purple_200"
- app:layout_constraintBottom_toBottomOf="parent"
- app:layout_constraintEnd_toEndOf="parent"
- app:layout_constraintStart_toStartOf="parent" />
- // seuraava plugin : https://github.com/anastr/SpeedView
- // hyödynnetään tätä pluginia sääasema (MQTT) -fragmentissa, muutetaan ulkoasua:
- <?xml version="1.0" encoding="utf-8"?>
- <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:app="http://schemas.android.com/apk/res-auto"
- xmlns:tools="http://schemas.android.com/tools"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- tools:context=".WeatherStationFragment">
- <!-- TODO: Update blank fragment layout -->
- <TextView
- android:id="@+id/textView_weather_data"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_margin="5sp"
- android:text="@string/hello_blank_fragment"
- android:textSize="24sp"
- android:textStyle="bold"
- app:layout_constraintEnd_toEndOf="parent"
- app:layout_constraintTop_toTopOf="parent" />
- </androidx.constraintlayout.widget.ConstraintLayout>
- // säädetään speedviewiä hieman, min ja max arvot välilläe -50 ja 50, ja yksiköksi celsius
- // otetaan myös tremble pois, koska se heiluttaa koko ajan arvoa, eikä vastaa oikeaa dataa
- <com.github.anastr.speedviewlib.SpeedView
- android:id="@+id/speedView"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_margin="30dp"
- app:layout_constraintBottom_toBottomOf="parent"
- app:layout_constraintEnd_toEndOf="parent"
- app:layout_constraintStart_toStartOf="parent"
- app:sv_withTremble="false"
- app:sv_minSpeed="-50"
- app:sv_maxSpeed="50"
- app:sv_unit="℃"
- app:layout_constraintTop_toBottomOf="@+id/textView_weather_data" />
- // nyt voidaan kytkeä sääasemadata speedviewiin MQTT-koodissa, esim.
- try {
- var item : WeatherStation = gson.fromJson(result, WeatherStation::class.java)
- // haetaan lämpötila WeatherStation-objektin kautta
- // haetaan myös ilmanpaine
- var temperature = item.d.get1().v.toString()
- var pressure = item.d.get2().v.toString()
- // rakennetaan simppeli teksti ulkoasua varten
- var output = "Temp: ${temperature} C\nPressure:${pressure}"
- // haetaan Float-muotoinen lämpötila speedviewiä varten
- var temperatureValue = item.d.get1().v.toFloat()
- // ajetaan ulkoasuun liittyvät asiat UI-säikeessä
- // koska MQTT toimii itsessään taustasäikeessä
- // ilman tätä, ohjelma kaatuu
- activity?.runOnUiThread(java.lang.Runnable {
- binding.textViewWeatherData.text = output
- binding.speedView.speedTo(temperatureValue)
- })
- }
- // kokeillaan kustomikalenteria, muista myös jitpack lisätä settings.gradleen (ks. aiemmat ohjeet), import:
- implementation 'com.github.npanigrahy:Custom-Calendar-View:v1.1'
- Ohjeet (mutta vain Javalle):
- https://github.com/npanigrahy/Custom-Calendar-View
- Hae ohjeista XML joka lisätään ulkoasuun (default riittää)
- Esim. CalendarFragment, onCreateView:
- // haetaan javan peruskalenteriolio
- val currentCalendar = Calendar.getInstance(Locale.getDefault())
- // the binding -object allows you to access views in the layout, textviews etc.
- //Show Monday as first date of week
- binding.calendarView.setFirstDayOfWeek(Calendar.MONDAY)
- //Show/hide overflow days of a month
- binding.calendarView.setShowOverflowDate(false)
- //call refreshCalendar to update calendar the view
- binding.calendarView.refreshCalendar(currentCalendar)
- //Handling custom calendar events
- binding.calendarView.setCalendarListener(object : CalendarListener {
- override fun onDateSelected(date: Date?) {
- val df = SimpleDateFormat("dd-MM-yyyy")
- Toast.makeText(activity as Context, df.format(date), Toast.LENGTH_SHORT).show()
- }
- override fun onMonthChanged(date: Date?) {
- val df = SimpleDateFormat("MM-yyyy")
- Toast.makeText(activity as Context, df.format(date), Toast.LENGTH_SHORT).show()
- }
- })
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement