Skip to content

Commit 17da95b

Browse files
committed
Update DI, stateFlow
1 parent 236e108 commit 17da95b

File tree

12 files changed

+106
-116
lines changed

12 files changed

+106
-116
lines changed

app/build.gradle.kts

Lines changed: 5 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -146,7 +146,7 @@ dependencies {
146146

147147
// List of KTX extensions
148148
// https://developer.android.com/kotlin/ktx/extensions-list
149-
implementation("androidx.core:core-ktx:1.9.0-alpha02")
149+
implementation("androidx.core:core-ktx:1.9.0-alpha03")
150150
implementation("androidx.activity:activity-ktx:1.4.0")
151151
implementation("androidx.fragment:fragment-ktx:1.4.1")
152152

@@ -199,8 +199,8 @@ dependencies {
199199

200200
// stetho
201201
// http://facebook.github.io/stetho/
202-
implementation("com.facebook.stetho:stetho:1.5.1")
203-
implementation("com.facebook.stetho:stetho-okhttp3:1.5.1")
202+
// implementation("com.facebook.stetho:stetho:1.5.1")
203+
// implementation("com.facebook.stetho:stetho-okhttp3:1.5.1")
204204

205205
// glide
206206
// https://github.com/bumptech/glide
@@ -220,7 +220,7 @@ dependencies {
220220
// firebase
221221
// https://firebase.google.com/docs/android/setup
222222
implementation("com.google.firebase:firebase-analytics:20.1.2")
223-
implementation("com.google.firebase:firebase-crashlytics:18.2.9")
223+
implementation("com.google.firebase:firebase-crashlytics:18.2.10")
224224

225225
// lottie
226226
// https://github.com/airbnb/lottie-android
@@ -240,7 +240,7 @@ dependencies {
240240
testImplementation("io.mockk:mockk:1.10.2")
241241
testImplementation("androidx.arch.core:core-testing:2.1.0")
242242
testImplementation("com.squareup.okhttp3:mockwebserver:5.0.0-alpha.2")
243-
testImplementation("org.jetbrains.kotlin:kotlin-stdlib:1.6.10")
243+
testImplementation("org.jetbrains.kotlin:kotlin-stdlib:1.6.21")
244244
// testImplementation("org.robolectric:robolectric:4.3")
245245

246246
/**
@@ -421,7 +421,6 @@ project.afterEvaluate {
421421
"**/com/example/moviedb/ui/navigation/**/*.*",
422422
"**/com/example/moviedb/ui/widgets/**/*.*"
423423
)
424-
425424
//Explain to Jacoco where are you .class file java and kotlin
426425
classDirectories.setFrom(
427426
fileTree("${project.buildDir}/intermediates/classes/${sourcePath}").exclude(
@@ -436,15 +435,11 @@ project.afterEvaluate {
436435
"src/$productFlavorName/java",
437436
"src/$buildTypeName/java"
438437
)
439-
440438
additionalSourceDirs.setFrom(files(coverageSourceDirs))
441-
442439
//Explain to Jacoco where is your source code
443440
sourceDirectories.setFrom(files(coverageSourceDirs))
444-
445441
//execute file .exec to generate data report
446442
executionData.setFrom(files("${project.buildDir}/jacoco/${testTaskName}.exec"))
447-
448443
reports {
449444
xml.isEnabled = true
450445
html.isEnabled = true
Lines changed: 2 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,11 @@
11
package com.example.moviedb
22

33
import android.app.Application
4-
import android.content.Intent
5-
import android.os.Looper
6-
import android.widget.Toast
74
import androidx.multidex.MultiDex
8-
import com.example.moviedb.ui.screen.main.MainActivity
9-
import com.facebook.stetho.Stetho
105
import dagger.hilt.android.HiltAndroidApp
116
import kotlinx.coroutines.CoroutineScope
127
import kotlinx.coroutines.SupervisorJob
138
import timber.log.Timber
14-
import kotlin.system.exitProcess
159

1610
@HiltAndroidApp
1711
class MainApplication : Application() {
@@ -23,52 +17,13 @@ class MainApplication : Application() {
2317

2418
override fun onCreate() {
2519
super.onCreate()
26-
2720
MultiDex.install(this)
28-
29-
if (enableLogging()) {
21+
if (isDevMode()) {
3022
// init timber
3123
Timber.plant(Timber.DebugTree())
32-
33-
// init stetho
34-
Stetho.initializeWithDefaults(this)
3524
} else {
36-
// handleUncaughtException()
37-
}
38-
}
39-
40-
/**
41-
* prevent uncaught exception to crash app
42-
* restart app for better UX
43-
*/
44-
private fun handleUncaughtException() {
45-
Thread.setDefaultUncaughtExceptionHandler { t, e ->
46-
object : Thread() {
47-
override fun run() {
48-
Looper.prepare()
49-
Toast.makeText(applicationContext, R.string.unknown_error, Toast.LENGTH_SHORT)
50-
.show()
51-
Looper.loop()
52-
}
53-
}.start()
54-
55-
Thread.sleep(2000)
56-
57-
val intent = Intent(this, MainActivity::class.java)
58-
// to custom behaviour, add extra params for intent
59-
intent.addFlags(
60-
Intent.FLAG_ACTIVITY_CLEAR_TOP
61-
or Intent.FLAG_ACTIVITY_CLEAR_TASK
62-
or Intent.FLAG_ACTIVITY_NEW_TASK
63-
)
64-
startActivity(intent)
65-
try {
66-
exitProcess(2)
67-
} catch (e: Exception) {
68-
startActivity(intent)
69-
}
7025
}
7126
}
7227
}
7328

74-
fun enableLogging() = BuildConfig.BUILD_TYPE != "release"
29+
fun isDevMode() = BuildConfig.BUILD_TYPE != "release"

app/src/main/java/com/example/moviedb/data/remote/api/ApiService.kt

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
1-
package com.example.moviedb.data.remote
1+
package com.example.moviedb.data.remote.api
22

33
import com.example.moviedb.data.model.Movie
4-
import com.example.moviedb.data.remote.api.ApiPath
54
import com.example.moviedb.data.remote.response.GetCastAndCrewResponse
65
import com.example.moviedb.data.remote.response.GetMovieImages
76
import com.example.moviedb.data.remote.response.GetMovieListResponse

app/src/main/java/com/example/moviedb/data/repository/impl/UserRepositoryImpl.kt

Lines changed: 40 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -2,83 +2,90 @@ package com.example.moviedb.data.repository.impl
22

33
import com.example.moviedb.data.local.dao.MovieDao
44
import com.example.moviedb.data.model.Movie
5-
import com.example.moviedb.data.remote.ApiService
5+
import com.example.moviedb.data.remote.api.ApiService
66
import com.example.moviedb.data.remote.response.GetCastAndCrewResponse
77
import com.example.moviedb.data.remote.response.GetMovieListResponse
88
import com.example.moviedb.data.remote.response.GetTvListResponse
99
import com.example.moviedb.data.repository.UserRepository
10+
import kotlinx.coroutines.CoroutineDispatcher
11+
import kotlinx.coroutines.withContext
1012
import javax.inject.Inject
13+
import javax.inject.Named
1114

1215
class UserRepositoryImpl @Inject constructor(
1316
private val apiService: ApiService,
14-
private val movieDao: MovieDao
17+
private val movieDao: MovieDao,
18+
@Named("io") private val ioDispatcher: CoroutineDispatcher
1519
) : UserRepository {
1620

1721
override suspend fun getMovieList(
1822
hashMap: HashMap<String, String>
19-
): GetMovieListResponse {
20-
return apiService.getDiscoverMovie(hashMap)
23+
): GetMovieListResponse = withContext(ioDispatcher) {
24+
apiService.getDiscoverMovie(hashMap)
2125
}
2226

23-
override suspend fun getCastAndCrew(movieId: String): GetCastAndCrewResponse {
24-
return apiService.getMovieCredits(movieId)
25-
}
27+
override suspend fun getCastAndCrew(movieId: String): GetCastAndCrewResponse =
28+
withContext(ioDispatcher) {
29+
apiService.getMovieCredits(movieId)
30+
}
2631

2732
override suspend fun getTvList3(
2833
hashMap: HashMap<String, String>
29-
): GetTvListResponse {
30-
return apiService.getDiscoverTv(hashMap)
34+
): GetTvListResponse = withContext(ioDispatcher) {
35+
apiService.getDiscoverTv(hashMap)
3136
}
3237

3338
override suspend fun insertDB(
3439
list: List<Movie>
35-
) {
40+
) = withContext(ioDispatcher) {
3641
movieDao.insert(list)
3742
}
3843

3944
override suspend fun updateDB(
4045
movie: Movie
41-
) {
46+
) = withContext(ioDispatcher) {
4247
movieDao.update(movie)
4348
}
4449

45-
override suspend fun getMovieListLocal(): List<Movie>? {
46-
return movieDao.getMovieList()
50+
override suspend fun getMovieListLocal(): List<Movie>? = withContext(ioDispatcher) {
51+
movieDao.getMovieList()
4752
}
4853

49-
override suspend fun getMovieLocal(id: String): Movie? {
50-
return movieDao.getMovie(id)
54+
override suspend fun getMovieLocal(id: String): Movie? = withContext(ioDispatcher) {
55+
movieDao.getMovie(id)
5156
}
5257

53-
override suspend fun insertLocal(movie: Movie) {
54-
return movieDao.insert(movie)
58+
override suspend fun insertLocal(movie: Movie) = withContext(ioDispatcher) {
59+
movieDao.insert(movie)
5560
}
5661

57-
override suspend fun insertLocal(list: List<Movie>) {
58-
return movieDao.insert(list)
62+
override suspend fun insertLocal(list: List<Movie>) = withContext(ioDispatcher) {
63+
movieDao.insert(list)
5964
}
6065

61-
override suspend fun updateLocal(movie: Movie) {
62-
return movieDao.update(movie)
66+
override suspend fun updateLocal(movie: Movie) = withContext(ioDispatcher) {
67+
movieDao.update(movie)
6368
}
6469

65-
override suspend fun deleteMovieLocal(movie: Movie) {
66-
return movieDao.deleteMovie(movie)
70+
override suspend fun deleteMovieLocal(movie: Movie) = withContext(ioDispatcher) {
71+
movieDao.deleteMovie(movie)
6772
}
6873

69-
override suspend fun deleteMovieLocal(id: String) {
70-
return movieDao.deleteMovie(id)
74+
override suspend fun deleteMovieLocal(id: String) = withContext(ioDispatcher) {
75+
movieDao.deleteMovie(id)
7176
}
7277

73-
override suspend fun deleteAllLocal() {
74-
return movieDao.deleteAll()
78+
override suspend fun deleteAllLocal() = withContext(ioDispatcher) {
79+
movieDao.deleteAll()
7580
}
7681

77-
override suspend fun getMoviePageLocal(pageSize: Int, pageIndex: Int): List<Movie>? {
78-
return movieDao.getMoviePage(pageSize, pageIndex)
79-
}
82+
override suspend fun getMoviePageLocal(pageSize: Int, pageIndex: Int): List<Movie>? =
83+
withContext(ioDispatcher) {
84+
movieDao.getMoviePage(pageSize, pageIndex)
85+
}
8086

81-
override suspend fun getFavoriteLocal(pageSize: Int, pageIndex: Int): List<Movie>? {
82-
return movieDao.getFavorite(pageSize = pageSize, pageIndex = pageIndex)
83-
}
87+
override suspend fun getFavoriteLocal(pageSize: Int, pageIndex: Int): List<Movie>? =
88+
withContext(ioDispatcher) {
89+
movieDao.getFavorite(pageSize = pageSize, pageIndex = pageIndex)
90+
}
8491
}
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
package com.example.moviedb.di
2+
3+
import dagger.Module
4+
import dagger.Provides
5+
import dagger.hilt.InstallIn
6+
import dagger.hilt.components.SingletonComponent
7+
import kotlinx.coroutines.CoroutineDispatcher
8+
import kotlinx.coroutines.Dispatchers
9+
import javax.inject.Named
10+
import javax.inject.Singleton
11+
12+
@InstallIn(SingletonComponent::class)
13+
@Module
14+
class CoroutineModule {
15+
16+
@Provides
17+
@Singleton
18+
@Named("main")
19+
fun provideMainDispatcher(): CoroutineDispatcher = Dispatchers.Main
20+
21+
@Provides
22+
@Singleton
23+
@Named("io")
24+
fun provideIODispatcher(): CoroutineDispatcher = Dispatchers.IO
25+
26+
@Provides
27+
@Singleton
28+
@Named("unconfined")
29+
fun provideUnconfinedDispatcher(): CoroutineDispatcher = Dispatchers.Unconfined
30+
31+
@Provides
32+
@Singleton
33+
@Named("main_immediate")
34+
fun provideMainImmediateDispatcher(): CoroutineDispatcher = Dispatchers.Main.immediate
35+
36+
@Provides
37+
@Singleton
38+
@Named("default")
39+
fun provideDefaultDispatcher(): CoroutineDispatcher = Dispatchers.Default
40+
}

app/src/main/java/com/example/moviedb/di/NetworkModule.kt

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,17 +3,14 @@ package com.example.moviedb.di
33
import android.content.Context
44
import android.content.res.AssetManager
55
import com.example.moviedb.BuildConfig
6-
import com.example.moviedb.data.remote.ApiService
6+
import com.example.moviedb.data.remote.api.ApiService
77
import com.example.moviedb.data.remote.api.MockInterceptor
8-
import com.example.moviedb.enableLogging
9-
import com.facebook.stetho.okhttp3.StethoInterceptor
10-
import com.localebro.okhttpprofiler.OkHttpProfilerInterceptor
8+
import com.example.moviedb.isDevMode
119
import com.squareup.moshi.Moshi
1210
import dagger.Module
1311
import dagger.Provides
1412
import dagger.hilt.InstallIn
1513
import dagger.hilt.components.SingletonComponent
16-
import okhttp3.Authenticator
1714
import okhttp3.Cache
1815
import okhttp3.Interceptor
1916
import okhttp3.OkHttpClient
@@ -40,7 +37,7 @@ class NetworkModule {
4037
@Named("logging")
4138
fun provideLoggingInterceptor(): Interceptor =
4239
HttpLoggingInterceptor().apply {
43-
level = if (enableLogging()) HttpLoggingInterceptor.Level.BODY
40+
level = if (isDevMode()) HttpLoggingInterceptor.Level.BODY
4441
else HttpLoggingInterceptor.Level.NONE
4542
}
4643

@@ -80,8 +77,7 @@ class NetworkModule {
8077
.writeTimeout(TIMEOUT, TimeUnit.SECONDS)
8178
.apply {
8279
addInterceptor(logging)
83-
if (BuildConfig.DEBUG) addNetworkInterceptor(StethoInterceptor())
84-
if (BuildConfig.DEBUG) addInterceptor(OkHttpProfilerInterceptor())
80+
// if (BuildConfig.DEBUG) addInterceptor(OkHttpProfilerInterceptor())
8581
addInterceptor(header)
8682
// authenticator(authenticator)
8783
if (BuildConfig.DEBUG && BuildConfig.MOCK_DATA) addInterceptor(mockInterceptor)

app/src/main/java/com/example/moviedb/ui/screen/moviedetail/MovieDetailFragment.kt

Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import android.os.Bundle
44
import android.view.View
55
import android.widget.ImageView
66
import androidx.fragment.app.viewModels
7+
import androidx.lifecycle.lifecycleScope
78
import androidx.navigation.fragment.FragmentNavigatorExtras
89
import androidx.navigation.fragment.navArgs
910
import com.example.moviedb.R
@@ -12,16 +13,14 @@ import com.example.moviedb.ui.base.BaseFragment
1213
import com.example.moviedb.ui.base.getNavController
1314
import com.example.moviedb.utils.setSingleClick
1415
import dagger.hilt.android.AndroidEntryPoint
16+
import kotlinx.coroutines.flow.collectLatest
1517

1618
@AndroidEntryPoint
1719
class MovieDetailFragment : BaseFragment<FragmentMovieDetailBinding, MovieDetailViewModel>() {
1820

1921
override val layoutId: Int = R.layout.fragment_movie_detail
20-
2122
override val viewModel: MovieDetailViewModel by viewModels()
22-
2323
private val args: MovieDetailFragmentArgs by navArgs()
24-
2524
private val castAdapter = CastAdapter(itemClickListener = { imageView, cast ->
2625
cast.getFullProfilePath()?.let {
2726
toFullImage(imageView, it)
@@ -41,22 +40,19 @@ class MovieDetailFragment : BaseFragment<FragmentMovieDetailBinding, MovieDetail
4140
toFullImage(viewBinding.imageBackdrop, it)
4241
}
4342
}
44-
4543
viewModel.apply {
4644
args.movie.let {
4745
movie.value = it
4846
checkFavorite(it.id)
4947
loadCastAndCrew(it.id)
5048
}
5149
}
52-
5350
if (viewBinding.recyclerCast.adapter == null) {
5451
viewBinding.recyclerCast.adapter = castAdapter
5552
}
56-
57-
viewModel.apply {
58-
cast.observe(viewLifecycleOwner) {
59-
castAdapter.submitList(it)
53+
lifecycleScope.launchWhenStarted {
54+
viewModel.castList.collectLatest { castList ->
55+
castAdapter.submitList(castList)
6056
}
6157
}
6258
}

0 commit comments

Comments
 (0)