Skip to content

Commit

Permalink
Bookmark取得処理にコルーチンを適用
Browse files Browse the repository at this point in the history
  • Loading branch information
jageishi committed Jun 8, 2020
1 parent 4036c8c commit 020682e
Show file tree
Hide file tree
Showing 8 changed files with 305 additions and 309 deletions.
6 changes: 6 additions & 0 deletions app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,11 @@ android {
}
}

compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}

dataBinding {
enabled = true
}
Expand All @@ -47,6 +52,7 @@ dependencies {
implementation 'com.github.bumptech.glide:glide:4.9.0'
implementation 'com.google.code.gson:gson:2.8.5'
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.6'
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.6'

def okhttp_version = '4.2.0'
implementation "com.squareup.okhttp3:okhttp:$okhttp_version"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.launch
import org.ageage.eggplant.common.enums.SortType
import org.ageage.eggplant.common.model.Bookmark
Expand All @@ -26,16 +25,15 @@ class BookmarksViewModel(

private var isAlreadyLoaded = false

fun loadBookmarks(url: String, sortType: SortType, forceLoad: Boolean = false) {
if (isAlreadyLoaded && !forceLoad) {
return
}


fun loadBookmarks(url: String, sortType: SortType, forceLoad: Boolean = false) =
viewModelScope.launch {
if (isAlreadyLoaded && !forceLoad) {
return@launch
}

_isLoading.value = true
try {
repository.fetchBookmarks(url).collect {
repository.fetchBookmarks(url).let {
_bookmarks.value =
when (sortType) {
SortType.POPULAR -> {
Expand All @@ -48,6 +46,7 @@ class BookmarksViewModel(
.sortedByDescending { bookmark -> bookmark.timeStamp }
}
}

}
isAlreadyLoaded = true
} catch (e: Throwable) {
Expand All @@ -56,5 +55,4 @@ class BookmarksViewModel(
_isLoading.value = false
}
}
}
}
Original file line number Diff line number Diff line change
@@ -1,15 +1,14 @@
package org.ageage.eggplant.common.api

import kotlinx.coroutines.flow.Flow
import org.ageage.eggplant.common.api.response.BookmarkEntryResponse
import org.ageage.eggplant.common.api.response.BookmarkStarResponse
import retrofit2.http.GET
import retrofit2.http.Query

interface BookmarkService {
@GET("/entry/jsonlite/")
fun bookmarkEntry(@Query("url") url: String): Flow<BookmarkEntryResponse>
suspend fun bookmarkEntry(@Query("url") url: String): BookmarkEntryResponse

@GET("/entry.json")
fun startCount(@Query("uri") url: String): Flow<BookmarkStarResponse>
suspend fun startCount(@Query("uri") url: String): BookmarkStarResponse
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
package org.ageage.eggplant.common.repository

import android.text.format.DateFormat
import kotlinx.coroutines.flow.*
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.async
import kotlinx.coroutines.awaitAll
import kotlinx.coroutines.withContext
import org.ageage.eggplant.common.api.BookmarkService
import org.ageage.eggplant.common.api.Client
import org.ageage.eggplant.common.api.response.mapper.toBookmarks
Expand All @@ -12,33 +15,35 @@ import java.util.*

class BookmarkRepository {

fun fetchBookmarks(url: String): Flow<List<Bookmark>> {
suspend fun fetchBookmarks(url: String): List<Bookmark> {
val service =
Client.retrofitClient(Endpoint.HATENA_BOOKMARK)
.create(BookmarkService::class.java)

return service.bookmarkEntry(url)
.flatMapConcat { bookmarkEntry ->
val list = mutableListOf<Bookmark>()
withContext(Dispatchers.IO) {
service.bookmarkEntry(url).let { bookmarkEntry ->
bookmarkEntry.bookmarkResponses
.asFlow()
.filter {
it.comment.isNotEmpty()
}
.flatMapConcat { bookmark ->
val timestamp =
DateFormat.format(
"yyyyMMdd",
SimpleDateFormat(
"yyyy/MM/dd HH:mm",
Locale.US
).parse(bookmark.timestamp)
)
// TODO 並列実行したい
Client.retrofitClient(Endpoint.HATENA_STAR)
.create(BookmarkService::class.java)
.startCount("${Endpoint.HATENA_BOOKMARK.url}/${bookmark.user}/${timestamp}#bookmark-${bookmarkEntry.eid}")
.map { bookmark ->
async {
val timestamp =
DateFormat.format(
"yyyyMMdd",
SimpleDateFormat(
"yyyy/MM/dd HH:mm",
Locale.US
).parse(bookmark.timestamp)
)
Client.retrofitClient(Endpoint.HATENA_STAR)
.create(BookmarkService::class.java)
.startCount("${Endpoint.HATENA_BOOKMARK.url}/${bookmark.user}/${timestamp}#bookmark-${bookmarkEntry.eid}")
}
}
.map { responses ->
.awaitAll()
.let { responses ->
bookmarkEntry.bookmarkResponses
.filter {
it.comment.isNotEmpty()
Expand All @@ -47,8 +52,11 @@ class BookmarkRepository {

bookmarkResponse.entry = responses[index].entries.elementAtOrNull(0)
}
bookmarkEntry.bookmarkResponses.toBookmarks()
list.addAll(bookmarkEntry.bookmarkResponses.toBookmarks())
}
}
}

return list
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ package org.ageage.eggplant.bookmarks
import androidx.arch.core.executor.testing.InstantTaskExecutorRule
import androidx.lifecycle.Observer
import com.nhaarman.mockitokotlin2.*
import io.reactivex.Observable
import org.ageage.eggplant.common.TestCoroutineRule
import org.ageage.eggplant.common.enums.SortType
import org.ageage.eggplant.common.model.Bookmark
import org.ageage.eggplant.common.repository.BookmarkRepository
Expand All @@ -21,7 +21,10 @@ import java.util.*
class BookmarksViewModelTest {

@get:Rule
var instantTaskExecutorRule = InstantTaskExecutorRule()
val instantTaskExecutorRule = InstantTaskExecutorRule()

@get:Rule
val testCoroutineRule = TestCoroutineRule()

@Mock
private lateinit var bookmarksObserver: Observer<List<Bookmark>>
Expand All @@ -37,9 +40,9 @@ class BookmarksViewModelTest {
}

@Test
fun loodBookmarks_onSuccess_popular() {
fun loodBookmarks_onSuccess_popular() = testCoroutineRule.runBlockingTest {
val mockRepository = mock<BookmarkRepository> {
on { fetchBookmarks(url) } doReturn Observable.just(fakeBookmarks)
onBlocking { fetchBookmarks(url) } doReturn fakeBookmarks
}

val viewModel = BookmarksViewModel(mockRepository, TrampolineSchedulerProvider())
Expand All @@ -59,9 +62,9 @@ class BookmarksViewModelTest {
}

@Test
fun loadBookmarks_onSuccess_recent() {
fun loadBookmarks_onSuccess_recent() = testCoroutineRule.runBlockingTest {
val mockRepository = mock<BookmarkRepository> {
on { fetchBookmarks(url) } doReturn Observable.just(fakeBookmarks)
onBlocking { fetchBookmarks(url) } doReturn fakeBookmarks
}

val viewModel = BookmarksViewModel(mockRepository, TrampolineSchedulerProvider())
Expand All @@ -81,9 +84,9 @@ class BookmarksViewModelTest {
}

@Test
fun loadBookmarks_onError() {
fun loadBookmarks_onError() = testCoroutineRule.runBlockingTest {
val mockRepository = mock<BookmarkRepository> {
on { fetchBookmarks(url) } doReturn Observable.error(Throwable())
onBlocking { fetchBookmarks(url) } doThrow RuntimeException()
}

val viewModel = BookmarksViewModel(mockRepository, TrampolineSchedulerProvider())
Expand All @@ -101,9 +104,9 @@ class BookmarksViewModelTest {
}

@Test
fun loadBookmarks_twice() {
fun loadBookmarks_twice() = testCoroutineRule.runBlockingTest {
val mockRepository = mock<BookmarkRepository> {
on { fetchBookmarks(url) } doReturn Observable.just(fakeBookmarks)
onBlocking { fetchBookmarks(url) } doReturn fakeBookmarks
}

val viewModel = BookmarksViewModel(mockRepository, TrampolineSchedulerProvider())
Expand All @@ -116,9 +119,9 @@ class BookmarksViewModelTest {


@Test
fun loadBookmarks_twice_forcibly() {
fun loadBookmarks_twice_forcibly() = testCoroutineRule.runBlockingTest {
val mockRepository = mock<BookmarkRepository> {
on { fetchBookmarks(url) } doReturn Observable.just(fakeBookmarks)
onBlocking { fetchBookmarks(url) } doReturn fakeBookmarks
}

val viewModel = BookmarksViewModel(mockRepository, TrampolineSchedulerProvider())
Expand Down
26 changes: 26 additions & 0 deletions app/src/test/java/org/ageage/eggplant/common/TestCoroutineRule.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package org.ageage.eggplant.common

import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.test.*
import org.junit.rules.TestWatcher
import org.junit.runner.Description

class TestCoroutineRule : TestWatcher() {

private val testCoroutineDispatcher = TestCoroutineDispatcher()

override fun starting(description: Description?) {
super.starting(description)
Dispatchers.setMain(testCoroutineDispatcher)
}

override fun finished(description: Description?) {
super.finished(description)
Dispatchers.resetMain()
testCoroutineDispatcher.cleanupTestCoroutines()
}

fun runBlockingTest(block: suspend TestCoroutineScope.() -> Unit) {
testCoroutineDispatcher.runBlockingTest { block() }
}
}

0 comments on commit 020682e

Please sign in to comment.