For this post, I am going to share the technical aspects behind Mallsyok app. I have previously written two posts regarding Mallsyok introduction and workflow with tools. Make sure to read the previous posts by clicking the link below and give some 👏
In the images below are the screens available in Mallsyok and how they interact with one another. Firstly, users will need select one from list of malls which will then bring them to a list of outlets based on their mall selection. Once a mall is selected, they can either select an outlet from list of outlets, select map (flow 1) or select other information related to the mall (flow 2).
Mallsyok uses the basic MVC which stands of Model-View-Controller pattern. This helps to isolate the different roles of this application. By default, the tools offered by Android Studio with layouts, activities and data structure steers any application into MVC pattern. Model represents the data layer. Mallsyok uses model to obtain and store information regarding malls and outlets. View is the user interface layer or what the user sees on their screen. Controller is the logic layer which gets notified of users’ behaviour and updates model if needed. This logic layer does all data processing, controls the visibility of certain UI components and responsible for retrieving information from database in background.
Here is how it looks like at high level for our Mallsyok app in MVC.
Mallsyok stores all mall and outlet information in the database. Back then we got to know Firebase Realtime Database from some video tutorials and decided to try it. NoSQL was relatively new to us in the sense we had to design the simplest and denormalised or flattened data structure. Due to its ease of implementation, we were able to integrate RTDB into our app and got it running in no time.
Then Firebase Cloud Firestore came swinging by and we were interested as well. Different from RTDB which stores data in form of JSON tree structure, Cloud Firestore stores them in collections of documents. A document stores key-value pairs whereas collection stores a set of documents.
Click on this link to understand the difference in features between RTDB and Firestore.
We migrated to Firestore because we were convinced it was a better option compare to RTDB. However it was few days after our app was officially out in the playstore that we realised that it was a mistake 😰.
This is due to the way Firestore is charging and the way our app works. Firestore charges by the number of reads, writes and deletes. If you go for the free account, there is a limited number of each operation per day. If you go beyond that limit then you won’t be able to perform that specific operation until the next day when the counter resets. Let’s assume a user chooses a mall that contains 1,000 outlets so that would be 1,000 read operations. Due to this, Mallsyok can easily exceed the limited operations in a day. A better option will be RTDB where it charges by amount of data in GB stored and downloaded.
You can understand more on the differences in charging here.
Let’s start to dive into some of the special features and how it was implemented in Mallsyok!
This feature helps user to skip selection of mall if they are already at that mall. By using combination of network and GPS, depending on which is stronger, Mallsyok is able to obtain location of user’s phone and matches to the nearest mall. Initially LocationManager was used to obtain user location but this depends only on GPS signal. Unfortunately when user is inside the mall, GPS signal will be too weak and in the end the app just shows time out when user requests for auto locate. Luckily we found FusedLocationProviderClient which uses combination of network or GPS to obtain user location. To use this api, firstly we need to declare the permission needed in AndroidManifest.xml
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
Next we can build location settings request. In this request we can set specific parameters such as interval of location update and accuracy. More information on the location settings here.
These parameters will be pass to LocationSettingsRequest to be built.
We use checkLocationSettings check if these settings request is satisfactory. We too need to check if user has granted access for the app to use their location. Finally we request for user location either in continuous updates or just last known location using getLastLocation method and return this location on the addOnSuccessListener.
You can test location on android emulator by setting latitude and longitude. To do this, click on the more icon to bring out the extended control window. Click on location and enter both latitude and longitude. The method getLastLocation may return null because the location cache is not updated. Hence launch google map to force updated location cache and getLastLocation should be able to return the location that you entered. Can more information here.
Mallsyok has a search bar function for users to be able to find malls or outlets quickly. The listview which displays list of malls or outlets will updates itself whenever there is a change in text entered in search bar.
Retrieving the list again and again from Firestore is expensive, hence we store the list as global variable and reload listview when user resets the search bar.
We added this feature to prevent user from having bad UI experience when they are cut off from internet. Hence we added a check for network availability whenever a new screen is loaded.
If isNetworkAvailable returns a false, we simply load a screen with refresh icon and toast saying no internet detected. When the network is available again, user just tap on the refresh icon and it will reload the screen.
Interactive Static Information
Mallsyok helps to provide information such as contact, address and website. But rather than to display static information, Mallsyok extends to help users interact with the information. Simply tapping those information, users can perform action based on it. For those to happen, we simply pass the string tapped by user into respective helper function to start new a intent.
User can view floor plans in Mallsyok when they tap on Map menu. For this to happen, we store all images in Firebase Storage with floor number as their file name. We need to store information of how many levels a mall has, hence we keep it in the Firebase Cloud Firestore. Hence, when user taps on Map, our app grabs the list of floor levels and from the list, grabs the correct images to be rendered on the screen. For image downloading, we use Picasso which is powerful and easy to implement library.
To start using Picasso, simply add in build.gradle (Module:app)
To render the image on the screen, we use TouchImageView implementation by MikeOrtiz. His amazing implementation helps you to render image with extensive features such as dragging, pinch zoom, fling, double tap zoom and animation polish. To start using, simply place TouchImageView.java into your project and assign image just like how you do it with ImageView. See the magic below 🤤
Well I guess this post wraps up everything that I need to share about Mallsyok. If you like this post and find it informative, kindly click the 👏 to encourage me to write more 😄👍
Feel free to try out the app itself on Android. Apologies to iphone 📱 users that this app is not available 🙏