Dynamic Base URL Support in the Open Event Organizer App

Open Event API Server acts as a backend for Open Event Organizer Android App. The server has a development instance running on the web for developers. Developers use this instance to try out new feature additions, bug fixings and other such changes in the source code. And when confirmed working, these changes are updated to the main running instance which is kept live throughout for the users. Similarly for Android app developers, to test the app with both the instances, we have implemented the dynamic base URL support in the app. The app has a default base URL set to development instance or main instance dependent on the debug mode. That means the app will use a server on developer instance when used under debug mode and will use a main instance server if used under release mode. The app also provides an option to enter an alternate URL while login in the app which replaces default base URL in the app for the session. In the organizer app, we are using Retrofit + Okhttp for handling network requests and dagger for dependency injection. The OkhttpClient provider in NetworkModule class looks like: @Provides @Singleton OkHttpClient providesOkHttpClient(HostSelectionInterceptor interceptor) { return new OkHttpClient.Builder() .addNetworkInterceptor(new StethoInterceptor()) .build(); }   Retrofit had a support for mutable base URL in the earlier versions but the feature is no longer available in the recent versions. We are using Interceptor class for changing base URL. The class has a method named intercept, which gets called at each network request. In this method, base URL is reset to the new URL. So first you have to extend Interceptor class and reset base URL in the intercept method. The Interceptor class in the app looks like: public final class HostSelectionInterceptor implements Interceptor { private String host; private String scheme; public HostSelectionInterceptor(){ //Intentionally left blank } public void setInterceptor(String url) { HttpUrl httpUrl = HttpUrl.parse(url); scheme = httpUrl.scheme(); host = httpUrl.host(); } @Override public Response intercept(Chain chain) throws IOException { Request original = chain.request(); // If new Base URL is properly formatted then replace the old one if (scheme != null && host != null) { HttpUrl newUrl = original.url().newBuilder() .scheme(scheme) .host(host) .build(); original = original.newBuilder() .url(newUrl) .build(); } return chain.proceed(original); } }   The class has a private string field host to save base URL. The method setInterceptor is used to change the base URL. Once the base URL is changed, thereafter all the network requests use changed URL to call. So now our interceptor is ready which can be used to support dynamic base URL in the app. This interceptor is added to Okhttp builder using its method addInterceptor. @Provides @Singleton HostSelectionInterceptor providesHostSelectionInterceptor() { return new HostSelectionInterceptor(); } @Provides @Singleton OkHttpClient providesOkHttpClient(HostSelectionInterceptor interceptor) { return new OkHttpClient.Builder() .addInterceptor(interceptor) .addNetworkInterceptor(new StethoInterceptor()) .build(); }   And now you are able to change base URL just by using the setInterceptor method of Interceptor class from anywhere in the app. And by then all the network calls use the updated base URL.…

Continue ReadingDynamic Base URL Support in the Open Event Organizer App

Implementing Sponsors API in Open Event Frontend to Display Sponsors

This article will illustrate how the sponsors have been displayed on the public event page in Open Event Frontend using the Open-Event-Orga sponsors API. As we know that the project is an ember application so, it uses Ember data to consume the API. For fetching the sponsors, we would be mainly focusing on the following API endpoint: GET /v1/events/{event_identifier}/sponsors   In the application we need to display the sponsors is the event’s public page which contains the event details, ticketing information, speaker details etc. along with the list of sponsors so, we will be only concerned with the public/index route in the application. As the sponsors details are nested within the events model so we need to first fetch the event and then from there we need to fetch the sponsors list from the model. The model to fetch the event details looks like this: model(params) { return this.store.findRecord('event', params.event_id, { include: 'social-links' }); }   But we can easily observe that there is no parameter related to sponsor in the above model. The reason behind this is the fact that we want our sponsors to be displayed only on the event’s index route rather than displaying them on all the sub routes under public route. To display the sponsors on the public/index route our modal looks like this: model() { const eventDetails = this._super(...arguments); return RSVP.hash({ event : eventDetails, sponsors: eventDetails.get('sponsors') }); }   As we can see in the above code that we have used this._super(...arguments) to fetch the event details from the event’s public route model which contains all the information related to the event thereby eliminating the need of another API call to fetch sponsors. Now using the ember’s get method we are fetching the sponsors from the eventDetails and putting it inside the sponsors JSON object for using it lately to display sponsors in public/index route. Till now, we’ve fetched and stored the sponsors now our next task is to display the sponsors list on the event’s index page. The code for displaying the sponsors list on the index page is {{public/sponsor-list sponsors=model.sponsors}}   The sample user interface without  for displaying the sponsors looks like this:   Fig. 1: The sample user interface for displaying the sponsors After replacing the real time data with the sample one, the user interface (UI) for the sponsors looks like this. Fig. 2: The user interface for sponsors with real time data The entire code for implementing the sponsors API can be seen here. To conclude, this is how we efficiently fetched the sponsors list using the Open-Event-Orga sponsors API, ensuring that there is no unnecessary API call to fetch the data.   Resources: Open Event API Docs Official Ember Data documentation Lodash documentation An article on how to create GET requests in the ember in the blog by asommer7

Continue ReadingImplementing Sponsors API in Open Event Frontend to Display Sponsors

Presenter Abstraction Layer in Open Event Organizer Android App

Open Event Organizer App design follows Model View Presenter (MVP) architecture which enables heavy unit testing. MVP is a trending architecture design followed these days. If you are not aware of MVP architecture, then please refer any of the tutorial (few links are given at the end of this blog) about it before reading this. In the design, the code becomes little repetitive as the application size increases due to so many presenters and views, which degrades the code readability. So to avoid this and keep the functionality code clean in the App, we have created a Presenter Abstraction Layer which contains the repetitive code and the layer is extended wherever required in the app. I will be talking about the Presenter Abstraction Layer implementation through the App in this blog. First of all, create a base interface. The base interface contains methods which every presenter will have. The base interface for presenter in the App looks like: public interface IBasePresenter { void start(); void detach(); }   In the method start, presenter loads all the required data from the model and sends it to the view. And releases all the resources in detach. These two methods are required in all the presenters. This interface is extended by other two interfaces which will be actually used by the views. The relevant code is: public interface IPresenter<V> extends IBasePresenter { void attach(V view); } public interface IDetailPresenter<K, V> extends IBasePresenter { void attach(K key, V view); }   Method attach is used to attach view and the data id (if required) to the presenter. In the app, most of the presenters require an extra data which is used in loading data from the model. Hence two interfaces are extended from the base interface. Now comes the implementation part. public abstract class BasePresenter<V> implements IPresenter<V> { private V view; private CompositeDisposable compositeDisposable; @Override @CallSuper public void attach(V view) { this.view = view; this.compositeDisposable = new CompositeDisposable(); } @Override @CallSuper public void detach() { view = null; compositeDisposable.dispose(); } protected V getView() { return view; } protected CompositeDisposable getDisposable() { return compositeDisposable; } }   The App uses ReactiveX Observables for async operations which contain fragment/activity context hence these need to be disposed at some lifecycle of fragment/activity. detach nulls the view and disposes the compositeDisposable. This method is called at the onStop lifecycle of fragment/activity. The observable subscriptions are one of the major reasons for memory leaks if not disposed at correct lifecycle in Android. So the detach method is called at onStop lifecycle when activity goes into background or fragment is switched by FragmentTransaction. Another base presenter class looks like: public abstract class BaseDetailPresenter<K, V> extends BasePresenter<V> implements IDetailPresenter<K, V> { private K id; @Override @CallSuper public void attach(K id, V view) { super.attach(view); this.id = id; } protected K getId() { return id; } }   This class extends the previous one except for the attach method. As the presenters extending this, require an extra data id which is passed…

Continue ReadingPresenter Abstraction Layer in Open Event Organizer Android App

Customizing Serializers in Open Event Front-end

Open Event Front-end project primarily uses Ember Data for API requests, which handles sending the request to correct endpoint, serializing and deserializing the request/response. The Open Event API project uses JSON API specs for implementation of the API, supported by Ember data. While sending request we might want to customize the payload using a custom serializer. While implementing the Users API in the project, we faced a similiar problem. Let’s see how we solved it. Creating a serializer for model A serializer is created for a model, in this example we will create a user serializer for the user model. One important thing that we must keep in mind while creating a serializer is to use same name as that of model, so that ember can map the model with the serializer. We can create a serializer using ember-cli command: ember g serializer user   Customizing serializer In Open Event Front-end project every serializer extends the base serializer application.js which defines basic serialization like omitting readOnly attributes from the payload. The user serializer provides more customization for the user model on top of application model. We override the serialize function, which lets us manipulate the payload of the request. We use `snapshot.id` to differentiate between a create request & an update request. If `snapshot.id` exists then it is an update request else it is a create request. While manipulation user properties like email, contact etc we do not need to pass ‘password’ in the payload. We make use of ‘adapterOptions’ property associated with the ‘save()’ method. If the adapterOptions are associated and the ‘includePassword’ is set then we add ‘password’ attribute to the payload. import ApplicationSerializer from 'open-event-frontend/serializers/application'; import { pick, omit } from 'lodash'; export default ApplicationSerializer.extend({ serialize(snapshot, options) { const json = this._super(...arguments); if (snapshot.id) { let attributesToOmit = []; if (!snapshot.adapterOptions || !snapshot.adapterOptions.includePassword) { attributesToOmit.push('password'); } json.data.attributes = omit(json.data.attributes, attributesToOmit); } else if (options && options.includeId) { json.data.attributes = pick(json.data.attributes, ['email', 'password']); } return json; } }); If we want to add the password in the payload we can simply add ‘includePassword’ property to the ‘adapterOptions’ and pass it in the save method for operations like changing the password of the user. user.save({ adapterOptions: { includePassword: true } }) Thank you for reading the blog, you can check the source code for the example here. Resources Official Ember Data documentation Official Lodash documentation Learn more about how to customize serializers in ember data here

Continue ReadingCustomizing Serializers in Open Event Front-end

Displaying Upcoming Sessions at a Microlocation Open Event Android

“When I am attending a session in a room, I don't get information on what is coming up.” The issue that the user expressed was that he wanted to know what were the upcoming sessions at a microlocation. While I took up this issue in Open Event Android a few days back, I was thinking of ways about how this can be implemented. The app should be easy-to-use even for non-developers and thus, any new feature shouldn’t be too complex in its implementation. We decided upon doing the following: Adding an “upcoming” option in the options menu of the Location activity. This option’s purpose was to trigger the app to show information about the upcoming session in that microlocation. Initial changes in LocationActivity.java First of all, we added a new icon in the options menu of LocationActivity.java. One of the things that we learnt there was to use ifRoom|collapseActionView option for the app:showAsAction   attribute as frequently as possible. This option ensures that the title in the option’s menu is visible at all times irrespective of the options being visible along with their icons. So in case, the title is too big and there is very little room for the options to appear individually, then instead of squeezing down the title, the “ifRoom” attribute will collapse the option icons and insert a 3-dotted drop-down option list with all the options appearing in the drop-down. Something like this: The icon’s XML element and UI looked something like this: <item android:id="@+id/upcoming_sessions" android:icon="@drawable/ic_timeline_white_24dp" android:title="@string/upcoming" app:showAsAction="ifRoom|collapseActionView" app:actionViewClass="android.support.v7.widget.Button"/> About the drawable icon that you see in the screenshot above, it was a tough find. Before I talk about how I came across this icon, I will talk about adding an icon in Android Studio. How to add an icon in Android Studio? Adding an item in Android studio means adding a drawable at a basic level. You can find all drawables under the app/src/main/res/drawable folder. To add a new drawable, right-click on the drawable folder and go to new -->Vector asset. A window similar to what is shown below will appear. Now, on selecting the “icon” option you will be taken to a huge list of icons that you can add in your app and then use them subsequently. But the problem here is that it is tough at times to find the icon that will be fit for your purpose. Like in my case, there was no direct icon for “upcoming”. This is when we had to do something more. We had to browse to this amazing site by Google: https://material.io/icons/ This site shows all the available icons in a much more interactive way and it was a lot more easier for me to come across the icon we wanted using this site. The vector drawable file for the icon we chose looks like this: <vector xmlns:android="http://schemas.android.com/apk/res/android" android:width="24dp" android:height="24dp" android:viewportWidth="24.0" android:viewportHeight="24.0"> <path android:fillColor="#FFFFFF" android:pathData="M23,8c0,1.1 -0.9,2 -2,2 -0.18,0 -0.35,-0.02 -0.51,-0.07l-3.56,3.55c0.05,0.16 0.07,0.34 0.07,0.52 0,1.1 -0.9,2 -2,2s-2,-0.9 -2,-2c0,-0.18 0.02,-0.36 0.07,-0.52l-2.55,-2.55c-0.16,0.05 -0.34,0.07 -0.52,0.07s-0.36,-0.02 -0.52,-0.07l-4.55,4.56c0.05,0.16 0.07,0.33 0.07,0.51 0,1.1 -0.9,2…

Continue ReadingDisplaying Upcoming Sessions at a Microlocation Open Event Android

File Upload Validations on Open Event Frontend

In Open Event Frontend we have used semantics ui’s form validations to validate different fields of a form. There are certain instances in our app where the user has to upload a file and it is to be validated against the suggested format before uploading it to the server. Here we will discuss how to perform the validation. Semantics ui allows us to validate by facilitating pass of an object along with rules for its validation. For fields like email and contact number we can pass type as email and number respectively but for validation of file we have to pass a regular expression with allowed extension.The following walks one through the process. fields : { file: { identifier : 'file', rules : [ { type : 'empty', prompt : this.l10n.t('Please upload a file') }, { type : 'regExp', value : '/^(.*.((zip|xml|ical|ics|xcal)$))?[^.]*$/i', prompt : this.l10n.t('Please upload a file in suggested format') } ] } } Here we have passed file element (which is to be validated) inside our fields object identifier, which for this field is ‘file’, and can be identified by its id, name or data-validate property of the field element. After that we have passed an array of rules against which the field element is validated. First rule gives an error message in the prompt field in case of an empty field. The next rule checks for allowed file extensions for the file. The type of the rule will be regExp as we are passing a regular expression which is as follows- /^(.*.((zip|xml|ical|ics|xcal)$))?[^.]*$/i It is little complex to explain it from the beginning so let us breakdown it from end-   $ Matches end of the string [^.]* Negated set. Match any character not in this set. * represents 0 or more preceding token ( ... )? Represents if there is something before (the last ?) .*.((zip|xml|ical|ics|xcal)$) This is first capturing group ,it contains tocken which are combined to create a capture group ( zip|xml|ical|ics|xcal ) to extract a substring ^ the beginning of the string Above regular expression filters all the files with zip/xml/ical/xcal extensions which are the allowed format for the event source file. References Ivaylo Gerchev blog on form validation in semantic ui Drmsite blog on semantic ui form validation Semantic ui form validation docs Stackoverflow regex for file extension

Continue ReadingFile Upload Validations on Open Event Frontend

Adding Sentry Integration in Open Event Orga Android App

Sentry is a service that allows you to track events, issues and crashes in your apps and provide deep insights with context about them. This blog post will discuss how we implemented it in Open Event Orga App (Github Repo). Configuration First, we need to include the gradle dependency in build.gradle compile 'io.sentry:sentry-android:1.3.0' Now, our project uses proguard for release builds which obfuscates the code and removes unnecessary class to shrink the app. For the crash events to make sense in Sentry dashboard, we need proguard mappings to be uploaded every time release build is generated. Thankfully, this is automatically handled by sentry through its gradle plugin, so to include it, we add this in our project level build.gradle in dependencies block classpath 'io.sentry:sentry-android-gradle-plugin:1.3.0'   And then apply the plugin by writing this at top of our app/build.gradle apply plugin: 'io.sentry.android.gradle'   And then configure the options for automatic proguard configuration and mappings upload sentry { // Disables or enables the automatic configuration of proguard // for Sentry. This injects a default config for proguard so // you don't need to do it manually. autoProguardConfig true // Enables or disables the automatic upload of mapping files // during a build. If you disable this you'll need to manually // upload the mapping files with sentry-cli when you do a release. autoUpload false }   We have set the autoUpload to false as we wanted Sentry to be an optional dependency to the project. If we turn it on, the build will crash if sentry can’t find the configuration, which we don’t want to happen. Now, as we want Sentry to configurable, we need to set Sentry DSN as one of the configuration options. The easiest way to externalize configuration is to use environment variables. There are other methods to do it given in the official documentation for config https://docs.sentry.io/clients/java/config/ Lastly, for proguard configuration, we also need 3 other config options, namely: defaults.project=your-project defaults.org=your-organisation auth.token=your-auth-token   For getting the auth token, you need to go to https://sentry.io/api/ Now, the configuration is complete and we’ll move to the code Implementation First, we need to initialise the sentry instance for all further actions to be valid. This is to be done when the app starts, so we add it in onCreate method Application class of our project by calling this method // Sentry DSN must be defined as environment variable // https://docs.sentry.io/clients/java/config/#setting-the-dsn-data-source-name Sentry.init(new AndroidSentryClientFactory(getApplicationContext()));   Now, we’re all set to send crash reports and other events to our Sentry server. This would have required a lot of refactoring if we didn’t use Timber for logging. We are using default debug tree for debug build and a custom Timber tree for release builds. if (BuildConfig.DEBUG) Timber.plant(new Timber.DebugTree()); else Timber.plant(new ReleaseLogTree());   The ReleaseLogTree extends Timber.Tree which is an abstract class requiring you to override this function: @Override protected void log(int priority, String tag, String message, Throwable throwable) { }   This function is called whenever there is a log event through Timber and this…

Continue ReadingAdding Sentry Integration in Open Event Orga Android App

Implementing Attendee Detail BottomSheet UI in Open Event Orga App

In Open Event Orga App (Github Repo), we allow the option to check the attendee details before checking him/her in or out. Originally, a dialog was shown showing the attendee details, which did not contain much information about the attendee, ticket or the order. The disadvantage of such design was also that it was tied to only one view. We couldn’t show the check in dialog elsewhere in the app, like during QR scanning. So we had to switch back to the attendee view for showing the check in dialog. We decided to create a usable detached component in the form of a bottom sheet containing all required information. This blog will outline the procedure we employed to design the bottom sheet UI. The attendee check in dialog looked like this: So, first we decide what we need to show on the check in bottom sheet: Attendee Name Attendee Email Attendee Check In Status Order Status ( Completed, Pending, etc ) TIcket Type ( Free, Paid, Donation ) Ticket Price Order Date Invoice Number Order ‘Paid Via’ As we are using Android Data Binding in our layout, we’ll start by including the variables required in the layout. Besides the obvious attendee variable, we need presenter instance to handle the check in and check out of the attendee and DateUtils class to parse the order date. Additionally, to handle the visibility of views, we need to include the View class too <data> <import type="org.fossasia.openevent.app.utils.DateUtils" /> <import type="android.view.View" /> <variable name="presenter" type="org.fossasia.openevent.app.event.checkin.contract.IAttendeeCheckInPresenter" /> <variable name="checkinAttendee" type="org.fossasia.openevent.app.data.models.Attendee" /> </data>   Then, we make the root layout to be CoordinatorLayout and add a NestedScrollView inside it, which contains a vertical linear layout in it. This vertical linear layout will contain our fields. Note: For brevity, I’ll skip most of the layout attributes from the blog and only show the ones that correspond to the text Firstly, we show the attendee name: <TextView style="@style/TextAppearance.AppCompat.Headline" android:text='@{attendee.firstName + " " + attendee.lastName }' tools:text="Name" />   The perks of using data binding can be seen here, as we are using string concatenation in layout itself. Furthermore, data binding also handles null checks for us if we add a question mark at the end of the variable name ( attendee.firstName? ). But our server ensures that both these fields are not null, so we skip that part. Next up, we display the attendee email <TextView android:text="@{ checkinAttendee.email }" tools:text="xyz@example.com" />   And then the check in status of the attendee <TextView android:text="@{ checkinAttendee.checkedIn ? @string/checked_in : @string/checked_out }" android:textColor="@{ checkinAttendee.checkedIn ? @color/light_green_500 : @color/red_500 }" tools:text="CHECKED IN" />   Notice that we dynamically change the color and text based on the check in status of the attendee Now we begin showing the fields with icons to their left. You can use Compound Drawable to achieve this effect, but we use vector drawables which are incompatible with compound drawables on older versions of Android, so we use a horizontal LinearLayout instead. The first field is the order status denoting…

Continue ReadingImplementing Attendee Detail BottomSheet UI in Open Event Orga App

Invalidating user login using JWT in Open Event Orga App

User authentication is an essential part of Open Event Orga App (Github Repo), which allows an organizer to log in and perform actions on the event he/she organizes. Backend for the application, Open Event Orga Server sends an authentication token on successful login, and all subsequent privileged API requests must include this token. The token is a JWT (Javascript Web Token) which includes certain information about the user, such as identifier and information about from when will the token be valid, when will it expire and a signature to verify if it was tampered. Parsing the Token Our job was to parse the token to find two fields: Identifier of user Expiry time of the token We stored the token in our shared preference file and loaded it from there for any subsequent requests. But, the token expires after 24 hours and we needed our login model to clear it once it has expired and shown the login activity instead. To do this, we needed to parse the JWT and compare the timestamp stored in the exp field with the current timestamp and determine if the token is expired. The first step in the process was to parse the token, which is essentially a Base 64 encoded JSON string with sections separated by periods. The sections are as follows: Header ( Contains information about algorithm used to encode JWT, etc ) Payload ( The data in JWT - exp. Iar, nbf, identity, etc ) Signature ( Verification signature of JWT ) We were interested in payload and for getting the JSON string from the token, we could have used Android’s Base64 class to decode the token, but we wanted to unit test all the util functions and that is why we opted for a custom Base64 class for only decoding our token. So, first we split the token by the period and decoded each part and stored it in a SparseArrayCompat public static SparseArrayCompat<String> decode(String token) { SparseArrayCompat<String> decoded = new SparseArrayCompat<>(2); String[] split = token.split("\\."); decoded.append(0, getJson(split[0])); decoded.append(1, getJson(split[1])); return decoded; }   The getJson function is primarily decoding the Base64 string private static String getJson(String strEncoded) { byte[] decodedBytes = Base64Utils.decode(strEncoded); return new String(decodedBytes); } The decoded information was stored in this way 0={"alg":"HS256","typ":"JWT"}, 1={"nbf":1495745400,"iat":1495745400,"exp":1495745800,"identity":344} Extracting Information Next, we create a function to get the expiry timestamp from the token. We could use GSON or Jackson for the task, but we did not want to map fields into any object. So we simply used JSONObject class which Android provides. It took 5 ms on average to parse the JSON instead of 150 ms by GSON public static long getExpiry(String token) throws JSONException { SparseArrayCompat<String> decoded = decode(token); // We are using JSONObject instead of GSON as it takes about 5 ms instead of 150 ms taken by GSON return Long.parseLong(new JSONObject(decoded.get(1)).get("exp").toString()); }   Next, we wanted to get the ID of user from token to determine if a new user is logging in or an old one, so…

Continue ReadingInvalidating user login using JWT in Open Event Orga App

Persistence Layer in Open Event Organizer Android App

Open Event Organizer is an Event Managing Android App with the core features of Attendee Check In by QR Code Scan and Data Sync with the Open Event API Server. As an event can be large, so the app will be dealing with a large amount of a data. Hence to avoid repetitive network requests for fetching the data, the app maintains a local database containing all the required data and the database is synced with the server. Android provides android.database.sqlite package which contains the API needed to use the database on the Android. But it is really not a good practice to use the sqlite queries everywhere in the app. So there comes a persistence layer. A persistence layer works between the database and the business logic. Open Event Organizer uses Raizlabs's DbFlow, an ORM based Android Database Library for the same. I will be talking about its implementation through the app in this blog. First of all, you declare the base class of the database which is used to create the database by Android for the app. You declare all the base constants here. The class looks like: @Database( name = OrgaDatabase.NAME, version = OrgaDatabase.VERSION, ... ) public class OrgaDatabase { public static final String NAME = "orga_database"; public static final int VERSION = 2; ... } OrgaDatabase.java app/src/main/java/org/fossasia/openevent/app/data/db/configuration/OrgaDatabase.java Initialise the database in the Application class using FlowManager provided by the library. Choose the Application class to do this to ensure that the library finds the generated code in the DbFlow. FlowManager.init( new FlowConfig.Builder(context) .addDatabaseConfig( new DatabaseConfig.Builder(OrgaDatabase.class) ... .build() ) .build()); OrgaApplication.java app/src/main/java/org/fossasia/openevent/app/OrgaApplication.java The database is created now. For tables creation, DbFlow uses model classes which must be annotated using the annotations provided by the library. The basic annotations are - @Table, @PrimaryKey, @Column, @ForeignKey etc. For example, the Attendee class in the app looks like: @Table(database = OrgaDatabase.class) public class Attendee ... { @PrimaryKey public long id; @Column public boolean checkedIn; ... ... @ForeignKey( onDelete = ForeignKeyAction.CASCADE, onUpdate = ForeignKeyAction.CASCADE) public Order order; ... } Attendee.java app/src/main/java/org/fossasia/openevent/app/data/models/Attendee.java This will create a table named attendee with the columns and relationships annotated. Now comes the part of accessing data from the database. Open Event App uses RxJava's support to the DbFlow library which enables async data accessing. The getItems method from DataBaseRepository looks like: public <T> Observable<T> getItems(Class<T> typeClass, SQLOperator... conditions) { return RXSQLite.rx(SQLite.select() .from(typeClass) .where(conditions)) .queryList() .flattenAsObservable(items -> items); }   The method returns an observable emitting the items from the result. For data saving, the method looks like: DatabaseDefinition database = FlowManager.getDatabase(OrgaDatabase.class); FastStoreModelTransaction<T> transaction = FastStoreModelTransaction .insertBuilder(FlowManager.getModelAdapter(itemClass)) .addAll(items) .build(); database.executeTransaction(transaction);   And for updating data, the method looks like: ModelAdapter<T> modelAdapter = FlowManager.getModelAdapter(classType); modelAdapter.update(item); DatabaseRepository.java app/src/main/java/org/fossasia/openevent/app/data/db/DatabaseRepository.java DbFlow provides DirectModelNotifier which is used to get notified of the database change anywhere in the app. Open Event App uses PublishSubjects to send notifications on database change event. The implementation of the DatabaseChangeListener in the app looks like: public class DatabaseChangeListener<T> ... { private PublishSubject<ModelChange<T>> publishSubject = PublishSubject.create(); private DirectModelNotifier.ModelChangedListener<T>…

Continue ReadingPersistence Layer in Open Event Organizer Android App