How to set up Viewmodel class properly? - kotlin

I'm trying to follow some tutotial from github about MVVM model and i'm stuck at viewmodel class because there's an error says
Not enough information to infer type variable T
and
Type mismatch.
Required:Resource<Movie>
Found:Unit
And when i check my other class like ApiService, Dao, NetworkBoundResource, ApiResponse, Resources and respository everthing fine like this
ApiService :
interface ApiService {
#GET("3/movie/popular")
fun getMyMovie(#Query("api_key") api : String = "32bbbffe944d16d1d2a3ee46cfc6aaa0"
) : Flow<ApiResponse<MovieResponse.Movie>>
}
MovieDao:
#Dao
interface MovieDao : BaseDao<Movie> {
// #Insert(onConflict = OnConflictStrategy.REPLACE)
// fun insertMovie(movie: List<Movie>)
#Query("SELECT * FROM `movie` ORDER by movie_id DESC")
fun getMyMovie() : Flow<Movie>
#Query("SELECT * FROM `movie` ORDER by movie_id DESC")
fun findAllMovie() : Maybe<List<Movie>>
#Query("SELECT * FROM `movie` ORDER by movie_id DESC")
fun streamAll() : Flowable<List<Movie>>
#Query("DELETE FROM `movie`")
fun deleteAll()
}
MovieRespository:
class MovieRespository (val apiService: ApiService, val movieDao: MovieDao) {
fun getListMovie() : Flow<Resource<Movie>> {
return networkBoundResource(
fetchFromLocal = { movieDao.getMyMovie() },
shouldFetchFromRemote = {true},
fetchFromRemote = {apiService.getMyMovie()},
processRemoteResponse = {},
saveRemoteData = {movieDao.insert(
it.results.let {
it.map { data -> Movie.from(data) }
}
)},
onFetchFailed = {_, _ ->}
).flowOn(Dispatchers.IO)
}
NeteorkBoundResource:
inline fun <DB, REMOTE> networkBoundResource(
crossinline fetchFromLocal: () -> Flow<DB>,
crossinline shouldFetchFromRemote: (DB?) -> Boolean = { true },
crossinline fetchFromRemote: () -> Flow<ApiResponse<REMOTE>>,
crossinline processRemoteResponse: (response: ApiSuccessResponse<REMOTE>) -> Unit = { Unit },
crossinline saveRemoteData: (REMOTE) -> Unit = { Unit },
crossinline onFetchFailed: (errorBody: String?, statusCode: Int) -> Unit = { _: String?, _: Int -> Unit }
) = flow<Resource<DB>> {
emit(Resource.Loading(null))
val localData = fetchFromLocal().first()
if (shouldFetchFromRemote(localData)) {
emit(Resource.Loading(localData))
fetchFromRemote().collect { apiResponse ->
when (apiResponse) {
is ApiSuccessResponse -> {
processRemoteResponse(apiResponse)
apiResponse.body?.let { saveRemoteData(it) }
emitAll(fetchFromLocal().map { dbData ->
Resource.Success(dbData)
})
}
is ApiErrorResponse -> {
onFetchFailed(apiResponse.errorMessage, apiResponse.statusCode)
emitAll(fetchFromLocal().map {
Resource.Error(
apiResponse.errorMessage,
it
)
})
}
}
}
} else {
emitAll(fetchFromLocal().map { Resource.Success(it) })
}
}
ApiResponse:
sealed class ApiResponse<T> {
companion object {
fun <T> create(error: Throwable): ApiErrorResponse<T> {
return ApiErrorResponse(
error.message ?: "Unknown error",
0
)
}
fun <T> create(response: Response<T>): ApiResponse<T> {
return if (response.isSuccessful) {
val body = response.body()
val headers = response.headers()
if (body == null || response.code() == 204) {
ApiEmptyResponse()
} else {
ApiSuccessResponse(
body,
headers
)
}
} else {
val msg = response.errorBody()?.string()
val errorMsg = if (msg.isNullOrEmpty()) {
response.message()
} else {
msg
}
ApiErrorResponse(
errorMsg ?: "Unknown error",
response.code()
)
}
}
}
}
/**
* separate class for HTTP 204 responses so that we can make ApiSuccessResponse's body non-null.
*/
class ApiEmptyResponse<T> : ApiResponse<T>()
data class ApiSuccessResponse<T>(
val body: T?,
val headers: okhttp3.Headers
) : ApiResponse<T>()
data class ApiErrorResponse<T>(val errorMessage: String, val statusCode: Int) : ApiResponse<T>()
Resource:
data class Resource<out T>(val status: Status, val data: T?, val message: String?) {
// data class Loading<T>(val loadingData: T?) : Resource<T>(Status.LOADING, loadingData, null)
// data class Success<T>(val successData: T?) : Resource<T>(Status.SUCCESS, successData, null)
// data class Error<T>(val msg: String, val error: T?) : Resource<T>(Status.ERROR, error, msg)
companion object {
fun <T> Success(data: T?): Resource<T> {
return Resource(Status.SUCCESS, data,null)
}
fun <T> Error(msg: String, data: T? = null): Resource<T> {
return Resource(Status.ERROR, data, msg)
}
fun <T> Loading(data: T? = null): Resource<T> {
return Resource(Status.LOADING, data, null)
}
}
}
MainViewModel:
class MainViewModel(private val movieRespository: MovieRespository) : ViewModel() {
#ExperimentalCoroutinesApi
val getListMovies: LiveData<Resource<Movie>> = movieRespository.getListMovie().map {
when(it.status){
Resource.Loading() ->{}
Resource.Success() ->{}
Resource.Error() ->{}
}
}.asLiveData(viewModelScope.coroutineContext)
}
to be specific this what the error looks like and this is the link of tutorial i learn
https://github.com/hadiyarajesh/flower
viewModel Class Error

You get the error, because Inside the when, you are trying to construct a new instance of Resource.Loading() etc, but those require a type, so it would need to be something like Resource.Loading<Movie>().
Tht being said, you are doing when(it.status), so the cases in the when, should not be a Resource.Loading, but Status.LOADING instead:
class MainViewModel(private val movieRespository: MovieRespository) : ViewModel() {
#ExperimentalCoroutinesApi
val getListMovies: LiveData<Resource<Movie>> = movieRespository.getListMovie().map {
when(it.status){
Status.LOADING ->{}
Status.SUCCESS ->{}
Status.ERROR ->{}
}
return#map it
}.asLiveData(viewModelScope.coroutineContext)
}
Also, since you are declaring LiveData<Resource<Movie>>, you need to return a Resource<Movie> from the map {} (we could drop return#map, it is just to be explicit)

Related

Custom multipart-form-data serializable in Kotlin/Ktor

Does anyone know how to program the override function convertForReceive of a custom Multipart.FormData converter?
I want to convert the multipart request to my class with the converter but I don't know how it works.
I have:
Application.kt
install(ContentNegotiation) {
json()
register(ContentType.MultiPart.FormData, CustomMultipartConverter)
}
CustomMultipartConverter
object CustomMultipartConverter: ContentConverter {
override suspend fun convertForReceive(context: PipelineContext<ApplicationReceiveRequest, ApplicationCall>): Any? {
TODO("Not yet implemented")
}
override suspend fun convertForSend(
context: PipelineContext<Any, ApplicationCall>,
contentType: ContentType,
value: Any
): Any? {
TODO("Not yet implemented")
}
}
REQUEST CLASS
class CreatePostRequest(
val text: String,
val image: File? = null
)
ROUTE
route("v1/posts") {
authenticate {
route("create") {
val authJWT = call.authentication.principal as JWTAtuh
val request = call.receive<CreatePostRequest>()
//myCode
call.respond(HttpStatusCode.OK)
}
}
}
You can take SerializationConverter as a reference:
override suspend fun convertForReceive(context: PipelineContext<ApplicationReceiveRequest, ApplicationCall>): Any? {
val request = context.subject
val channel = request.value as? ByteReadChannel ?: return null
val charset = context.call.request.contentCharset() ?: defaultCharset
val serializer = format.serializersModule.serializer(request.typeInfo)
val contentPacket = channel.readRemaining()
return when (format) {
is StringFormat -> format.decodeFromString(serializer, contentPacket.readText(charset))
is BinaryFormat -> format.decodeFromByteArray(serializer, contentPacket.readBytes())
else -> {
contentPacket.discard()
error("Unsupported format $format")
}
}
}

How to ignore empty database result for the first time and wait for server result in application?

My app using room as a database and retrofit as a network calling api.
i am observing database only as a single source of truth. every thing is working fine. But i am not finding solution of one scenario.
Like for the first time when user open app it do following operations
fetch data from db
fetch data from server
because currently database is empty so it sends empty result to observer which hide progress bar . i want to discard that event and send result to observer when server dump data to database. even server result is empty. so progress bar should always hide once their is confirmation no data exists.
in other words application should always rely on database but if it empty then it should wait until server response and then notify observer.
this is my code
observer
viewModel.characters.observe(viewLifecycleOwner, Observer {
Log.e("status is ", "${it.message} at ${System.currentTimeMillis()}")
when (it.status) {
Resource.Status.SUCCESS -> {
binding.progressBar.visibility = View.GONE
if (!it.data.isNullOrEmpty()) adapter.setItems(ArrayList(it.data))
}
Resource.Status.ERROR -> {
Toast.makeText(requireContext(), it.message, Toast.LENGTH_SHORT).show()
binding.progressBar.visibility = View.GONE
}
Resource.Status.LOADING ->
binding.progressBar.visibility = View.VISIBLE
}
})
ViewModel
#HiltViewModel
class CharactersViewModel #Inject constructor(
private val repository: CharacterRepository
) : ViewModel() {
val characters = repository.getCharacters()
}
Repository
class CharacterRepository #Inject constructor(
private val remoteDataSource: CharacterRemoteDataSource,
private val localDataSource: CharacterDao
) {
fun getCharacters() : LiveData<Resource<List<Character>>> {
return performGetOperation(
databaseQuery = { localDataSource.getAllCharacters() },
networkCall = { remoteDataSource.getCharacters() },
saveCallResult = { localDataSource.insertAll(it.results) }
)
}
}
Utility function for all api and database handling
fun <T, A> performGetOperation(databaseQuery: () -> LiveData<T>,
countQuery: () -> Int,
networkCall: suspend () -> Resource<A>,
saveCallResult: suspend (A) -> Unit): LiveData<Resource<T>> =
liveData(Dispatchers.IO) {
emit(Resource.loading())
val source = databaseQuery().map { Resource.success(it,"database") }.distinctUntilChanged()
emitSource(source)
val responseStatus = networkCall()
if (responseStatus.status == SUCCESS) {
saveCallResult(responseStatus.data!!)
} else if (responseStatus.status == ERROR) {
emit(Resource.error(responseStatus.message!!))
}
}
LocalDataSource
#Dao
interface CharacterDao {
#Query("SELECT * FROM characters")
fun getAllCharacters() : LiveData<List<Character>>
#Insert(onConflict = OnConflictStrategy.REPLACE)
suspend fun insertAll(characters: List<Character>)
#Insert(onConflict = OnConflictStrategy.REPLACE)
suspend fun insert(character: Character)
}
DataSource
class CharacterRemoteDataSource #Inject constructor(
private val characterService: CharacterService
): BaseDataSource() {
suspend fun getCharacters() = getResult { characterService.getAllCharacters() }}
}
Base Data Source
abstract class BaseDataSource {
protected suspend fun <T> getResult(call: suspend () -> Response<T>): Resource<T> {
try {
Log.e("status is", "started")
val response = call()
if (response.isSuccessful) {
val body = response.body()
if (body != null) return Resource.success(body,"server")
}
return error(" ${response.code()} ${response.message()}")
} catch (e: Exception) {
return error(e.message ?: e.toString())
}
}
private fun <T> error(message: String): Resource<T> {
Timber.d(message)
return Resource.error("Network call has failed for a following reason: $message")
}
}
Character Service
interface CharacterService {
#GET("character")
suspend fun getAllCharacters() : Response<CharacterList>
}
Resource
data class Resource<out T>(val status: Status, val data: T?, val message: String?) {
enum class Status {
SUCCESS,
ERROR,
LOADING
}
companion object {
fun <T> success(data: T,message : String): Resource<T> {
return Resource(Status.SUCCESS, data, message)
}
fun <T> error(message: String, data: T? = null): Resource<T> {
return Resource(Status.ERROR, data, message)
}
fun <T> loading(data: T? = null): Resource<T> {
return Resource(Status.LOADING, data, "loading")
}
}
}
CharacterList
data class CharacterList(
val info: Info,
val results: List<Character>
)
What is the best way by that i ignore database if it is empty and wait for server response and then notify observer

