Android New App Architecture Example

Mohit Sharma
3 min readMay 23, 2017

--

In my last article, I discussed new architecture. In this article lets implement that new Pattern in the Sample App. It’s a pretty simple app that shows basic UI in which you can enter Github username and it will display the name of all your repos. Below is the screenshot of the UI.

Show all repos name based on github username

You need Android Studio 3.0 for this sample. You can download it from this link:

Note* This is still in the canary channel. so instead of updating the Android Studio from canary channel please install a separate copy of this version.

(1) Open build.gradle from app module and add the following Dependency.

compile "android.arch.lifecycle:runtime:1.0.0-alpha1"
compile "android.arch.lifecycle:extensions:1.0.0-alpha1"
annotationProcessor "android.arch.lifecycle:compiler:1.0.0-alpha1"

(2) Also add the Kotlin in your build.gradle as we are going to write a sample code in Kotlin. Also added tons of other dependencies in my project for Retrofit, RxJava, Dagger etc.

(3) Set up the network component using Dagger. As this article is not about dagger I am not going to explain much about the Dagger. you can find more information from this link.

(4) Created a model class named Repo that has “name” property, which we are using for the demo purposes and also set up service layer using Retrofit for which more info can be found here.

(5) Created a DataRepository class in repository package. It takes retrofit service as an argument in the constructor. Right now we only have Retrofit service in this module but based on the requirement we can also DAO which will help us to access the database or provide both. It’s pretty simple as userNameObservable will be called from ViewModel which will then send any user name entered in UI and based on that it will make the network request and send the results back.

class DataRepository(private val repoService: RepoService) {
companion object {
private val TAG = DataRepository.javaClass.name
}

var repoResponse = PublishSubject.create<List<Repo>>()
val userNameObservable = PublishSubject.create<String>()

init {
userNameObservable.subscribe { userName ->
repoService.fetchUserRepos(userName, object : Observer<List<Repo>> {
override fun onCompleted() {
Log.v(TAG, "On complete called")
}

override fun onError(e: Throwable) {
Log.v(TAG, "on error called " + e.message)
}

override fun onNext(repoList: List<Repo>) {
repoResponse.onNext(repoList)
}
})

}
}
}

Note* Right now I am not handling error state we can send a different signal on error so that the view model can tell view to show an appropriate error in the UI.

(6) RepoViewModel extends ViewModel class. This class should have all the business logic and make changes to data it got from Retrofit service. It also passes any interaction from UI to Repository which make the network request to get the info. Please try to makes any LiveData property private so that we don’t have to access to its setter value in Fragment/Activity.

class RepoViewModel(dataRepository: DataRepository) : ViewModel() {
private var repoResponse: MutableLiveData<List<Repo>> = MutableLiveData()
val repoObservable = PublishSubject.create<String>()

init {
repoObservable.subscribe(dataRepository.userNameObservable)
dataRepository.repoResponse.subscribe {
repoResponse.value = it
}
}

fun getRepos(): MutableLiveData<List<Repo>> {
return repoResponse
}

}

(7) MainActivity class will inject the repository module which will be passed to view model so that it can pass any data request to repository module where we will handle data request.

class MainActivity : LifecycleActivity() {
@Inject
lateinit var dataRepository: DataRepository

private val repoViewModel: RepoViewModel by lazy {
RepoViewModel(dataRepository)
}

private lateinit var button: Button
private lateinit var repoNameTextView: TextView
private lateinit var userName: EditText

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
(applicationContext as MyApplication).repositoryComponent.inject(this)
button = findViewById(R.id.button) as Button
repoNameTextView = findViewById(R.id.repo_names) as TextView
userName = findViewById(R.id.user_name) as EditText

repoViewModel.getRepos().observe(this, Observer { repoList ->
var repoNames = ""
repoList?.forEach { repo ->
repoNames = repoNames.plus(repo.name).plus(",")
}
repoNameTextView.text = "Names of all repos ${repoNames}"
})

button.setOnClickListener {
repoViewModel.repoObservable.onNext(userName.text.toString())
}


}
}

You can find the sample code for this app here.

--

--