swift "completion: #escaping" in kotlin language. How to use callback in kotlin? - android

I am looking for a way of completion block for my kotlin code. In Swift i have my function:
func fetchRegister(with request: RegisterRequest, completion: #escaping (Result<RegisterResponse,DataResponseError>) -> Void) {
//do some stuff
// if i got error i can use completion(Result.failure(DataResponseError.networking))
}
in kotlin my current code is:
fun fetchRegister(withRequest: RegisterRequest, callback: (Result<RegisterResponse,DataResponseError>) -> Unit) {
//do some stuff
//cant use callback.onFailure(DataResponseError.networking)
}
My result interface:
interface Result<T,U: DataResponseError> {
fun onSuccess(data: T)
fun onFailure(Error: U)
}
and my DataResponseError:
enum class DataResponseError(val errorMessage: String) {
httpBody("An error occured while creating httpBody"),
token("An error occured while getting token"),
networking("An error occured while fetching data"),
decoding("An error occured while decoding data")
}
at this moment data cant get out from this function , i cant use callback.onfailure or onSuccess with passing data. How can i fix it?

There are two ways of implementing callbacks in kotlin.
You can have some interface and pass the reference of interface from actvity to the viewModel or the adapter and then you can call specific function from there. Example: Interface:
interface CompletionHandler {
fun onSuccess(data: SomeClass)
fun onFailure(error: String)
}
Class:
class MainActivity : AppCompatActivity() {
private val viewModel: MainViewModel by viewModels()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
viewModel.fetchData(this)
}
fun onSuccess(data: SomeClass) {
//onSuccess
}
fun onFailure(error: String) {
//onFailure
}
}
ViewModel / Adapter class:
class MainViewModel(): ViewModel() {
fun fetchData(completion: CompletionHandler) {
//Logic
completion.onSuccess(responseData)
}
}
Just like in IOS(swift) we can also use anonymous functions for callback into activities.Example:Class:
class MainActivity : AppCompatActivity() {
private val viewModel: MainViewModel by viewModels()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
viewModel.fetchData(data) { data ->
//Logic
}
}
}
ViewModel / Adapter class:
class MainViewModel(): ViewModel() {
fun fetchData(data: String, completion: (SomeClass) -> Unit) {
//Logic
completion(responseData)
}
}

Replace your fetchRegister function with:
fun fetchRegister(withRequest: RegisterRequest, callback: Result<RegisterResponse,DataResponseError>){
//In case of success
callback.onSuccess(data)
// In case of failure
callback.onFailure(DataResponseError.networking)
}
val callback = object : Result<RegisterResponse,DataResponseError> {
override fun onSuccess(response: RegisterResponse) {
// Do Something
}
override fun onFailure(error: DataResponseError) {
// Do Something
}
}
fetchRegister(request, callback)

Related

Android Unit testing Mockk argument capture

interface SomeAPIHandler {
fun getUserContent(apiInterface: APIInterface<UserModel>)
}
interface APIInterface<T> {
fun onSuccess(responseModel: T)
fun onError(errorModel: ErrorModel)
}
In my presenter class, it is called like:
apiClient.getUserContent(object : APIInterface<UserModel> {
override fun onSuccess(responseModel: UserModel) = handleSuccess(responseModel)
override fun onError(errorModel: ErrorModel) = handleGetUserModelError()
})
I am getting code coverage issue from SonarQube for this two lines in presentor class:
override fun onSuccess(responseModel: UserModel) = handleSuccess(responseModel)
override fun onError(errorModel: ErrorModel) = handleGetUserModelError()
I am using mockk.io and I think i need to use slot for this. Can someone help how to cover this ?

where I am making mistake in mainactivity?

I am developing android app and I am getting error screenshot below when I have implemented network call in mainactivity.kt I want to know where I am making mistake
below my MainActivity.kt
class MainActivity : AppCompatActivity() {
private var adapter: CurrenciesAdapter? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
recycler_main.layoutManager = LinearLayoutManager(this#MainActivity)
adapter = CurrenciesAdapter(this)
recycler_main.adapter = adapter
if (isInternetAvailable()) {
getUsersData()
}
}
private fun getUsersData() {
showProgressBar()
var apiInterface: CurrenciesResponse = CurrencyClient().getApiClient()!!.create(
CurrenciesResponse::class.java
)
apiInterface.getCurrencies().enqueue(object : Callback <List<CurrencyResponse>> {
override fun onResponse(
call: Call<List<CurrencyResponse>>,
response: Response<List<CurrencyResponse>>)
{
hideProgressBar()
val currencyResponse = response.body()
adapter?.list = currencyResponse!!
}
override fun onFailure(call: Call<List<CurrencyResponse>>, t: Throwable) {
hideProgressBar()
Log.e("error", t.localizedMessage)
}
})
}
}
what I have done I have changed to response type from <List to CurrencyResponse but I am still getting response below whole gist code
https://gist.github.com/kyodgorbek/d0d9b3749ac64f15b4db87874cfe13e7
Your getCurrencies() method in CurrenciesResponse.class has a return type of CurrenciesResponse whereas it should be List<CurrenciesResponse>.
You need to fix your retrofit's service interface.