org.koin.core.error.InstanceCreationException: Could not create instance for [Factory:'com.pokemonsearch.presentation.search.SearchViewModel']

I am using Koin as depenedency Injection framework in my Kotlin Application. I am trying to save data to Room database using coroutines. I have a usecase "AddToFavourite" class which was calling from viewmodel. While running the app the app crash with below error. When I check I understand that koin could not find some dependency. Can any one please help me out with a solution. Please find the repository, usecase, viewmodel, database and di modules as below
Process: com.debin.pokemonsearch, PID: 16027
java.lang.RuntimeException: Unable to start activity ComponentInfo{com.debin.pokemonsearch/com.debin.pokemonsearch.HomeActivity}: org.koin.core.error.InstanceCreationException: Could not create instance for [Factory:'com.debin.pokemonsearch.presentation.search.SearchViewModel']
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2817`
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2892)
at android.app.ActivityThread.-wrap11(Unknown Source:0)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1593)
at android.os.Handler.dispatchMessage(Handler.java:105)
at android.os.Looper.loop(Looper.java:164)
at android.app.ActivityThread.main(ActivityThread.java:6541)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.Zygote$MethodAndArgsCaller.run(Zygote.java:240)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:767)
Caused by: org.koin.core.error.InstanceCreationException: Could not create instance for [Factory:'com.debin.pokemonsearch.presentation.search.SearchViewModel']
at org.koin.core.instance.InstanceFactory.create(InstanceFactory.kt:59)
at org.koin.core.instance.FactoryInstanceFactory.get(FactoryInstanceFactory.kt:36)
at org.koin.core.registry.InstanceRegistry.resolveInstance$koin_core(InstanceRegistry.kt:87)
at org.koin.core.scope.Scope.resolveInstance(Scope.kt:214)
at org.koin.core.scope.Scope.get(Scope.kt:181)
at org.koin.android.viewmodel.ViewModelFactoryKt$defaultViewModelFactory$1.create(ViewModelFactory.kt:13)
at androidx.lifecycle.ViewModelProvider.get(ViewModelProvider.java:187)
at androidx.lifecycle.ViewModelProvider.get(ViewModelProvider.java:150)
at org.koin.android.viewmodel.ViewModelResolutionKt.get(ViewModelResolution.kt:21)
at org.koin.android.viewmodel.ViewModelResolutionKt.resolveInstance(ViewModelResolution.kt:10)
at org.koin.android.viewmodel.scope.ScopeExtKt.getViewModel(ScopeExt.kt:68)
at org.koin.android.viewmodel.scope.ScopeExtKt.getViewModel(ScopeExt.kt:56)
at org.koin.android.viewmodel.koin.KoinExtKt.getViewModel(KoinExt.kt:34)
at org.koin.android.viewmodel.ext.android.ViewModelStoreOwnerExtKt.getViewModel(ViewModelStoreOwnerExt.kt:66)
at com.debin.pokemonsearch.presentation.search.SearchFragment$$special$$inlined$viewModel$1.invoke(ViewModelStoreOwnerExt.kt:71)
at com.debin.pokemonsearch.presentation.search.SearchFragment$$special$$inlined$viewModel$1.invoke(Unknown Source:0)
at kotlin.UnsafeLazyImpl.getValue(Lazy.kt:81)
at com.debin.pokemonsearch.presentation.search.SearchFragment.getViewModel(Unknown Source:2)
at com.debin.pokemonsearch.presentation.search.SearchFragment.observePokemon(SearchFragment.kt:39)
at com.debin.pokemonsearch.presentation.search.SearchFragment.onViewCreated(SearchFragment.kt:31)
at androidx.fragment.app.FragmentStateManager.createView(FragmentStateManager.java:332)
at androidx.fragment.app.FragmentManager.moveToState(FragmentManager.java:1187)
at androidx.fragment.app.FragmentManager.moveToState(FragmentManager.java:1356)
at androidx.fragment.app.FragmentManager.moveFragmentToExpectedState(FragmentManager.java:1434)
at androidx.fragment.app.FragmentManager.moveToState(FragmentManager.java:1497)
at androidx.fragment.app.FragmentManager.dispatchStateChange(FragmentManager.java:2625)
at androidx.fragment.app.FragmentManager.dispatchActivityCreated(FragmentManager.java:2577)
at androidx.fragment.app.Fragment.performActivityCreated(Fragment.java:2722)
at androidx.fragment.app.FragmentStateManager.activityCreated(FragmentStateManager.java:346)
at androidx.fragment.app.FragmentManager.moveToState(FragmentManager.java:1188)
at androidx.fragment.app.FragmentManager.moveToState(FragmentManager.java:1356)
at androidx.fragment.app.FragmentManager.moveFragmentToExpectedState(FragmentManager.java:1434)
at androidx.fragment.app.FragmentManager.moveToState(FragmentManager.java:1497)
2021-01-24 19:49:54.088 16027-16027/com.debin.pokemonsearch E/AndroidRuntime: at androidx.fragment.app.FragmentManager.dispatchStateChange(FragmentManager.java:2625)
at androidx.fragment.app.FragmentManager.dispatchActivityCreated(FragmentManager.java:2577)
at androidx.fragment.app.FragmentController.dispatchActivityCreated(FragmentController.java:247)
at androidx.fragment.app.FragmentActivity.onStart(FragmentActivity.java:541)
at androidx.appcompat.app.AppCompatActivity.onStart(AppCompatActivity.java:210)
at android.app.Instrumentation.callActivityOnStart(Instrumentation.java:1333)
at android.app.Activity.performStart(Activity.java:6992)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2780)
... 9 more
Caused by: org.koin.core.error.InstanceCreationException: Could not create instance for [Factory:'com.debin.pokemonsearch.pokemoncore.interactors.AddToFavourites']
at org.koin.core.instance.InstanceFactory.create(InstanceFactory.kt:59)
at org.koin.core.instance.FactoryInstanceFactory.get(FactoryInstanceFactory.kt:36)
at org.koin.core.registry.InstanceRegistry.resolveInstance$koin_core(InstanceRegistry.kt:87)
at org.koin.core.scope.Scope.resolveInstance(Scope.kt:214)
at org.koin.core.scope.Scope.get(Scope.kt:181)
at com.debin.pokemonsearch.di.ViewModelModuleKt$viewModelModule$1$1.invoke(ViewModelModule.kt:24)
at com.debin.pokemonsearch.di.ViewModelModuleKt$viewModelModule$1$1.invoke(Unknown Source:4)
at org.koin.core.instance.InstanceFactory.create(InstanceFactory.kt:50)
... 49 more
Caused by: org.koin.core.error.InstanceCreationException: Could not create instance for [Single:'com.debin.pokemonsearch.pokemoncore.domain.repository.IPokemonCoreRepository']
at org.koin.core.instance.InstanceFactory.create(InstanceFactory.kt:59)
at org.koin.core.instance.SingleInstanceFactory.create(SingleInstanceFactory.kt:40)
at org.koin.core.instance.SingleInstanceFactory.get(SingleInstanceFactory.kt:48)
at org.koin.core.registry.InstanceRegistry.resolveInstance$koin_core(InstanceRegistry.kt:87)
at org.koin.core.scope.Scope.resolveInstance(Scope.kt:214)
at org.koin.core.scope.Scope.get(Scope.kt:181)
at com.debin.pokemonsearch.di.UseCaseModuleKt$useCaseModule$1$3.invoke(UseCaseModule.kt:23)
at com.debin.pokemonsearch.di.UseCaseModuleKt$useCaseModule$1$3.invoke(Unknown Source:4)
at org.koin.core.instance.InstanceFactory.create(InstanceFactory.kt:50)
... 56 more
Caused by: org.koin.core.error.InstanceCreationException: Could not create instance for [Single:'com.debin.pokemonsearch.pokemoncore.data.datasource.PokemonCoreDataSource']
at org.koin.core.instance.InstanceFactory.create(InstanceFactory.kt:59)
at org.koin.core.instance.SingleInstanceFactory.create(SingleInstanceFactory.kt:40)
at org.koin.core.instance.SingleInstanceFactory.get(SingleInstanceFactory.kt:48)
at org.koin.core.registry.InstanceRegistry.resolveInstance$koin_core(InstanceRegistry.kt:87)
at org.koin.core.scope.Scope.resolveInstance(Scope.kt:214)
at org.koin.core.scope.Scope.get(Scope.kt:181)
at com.debin.pokemonsearch.di.RepositoryModuleKt$repositoryModule$1$3.invoke(RepositoryModule.kt:19)
at com.debin.pokemonsearch.di.RepositoryModuleKt$repositoryModule$1$3.invoke(Unknown Source:4)
at org.koin.core.instance.InstanceFactory.create(InstanceFactory.kt:50)
... 64 more
Caused by: org.koin.core.error.NoBeanDefFoundException: No definition found for class:'com.debin.pokemonsearch.framework.db.PokemonDatabase'. Check your definitions!
at org.koin.core.scope.Scope.throwDefinitionNotFound(Scope.kt:246)
at org.koin.core.scope.Scope.resolveInstance(Scope.kt:216)
at org.koin.core.scope.Scope.get(Scope.kt:181)
at com.debin.pokemonsearch.di.DataSourceModuleKt$dataSourceModule$1$3.invoke(DataSourceModule.kt:19)
at com.debin.pokemonsearch.di.DataSourceModuleKt$dataSourceModule$1$3.invoke(Unknown Source:4)
at org.koin.core.instance.InstanceFactory.create(InstanceFactory.kt:50)
... 72 more
AddToFavourites Usecase:
class AddToFavourites(private val coreRepository: IPokemonCoreRepository) {
suspend fun invokeAddToFavourites(pokemon: Pokemon) {
coreRepository.addPokemonToFavourites(pokemon)
}
}
Repository interface and model in domain layer
interface IPokemonCoreRepository {
suspend fun addPokemonToFavourites(pokemon: Pokemon)
suspend fun getFavouritePokemon() : List<Pokemon>
suspend fun removePokemonFromFavourite(pokemon: Pokemon)
}
data class Pokemon(
val id : Int,
val name : String,
val description : String,
val imageUrl : String
)
Repository Implementation and datasourse in data layer:
class PokemonCoreRepository(private val dataSource: PokemonCoreDataSource) : IPokemonCoreRepository {
override suspend fun addPokemonToFavourites(pokemon: Pokemon) {
return dataSource.addPokemonToFavourites(pokemon)
}
override suspend fun getFavouritePokemon(): List<Pokemon> {
return dataSource.getFavouritePokemon()
}
override suspend fun removePokemonFromFavourite(pokemon: Pokemon) {
return dataSource.removePokemonFromFavourite(pokemon)
}
}
interface PokemonCoreDataSource {
suspend fun addPokemonToFavourites(pokemon: Pokemon)
suspend fun getFavouritePokemon() : List<Pokemon>
suspend fun removePokemonFromFavourite(pokemon: Pokemon)
}
Datasourse implementaation in framework layer:
class PokemonCoreDataSourceImpl(private val database : PokemonDatabase) : PokemonCoreDataSource{
override suspend fun addPokemonToFavourites(pokemon: Pokemon) {
return database.pfDao.addToFavourite(PokemonFavouriteEntity(id = pokemon.id, name = pokemon.name,
description = pokemon.description, imageUrl = pokemon.imageUrl))
}
override suspend fun getFavouritePokemon(): List<Pokemon> {
return database.pfDao.getFavouritePokemon().map {
Pokemon(id = it.id, name = it.name, description = it.description, imageUrl = it.imageUrl)
}
}
override suspend fun removePokemonFromFavourite(pokemon: Pokemon) {
return database.pfDao.removeFromFavourite(PokemonFavouriteEntity(
id = pokemon.id, name = pokemon.name,
description = pokemon.description, imageUrl = pokemon.imageUrl
))
}
}
Koin di Modules :
val useCaseModule = module {
factory { AddToFavourites(get()) }
factory { GetFavourites(get()) }
factory { RemoveFromFavourite(get()) }
}
val repositoryModule = module {
single<IPokemonCoreRepository> { PokemonCoreRepository(get()) }
}
val dataSourceModule = module {
single<PokemonCoreDataSource> { PokemonCoreDataSourceImpl(get()) }
}
val databaseModule = module {
single { PokemonDatabaseFactory.getDBInstance(get()) }
}
val viewModelModule = module {
viewModel { SearchViewModel(get(), get(), get()) }
}
Database and entity in framework layer:
#Database(entities = [PokemonFavouriteEntity::class], version = 1, exportSchema = false)
abstract class PokemonDatabase : RoomDatabase() {
abstract val pfDao : PokemonFavouriteDao
}
object PokemonDatabaseFactory {
fun getDBInstance(context: Context) {
Room.databaseBuilder(context, PokemonDatabase::class.java, "PokemonDB")
.fallbackToDestructiveMigration()
.build()
}
}
#Dao
interface PokemonFavouriteDao {
#Insert(onConflict = REPLACE)
suspend fun addToFavourite(pokemon : PokemonFavouriteEntity)
}
#Entity(tableName = "favourites")
data class PokemonFavouriteEntity(
#PrimaryKey(autoGenerate = true) val id : Int,
#ColumnInfo(name = "pokemonName") val name : String = "",
#ColumnInfo(name = "pokemonDescription") val description : String = "",
#ColumnInfo(name = "pokemonImage")val imageUrl : String = ""
)
Viewmodel in the presentation layer:
class SearchViewModel (private val getPokemonDescription: GetPokemonDescription,
private val getPokemonSprites: GetPokemonSprites,
private val addToFavourites: AddToFavourites) : ViewModel() {
private val _pokemon = MutableLiveData<Resource<PokemonResponse>>()
private val _pokemonSprites = MutableLiveData<Resource<List<String>>>()
private val _pokemonSpecies = MutableLiveData<Resource<PokemonSpeciesResponse>>()
val pokemon: LiveData<Resource<PokemonResponse>> get() = _pokemon
val pokemonSpecies: LiveData<Resource<PokemonSpeciesResponse>> get() = _pokemonSpecies
fun getPokemonDetails(pokemonName: String) {
_pokemon.value = Resource.Loading()
getPokemonSprites.execute(PokemonSubscriber(), pokemonName)
}
fun getPokemonSpeciesDetails(pokemonName: String) {
_pokemonSpecies.value = Resource.Loading()
getPokemonDescription.execute(PokemonSpeciesSubscriber(), pokemonName)
}
fun addToFavourite() {
viewModelScope.launch {
withContext(Dispatchers.IO) {
addToFavourites.invokeAddToFavourites(getPokemonDetails())
}
}
}
inner class PokemonSubscriber : DisposableSingleObserver<PokemonResponse>() {
override fun onSuccess(pokemonResponse: PokemonResponse) {
_pokemon.value = Resource.Success(pokemonResponse)
}
override fun onError(error: Throwable) {
_pokemon.value = Resource.Error(error.message)
}
}
inner class PokemonSpeciesSubscriber : DisposableSingleObserver<PokemonSpeciesResponse>() {
override fun onSuccess(pokemonSpeciesResponse: PokemonSpeciesResponse) {
_pokemonSpecies.value = Resource.Success(pokemonSpeciesResponse)
}
override fun onError(error: Throwable) {
_pokemonSpecies.value = Resource.Error(error.message)
}
}
private fun getPokemonDetails(): Pokemon {
var pokemonId = 0
var pokemonName = ""
var pokemonDescription = ""
var pokemonImage = ""
_pokemon.observeForever {
when (it) {
is Resource.Success -> {
pokemonImage = it.result.sprites.front_default
}
else -> {
}
}
}
_pokemonSpecies.observeForever {
when (it) {
is Resource.Success -> {
pokemonId = it.result.id
pokemonName = it.result.name
pokemonDescription = it.result.flavor_text_entries[0].flavor_text
}
else -> {
}
}
}
return Pokemon(pokemonId, pokemonName, pokemonDescription, pokemonImage)
}
override fun onCleared() {
super.onCleared()
getPokemonDescription.dispose()
getPokemonSprites.dispose()
}
}
You are not returning the created Database instance. Add return statement to the factory function or return using =
Like this:
object PokemonDatabaseFactory {
fun getDBInstance(context: Context) =
Room.databaseBuilder(context, PokemonDatabase::class.java, "PokemonDB")
.fallbackToDestructiveMigration()
.build()
}
Update
Actually, you don't need a factory function in Database. You can directly create an DB object from module through Koin, like this :
single {
Room.databaseBuilder(context, PokemonDatabase::class.java, "PokemonDB")
.fallbackToDestructiveMigration()
.build()
}

How to fix wrong constructor parameters in kotlin

I have an interesting error with reflections in kotlin.
So, im using 'argTypes' method for getting all parameter type of args.
private fun argTypes(vararg args: Any): Array<Class<*>> {
val argTypes = ArrayList<Class<*>>()
args.forEach { argTypes.add(it::class.java) }
return argTypes.toTypedArray()
}
Im using it with like that:
fun <T> newInstance(clazz: Class<*>, argTypes: Array<Class<*>>, vararg args: Any): T {
return clazz.getDeclaredConstructor(*argTypes).newInstance(*args) as T
}
In the end:
ReflectionUtil.instance.newInstance<IBossBar>(
PacketBossBar1_13_R2::class.java,
TextComponent("asd"),Color.BLUE,Style.PROGRESS,100F)
I use a float parameters thats '100F'.
When i use that method, the type is going to be java.lang.Float but my 'PacketBossBar1_13_R2' constructor has a float parameters like that:
constructor(
message: TextComponent,
color: Color,
style: Style,
progress: Float
): this(ComponentSerializer.toString(message), color, style, progress)
When i getting the constructor as a manual, its return
public io.github.utsukushihito.utsutil.nms.v1_13_R2.PacketBossBar1_13_R2(net.md_5.bungee.api.chat.TextComponent,io.github.utsukushihito.utsutil.api.bossbar.enums.Color,io.github.utsukushihito.utsutil.api.bossbar.enums.Style,float)
When i use automatic way its returning NoSucMethodException like that:
java.lang.NoSuchMethodException: io.github.utsukushihito.utsutil.nms.v1_13_R2.PacketBossBar1_13_R2.<init>(net.md_5.bungee.api.chat.TextComponent, io.github.utsukushihito.utsutil.api.bossbar.enums.Color, io.github.utsukushihito.utsutil.api.bossbar.enums.Style, java.lang.Float)
Also my ReflectionUtil and PackateBossBar classes:
package io.github.utsukushihito.utsutil.api.misc
import org.bukkit.Bukkit
import java.lang.reflect.Field
import java.lang.reflect.Method
import java.lang.reflect.Modifier
import java.util.*
import java.util.stream.Collectors
class ReflectionUtil {
private val nmsVersion: String
get() = nms().split("\\.".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray()[3]
val craftBukkitVersion: String
get() = cb().split("\\.".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray()[3]
private fun nms(): String {
return exec<Any>(Bukkit.getServer(), "getServer").javaClass.getPackage().name
}
private fun cb(): String {
return Bukkit.getServer().javaClass.getPackage().name
}
fun getPackageName(nmsObject: Any): String {
return nmsObject.javaClass.getPackage().name
}
fun getBukkitClass(craftObject: Any): Class<*> {
var clazz: Class<*> = craftObject.javaClass
while (clazz.canonicalName.contains(".craftbukkit.")) {
clazz = clazz.superclass
}
return clazz
}
fun getCustomBukkitClass(className: String): Class<*> {
return Class.forName("org.bukkit.craftbukkit.$nmsVersion.$className")
}
fun getNMSClass(name: String): Class<*> {
return Class.forName("net.minecraft.server.$nmsVersion.$name")
}
fun <T> execStatic(clazz: Class<*>, methodName: String, vararg args: Any): T {
val method = getMethod(clazz, methodName, *argTypes(*args))
val wasAccessible = method.isAccessible
method.isAccessible = true
try {
return method.invoke(null, *args) as T
} finally {
method.isAccessible = wasAccessible
}
}
fun <T> execStatic(clazz: Class<*>, methodName: String, argTypes: Array<Class<*>>, vararg args: Any): T {
val method = getMethod(clazz, methodName, *argTypes)
val wasAccessible = method.isAccessible
method.isAccessible = true
try {
return method.invoke(null, *args) as T
} finally {
method.isAccessible = wasAccessible
}
}
fun <T> exec(obj: Any, methodName: String, argTypes: Array<Class<*>>, vararg args: Any): T {
val aClass = obj.javaClass
val method = getMethod(aClass, methodName, *argTypes)
val wasAccessible = method.isAccessible
method.isAccessible = true
try {
return method.invoke(obj, *args) as T
} finally {
method.isAccessible = wasAccessible
}
}
fun getMethod(aClass: Class<*>, methodName: String, vararg argTypes: Class<*>): Method {
return aClass.getDeclaredMethod(methodName, *argTypes)
}
fun findMethod(aClass: Class<*>, returnType: Class<*>, vararg argTypes: Class<*>): Method {
return findMethods(aClass, returnType, *argTypes)[0]
}
fun findMethods(aClass: Class<*>, returnType: Class<*>, vararg argTypes: Class<*>): List<Method> {
val methods = ArrayList<Method>()
for (m in aClass.declaredMethods) {
if (m.returnType == returnType && m.parameterTypes.size == argTypes.size) {
val mLookup = aClass.getMethod(m.name, *argTypes)
if (mLookup != null) methods.add(mLookup)
}
}
return methods
}
fun <T> exec(obj: Any, methodName: String, vararg args: Any): T {
return exec(obj, methodName, argTypes(*args), *args) as T
}
fun <T> getField(clazz: Class<*>, fieldName: String): T {
val field = getFieldFromClass(clazz, fieldName)
val wasAccessible = field.isAccessible
field.isAccessible = true
try {
return field.get(null) as T
} finally {
field.isAccessible = wasAccessible
}
}
fun <T> getField(obj: Any, fieldName: String): T {
val field = getFieldInternal(obj, fieldName)
val wasAccessible = field.isAccessible
field.isAccessible = true
try {
return field.get(obj) as T
} finally {
field.isAccessible = wasAccessible
}
}
fun getFieldInternal(obj: Any, fieldName: String): Field {
return getFieldFromClass(obj.javaClass, fieldName)
}
fun getFieldFromClass(aClass: Class<*>, fieldName: String): Field {
return try {
aClass.getDeclaredField(fieldName)
} catch (e: NoSuchFieldException) {
try {
aClass.getField(fieldName)
} catch (e1: NoSuchFieldException) {
getFieldFromClass(aClass.superclass, fieldName)
}
}
}
fun setField(obj: Any, fieldName: String, field: Any?) {
val declaredField = getFieldInternal(obj, fieldName)
val wasAccessible = declaredField.isAccessible
declaredField.isAccessible = true
try {
declaredField.set(obj, field)
} finally {
declaredField.isAccessible = wasAccessible
}
}
fun <T> newInstance(clazz: Class<*>, argTypes: Array<Class<*>>, vararg args: Any): T {
return clazz.getDeclaredConstructor(*argTypes).newInstance(*args) as T
}
fun <T> newInstance(clazz: Class<*>, vararg args: Any): T {
return newInstance(clazz, argTypes(*args), *args)
}
fun <T> newInstance(className: String, vararg args: Any): T {
return newInstance(className, argTypes(*args), *args)
}
private fun argTypes(vararg args: Any): Array<Class<*>> {
val argTypes = ArrayList<Class<*>>()
args.forEach { argTypes.add(it::class.java) }
return argTypes.toTypedArray()
}
fun dumpMethods(aClass: Class<*>): List<String> {
val methods = aClass.declaredMethods
val methodDescriptions = ArrayList<String>()
val version = nmsVersion
for (m in methods) {
var parmString = Arrays.toString(Arrays.stream(m.parameterTypes).map<String>{ it.name }.toArray())
parmString = parmString.substring(1, parmString.length - 1)
var description = ((if (Modifier.isPublic(m.modifiers)) "public " else if (Modifier.isPrivate(m.modifiers)) "private " else "")
+ (if (Modifier.isStatic(m.modifiers)) "static " else "")
+ m.returnType + " " + m.name
+ "(" + parmString + ")")
description = description
.replace("class net.minecraft.server.$version.".toRegex(), "")
.replace("net.minecraft.server.$version.".toRegex(), "")
.replace("java.lang.".toRegex(), "")
methodDescriptions.add(description)
}
val list = ArrayList<String>()
list.add(aClass.toString().replace("class net.minecraft.server.$version.".toRegex(), "")
.replace("net.minecraft.server.$version.".toRegex(), "")
.replace("java.lang.".toRegex(), "") + ":")
list.addAll(methodDescriptions.stream().sorted { obj, anotherString -> obj.compareTo(anotherString) }.collect(Collectors.toList()))
return list
}
companion object {
val instance = ReflectionUtil()
}
}
package io.github.utsukushihito.utsutil.nms.v1_13_R2
import io.github.utsukushihito.utsutil.api.bossbar.addBossBarForPlayer
import io.github.utsukushihito.utsutil.api.bossbar.enums.Color
import io.github.utsukushihito.utsutil.api.bossbar.enums.Property
import io.github.utsukushihito.utsutil.api.bossbar.enums.Style
import io.github.utsukushihito.utsutil.api.bossbar.removeBossBarForPlayer
import io.github.utsukushihito.utsutil.api.misc.ReflectionUtil
import io.github.utsukushihito.utsutil.api.nms.IBossBar
import net.md_5.bungee.api.chat.TextComponent
import net.md_5.bungee.chat.ComponentSerializer
import net.minecraft.server.v1_13_R2.BossBattle
import net.minecraft.server.v1_13_R2.IChatBaseComponent
import net.minecraft.server.v1_13_R2.PacketPlayOutBoss
import org.bukkit.Location
import org.bukkit.craftbukkit.v1_13_R2.entity.CraftPlayer
import org.bukkit.entity.Player
import java.util.*
class PacketBossBar1_13_R2(
private var message: String,
private var color: Color,
private var style: Style,
private var progress: Float,
vararg properties: Property
) : IBossBar{
private val receivers = ArrayList<Player>()
private val uuid = UUID.randomUUID()
private var darkenSky: Boolean = false
private var playMusic: Boolean = false
private var createFog: Boolean = false
private var visible: Boolean = false
constructor(
message: TextComponent,
color: Color,
style: Style,
progress: Float,
vararg properties: Property
): this(ComponentSerializer.toString(message), color, style, progress, *properties)
// I Try to run this cotr with the reflection util.
constructor(
message: TextComponent,
color: Color,
style: Style,
progress: Float
): this(ComponentSerializer.toString(message), color, style, progress)
init {
setMessage(message)
setProgress(progress)
properties.forEach {
setProperty(it,true)
}
}
override fun getPlayers(): Collection<Player> {
return ArrayList(this.receivers)
}
override fun addPlayer(player: Player) {
if (!receivers.contains(player)) {
receivers.add(player)
sendPacket(PacketPlayOutBoss.Action.ADD, player)
player.addBossBarForPlayer(this)
}
}
override fun removePlayer(player: Player) {
if (receivers.contains(player)) {
receivers.remove(player)
sendPacket(PacketPlayOutBoss.Action.REMOVE, player)
player.removeBossBarForPlayer(this)
}
}
override fun getColor(): Color {
return color
}
override fun setColor(color: Color) {
if (color != this.color) {
this.color = color;
sendPacket(PacketPlayOutBoss.Action.UPDATE_STYLE, null);
}
}
override fun getStyle(): Style {
return style
}
override fun setStyle(style: Style) {
if (style != this.style) {
this.style = style
sendPacket(PacketPlayOutBoss.Action.UPDATE_STYLE, null)
}
}
override fun setProperty(property: Property, flag: Boolean) {
when (property) {
Property.DARKEN_SKY -> darkenSky = flag
Property.PLAY_MUSIC -> playMusic = flag
Property.CREATE_FOG -> createFog = flag
}
sendPacket(PacketPlayOutBoss.Action.UPDATE_PROPERTIES, null)
}
override fun setMessage(message: String) {
if (!message.startsWith("{") || !message.endsWith("}")) {
throw IllegalArgumentException("Invalid JSON")
}
if (message != this.message) {
this.message = message
sendPacket(PacketPlayOutBoss.Action.UPDATE_NAME, null)
}
}
override fun getMessage(): String {
return message;
}
override fun setVisible(flag: Boolean) {
if (flag != this.visible) {
this.visible = flag
sendPacket(if (flag) PacketPlayOutBoss.Action.ADD else PacketPlayOutBoss.Action.REMOVE, null)
}
}
override fun isVisible(): Boolean {
return visible
}
override fun getProgress(): Float {
return progress
}
override fun setProgress(progress: Float) {
if (progress > 1) this.progress = progress / 100F
if (progress != this.progress) {
this.progress = progress
sendPacket(PacketPlayOutBoss.Action.UPDATE_PCT, null)
}
}
private fun sendPacket(action: PacketPlayOutBoss.Action, player: Player?) {
try {
val packet = PacketPlayOutBoss()
val ref = ReflectionUtil.instance
ref.setField(packet,"a",uuid)
ref.setField(packet,"b",action)
ref.setField(packet,"c",IChatBaseComponent.ChatSerializer.a(message)?: "")
ref.setField(packet,"d",progress)
ref.setField(packet,"e", BossBattle.BarColor.a(color.id))
ref.setField(packet,"f",BossBattle.BarStyle.a(style.id))
ref.setField(packet,"g",darkenSky)
ref.setField(packet,"h",playMusic)
ref.setField(packet,"i",createFog)
if (player != null) {
(player as CraftPlayer).handle.playerConnection.sendPacket(packet)
} else {
for (player1 in this.getPlayers()) {
(player1 as CraftPlayer).handle.playerConnection.sendPacket(packet)
}
}
} catch (e: ReflectiveOperationException) {
throw RuntimeException(e)
}
}
override fun getMaxHealth(): Float {
return 100F
}
override fun setHealth(percentage: Float) {
setProgress(percentage / 100F)
}
override fun getHealth(): Float {
return getProgress() * 100F
}
override fun getReceiver(): Player {
throw UnsupportedOperationException()
}
override fun getLocation(): Location {
throw UnsupportedOperationException()
}
override fun updateMovement() {
throw UnsupportedOperationException()
}
}```
You can fix this specific case by doing
private fun argTypes(vararg args: Any): Array<Class<*>> {
val argTypes = args.map { it::class.javaPrimitiveType ?: it::class.java }
return argTypes.toTypedArray()
}
but then this wouldn't find a constructor which expects java.lang.Float.
Simply put: if you know the actual arguments for a constructor/method, there are many options for the types in the signature, so trying just one (as fun argTypes does) can't possibly work in general. In addition to the problem you ran into, the declared parameter type could be a supertype of an argument's class, the constructor could have varargs, etc.
A possible solution is just to get all constructors, feed your arguments to them and use the first one which doesn't throw an exception. You still need to be careful about varargs. Whether the performance cost is acceptable will depend on your use-case.

