Skip to content

Commit 0f7bf8c

Browse files
committed
initial commit
0 parents  commit 0f7bf8c

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

48 files changed

+1044
-0
lines changed

.gitignore

+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
*.iml
2+
.gradle
3+
/local.properties
4+
/.idea
5+
/.idea/caches
6+
/.idea/libraries
7+
/.idea/modules.xml
8+
/.idea/workspace.xml
9+
/.idea/navEditor.xml
10+
/.idea/assetWizardSettings.xml
11+
.DS_Store
12+
/build
13+
/captures
14+
.externalNativeBuild
15+
.cxx

README.md

+31
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
# Using Retrofit with Kotlin Coroutines in Android: Sample App
2+
[![MindOrks](https://img.shields.io/badge/mindorks-opensource-blue.svg)](https://mindorks.com/open-source-projects)
3+
[![MindOrks Community](https://img.shields.io/badge/join-community-blue.svg)](https://mindorks.com/join-community)
4+
5+
This repository contains a sample app that implements MVVM architecture using Kotlin, ViewModel, Retrofit, Coroutines and etc.
6+
<p align="center">
7+
<img src="">
8+
</p>
9+
<br>
10+
<br>
11+
12+
### Concept reference resources - [ Using Retrofit with Kotlin Coroutines in Android]()
13+
14+
#### The app has following packages:
15+
1. **data**: It contains all the data accessing and manipulating components.
16+
3. **ui**: View classes along with their corresponding ViewModel.
17+
4. **utils**: Utility classes.
18+
19+
### Library reference resources:
20+
1. Coroutines: [Check here](https://blog.mindorks.com/mastering-kotlin-coroutines-in-android-step-by-step-guide)
21+
22+
### Looking for Kotlin MVP Architecture - [Check here](https://github.com/MindorksOpenSource/android-kotlin-mvp-architecture)
23+
24+
### Looking for MVP Architecture - [Check here](https://github.com/MindorksOpenSource/android-mvp-architecture)
25+
26+
### Learn to build a ride-sharing Android app like Uber, Lyft - [Check here](https://github.com/MindorksOpenSource/ridesharing-uber-lyft-app)
27+
28+
[Check out MindOrks awesome open source projects here](https://mindorks.com/open-source-projects)
29+
30+
### Contributing to Using retrofit with Kotlin Coroutines in Android
31+
Just make pull request. You are in!

app/.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
/build

app/build.gradle

+56
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
apply plugin: 'com.android.application'
2+
apply plugin: 'kotlin-android'
3+
apply plugin: 'kotlin-android-extensions'
4+
5+
android {
6+
compileSdkVersion 29
7+
buildToolsVersion "29.0.2"
8+
9+
defaultConfig {
10+
applicationId "com.mindorks.retrofit.coroutines"
11+
minSdkVersion 21
12+
targetSdkVersion 29
13+
versionCode 1
14+
versionName "1.0"
15+
16+
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
17+
}
18+
19+
buildTypes {
20+
release {
21+
minifyEnabled false
22+
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
23+
}
24+
}
25+
26+
}
27+
28+
dependencies {
29+
implementation fileTree(dir: 'libs', include: ['*.jar'])
30+
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
31+
implementation 'androidx.appcompat:appcompat:1.1.0'
32+
implementation 'androidx.core:core-ktx:1.2.0'
33+
implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
34+
35+
implementation 'androidx.recyclerview:recyclerview:1.1.0'
36+
implementation 'com.github.bumptech.glide:glide:4.9.0'
37+
38+
//LifeCycle
39+
implementation 'androidx.lifecycle:lifecycle-common:2.2.0'
40+
implementation 'androidx.lifecycle:lifecycle-runtime:2.2.0'
41+
implementation 'android.arch.lifecycle:extensions:2.2.0'
42+
implementation 'androidx.lifecycle:lifecycle-livedata-ktx:2.2.0'
43+
44+
//Retrofit
45+
implementation 'com.squareup.retrofit2:retrofit:2.6.0'
46+
implementation 'com.google.code.gson:gson:2.8.5'
47+
implementation 'com.squareup.retrofit2:converter-gson:2.5.0'
48+
implementation 'com.squareup.okhttp3:logging-interceptor:3.12.0'
49+
50+
//Coroutines
51+
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.5'
52+
53+
testImplementation 'junit:junit:4.12'
54+
androidTestImplementation 'androidx.test.ext:junit:1.1.1'
55+
androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
56+
}

app/proguard-rules.pro

+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
# Add project specific ProGuard rules here.
2+
# You can control the set of applied configuration files using the
3+
# proguardFiles setting in build.gradle.
4+
#
5+
# For more details, see
6+
# http://developer.android.com/guide/developing/tools/proguard.html
7+
8+
# If your project uses WebView with JS, uncomment the following
9+
# and specify the fully qualified class name to the JavaScript interface
10+
# class:
11+
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
12+
# public *;
13+
#}
14+
15+
# Uncomment this to preserve the line number information for
16+
# debugging stack traces.
17+
#-keepattributes SourceFile,LineNumberTable
18+
19+
# If you keep the line number information, uncomment this to
20+
# hide the original source file name.
21+
#-renamesourcefileattribute SourceFile
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
package com.mindorks.retrofit.coroutines
2+
3+
import androidx.test.platform.app.InstrumentationRegistry
4+
import androidx.test.ext.junit.runners.AndroidJUnit4
5+
6+
import org.junit.Test
7+
import org.junit.runner.RunWith
8+
9+
import org.junit.Assert.*
10+
11+
/**
12+
* Instrumented test, which will execute on an Android device.
13+
*
14+
* See [testing documentation](http://d.android.com/tools/testing).
15+
*/
16+
@RunWith(AndroidJUnit4::class)
17+
class ExampleInstrumentedTest {
18+
19+
@Test
20+
fun useAppContext() {
21+
// Context of the app under test.
22+
val appContext = InstrumentationRegistry.getInstrumentation().targetContext
23+
assertEquals("com.mindorks.mvvm.retrofit.coroutines", appContext.packageName)
24+
}
25+
}

app/src/main/AndroidManifest.xml

+23
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<manifest package="com.mindorks.retrofit.coroutines"
3+
xmlns:android="http://schemas.android.com/apk/res/android">
4+
5+
<uses-permission android:name="android.permission.INTERNET"/>
6+
7+
<application
8+
android:allowBackup="true"
9+
android:icon="@mipmap/ic_launcher"
10+
android:label="@string/app_name"
11+
android:roundIcon="@mipmap/ic_launcher_round"
12+
android:supportsRtl="true"
13+
android:theme="@style/AppTheme">
14+
<activity android:name="com.mindorks.retrofit.coroutines.ui.main.view.MainActivity">
15+
<intent-filter>
16+
<action android:name="android.intent.action.MAIN" />
17+
18+
<category android:name="android.intent.category.LAUNCHER" />
19+
</intent-filter>
20+
</activity>
21+
</application>
22+
23+
</manifest>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
package com.mindorks.retrofit.coroutines.data.api
2+
3+
class ApiHelper(private val apiService: ApiService) {
4+
5+
suspend fun getUsers() = apiService.getUsers()
6+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
package com.mindorks.retrofit.coroutines.data.api
2+
3+
import com.mindorks.retrofit.coroutines.data.model.User
4+
import retrofit2.http.GET
5+
6+
interface ApiService {
7+
8+
@GET("users")
9+
suspend fun getUsers(): List<User>
10+
11+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
package com.mindorks.retrofit.coroutines.data.api
2+
3+
import retrofit2.Retrofit
4+
import retrofit2.converter.gson.GsonConverterFactory
5+
6+
object RetrofitBuilder {
7+
8+
private const val BASE_URL = "https://5e510330f2c0d300147c034c.mockapi.io/"
9+
10+
private fun getRetrofit(): Retrofit {
11+
return Retrofit.Builder()
12+
.baseUrl(BASE_URL)
13+
.addConverterFactory(GsonConverterFactory.create())
14+
.build()
15+
}
16+
17+
val apiService: ApiService = getRetrofit().create(ApiService::class.java)
18+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
package com.mindorks.retrofit.coroutines.data.model
2+
3+
data class User(
4+
val avatar: String,
5+
val email: String,
6+
val id: String,
7+
val name: String
8+
)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
package com.mindorks.retrofit.coroutines.data.repository
2+
3+
import com.mindorks.retrofit.coroutines.data.api.ApiHelper
4+
5+
class MainRepository(private val apiHelper: ApiHelper) {
6+
7+
suspend fun getUsers() = apiHelper.getUsers()
8+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
package com.mindorks.retrofit.coroutines.ui.base
2+
3+
import androidx.lifecycle.ViewModel
4+
import androidx.lifecycle.ViewModelProvider
5+
import com.mindorks.retrofit.coroutines.data.api.ApiHelper
6+
import com.mindorks.retrofit.coroutines.data.repository.MainRepository
7+
import com.mindorks.retrofit.coroutines.ui.main.viewmodel.MainViewModel
8+
9+
class ViewModelFactory(private val apiHelper: ApiHelper) : ViewModelProvider.Factory {
10+
11+
override fun <T : ViewModel?> create(modelClass: Class<T>): T {
12+
if (modelClass.isAssignableFrom(MainViewModel::class.java)) {
13+
return MainViewModel(MainRepository(apiHelper)) as T
14+
}
15+
throw IllegalArgumentException("Unknown class name")
16+
}
17+
18+
}
19+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
package com.mindorks.retrofit.coroutines.ui.main.adapter
2+
3+
import android.view.LayoutInflater
4+
import android.view.View
5+
import android.view.ViewGroup
6+
import androidx.recyclerview.widget.RecyclerView
7+
import com.bumptech.glide.Glide
8+
import com.mindorks.retrofit.coroutines.R
9+
import com.mindorks.retrofit.coroutines.data.model.User
10+
import com.mindorks.retrofit.coroutines.ui.main.adapter.MainAdapter.DataViewHolder
11+
import kotlinx.android.synthetic.main.item_layout.view.imageViewAvatar
12+
import kotlinx.android.synthetic.main.item_layout.view.textViewUserEmail
13+
import kotlinx.android.synthetic.main.item_layout.view.textViewUserName
14+
15+
class MainAdapter(private val users: ArrayList<User>) : RecyclerView.Adapter<DataViewHolder>() {
16+
17+
class DataViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
18+
19+
fun bind(user: User) {
20+
itemView.apply {
21+
textViewUserName.text = user.name
22+
textViewUserEmail.text = user.email
23+
Glide.with(imageViewAvatar.context)
24+
.load(user.avatar)
25+
.into(imageViewAvatar)
26+
}
27+
}
28+
}
29+
30+
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): DataViewHolder =
31+
DataViewHolder(LayoutInflater.from(parent.context).inflate(R.layout.item_layout, parent, false))
32+
33+
override fun getItemCount(): Int = users.size
34+
35+
override fun onBindViewHolder(holder: DataViewHolder, position: Int) {
36+
holder.bind(users[position])
37+
}
38+
39+
fun addUsers(users: List<User>) {
40+
this.users.apply {
41+
clear()
42+
addAll(users)
43+
}
44+
45+
}
46+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
package com.mindorks.retrofit.coroutines.ui.main.view
2+
3+
import android.os.Bundle
4+
import android.view.View
5+
import android.widget.Toast
6+
import androidx.appcompat.app.AppCompatActivity
7+
import androidx.lifecycle.Observer
8+
import androidx.lifecycle.ViewModelProviders
9+
import androidx.recyclerview.widget.DividerItemDecoration
10+
import androidx.recyclerview.widget.LinearLayoutManager
11+
import com.mindorks.retrofit.coroutines.R.*
12+
import com.mindorks.retrofit.coroutines.data.api.ApiHelper
13+
import com.mindorks.retrofit.coroutines.data.api.RetrofitBuilder
14+
import com.mindorks.retrofit.coroutines.data.model.User
15+
import com.mindorks.retrofit.coroutines.ui.base.ViewModelFactory
16+
import com.mindorks.retrofit.coroutines.ui.main.adapter.MainAdapter
17+
import com.mindorks.retrofit.coroutines.ui.main.viewmodel.MainViewModel
18+
import com.mindorks.retrofit.coroutines.utils.Status.ERROR
19+
import com.mindorks.retrofit.coroutines.utils.Status.LOADING
20+
import com.mindorks.retrofit.coroutines.utils.Status.SUCCESS
21+
import kotlinx.android.synthetic.main.activity_main.progressBar
22+
import kotlinx.android.synthetic.main.activity_main.recyclerView
23+
24+
class MainActivity : AppCompatActivity() {
25+
26+
private lateinit var viewModel: MainViewModel
27+
private lateinit var adapter: MainAdapter
28+
29+
override fun onCreate(savedInstanceState: Bundle?) {
30+
super.onCreate(savedInstanceState)
31+
setContentView(layout.activity_main)
32+
setupViewModel()
33+
setupUI()
34+
setupObservers()
35+
}
36+
37+
38+
private fun setupViewModel() {
39+
viewModel = ViewModelProviders.of(
40+
this,
41+
ViewModelFactory(ApiHelper(RetrofitBuilder.apiService))
42+
).get(MainViewModel::class.java)
43+
}
44+
45+
private fun setupUI() {
46+
recyclerView.layoutManager = LinearLayoutManager(this)
47+
adapter = MainAdapter(arrayListOf())
48+
recyclerView.addItemDecoration(
49+
DividerItemDecoration(
50+
recyclerView.context,
51+
(recyclerView.layoutManager as LinearLayoutManager).orientation
52+
)
53+
)
54+
recyclerView.adapter = adapter
55+
}
56+
57+
private fun setupObservers() {
58+
viewModel.getUsers().observe(this, Observer {
59+
it?.let { resource ->
60+
return@let when (resource.status) {
61+
SUCCESS -> {
62+
recyclerView.visibility = View.VISIBLE
63+
progressBar.visibility = View.GONE
64+
resource.data?.let { users -> retrieveList(users) }
65+
}
66+
ERROR -> {
67+
recyclerView.visibility = View.VISIBLE
68+
progressBar.visibility = View.GONE
69+
Toast.makeText(this, it.message, Toast.LENGTH_LONG).show()
70+
}
71+
LOADING -> {
72+
progressBar.visibility = View.VISIBLE
73+
recyclerView.visibility = View.GONE
74+
}
75+
}
76+
}
77+
})
78+
}
79+
80+
private fun retrieveList(users: List<User>) {
81+
adapter.apply {
82+
addUsers(users)
83+
notifyDataSetChanged()
84+
}
85+
}
86+
}

0 commit comments

Comments
 (0)