Reaction - handling method results in Kotlin

Anyone who has used Clean Architecture in development has faced the problem of transferring data between layers. The essence of the problem is always the same: you need to return either a result or an error. This can be represented, for example, like this:





interface Reaction

data class Success(val data: String) : Reaction
data class Error(message: String) : Reaction
      
      



Depending on the task, such reactions can be very different, so let's combine it into one class using Generics and Sealed classes .





sealed class Reaction<out T> {
   class Success<out T>(val data: T) : Reaction<T>()
   class Error(val exception: Throwable) : Reaction<Nothing>()
}
      
      



Let's look at an example of how it can be used.





class MyViewModel : ViewModel {
	private val repository: Repository
	
	fun doSomething() {
		viewModelScope.launch(Dispatchers.IO) {
			val result = repository.getData()
			when (result) {
				is Success -> //do something
				is Error -> // show error
			}
		}
	}
}
      
      



. .





class RepositoryImpl(private val dataSource: DataSource) : Repository {
  
	override suspend fun getData(): Reaction<Int> {
		return try {
			Reaction.Success(dataSource.data)
		} catch(e: Exception) {
			Reaction.Error(e)
		}
	}
}

      
      



- , Reaction, try-catch, - . , try-catch .





sealed class Reaction<out T> {

   class Success<out T>(val data: T) : Reaction<T>()
   class Error(val exception: Throwable) : Reaction<Nothing>()

   companion object {
       inline fun <T> on(f: () -> T): Reaction<T> = try {
           Success(f())
       } catch (ex: Exception) {
           Error(ex)
       }
   }
}
      
      



:





class RepositoryImpl(private val dataSource: DataSource) : Repository {

	suspend fun getData(): Reaction<Int> = Reaction.on { dataSource.data }
}
      
      



, 4 .





ViewModel when . , View.





class MyViewModel : ViewModel {
	private val repository: Repository
	private val _onData = MutableLiveData<State>()
	val onData: LiveData<State> = _onData

	fun doSomething() {
		viewModelScope.launch(Dispatchers.IO) {
			val result = repository.getData()
			when (result) {
				is Success -> _onData.postValue(State.Success)
				is Error -> onData.postValue(State.Error(result.message))
			}
		}
	}

	sealed class State {
  	object Progress : State()
  	object Success : State()
  	data class Error(message: String) : State()
	}
}
      
      



RxJava, Coroutines LiveData.

, , ViewModel , , zip, Reaction , LiveData





inline fun <T, R> Result<T>.zip(success: (T) -> R, error: (Exception) -> R): R =
   when (this) {
       is Reaction.Success -> success(this.data)
       is Reaction.Error -> error(this.exception)
   }
      
      



MyViewModel





class MyViewModel : ViewModel {
	private val repository: Repository
	private val _onData = MutableLiveData<State>()
	val onData: LiveData<State> = _onNewDirectory

	fun doSomething() {
		viewModelScope.launch(Dispatchers.IO) {
			repository.getData()
				.zip(
        	{ State.Success }, 
        	{ State.Error(result.message) }
        )
				.let { onData.postValue(it) }
		}
	}

	//...
}
      
      



, ViewModel , . View





:





class MyViewModel : ViewModel {
	//...
	fun doSomething() {
		viewModelScope.launch(Dispatchers.IO) {
			var firstData: Int = 0

			val reaction = repository.getData()
			when (reaction) {
				is Success -> firstData = reaction.data 
				is Error -> {
					onData.postValue(State.Error(reaction.message))
					return@launch
				}
			}

			val nextReaction = repository.getNextData(firstData)
      
			//..
		}		
	}
  
	//...
}
      
      



, callback hell, , Coroutines





class MyViewModel : ViewModel {
  //...
	fun doSomething() {
		viewModelScope.launch(Dispatchers.IO) {
			val firstData = repository.getData()
				.takeOrReturn {
					onData.postValue(State.Error(result.message)
					return@launch
				}
			val nextReaction= repository.getNextData(firstData)
      
			//..
		}		
	}
}
      
      



, :





  • on - Reaction





  • map -





  • flatMap - Reaction





  • doOnSuccess - , Reaction -









Github





3 .





  • Railway Kotlin

    :









    • 1





    :





    • try-catch





    • infix









  • Arrow-KT

    :









    :













    • ,





  • Result (Kotlin)

    :









    :









    • gradle, , Result, Kotlin





Reaction is a lightweight library with a minimal threshold of entry. it consists of 1 file, which provides the same power as the solution from Kotlin, but does not contain all its cons.





Github

https://github.com/taptappub/Reaction/








All Articles