Using Retrofit in Kotlin

I am trying to hit api using retrofit in kotlin
This is my DoinBackGround Method
private fun doinBackground() {
Utility.printMessage("in do in background.....")
try {
val hdr = HashMap<String, String>()
hdr.put("x-csrf-token", Utility.getToken(this.context!!))
val apiInterface = ApiCallRetrofit.getClient(this.mCrypt!!)!!.create(ApiInterface::class.java)
if (what.equals(0)) {
val body = RequestBody.create(MediaType.parse("application/json; charset=utf-8"), getQuery(para))
print("header...")
call = apiInterface.hitApi(url, hdr, body)
} else if (what.equals(1)) {
val imgPart = ArrayList<MultipartBody.Part>()
if (files != null) {
if (files.size > 0) {
for (i in files.indices) {
imgPart.add(preparePart("image/*", "document_file[" + files.get(i).key + "]", files.get(i).file))
}
}
call = apiInterface.hitApiImage(url, hdr, getMap(para), imgPart)
}
call?.enqueue(object : Callback<StandardReposnse> {
override fun onResponse(call: Call<StandardReposnse>, response: Response<StandardReposnse>) {
try {
Utility.printMessage("messege...." + response.body().message)
val resp = Gson().toJson(response.body())
Utility.printMessage("Response :$resp")
Utility.longLogPrint(response.body().data, "Full response : ")
Utility.printMessage("Error : " + Gson().toJson(response.errorBody()))
onPostExecute(Parseresponce(response.body()))
} catch (e: Exception) {
Parseresponce(null)
e.printStackTrace()
}
}
override fun onFailure(call: Call<StandardReposnse>, t: Throwable) {
t.printStackTrace()
if (progressDialog != null) {
progressDialog?.dismiss()
}
Parseresponce(null)
}
})
}
} catch (e: Exception) {
e.printStackTrace()
}
}
And this is my interface where I am defining all the POST methods
#POST
abstract fun hitApi(#Url api: String, #HeaderMap header: Map<String, Any>, #Body body: RequestBody): Call<StandardReposnse>
#POST
fun hitApiNoHeader(#Url api: String, #Body requestBody: RequestBody): Call<StandardReposnse>
#POST
fun test(#Url api: String, #HeaderMap headerMap: Map<String, String>, #Body requestBody: RequestBody): Call<JSONObject>
#Multipart
#POST
fun hitApiImage(#Url api: String, #HeaderMap headerMap: Map<String, String>, #PartMap bodyMap: Map<String, RequestBody>, #Part images: List<MultipartBody.Part>): Call<StandardReposnse>
Whenever I am trying to hit the Api I am getting the following exception :
java.lang.IllegalArgumentException: Parameter type must not include a type variable or wildcard: java.util.Map<java.lang.String, ?> (parameter #2)
for method ApiInterface.hitApi
at retrofit2.ServiceMethod$Builder.methodError(ServiceMethod.java:720)
at retrofit2.ServiceMethod$Builder.methodError(ServiceMethod.java:711)
at retrofit2.ServiceMethod$Builder.parameterError(ServiceMethod.java:729)
at retrofit2.ServiceMethod$Builder.build(ServiceMethod.java:193)
at retrofit2.Retrofit.loadServiceMethod(Retrofit.java:166)
This is the line where the exception occurs in doinbackground method
call = apiInterface.hitApi(url, hdr, body)
I tried #JvmSuppressWildcards before the RequestBody but it did not work, can anyone suggest whats the actual problem over here, plus nothing is printing in the log though I have used print() function should i use LOG.d?
Here i have fully example for it.
This dependancy add in gradle
implementation 'com.squareup.retrofit2:retrofit:2.5.0'
annotationProcessor 'com.squareup.retrofit2:retrofit:2.5.0'
implementation 'com.squareup.retrofit2:converter-gson:2.4.0'
Here now create ApiClient.kt file
object ApiClient {
val BASE_URL = "http://yourwebsite/services/"
private var retrofit: Retrofit? = null
val client: Retrofit
get() {
if (retrofit == null) {
retrofit = Retrofit.Builder()
.baseUrl(BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
.build()
}
return retrofit!!
}
}
Now create APIInterface.kt
#FormUrlEncoded
#POST("users/login")
fun POST_LOGIN(
#Field("imei_number") imei_number: String,
#Field("device_token") device_token: String,
#Field("mobile") mobile: String,
#Field("password") password: String
): Call<LoginResponse>
#GET("general/init-data")
fun GENERAL_MODULE(
#Header("Authorization") auth_key: String
): Call<InitResponse>
#GET("event-gallery/list")
fun GET_Event_GALLERY(
#Header("Authorization") auth_key: String
): Call<EventListResponse>
#GET("event-gallery/photo-list")
fun GET_Event_GALLERY_PHOTO(
#Header("Authorization") auth_key: String,
#Query("id") id: Int
): Call<EventGallerListResponse>
if Any Header for token the use #Header and also When call #GET that time params use #Query and #Post that time #Fields
Now Response file
data class EventListResponse(
#SerializedName("success")
var success: Boolean,
#SerializedName("data")
var data: EventgalleryModel?,
#SerializedName("server_error"),
#SerializedName("eventgallery")
var eventgallery: ArrayList<EventListData>
var server_error: Boolean,
#SerializedName("message")
var message: String
)
Then create Model class of Response
Now time to Activity code
private fun loadData() {
card_progress.visibility = View.VISIBLE
val apiService = ApiClient.client.create(ApiInterface::class.java)
val call =
apiService.GET_FEE_INSTALMENT_LIST(PreferenceManager.getAuthKey(this#FeesInstalmentActivity)!!)
call.enqueue(object : Callback<FeeInstalmentListResponse> {
override fun onResponse(
call: Call<FeeInstalmentListResponse>,
response: Response<FeeInstalmentListResponse>
) {
card_progress.visibility = View.GONE
val data = response.body()!!.data
if (response.code() == 200 && data != null) {
if (response.body()!!.server_error) {
txt_no_data_fee.visibility = View.VISIBLE
txt_no_data_fee.text = response.body()!!.message
} else {
Log.e("data", data.toString())
if (data != null && data.feesinstalment.isEmpty()) {
txt_no_data_fee.visibility = View.VISIBLE
} else {
txt_no_data_fee.visibility = View.GONE
adapter!!.setItem(data.feesinstalment)
}
}
} else if (response.code() == 401) {
PreferenceManager.removePref(this#FeesInstalmentActivity)
startActivity(
Intent(this#FeesInstalmentActivity, LoginActivity::class.java)
.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_ACTIVITY_CLEAR_TASK or Intent.FLAG_ACTIVITY_NEW_TASK)
)
finish()
} else {
Toast.makeText(
this#FeesInstalmentActivity,
R.string.somethingWrong,
Toast.LENGTH_SHORT
).show()
}
}
override fun onFailure(call: Call<FeeInstalmentListResponse>, t: Throwable) {
card_progress.visibility = View.GONE
Log.e("onFailure", t.message)
txt_no_data_fee.visibility = View.VISIBLE
}
})
}
Adapter
class FeeInstalmentAdapter(
private val context: Context,
private var items: ArrayList<FeeInstalmentListData>
) : RecyclerView.Adapter() {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
return ViewHolder(LayoutInflater.from(context).inflate(R.layout.row_fees_instalment_item, parent, false))
}
#SuppressLint("SetTextI18n")
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
holder.due_date.text = DateHelper.parseData(items[position].due_date!!, "yyyy-MM-dd", "dd MMM yyyy")
holder.instalment_title.text = items[position].instalment_title
if (items[position].paid_date == null) {
holder.paid_text.visibility = View.GONE
holder.paid_date.text = context.resources.getString(R.string.UnPaid)
holder.paid_date.setTextColor(Color.parseColor("#DC143C"))
} else {
holder.paid_date.text = DateHelper.parseData(items[position].due_date!!, "yyyy-MM-dd", "dd MMM yyyy")
holder.paid_date.setTextColor(Color.parseColor("#58A259"))
}
//holder.paid_date.text = items[position].paid_date
holder.amount.text = "Rs. " + items[position].amount
holder.amount.setTextColor(Color.parseColor("#ED7136"))
}
override fun getItemCount(): Int {
return items.size
}
override fun getItemId(position: Int): Long {
return position.toLong()
}
override fun getItemViewType(position: Int): Int {
return position
}
fun setItem(holidays: ArrayList<FeeInstalmentListData>) {
items = holidays
notifyDataSetChanged()
}
class ViewHolder(view: View) : RecyclerView.ViewHolder(view) {
val due_date = view.due_date
val instalment_title = view.instalment_title
val paid_date = view.paid_date
val amount = view.amount
val paid_text = view.paidText
}
}
You have used:
#POST
abstract fun hitApi(#Url api: String, #HeaderMap header: Map<String, Any>, #Body body: RequestBody): Call<StandardReposnse>
And exception is:
Parameter type must not include a type variable or wildcard: java.util.Map<java.lang.String, ?> (parameter #2)
And your hitApi #2 param use wildcard actually:
#HeaderMap header: Map<String, ?>
Try to specify argument (just change Any to String). Anyway you are not probably going to put Any object than String in your request header.
Call it in the below mentioned way.
val callWeather = NetworkUtils.getApiInterface().getWeatherResponse("03a7949903004a0bb2590633181104", "1.909,45.909", 7)
callWeather.enqueue(object : Callback<APIXUResponse> {
override fun onResponse(call: Call<APIXUResponse>, response: Response<APIXUResponse>) {
var api :APIXUResponse? = response.body()
}
override fun onFailure(call: Call<APIXUResponse>, t: Throwable) {
}
})