How to use the object value in another class in Kotlin and Microsoft Oauth 2.0

I want to use the below object in another class:
private var mSingleAccountApp: ISingleAccountPublicClientApplication? = null
PublicClientApplication.createSingleAccountPublicClientApplication(
this,
R.raw.auth_config_single_account,
object : IPublicClientApplication.ISingleAccountApplicationCreatedListener {
override fun onCreated(application: ISingleAccountPublicClientApplication) {
mSingleAccountApp = application
// loadAccount()
}
override fun onError(exception: MsalException) {
//txt_log.text = exception.toString()
}
}
)
I need to call the below method from another class
fun performOperationOnSignOut() {
mSingleAccountApp!!.signOut(object : ISingleAccountPublicClientApplication.SignOutCallback {
override fun onSignOut() {
}
override fun onError(exception: MsalException) {
//displayError(exception)
}
})
}
I tried to call but mSingleAccountApp always throws NullPointerException
How can I pass or use the mSingleAccountApp variable in another class?
ISingleAccountPublicClientApplication this is an interface
This is the simplest example I could come up with:
//class with one property
class Foo(val name : String){
}
class Bar(){
constructor(foo: Foo) : this() {
//access the property of the foo object
println(foo.name)
}
}
fun main() {
val foo = Foo("John Doe")
//pass foo-object in the constructor
val bar = Bar(foo)
}
see also: https://kotlinlang.org/docs/reference/properties.html
class CustomClass(var listener: ListenerAppImp){
private var mSingleAccountApp: ISingleAccountPublicClientApplication? = null
PublicClientApplication.createSingleAccountPublicClientApplication(
this,
R.raw.auth_config_single_account,
object : IPublicClientApplication.ISingleAccountApplicationCreatedListener {
override fun onCreated(application: ISingleAccountPublicClientApplication) {
mSingleAccountApp = application
listener.getAppValue(mSingleAccountApp) // todo mSingleAccountApp Value through interface
// loadAccount()
}
override fun onError(exception: MsalException) {
//txt_log.text = exception.toString()
}
}
)
}
// todo for example
interface ListenerAppImp {
fun getAppValue(mSingleAccountApp : ISingleAccountPublicClientApplication)
}
class User {
var customClass = CustomClass(object : ListenerAppImp{
override fun getAppValue(mSingleAccountApp: ISingleAccountPublicClientApplication) {
}
})
}
hope that may help you
In your case just implement interface ISingleAccountPublicClientApplication in another class for your understanding let's keep class name is Another
class Another : ISingleAccountPublicClientApplication {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
.....InitialiseYourInterfaceHere.....
}
override fun signOut(..yourcode...){
.......yourcode.......
}
}

How to get a variable from another class in kotlin?

I want to get a variable from an activity and use it in another class.
This variable will be filled by an user in a editText that is called editTextSerie
override fun searchSeries(listener: OnDataListener) {
val retrofit = Retrofit.Builder().addConverterFactory(GsonConverterFactory.create())
.baseUrl("http://api.themoviedb.org/3/")
.build()
val client = retrofit.create(MovieDBApiInterface::class.java)
val objetoClasse1 = SearchActivity()
var nomeS = objetoClasse1.editTextSerie.text.toString().trim()
val responseCall = client.searchSeries("API_KEY", "pt-BR", nomeS)
responseCall.enqueue(object : Callback<AllSeriesResponse> {
override fun onResponse(call: Call<AllSeriesResponse>?, response1: Response<AllSeriesResponse>?) {
listener.onSuccess(response1!!.body()!!.results)
}
override fun onFailure(call: Call<AllSeriesResponse>?, t: Throwable?) {
listener.onFailure(t!!.message.toString())
}
})
}
This function "searchSeries" is from the class "Series".
I want to get the "editTextSerie" from another class called "Search Activity",
so i created the variable "nomeS" to receive the value of it.
class SearchActivity : AppCompatActivity() {
var botaoSearch: AppCompatImageButton? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_search)
botaoSearch = findViewById(R.id.btn_search)
botaoSearch?.setOnClickListener {
var nomeSerie = editTextSerie.text.toString().trim()
}
}
}
I want to receive this value (value of editTextSerie comes from the XML of SearchActivity ) and use it at responseCall with the "nomeS" variable
What is OnDataListener? Not really sure it is interface or abstract class, so I' ll write some pseudo code.
First change your function searchSeries's params to
searchSeries(text: String, listener: OnDataListener)
So in the class Series, you can get the data in your function searchSeries:
override fun searchSeries(text: String, listener: OnDataListener) {
// ...
// you can get the "text" string
}
Then edit your SearActivity's listener:
class SearchActivity : AppCompatActivity() {
var botaoSearch: AppCompatImageButton? = null
// create class "Series"
val series = Series()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_search)
botaoSearch = findViewById(R.id.btn_search)
botaoSearch?.setOnClickListener {
var nomeSeries = editTextSerie.text.toString().trim()
searchSeries(nomeSeries)
}
}
private fun searchSeries(text: String) {
series.searchSeries(text, object : OnDataListener {
override onSuccess(a0: ...) {
}
override onFailure(message: String) {
}
})
}
}
If OnDataListener is a abstract class:
series.searchSeries(text, object : OnDataListener() {
override onSuccess(a0: ...) {
}
override onFailure(message: String) {
}
})

