diff --git a/app/build.gradle b/app/build.gradle index 45bd827..c56b082 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -19,9 +19,15 @@ android { testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" multiDexEnabled true } + android.defaultConfig { + testInstrumentationRunner 'android.support.test.runner.AndroidJUnitRunner' + } testOptions { unitTests.returnDefaultValues = true } + androidExtensions { + experimental = true + } buildTypes { release { minifyEnabled false @@ -56,6 +62,8 @@ kapt { } dependencies { + def room_version = "2.1.0-alpha04" + implementation fileTree(dir: 'libs', include: ['*.jar']) implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" implementation 'androidx.appcompat:appcompat:1.1.0-alpha03' @@ -74,9 +82,9 @@ dependencies { kapt 'tech.schoolhelper:moxy-x-compiler:1.5.6' implementation 'androidx.legacy:legacy-support-v4:1.0.0' - implementation 'androidx.room:room-runtime:2.1.0-alpha06' - kapt 'androidx.room:room-compiler:2.1.0-alpha06' - implementation 'androidx.room:room-rxjava2:2.1.0-alpha06' + implementation "androidx.room:room-runtime:$room_version" + implementation "androidx.room:room-coroutines:$room_version" + kapt "androidx.room:room-compiler:$room_version" implementation 'androidx.preference:preference:1.1.0-alpha04' implementation 'com.google.dagger:dagger:2.16' annotationProcessor 'com.google.dagger:dagger-compiler:2.16' @@ -89,4 +97,10 @@ dependencies { testImplementation 'junit:junit:4.12' testImplementation 'org.mockito:mockito-core:2.19.0' testImplementation 'org.mockito:mockito-inline:2.13.0' + implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:1.1.1" + implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.1.1" + implementation 'com.jakewharton.retrofit:retrofit2-kotlin-coroutines-adapter:0.9.2' + androidTestImplementation 'com.android.support.test:runner:1.0.2' + androidTestImplementation 'com.android.support.test:rules:1.0.2' + androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2' } diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 356b33f..6251313 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -1,6 +1,6 @@ + xmlns:tools="http://schemas.android.com/tools" package="itis.ru.insultgenerator"> @@ -11,7 +11,7 @@ android:label="@string/app_name" android:roundIcon="@mipmap/ic_launcher_round" android:supportsRtl="true" - android:theme="@style/AppTheme"> + android:theme="@style/AppTheme" tools:ignore="GoogleAppIndexingWarning"> - diff --git a/app/src/main/java/itis/ru/insultgenerator/InsultGeneratorApi.kt b/app/src/main/java/itis/ru/insultgenerator/InsultGeneratorApi.kt index 3738568..2d8ba2c 100644 --- a/app/src/main/java/itis/ru/insultgenerator/InsultGeneratorApi.kt +++ b/app/src/main/java/itis/ru/insultgenerator/InsultGeneratorApi.kt @@ -1,10 +1,10 @@ package itis.ru.insultgenerator -import io.reactivex.Observable import itis.ru.insultgenerator.model.Insult +import kotlinx.coroutines.Deferred import retrofit2.http.GET -interface InsultGeneratorApi{ +interface InsultGeneratorApi { @GET("generate_insult.php?lang=en&type=json") - fun getInsult(): Observable + fun getInsultAsync(): Deferred } diff --git a/app/src/main/java/itis/ru/insultgenerator/database/InsultDataDao.kt b/app/src/main/java/itis/ru/insultgenerator/database/InsultDataDao.kt index 68554d3..6022d67 100644 --- a/app/src/main/java/itis/ru/insultgenerator/database/InsultDataDao.kt +++ b/app/src/main/java/itis/ru/insultgenerator/database/InsultDataDao.kt @@ -3,14 +3,15 @@ package itis.ru.insultgenerator.database import androidx.room.* import io.reactivex.Single import itis.ru.insultgenerator.model.Insult +import kotlinx.coroutines.Deferred @Dao interface InsultDataDao { @Query("SELECT * FROM insult") - fun getAll(): Single> + fun getAllAsync(): Deferred> @Query("SELECT * FROM insult WHERE id = :id") - fun getById(id: Int): Single + fun getByIdAsync(id: Int): Deferred @Query("DELETE FROM insult") fun nukeTable() diff --git a/app/src/main/java/itis/ru/insultgenerator/di/module/NetModule.kt b/app/src/main/java/itis/ru/insultgenerator/di/module/NetModule.kt index 880af69..8c2f564 100644 --- a/app/src/main/java/itis/ru/insultgenerator/di/module/NetModule.kt +++ b/app/src/main/java/itis/ru/insultgenerator/di/module/NetModule.kt @@ -1,5 +1,6 @@ package itis.ru.insultgenerator.di.module +import com.jakewharton.retrofit2.adapter.kotlin.coroutines.CoroutineCallAdapterFactory import dagger.Module import dagger.Provides import itis.ru.insultgenerator.InsultGeneratorApi @@ -18,15 +19,19 @@ class NetModule { @Provides fun provideCallAdapterFactory(): RxJava2CallAdapterFactory = RxJava2CallAdapterFactory.create() + @Provides + fun provideCoroutineCallAdapterFactory(): CoroutineCallAdapterFactory = CoroutineCallAdapterFactory() + @Provides fun provideRetrofit( baseUrl: String, converterFactory: GsonConverterFactory, - callAdapterFactory: RxJava2CallAdapterFactory + callAdapterFactory: RxJava2CallAdapterFactory, + coroutineCallAdapterFactory: CoroutineCallAdapterFactory ): Retrofit = Retrofit.Builder() .baseUrl(baseUrl) .addConverterFactory(converterFactory) - .addCallAdapterFactory(callAdapterFactory) + .addCallAdapterFactory(coroutineCallAdapterFactory) .build() @Provides diff --git a/app/src/main/java/itis/ru/insultgenerator/model/InsultInteractor.kt b/app/src/main/java/itis/ru/insultgenerator/model/InsultInteractor.kt index 2ebcb84..fb4c103 100644 --- a/app/src/main/java/itis/ru/insultgenerator/model/InsultInteractor.kt +++ b/app/src/main/java/itis/ru/insultgenerator/model/InsultInteractor.kt @@ -1,16 +1,18 @@ package itis.ru.insultgenerator.model import android.content.Context -import androidx.annotation.Nullable -import io.reactivex.Observable import io.reactivex.Single import io.reactivex.android.schedulers.AndroidSchedulers import io.reactivex.schedulers.Schedulers import itis.ru.insultgenerator.InsultGeneratorApi import itis.ru.insultgenerator.database.InsultDataDao -import itis.ru.insultgenerator.di.component.DaggerDataComponent import itis.ru.insultgenerator.di.module.DatabaseModule import itis.ru.insultgenerator.di.module.NetModule +import kotlinx.coroutines.Deferred +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.withContext +import org.jetbrains.annotations.Nullable +import java.net.UnknownHostException import javax.inject.Inject private const val TAG: String = "InsultInteractor" @@ -35,32 +37,49 @@ class InsultInteractor(private val context: Context) { netComponent.inject(this) } - fun getInsultList(): Single> = - Observable.fromIterable(ITERABLE_ARRAY) - .flatMap { - service.getInsult() - } - .concatMap { - Observable.just(it) - } - .toList() - .map { - insultDataDao.nukeTable() - it - } - .map { - insultDataDao.insert(it) - it + suspend fun getInsultListAsync(): MutableList = withContext(Dispatchers.IO) { + val list: MutableList = mutableListOf() + + try { + for (i in 0 until 10) { + list.add(service.getInsultAsync().await()) } - .subscribeOn(Schedulers.io()) - .observeOn(AndroidSchedulers.mainThread()) + } catch (ex: UnknownHostException) { + ex.printStackTrace() + return@withContext insultDataDao.getAllAsync().await() + } - fun getInsultListFromDb(): Single>? { - return insultDataDao.getAll().subscribeOn(Schedulers.io()) - ?.observeOn(AndroidSchedulers.mainThread()) + insultDataDao.insert(list) + return@withContext list } - companion object { - private val ITERABLE_ARRAY = listOf(0, 1, 2, 3, 4, 5, 6, 7, 8, 9) + suspend fun getInsultListFromDb(): MutableList = withContext(Dispatchers.IO){ + return@withContext insultDataDao.getAllAsync().await() } } +/*Observable.fromIterable(ITERABLE_ARRAY) + .flatMap { + service.getInsultAsync() + } + .concatMap { + Observable.just(it) + } + .toList() + .map { + insultDataDao.nukeTable() + it + } + .map { + insultDataDao.insert(it) + it + } + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread())*/ + +/* +fun getInsultListFromDb(): Single>? { + return insultDataDao.getAll().subscribeOn(Schedulers.io()) + ?.observeOn(AndroidSchedulers.mainThread()) +} +*/ + diff --git a/app/src/main/java/itis/ru/insultgenerator/presenter/InsultListActivityPresenter.kt b/app/src/main/java/itis/ru/insultgenerator/presenter/InsultListActivityPresenter.kt index 3343cb0..b3dad8e 100644 --- a/app/src/main/java/itis/ru/insultgenerator/presenter/InsultListActivityPresenter.kt +++ b/app/src/main/java/itis/ru/insultgenerator/presenter/InsultListActivityPresenter.kt @@ -3,12 +3,13 @@ package itis.ru.insultgenerator.presenter import android.util.Log import com.arellomobile.mvp.InjectViewState import com.arellomobile.mvp.MvpPresenter -import io.reactivex.rxkotlin.subscribeBy import itis.ru.insultgenerator.model.Insult import itis.ru.insultgenerator.model.InsultInteractor import itis.ru.insultgenerator.model.SettingsInteractor import itis.ru.insultgenerator.utils.Screens import itis.ru.insultgenerator.view.InsultListView +import kotlinx.coroutines.GlobalScope +import kotlinx.coroutines.launch import ru.terrakok.cicerone.Router @InjectViewState @@ -18,8 +19,13 @@ class InsultListActivityPresenter( private val router: Router ) : MvpPresenter() { - fun updateInsultList() = insultInteractor - .getInsultList() + fun updateInsultList() { + GlobalScope.launch { + viewState.updateListView(insultInteractor.getInsultListAsync()) + } + + }/*insultInteractor + .getInsultListAsync() .doOnSubscribe { viewState.showProgress() } .doAfterTerminate { viewState.hideProgress() } .subscribeBy(onSuccess = { @@ -28,9 +34,9 @@ class InsultListActivityPresenter( }, onError = { Log.d("MYLOG", "presen error " + it.toString()) updateInsultListFromCache() - }) + })*/ - fun updateInsultListFromCache() = insultInteractor + fun updateInsultListFromCache(){} /*= insultInteractor .getInsultListFromDb() ?.doOnSubscribe { Log.d("MYLOG", "present subs " + it.toString()) @@ -42,12 +48,14 @@ class InsultListActivityPresenter( Log.d("MYLOG", it.toString()) }, onError = { Log.d("MYLOG", it.toString()) - }) + })*/ fun onInsultClick(insult: Insult) = router.navigateTo(Screens.InsultScreen(insult.insult ?: "")) - fun loadNextElements(i: Int) = insultInteractor - .getInsultList() + fun loadNextElements(i: Int) = { + + }/*insultInteractor + .getInsultListAsync() .doOnSubscribe { viewState.showProgress() } .doAfterTerminate { viewState.hideProgress() } .subscribeBy(onSuccess = { @@ -55,7 +63,7 @@ class InsultListActivityPresenter( viewState.addItemsToListView(it) }, onError = { Log.d("MYLOG", "presen error " + it.toString()) - }) + })*/ fun getPaginationSize(): Int = settingsInteractor.getPaginationSize() ?: 0 diff --git a/app/src/main/java/itis/ru/insultgenerator/view/InsultListActivity.kt b/app/src/main/java/itis/ru/insultgenerator/view/InsultListActivity.kt index b349955..9ec6c6f 100644 --- a/app/src/main/java/itis/ru/insultgenerator/view/InsultListActivity.kt +++ b/app/src/main/java/itis/ru/insultgenerator/view/InsultListActivity.kt @@ -1,6 +1,7 @@ package itis.ru.insultgenerator.view import android.content.Intent +import android.content.res.Configuration import android.os.Bundle import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.RecyclerView @@ -95,11 +96,11 @@ class InsultListActivity : MvpAppCompatActivity(), InsultListView { } return true } -/* - override fun onConfigurationChanged(newConfig: Configuration?) { + + override fun onConfigurationChanged(newConfig: Configuration) { super.onConfigurationChanged(newConfig) presenter.updateInsultListFromCache() - }*/ + } override fun updateListView(list: MutableList) { insultAdapter?.submitList(list) diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml index 41795e3..d749ca0 100644 --- a/app/src/main/res/layout/activity_main.xml +++ b/app/src/main/res/layout/activity_main.xml @@ -1,22 +1,12 @@ - + - - - \ No newline at end of file + + diff --git a/app/src/test/java/itis/ru/insultgenerator/InsultListActivityPresenterTest.kt b/app/src/test/java/itis/ru/insultgenerator/InsultListActivityPresenterTest.kt index 8bbd13e..27a9612 100644 --- a/app/src/test/java/itis/ru/insultgenerator/InsultListActivityPresenterTest.kt +++ b/app/src/test/java/itis/ru/insultgenerator/InsultListActivityPresenterTest.kt @@ -32,7 +32,7 @@ class InsultListActivityPresenterTest { @Throws(Exception::class) fun setUp() { MockitoAnnotations.initMocks(this) - `when`(insultInteractor.getInsultList()).thenReturn(Single.just(testList)) + `when`(insultInteractor.getInsultListAsync()).thenReturn(Single.just(testList)) `when`(insultInteractor.getInsultListFromDb()).thenReturn(Single.just(testList)) `when`(settingsInteractor.getPaginationSize()).thenReturn(0) doNothing().`when`(settingsInteractor).savePaginationSize(ArgumentMatchers.isA(Int::class.java)) @@ -43,7 +43,7 @@ class InsultListActivityPresenterTest { @Test fun testUpdateInsultListWhenSuccess() { presenter.updateInsultList() - verify(insultInteractor).getInsultList() + verify(insultInteractor).getInsultListAsync() verify(view).updateListView(Mockito.anyList()) }