---
title: Tropos For Android
teaser: Announcing Tropos for Android, an open sourced simple weather conditions and
  forecast app.
tags: android,news,open source,tropos,kotlin
author: Amanda Hill
published_on: 2017-01-31
---

A long time ago, in a galaxy far, far away we [released Tropos for
iOS](https://thoughtbot.com/blog/tropos-phrase-based-weather-conditions) : a
simple weather conditions app. Today, from this galaxy, I am thrilled to
announce that we have released Tropos for Android.

![](https://images.thoughtbot.com/blog-vellum-image-uploads/gsX6W8J9TL69N5KOB5RI_screenshot.png)

## Backstory & Design

Tropos was designed with a single question in mind:

> "What does it feel like outside?

Tropos answers this by relating the current conditions to the conditions at the
same time yesterday. It turns the weather into information you can act on.

## Code

A few months after we released Tropos for iOS [we open sourced the
code](https://thoughtbot.com/blog/open-sourcing-tropos) for the app. And since
anything iOS developers can do, Android developers can do better(💪), we
are making the source code [available on
GitHub](https://github.com/thoughtbot/tropos-android) today!

For those of you who didn't immediately click on the link to the code and are
still reading this, hello! 👋 Thanks for sticking around! As a consolation
prize, here are some of the technical specs of the app that might make you want
to go back and click that link!

### Language

We decided to write the entire app (including all the tests) in
[Kotlin](https://kotlinlang.org/). While have used Kotlin in a few of our client
apps, we were excited to try it out with such a design and custom view heavy
app. Custom views turned out to be a fantastic learning tool and an interesting
way to test out the merits and interoperability of a new language. Unlike model
objects, or generic logic classes where the developer has total freedom when it
comes to how to write and design their code, custom view classes come with
stricter rules enforced by the API and design of the framework.

### Architecture

This app is relatively small in terms of backend logic (there are only two
network requests) and number of screens (there's only one). So we decided to
have a little fun with our architecture and not strictly adhere to any single
pattern. We knew we wanted optimize for testability, so we decided to take the
best of both MVP and MVVM and mix them in with some of Kotlin's fancy language
features like, [Delegated
Properties](https://kotlinlang.org/docs/reference/delegated-properties.html).

For example, the main activity of the app, aptly named `MainActivity`, passes
all of it's business logic off to a presenter class,  `MainPresenter`. As with
any classic MVP app, the presenter tells the view (in Android's case, the
`Activity`), what to do via a view interface. But rather than have several
methods for each individual view update (i.e. `setTitle()`, `setSubtitle()`) we
have only a single variable in our `MainView` interface - `viewState`.

`viewState` is of the type `ViewState` which is a [sealed class] that has
subclasses for each of the different states our main screen could be in -
loading, showing the weather, and an error state. Sealed classes are Java enums
on steroids 💉, but if steroids compiled on the JVM. They allow each case to
have their own associated values which can be passed through at run time - very
similar to how Swift enums work. So for us, that meant that each `ViewState`
could pass along their own `ToolbarViewModel` which we could build at runtime.
For example, the `Weather` case is instantiated with a `WeatherToolbarViewModel`
which uses the users current location as the title.

[sealed class]: https://kotlinlang.org/docs/reference/classes.html#sealed-classes

This approach also made our unit tests more flexible. The `MainPresenterTest`
now only has to check that our view is in the expected state:

```kotlin
verify(view).viewState = isA<ViewState.Weather>()
```

While the `WeatherToolbarViewModelTest` handles all the testing for what the
expected values should be:

```kotlin
@Test
fun testSubtitle() {
  val viewModel = WeatherToolbarViewModel(context, mockCondition)
  val expected = "Updated at 4:16 PM"
  val actual = viewModel.subtitle()

  assertEquals(expected, actual)
}
```

This means that down the line if we added more views to a particular state, i.e.
we added a fancy icon to the toolbar, the presenter test remains the same and
only the view model test has to be updated.

### Dependencies

In case all these patterns and approaches weren't enough, when it came time to
design our networking layer, we decided to add one more paradigm - Rx (reactive
programming). Because the entire app stems from a single piece of information - the
weather - the reactive paradigm felt like a good fit. To that end, we used
[RxJava2](https://github.com/ReactiveX/RxJava/wiki/What's-different-in-2.0) in
conjunction with [Retrofit](https://github.com/square/retrofit) as our
networking client.

### Custom Views and Layouts

As aforementioned, we really wanted to use this app as a way to explore all the
features of Kotlin and test it against as much of the Android framework as
possible, so when it came time to the views and interactions in the app we
wanted to make as much of it from scratch as possible. The hardest challenge was
the custom
[`PullToRefreshLayout`](https://github.com/thoughtbot/tropos-android/blob/master/app/src/main/kotlin/com/thoughtbot/tropos/refresh/PullToRefreshLayout.kt)
. It has several (literal) moving pieces - from the content on the screen that
actually shifts down, to the animating striped background to the progress wheel
that animates based on how much the user is dragging their finger.

![](https://images.thoughtbot.com/blog-vellum-image-uploads/KnD4AvMsSuTEen2B77Q3_android_screenshot-01_26_17-11_49_16.png)

But there were also a few smaller components that we also wanted to get just
right. At the bottom of the screen we show the current wind conditions along
with a quick overview of the day's high, low, and current temperatures. While
the standard Android `TextView` does allow you to set an image within the
`TextView` widget it doesn't allow for exact placement or alignment. While we
could have used a simple `LinearLayout` to display the icons along side the
text, we wanted to keep the layout hierarchy as flat as possible,
because #Perfmatters 🐎🚗 so we made [`DrawableTextLabel`] to allow us control
over the vertical alignment and size of the icon.

![](https://images.thoughtbot.com/blog-vellum-image-uploads/QRiM2WQ2SmcQWyWJYYw8_android_screenshot-01_26_17-12_04_52.png)

## Download

[Download](https://play.google.com/store/apps/details?id=com.thoughtbot.tropos)
or [check out](https://github.com/thoughtbot/tropos-android) Tropos today!

[`DrawableTextLabel`]: https://github.com/thoughtbot/tropos-android/blob/master/app/src/main/kotlin/com/thoughtbot/tropos/widgets/DrawableTextLabel.kt

Visit our [Open Source page](https://thoughtbot.com/open-source) to learn more about our team's contributions.