Kotlin: How to inherit from RxJava Subscriber

I want my NewsListSubscriber to inherit from an RxJava Subscriber which use a generic type but I get a "Type mismatch" error when I call the UseCase execute method. I read many times the generics page from the Kotlin documentation but I can't find the solution.
Here is my UseCase:
abstract class UseCase(private val threadExecutor: IThreadExecutor,
private val postExecutionThread: IPostExecutionThread) {
private var subscription = Subscriptions.empty()
fun execute(UseCaseSubscriber: rx.Subscriber<Any>) {
subscription = buildUseCaseObservable()
.subscribeOn(Schedulers.from(threadExecutor))
.observeOn(postExecutionThread.getScheduler())
.subscribe(UseCaseSubscriber)
}
protected abstract fun buildUseCaseObservable(): Observable<out Any>
fun unsubscribe() {
if (!subscription.isUnsubscribed) {
subscription.unsubscribe()
}
}
}
And here is how I call it:
override fun loadNewsList() {
getNewsListInteractor.execute(NewsListSubscriber())
}
private inner class NewsListSubscriber : rx.Subscriber<List<NewsModel>>() {
override fun onCompleted() {// TODO}
override fun onError(e: Throwable) {// TODO}
override fun onNext(t: List<NewsModel>) {// TODO}
}
The error is
"Type mismatch. Required: rx.Subscriber. Found: Presenters.NewsListPresenter.NewsListSubscriber"
in the "execute(NewsListSubscriber())" line. I tried playing with the "in" and "out" keywords but I still have the same error.
There is actually a better way to solve this problem. I ran into the same issue and a type cast inside every derived subscriber class was not an option.
Just update the abstract UseCase class with an generic type parameter.
abstract class UseCase<T>(private val threadExecutor: IThreadExecutor,
private val postExecutionThread: IPostExecutionThread) {
private var subscription = Subscriptions.empty()
fun execute(UseCaseSubscriber: rx.Subscriber<T>) {
subscription = buildUseCaseObservable()
.subscribeOn(Schedulers.from(threadExecutor))
.observeOn(postExecutionThread.getScheduler())
.subscribe(UseCaseSubscriber)
}
protected abstract fun buildUseCaseObservable(): Observable<T>
fun unsubscribe() {
if (!subscription.isUnsubscribed) {
subscription.unsubscribe()
}
}
}
When you declare your derived UseCase classes, use your concrete type for the generic parameter when calling the super class.
class ConcreteUseCase(val threadExecutor: IThreadExecutor,
val postExecutionThread: IPostExecutionThread)
: UseCase<ConcreteType>(threadExecutor, postExecutionThread)
Doing so, you can use typed Subscribers in your execute call.
getNewsListInteractor.execute(NewsListSubscriber())
...
private inner class NewsListSubscriber : rx.Subscriber<List<NewsModel() {
override fun onCompleted() {// TODO}
override fun onError(e: Throwable) {// TODO}
override fun onNext(t: List<NewsModel>) {// TODO}
}
I found the solution that is pretty simple actually: my NewsListSubscriber class has to extends from rx.Subscriber<Any> instead of rx.Subscriber<MyWantedClass>. It means I need to cast the received objects to the wanted type.
private inner class NewsListSubscriber : DefaultSubscriber<Any>() {
override fun onCompleted() {}
override fun onError(e: Throwable) {}
override fun onNext(t: Any?) {
val newsList = t as List<News>
...
}
}
In Java the cast is done in background but in Kotlin we need to do it ourself.
I also removed all "in" or "out" keywords in my UseCase class.

Categories

Resources