Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- // Edistynyt mobiiliohjelmointi, 24.3.2023, ILTAPÄIVÄRYHMÄ
- 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.
- 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 13:30
- // uusi fragmentti, RemoteMessageFragment, lisätään päävalikkoon, pohjakoodi:
- 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!!
- override fun onCreateView(
- inflater: LayoutInflater,
- container: ViewGroup?,
- savedInstanceState: Bundle?
- ): View? {
- _binding = FragmentRemoteMessageBinding.inflate(inflater, container, false)
- val root: View = binding.root
- return root
- }
- override fun onDestroyView() {
- super.onDestroyView()
- _binding = null
- }
- }
- // lisätään RemoteMessageFragmentin ulkoasuun TextView ja Button,
- <?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:text="Waiting..."
- 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="20dp"
- android:text="SEND MESSAGE" />
- </LinearLayout>
- // Yhdistetään MQTT:hen omilla HiveMQ-tunnuksilla
- 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!!
- // MQTT -client tarvitaan
- 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
- client = MqttClient.builder()
- .useMqttVersion3()
- .sslWithDefaultConfig()
- .identifier("kagjjkadsfhjksdfh784973")
- .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.")
- } else {
- // Setup subscribes or start publishing
- subscribeToTopic()
- }
- }
- return root
- }
- fun subscribeToTopic()
- {
- client.subscribeWith()
- .topicFilter(BuildConfig.HIVEMQ_TOPIC)
- .callback { publish ->
- // this callback runs everytime your code receives new data payload
- var result = String(publish.getPayloadAsBytes())
- Log.d("ADVTECH", result)
- // laitetaan vastaanotettu data ulkoasuun
- 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
- // hyvä tapa sammuttaa MQTT-client kun poistutaan fragmentista
- client.disconnect()
- }
- }
- // jos halutaan napilla lähettää dataa, onCreateViewiin esim: (koodissa pitää olla button_send_remote_message id:llä Button)
- // kun nappia painetaa, lähetetään satunnainen hello world -viesti
- // topicciin
- 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 komponentit, SpinKit
- https://github.com/ybq/Android-SpinKit
- // lisätään importti
- implementation 'com.github.ybq:Android-SpinKit:1.4.0'
- // koska iso osa kolmannen osa puolen komponenteista on jitpack.io -palvelussa, pitää meidän lisätä myös sen osoite
- settings.gradle:
- molempiin repositoryihin:
- maven { url "https://jitpack.io" }
- Eli esim.
- 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" }
- }
- }
- // kokeillaan esim home fragmentin ulkoasussa:
- <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"
- app:layout_constraintTop_toBottomOf="@+id/text_home" />
- // speedometer, implementation 'com.github.anastr:speedviewlib:1.6.0'
- // ohjeet: https://github.com/anastr/SpeedView
- // WeatherStationFragmentin ulkoasu, otetaan constraintlayout käyttöön jotta saadaan speedview helposti mukaan
- <?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_station_temperature"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_margin="5dp"
- android:layout_marginStart="5dp"
- android:layout_marginEnd="4dp"
- android:text="Waiting data..."
- android:textSize="22sp"
- android:textStyle="bold"
- app:layout_constraintEnd_toEndOf="parent"
- app:layout_constraintStart_toStartOf="parent"
- app:layout_constraintTop_toTopOf="parent" />
- </androidx.constraintlayout.widget.ConstraintLayout>
- // mittarin xml:
- <com.github.anastr.speedviewlib.SpeedView
- android:id="@+id/speedView"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- app:layout_constraintBottom_toBottomOf="parent"
- app:layout_constraintEnd_toEndOf="parent"
- app:layout_constraintStart_toStartOf="parent"
- />
- // säädetään parametreja, min ja max ja unitm sekä tremble oius
- <com.github.anastr.speedviewlib.SpeedView
- android:id="@+id/speedView"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- app:sv_withTremble="false"
- app:sv_minSpeed="-50"
- app:sv_maxSpeed="50"
- app:sv_unit="℃"
- app:layout_constraintBottom_toBottomOf="parent"
- app:layout_constraintEnd_toEndOf="parent"
- app:layout_constraintStart_toStartOf="parent"
- />
- // kustomikalenteri, linkki:
- https://github.com/npanigrahy/Custom-Calendar-View
- Muista asentaa versio 1.1, 1.0 ei toimi
- implementation 'com.github.npanigrahy:Custom-Calendar-View:v1.1'
- Uusi fragment, CalendarFragment, ulkoasu;
- <?xml version="1.0" encoding="utf-8"?>
- <FrameLayout 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"
- tools:context=".CalendarFragment">
- <com.stacktips.view.CustomCalendarView
- android:id="@+id/calendar_view"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:background="#ffffff">
- </com.stacktips.view.CustomCalendarView>
- </FrameLayout>
- // CalendarFragment.kt:
- class CalendarFragment : Fragment() {
- // change this to match your fragment name
- private var _binding: FragmentCalendarBinding? = null
- // This property is only valid between onCreateView and
- // onDestroyView.
- private val binding get() = _binding!!
- override fun onCreateView(
- inflater: LayoutInflater,
- container: ViewGroup?,
- savedInstanceState: Bundle?
- ): View? {
- _binding = FragmentCalendarBinding.inflate(inflater, container, false)
- val root: View = binding.root
- //Initialize calendar with date
- val currentCalendar: Calendar = Calendar.getInstance(Locale.getDefault())
- //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()
- }
- })
- // the binding -object allows you to access views in the layout, textviews etc.
- return root
- }
- override fun onDestroyView() {
- super.onDestroyView()
- _binding = null
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement