FOSSASIA’s Open Event Organizer is an Android Application for Event Management. The core feature it provides is two way attendee check in, directly by searching name in the list of attendees or just by scanning a QR code from ticket. So as attendees of an event can be really large in number like 1000+ or more than that, it should not alter the performance of the App. Just imagine a big event with lot of attendees (lets say 1000+) and if check in feature of the app is slow what will be the mess at entrance where each attendee is waiting for his ticket to be scanned and verified. For example, a check in via QR code scan. A complete process is somewhat like this:
- QR scanner scans the ticket code and parse it into the ticket identifier string.
- Identifier string is parsed to get an attendee id from it.
- Using the attendee id, attendee is searched in the complete attendees list of the event.
- On match, attendee’s check in status is toggled by making required call to the server.
- On successful toggling the attendee is updated in database accordingly.
- And check in success message is shown on the screen.
From the above tasks 1st and 6th steps only are UI related. Remaining all are just background tasks which can be run on non-UI thread instead of carrying them on the same UI thread which is mainly responsible for all the user interaction with the app. ReactiveX, an API for asynchronous programming enables us to do this. Just for clarification asynchronous programming is not multithreading. It just means the tasks are independent and hence can be executed at same time. This will be another big topic to talk about. Here we have used ReactiveX just for running these tasks in background at the same time UI thread is running. Here is our code of barcode processing:
private void processBarcode(String barcode) { Observable.fromIterable(attendees) .filter(attendee -> attendee.getOrder() != null) .filter(attendee -> (attendee.getOrder().getIdentifier() + "-" + attendee.getId()).equals(barcode)) .subscribeOn(Schedulers.computation()) .observeOn(AndroidSchedulers.mainThread()) .subscribe(attendee -> { // here we get the attendee and // further processing can be called here scanQRView.onScannedAttendee(attendee); }); }
In the above code you will see the actual creation of an Observable. Observable class has a method fromIterable which takes list of items and create an Observable which emits these items. So hence we need to search the attendee in the attendees list we have already stored in database. Filter operator filters the items emitted using the function provided. Last two lines are important here which actually sets how our subscriber is going to work. You will need to apply this thread management setting to your observable while working on android. You don’t actually have to worry about it. Just remember subscribeOn sets the thread on which actually the background tasks will run and on item emission subscriber handle it on main thread which is set by observeOn method. Subscribe operator provides the function what actually we need to run on main thread after emitted item is caught. Once we find the attendee from barcode, network call is made to toggle check in status of the attendee. Here is the code of check in method:
public void toggleCheckIn() { eventRepository.toggleAttendeeCheckStatus(attendee.getEventId(), attendeeId) .subscribe(completed -> { ... String status = attendee.isCheckedIn() ? "Checked In" : "Checked Out"; attendeeCheckInView.onSuccess(status); }, throwable -> { throwable.printStackTrace(); ... }); }
In the above code toggleAttendeeCheckStatus method returns an Observable. As name suggests the Observable is to be observed and it emits signals (objects) which are caught by a Subscriber. So here observer is Subscriber. So in the above code toggleAttendeeCheckStatus is creating an Obseravable. Lets look into toggleAttendeeCheckStatus code:
public Observable<Attendee> toggleAttendeeCheckStatus(long eventId, long attendeeId) { return eventService.toggleAttendeeCheckStatus(eventId, attendeeId, getAuthorization()) .map(attendee -> { ... // updating database logic ... return attendee; }) .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()); }
We have used Retrofit+Okhttp for network calls. In the above code eventService.toggleAttendeeCheckStatus returns an Observable which emits updated Attendee object on server response. Here we have used Map operator provided by ReactiveX which applies function defined inside it on each item emitted by the observable and returns a new observable with these items. So here we have use it to make the related updates in the database. Now with ReactiveX support the complete check in process is:
(Tasks running in background in bold style)
- QR scanner scans the ticket code and parse it into the ticket identifier string.
- Using the identifier, attendee is searched in the complete attendees list of the event.
- On match, attendee’s check in status is toggled by making required call to the server.
- On successful toggling the attendee is updated in database accordingly.
- And check in success message is shown on the screen.
So now main thread runs only tasks related to the UI. And time consuming tasks are run in background and UI is updated on their completion accordingly. Hence check in process becomes smooth irrespective of size of the attendees. And app never crashes.