The Official Conference App for DroidKaigi 2019 Tokyo
Clone or download
tomoya0x00 Merge pull request #535 from NUmeroAndDev/remove_left_space
Fixed service sessions in search screen
Latest commit 1338dc9 Jan 19, 2019
Type Name Latest commit message Commit time
Failed to load latest commit information.
.circleci Disable gradle's parallel option on CI. Jan 13, 2019
.github Addressed proofreading comments Jan 9, 2019
.idea Added Lekton to dic.xml Jan 12, 2019
buildSrc Merge pull request #517 from ymnder/pinch_zoom_floor_map Jan 18, 2019
data Rename filename FireStore.kt to Firestore.kt Jan 17, 2019
ext Handle notifications while non-idle Jan 18, 2019
feature Merge pull request #535 from NUmeroAndDev/remove_left_space Jan 19, 2019
frontend Merge branch 'upstream/master' into deeplink Jan 18, 2019
frontendcomponent Merge pull request #509 from yt-tkhs/deeplink Jan 18, 2019
gradle Update dependency graph Dec 24, 2018
images Add README Architecture section Dec 24, 2018
model Modify code for max line length Jan 17, 2019
scripts Aggregate test reports correctly Jan 11, 2019
.editorconfig Fix code style Sep 23, 2018
.gitignore Merge branch 'master' into xcode-project Jan 13, 2019 Addressed proofreading comments Jan 9, 2019
LICENSE Create LICENSE Dec 28, 2018 Merge branch 'master' into jmatsu-patch-1 Jan 10, 2019
build.gradle make pinching zoom Jan 18, 2019
dependencies.kts Refactor dependency management Dec 9, 2018 Enable org.gradle.parallel for faster build Jan 12, 2019
gradlew First commit(add empty modules) Jun 24, 2018
gradlew.bat First commit(add empty modules) Jun 24, 2018 Update dependency graph Dec 24, 2018
settings.gradle Added a module for notification for now Jan 18, 2019
versions.kts Refactor dependency management Dec 9, 2018

DroidKaigi 2019 official Android app CircleCI

DroidKaigi 2019 is a conference tailored for developers on 7th and 8th February 2019.

You can download the binary built on master branch from Try it on your device via DeployGate

NOTE: Google Play Protect will show a warning dialog on some of devices when installing the current apk. The detailed specification of Google Play Protect is not public so we cannot address this matter. Please ignore the dialog for now. If you cannot install this apk without any error message, please disable Google Play Protect from Google Play Store's menus. Sorry for the inconvenience.


top detail
image image
  • View conference schedule and details of each session
  • Set notification for upcoming sessions on your preference
  • Search sessions and speakers and topics
  • Show Information Feed


We always welcome any and all contributions! See for more information


  • Android Studio 3.2.1 and higher.
  • Android Studio Kotlin Plugin 1.3.11-release-Studio

Check out following status.
Preference > Languages & Frameworks > Kotlin Updates

Older versions of the Kotlin plugin may cause build failures. If you still have a trouble after upgrading the plugin, please try using AndroidStudio 3.3 or 3.4 instead.

Development Environment

Multi module project

We separate the modules for each feature.


You can check generated module dependency diagram

Unidirectional data flow(Flux-based) Architecture

Unidirectional data flow(Flux-based) Architecture with Kotlin Coroutines and AndroidX Libraries(LiveData, ViewModel, Room) DataBinding, Dagger and AssistedInject, Firebase etc.


By using Groupie you can simplify the implementation around RecyclerView.

class SpeakerItem @AssistedInject constructor(
    @Assisted val speaker: Speaker, // Inject by AssistedInject
    val navController: NavController // Inject by Dagger
) : BindableItem<ItemSpeakerBinding>() {
    interface Factory {
        fun create(
            speaker: Speaker
        ): SpeakerItem

    override fun getLayout(): Int = R.layout.item_speaker

    override fun bind(itemBinding: ItemSpeakerBinding, position: Int) {
        itemBinding.speakerText.text =

We use AssistedInject for creating item.

    @Inject lateinit var speakerItemFactory: SpeakerItem.Factory
        val speakerItems = session
            .map { speakerItemFactory.create(it) }


Unidirectional data flow(Flux-based) Architecture with Kotlin Coroutines and AndroidX Libraries(LiveData, ViewModel, Room) DataBinding, dependency injection, Firebase etc.

Activity/Fragment -> Action Creator


Fragments just call Action Creator's method.

class SessionPagesFragment : DaggerFragment() {
    @Inject lateinit var announcementActionCreator: AnnouncementActionCreator
    override fun onActivityCreated(savedInstanceState: Bundle?) {

Action Creator <-> DB / API and Action Creator -> dispatcher


Action Creator fetches data from DB / API with Kotlin Coroutines suspend function. And Action Creator dispatches data loaded action and loading state changed actions.

class AnnouncementActionCreator @Inject constructor(
    override val dispatcher: Dispatcher,
    val firestore: Firestore,
    @PageScope val lifecycle: Lifecycle
) : CoroutineScope by lifecycle.coroutineScope,
    ErrorHandler {

    fun load() = launch {
        try {
            // fetch announcement by Kotlin Coroutines suspend function
        } catch (e: Exception) {

Actions are just data holder class.

sealed class Action {
    class AnnouncementLoadingStateChanged(val loadingState: LoadingState) : Action()
    class AnnouncementLoaded(val announcements: List<Announcement>) : Action()

Dispatcher -> Store


Store subscribe dispatcher's action with Kotlin Coroutines channel and transform it to AndroidX LiveData. This store is a ViewModel. But if the store is used by the whole application(ex: UserStore), you can change the store to a singleton.

class AnnouncementStore @Inject constructor(
    dispatcher: Dispatcher
) : ViewModel() {
    val loadingState: LiveData<LoadingState> = dispatcher
        .map { it.loadingState }
    val announcements: LiveData<List<Announcement>> = dispatcher
        .map { it.announcements }

Store -> Activity/Fragment


In the fragment, we can observe Store's LiveData. You can display the UI with LiveData.

    override fun onActivityCreated(savedInstanceState: Bundle?) {
        announcementStore.loadingState.changed(viewLifecycleOwner) {
            // apply loading state for progress bar
            progressTimeLatch.loading = it == LoadingState.LOADING
        announcementStore.announcements.changed(viewLifecycleOwner) { announcements ->
            // we can show UI with announcements


Thank you for contributing!


This project uses some modern Android libraries and source codes.