Taking Android Seriously: Keddit and More

Kevin Cianfarini
Aug 28, 2017 · 7 min read

In the time in between school and my summer internship, I’ve finally had the time and willpower to be able to dive a bit into the Android ecosystem. During that time, I followed a guide on ramping up to speed with Kotlin, RxJava, Retrofit, Dagger2, and some other goodies. This post seemed to be written at a level that glossed over some things that someone who has never really worked with Android before might be confused about. Here I hope to digest them further myself by going into detail with some of the concepts that were over my head initially.

First and foremost, for those who don’t know yet, Kotlin is a statically typed language for the JVM that touts full interop with Java. The guide above focuses on Kotlin as it has recently been upgraded to a first class language for Android.

The Result

The multiple Keddit posts got me to a point where I could query the Reddit API using Retrofit, pass the data around using RxJava, and clean up the code with Dagger. However, as far as actual usefulness goes, it ends up looking like this.

This image is straight from the Keddit postings

Cool as far as getting up to speed with Android goes, but not by any means usable. It lacks the functionality to actually interact with the posts. Thus, Keddit acts more of a starting point for me which I’ll add features onto later.

Kotlin Confusion

There were a couple of concepts that popped up that didn’t make a whole lot of sense to me a for a bit. The reified keyword and inline functions are a good example of that.

Inline functions were something new that I had never really worked with in any other language before. If we had a function that might look like this

inline fun foo(block: () -> Unit) {    println("before")
block()
println("after")
}

and we invoke it by passing it a lambda that prints out my name

foo {
println("Kevin")
}

No lambda expression would actually be created. Rather, the compiler would drop in the function body to where block is called resulting in this

println("before")
println("Kevin")
println("after")

In contrast, if the function were not inline, the function passed as a parameter would be invoked at runtime.

In both Kotlin and Java, generic types are non-reified, meaning that after compilation you don’t have access to the real generic class. However, in Kotlin, inline functions support reified generics. The compiler will resolve the generic type class rather than having it erased at compile time.

fun <T> foo() {
println(T::class) //does not compile
}
inline fun <reified T> foo() {
println(T::class) //will compile
}
//execution
foo<Int>() // this will print the class name for Int

So the catch here is wherever this inline function is dropped into, the generic type class will be substituted for T at compile time.

Rx: Pain Free Concurrency

Trying to develop for Android without having knowledge of concurrency and threading is going to be extremely painful and pretty much impossible. If you have anything running too long on the main UI thread, then your app will appear to be stopped. Worse yet, you might get something like a NetworkOnMainThreadException and your app won’t even run.

Before I knew about RxJava while I was taking a class last semester, I had some code that looked like this in one of my very rushed projects.

Thread thread = new Thread(new Runnable() {    @Override
public void run() {
Looper.prepare();
try {
// make an API call
Looper.loop();
} catch (InterruptedException e) {
Looper.loop();
}
});
thread.start();

To be honest, there’s probably not a whole lot right with the way I handled threading like above. Passing the data between these kinds of threads and the UI thread was always a source of errors and made the classes extremely long.

It’s a good thing I got my feet wet with RxJava and RxAndroid. In Keddit, we defined a function that returns an Observable.

fun getNews(): Observable<RedditNews> {
return Observable.create {
subscriber ->
...
// make an API call
...
if (response.isSuccessful) {
...
// manipulate data
...
subscriber.onNext(data)
subscriber.onCompleted()
} else {
subscriber.onError(Throwable(response.message()))
}
}
}

When we call this function, and get the Observable, we are then able to leverage RxJava’s concurrency power. We take the resulting Observable and

  • define where we want to subscribe (I think of this as predefined threads. This is where the observable code actually runs)
  • define where we want to observe (where the result of the asynchronous code will be consumed)
  • and subscribe to it.
val subscription = newsManager.getNews()
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(
{ data ->
(newsList.adapter as NewsAdapter)
.addNews(data.news)
},
{ e -> Snackbar.make(newsList,
e.message ?: "",
Snackbar.LENGTH_LONG).show() }
)

The subscribe function takes two parameters. One function for what to do on success, and one for what to do on error. These functions are executed where you defined the subscription to be observed on. Here it’s in the main thread which is a scheduler defined in RxAndroid.

Rx comes with a CompositeSubscription class which handles subscriptions. Add the new subscription we just made to and instance of CompositeSubscription and Rx will handle the rest.

protected var subscriptions = CompositeSubscription()...subscriptions.add(subscription)

So with this 1000 foot view of Rx we can now handle calling an API and passing that data back to the UI thread fairly easily. Cool beans.

Dagger2: Make your app SOLID

The internship I work at has a huge emphasis on the SOLID principles. It also took longer than I care to admit to get a full grasp on what SOLID is all about. Here are some more full explanations than these short blurbs.

  • Single Responsibility: Your classes should be responsible for exactly one thing.
  • Open Closed: Your class should be open for extension but not modification.
  • Liskov Substitution: Your class that expects an object of type foo should continue to work on all subclasses of type foo as drop in replacements
  • Interface Segregation: Basically single responsibility for interfaces
  • Dependency Inversion: This is what I would like to focus on here.

Dependency Inversion I always found the most challenging the wrap my head around without just using it. I do find that the example of implementing a Queue with a List cements it in my mind though.

Let’s say that we’re creating a class Queue which encapsulates a LinkedList for its operations enqueue and dequeue. We might implement it like this:

Here, the Queue has an absolute dependency on a LinkedList. In a normal world this would be fine for these operations, but for whatever reason let’s say that you want to implement it with an ArrayList as well. In doing that, you’ve violated the DRY code principle. You’ll have to re-implement the whole thing.

With dependency inversion, though, it would make sense to be dependent on an interface. The interface here acts as a contract. Your queue class will only be able to call the methods defined in the interface, and whatever we choose to drop in that implements the interface will have those methods.

In doing this, we’ve inverted the dependency upward. Now the queue class is agnostic about the implementation of the list class.

Dependency injection is a subset of dependency inversion. With dependency injection, you supply a class with any dependencies it might need outside of the class itself. The simplest version of this is constructor dependency injection.

class Queue(List items) {
private val list: List
init {
list = items
}
}
//instantiationval queue = Queue(ArrayList())
val linkedQueue = Queue(LinkedList())

The problem with constructor injection however is that it ends up polluting your code somewhere when manually injecting your dependencies. That’s what Dagger2 aims to solve (among other things).

In Keddit, we don’t use multiple implementations of an interface in places that interact with Dagger. But it is helpful when testing with mocks. Full disclaimer, Dagger was probably the part of this I least understood. Please feel free to correct anything on here for my benefit.

Dagger provides us annotations to use to combat polluting code with constructor injection.

  • @Injects: Requests dependencies
  • @Provides and @Module: Offers up classes annotated with this as dependencies
  • @Component: Bridges the gap between injections and modules

Using Dagger, we can inject the News Api to the NewsManager with an annotation.

@Singleton
class NewsManager @Inject constructor(private val api: NewsAPI) {
...
}

But to be able to inject that dependency, we need to provide it from somewhere. That happens in the NewsModule.

@Module
class NewsModule {

@Provides @Singleton
fun provideNewsAPI(redditApi: RedditApi): NewsAPI =
NewsRestApi(redditApi)

@Provides @Singleton
fun provideRedditApi(retrofit: Retrofit): RedditApi =
retrofit.create(RedditApi::class.java)
}

And then we need to bridge them together

@Singleton @Component(modules = arrayOf(
AppModule::class,
NewsModule::class,
NetworkModule::class
)) interface NewsComponent {
fun inject(newsFragment: NewsFragment)
}

There were more dependencies injected in Keddit, but nothing more interesting than this. However, for all of this to function we need to have an entry point for Dagger somewhere. That happens in a class that extends Application.

class KedditApp : Application() {

companion object {
lateinit var newsComponent: NewsComponent
}

override fun onCreate() {
super.onCreate()
newsComponent = DaggerNewsComponent.builder()
.appModule(AppModule(this))
.build()
}

}

Conclusion

That just about covers the things I was a bit unclear about at the start of writing this. This post sort of forced me to dig around and get answers. If you’d like to ask questions for yourself, I highly recommend the Kotlin slack channel.

In my next blog post, I’d like to go over testing and mocking in Keddit with Mockito as well as some modifications and extensions I’ve made to this project. If you’d like to check out the code now, you can find it on my github.

)
Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade