I was spending 3 hours and I couldn't find the parsing error reason.
I have this JSON
[
{
"id": "WMWSW31030T222518",
"modelName": "MINI",
"name": "Vanessa",
"make": "BMW",
"latitude": 48.134557,
"longitude": 11.576921,
"carImageUrl": "https://cdn.sixt.io/codingtask/images/mini.png"
},
{
"id": "WMWSU31070T077232",
"modelName": "MINI",
"name": "Regine",
"make": "BMW",
"latitude": 48.114988,
"longitude": 11.598359,
"carImageUrl": "https://cdn.sixt.io/codingtask/images/mini.png"
}
]
After parsing I got this error
An error happened: com.google.gson.JsonSyntaxException: java.lang.IllegalStateException: Expected BEGIN_OBJECT but was BEGIN_ARRAY at line 1 column 2
Here is my code
--Repository--
interface CarRepository {
suspend fun getCars(): LiveData<Resource<List<Car>>>
}
class CarRepositoryImpl(private val datasource: CarDatasource,
private val dao: CarDao): CarRepository{
override suspend fun getCars(): LiveData<Resource<List<Car>>> {
return object : NetworkBoundResource<List<Car>, ApiResult<Car>>() {
override fun processResponse(response: ApiResult<Car>): List<Car>
= response.items
override suspend fun saveCallResults(items: List<Car>)
= dao.save(items)
override fun shouldFetch(data: List<Car>?): Boolean
= data == null || data.isEmpty()
override suspend fun loadFromDb(): List<Car>
= dao.getCars()
override fun createCallAsync(): Deferred<ApiResult<Car>>
= datasource.fetchCars()
}.build().asLiveData()
}
}
--CarService--
interface CarService {
#GET("cars")
fun fetchCars(): Deferred<ApiResult<Car>>
}
--ApiResult--
data class ApiResult<T>(val items: List<T>)
--NetworkBoundResource--
abstract class NetworkBoundResource<ResultType, RequestType> {
private val result = MutableLiveData<Resource<ResultType>>()
private val supervisorJob = SupervisorJob()
suspend fun build(): NetworkBoundResource<ResultType, RequestType> {
withContext(Dispatchers.Main) { result.value =
Resource.loading(null)
}
CoroutineScope(coroutineContext).launch(supervisorJob) {
val dbResult = loadFromDb()
if (shouldFetch(dbResult)) {
try {
fetchFromNetwork(dbResult)
} catch (e: Exception) {
Log.e("NetworkBoundResource", "An error happened: $e")
setValue(Resource.error(e, loadFromDb()))
}
} else {
Log.d(NetworkBoundResource::class.java.name, "Return data from local database")
setValue(Resource.success(dbResult))
}
}
return this
}
fun asLiveData() = result as LiveData<Resource<ResultType>>
// ---
private suspend fun fetchFromNetwork(dbResult: ResultType) {
Log.d(NetworkBoundResource::class.java.name, "Fetch data from network")
setValue(Resource.loading(dbResult)) // Dispatch latest value quickly (UX purpose)
val apiResponse = createCallAsync().await()
Log.e(NetworkBoundResource::class.java.name, "Data fetched from network")
saveCallResults(processResponse(apiResponse))
setValue(Resource.success(loadFromDb()))
}
#MainThread
private fun setValue(newValue: Resource<ResultType>) {
Log.d(NetworkBoundResource::class.java.name, "Resource: "+newValue)
if (result.value != newValue) result.postValue(newValue)
}
#WorkerThread
protected abstract fun processResponse(response: RequestType): ResultType
#WorkerThread
protected abstract suspend fun saveCallResults(items: ResultType)
#MainThread
protected abstract fun shouldFetch(data: ResultType?): Boolean
#MainThread
protected abstract suspend fun loadFromDb(): ResultType
#MainThread
protected abstract fun createCallAsync(): Deferred<RequestType>
--Resource--
data class Resource<out T>(val status: Status, val data: T?, val error: Throwable?) {
companion object {
fun <T> success(data: T?): Resource<T> {
return Resource(
Status.SUCCESS,
data,
null
)
}
fun <T> error(error: Throwable, data: T?): Resource<T> {
return Resource(
Status.ERROR,
data,
error
)
}
fun <T> loading(data: T?): Resource<T> {
return Resource(
Status.LOADING,
data,
null
)
}
}
enum class Status {
SUCCESS,
ERROR,
LOADING
}
}
Could anyone tell me what was wrong here why the parser failing?
The error is here you should use a list instead ApiResult because ApiResult is an object with a list and GSON tries to parse an object and find a list with atribute name items.
//change to List<Car>
interface CarService {
#GET("cars")
fun fetchCars(): Deferred<List<Car>>
}
Related
I have this observer for my viewmodel so that I can setup my adapter but, when I run the app, it gives me the NullPointerException error on this line:
japaneseAdapter = it.data?.let { it1 -> JapaneseAdapter(it1) }!!
This is the activity with that line:
#AndroidEntryPoint
class JapaneseActivity : AppCompatActivity() {
private lateinit var binding: ActivityJapaneseBinding
private val japaneseViewModel by viewModels<JapaneseViewModel>()
private lateinit var japaneseAdapter: JapaneseAdapter
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityJapaneseBinding.inflate(layoutInflater)
setContentView(binding.root)
japaneseViewModel.japaneseResponse.observe(this, {
when(it.status){
Resource.Status.LOADING -> { }
Resource.Status.SUCCESS -> {
japaneseAdapter = it.data?.let { it1 -> JapaneseAdapter(it1) }!!
binding.rvNews.adapter = japaneseAdapter
}
Resource.Status.ERROR -> { Log.d("ERROR","ERROR RAISED") }
}
})
}
}
This is the adapter:
class JapaneseAdapter(private var japaneseResponse: List<JapaneseResponse>) :
RecyclerView.Adapter<JapaneseAdapter.ViewHolder>() {
inner class ViewHolder(
view: View
) : RecyclerView.ViewHolder(view) {
private val binding = NewsItemsBinding.bind(view)
private val itemTitle: TextView = binding.tvTitle
private val itemImage: ImageView = binding.ivNews
private val itemDescription: TextView = binding.tvDescription
fun bind(response: JapaneseResponse) {
Picasso.get().load(response.urlToImage).into(itemImage)
itemTitle.text = response.Title
itemDescription.text = response.Description
}
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
val v = LayoutInflater.from(parent.context).inflate(R.layout.news_items, parent, false)
return ViewHolder(v)
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
holder.bind(japaneseResponse[position])
}
override fun getItemCount(): Int {
return japaneseResponse.size
}
}
Generic data source:
abstract class BaseDataSource {
protected suspend fun <T> getResult(call: suspend () -> Response<ApiResponse<T>>): Resource<T> {
try {
val response = call()
// if(response.isSuccessful) {
// val body = response.body()?.data
// if(body != null) return Resource.success(body)
// }
val body = response.body()?.data
return Resource.success(body)
//return Resource.error("${response.code()}: ${response.message()}")
} catch (e: Exception) {
return Resource.error(e.message ?: "Generic error")
}
}
}
data class Resource<out T>(val status: Status, val data: T?, val message: String?) : Serializable {
enum class Status {
SUCCESS,
ERROR,
LOADING
}
companion object {
fun <T> success(data: T?): Resource<T> {
return Resource(
Status.SUCCESS,
data,
null
)
}
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,
null
)
}
}
fun isSuccessful() = status == Status.SUCCESS
fun isError() = status == Status.ERROR
fun isLoading() = status == Status.LOADING
}
The data source for the Japanese news:
class JapaneseDataSource #Inject constructor(private val japaneseService: JapaneseService) :
BaseDataSource() {
suspend fun getJpNews() = getResult { japaneseService.jpNews() }
}
Repository:
class JapaneseRepository #Inject constructor(
private val remote: JapaneseDataSource
) {
suspend fun jpNews() =
remote.getJpNews()
}
The service:
interface JapaneseService {
#GET("/v2/top-headlines?country=jp&apiKey=77acc490875643c5b2328fb615e0cf83")
suspend fun jpNews(): Response<ApiResponse<List<JapaneseResponse>>>
}
I can see that the response is there since I have okhttp logging it for me but for some reason it seems to be null and I am not sure why...
Any help?
japaneseAdapter = it.data?.let { it1 -> JapaneseAdapter(it1) }!!
!! is Kotlin's "crash the app" operator. It says that you want to crash the app if the value you are applying !! to is null. Your objective, as a Kotlin programmer, is to avoid using !!.
In this case, the fact that you are crashing on that line with that error means that !! is being applied to null. That will occur if it.data evaluates to null.
it.data appears to be a Resource object with a status of SUCCESS. So, presumably, you are calling success() with a value of null.
With all that in mind, you will need to use your debugger and see why val body = response.body()?.data is evaluating to null, or see where else you are getting a Resource with null data.
And, please, try to avoid using !!.
I have the following error wrapper in my application -
open class ResponseHandler {
fun <T : Any> handleSuccess(data: T): Resource<T> {
return Resource.success(data)
}
fun <T : Any> handleException(e: Exception): Resource<T> {
return when (e) {
is HttpException -> Resource.error(getErrorMessage(e.code()), null)
else -> Resource.error(getErrorMessage(Int.MAX_VALUE), null)
}
}
private fun getErrorMessage(code: Int): String {
return when (code) {
401 -> ERROR401
404 -> ERROR404
else -> GENERAL_ERROR
}
}
/**
* Wrapper class that enables error / loading / success handling.
*/
data class Resource<out T>(val status: Status, val data: T?, val message: String?) {
companion object {
fun <T> success(data: T?): Resource<T> {
return Resource(Status.SUCCESS, data, null)
}
fun <T> error(message: String, data: T?): Resource<T> {
return Resource(Status.ERROR, data, message)
}
fun <T> loading(data: T?): Resource<T> {
return Resource(Status.LOADING, data, null)
}
}
enum class Status {
SUCCESS,
ERROR,
LOADING
}
}
}
and when using Retrofit + Coroutines, the use it quite straight forward -
suspend fun getSomethingFromPath(): ResponseHandler.Resource<Any> {
return try {
responseHandler.handleSuccess(networkApi.getSomethingFromPath())
} catch (e : Exception) {
responseHandler.handleException(e)
}
}
But when I want to get data from my Firestore collection, I am having trouble implementing the method -
fun getAllApplicationActivities(groupsList: List<String>): ResponseHandler.Resource<ActivityCollectionModel> {
Firebase.firestore.collection(ACTIVITIES_COLLECTION)
.whereIn(GROUP_ID, groupsList)
.get()
.addOnSuccessListener { documents ->
val activitiesList = documents.toObjects(ActivityCollectionModel::class.java)
//Now what?
}
.addOnSuccessListener { exception ->
}
}
How can I make the function return a ResponseHandler.Resource<ActivityCollectionModel> from the addOnSuccessListener and addOnSuccessListener callbacks?
Use suspendCoroutine or suspendCancellableCoroutine
suspend fun getAllApplicationActivities(groupsList: List<String>) = suspendCoroutine { cont ->
Firebase.firestore.collection(ACTIVITIES_COLLECTION)
.whereIn(GROUP_ID, groupsList)
.get()
.addOnSuccessListener { documents ->
val activitiesList = documents.toObjects(ActivityCollectionModel::class.java)
cont.resume(activitiesList)
}
.addOnFailureListener { exception ->
cont.resumeWithException(exception)
}
}
I am creating a login for my app and would like to save the user details retrieved from the server. I am using mvvm. How do i save the data I receive into my roomdb?
Here is my response from from the server
{
"isSuccessful": true,
"message": "successful",
"user": [
{
"name": "Raymond Jezz",
"email": "rayjezz#gmail.com",
"phone": "254XXXXXXX"
}
]
}
my UserModel
data class User(
val name: String,
val email:String,
val phone:String
)
login response model
data class LoginResponse(
val isSuccessful:Boolean,
val message: String,
val user: List<User>
)
Room entity
#Entity(tableName = "user_table")
data class UserRoom(val name:String, val email:String, val phone:String) {
#PrimaryKey(autoGenerate = true)
var id: Int = 0
}
Dao class
#Dao
interface UserDao {
#Insert
fun insert(userRoom: UserRoom)
#Query("SELECT * FROM user_table")
fun getUserDetails(): LiveData<List<UserRoom>>
}
RoomDatabase
#Database(entities = [UserRoom::class], version = 1)
abstract class UserDatabase : RoomDatabase() {
abstract fun userDao(): UserDao
companion object {
private var instance: UserDatabase? = null
fun getInstance( context: Context): UserDatabase? {
if (instance == null) {
synchronized(UserDatabase::class.java) {
instance = Room.databaseBuilder(context.applicationContext, UserDatabase::class.java, "users_database")
.fallbackToDestructiveMigration()
.build()
}
}
return instance
}
}
}
Repository class
class UserRepository(application: Application) {
private lateinit var userDao: UserDao
private var userDetails: LiveData<List<UserRoom>>
init {
val database: UserDatabase? = UserDatabase.getInstance(application)
if (database != null) {
userDao = database.userDao()
}
userDetails = userDao.getUserDetails()
}
fun insert(userRoom: UserRoom){
val insertUserAsyncTask = InsertUserAsyncTask(userDao).execute(userRoom)
}
fun getUserDetails():LiveData<List<UserRoom>>{
return userDetails
}
private class InsertUserAsyncTask(userDao: UserDao) : AsyncTask<UserRoom, Unit, Unit>() {
val userDao = userDao
override fun doInBackground(vararg p0: UserRoom?) {
userDao.insert(p0[0]!!)
}
}
}
View model class
class LoginViewModel : ViewModel() {
fun userLogin(email: String, password: String): LiveData<String> {
val loginResponse = MutableLiveData<String>()
RetrofitClient.makeRetrofitApi().userLogin(email, password)
.enqueue(object : Callback<LoginResponse> {
override fun onFailure(call: Call<LoginResponse>, t: Throwable) {
loginResponse.value = t.message
}
override fun onResponse(call: Call<LoginResponse>, response: Response<LoginResponse>) {
if (response.isSuccessful){
loginResponse.value = response.body()?.message.toString()
}else{
loginResponse.value = response.body()?.message.toString()
}
}
})
return loginResponse
}
}
Firstly, in your UserDao create a insertAll() function.
#Insert(onConflict = OnConflictStrategy.REPLACE)
fun insertAllUsers(userRoomList : List<UserRoom>);
Then you should write the appropriate AsyncTask class to insert userlist into the database.
class LoginViewModel : ViewModel() {
fun userLogin(email: String, password: String): LiveData<String> {
val loginResponse = MutableLiveData<String>()
RetrofitClient.makeRetrofitApi().userLogin(email, password).enqueue(object : Callback<LoginResponse> {
override fun onFailure(call: Call<LoginResponse>, t: Throwable) {
loginResponse.value = t.message
}
override fun onResponse(call: Call<LoginResponse>, response: Response<LoginResponse>) {
if (response.isSuccessful) {
loginResponse.value = response.body()?.message.toString()
// create a List of User and get it by response.body().getUserList()
//iterate over this list and create another list of UserRoom class
//insert it into the database using the Repository class.
} else
loginResponse.value = response.body()?.message.toString()
}
});
return loginResponse
}
}
Trying to solve this problem about 4 days, help, please.
I'm creating an app with rest API (retrofit), try to implement LiveDataCallAdapter from Google samples
https://github.com/googlesamples/android-architecture-components/tree/master/GithubBrowserSample, but retrofit doesn't call adapter method adapt for getting a response from the server.
I'm edited only NetworkBoundResourse (for working without DB)
Trying to put breakpoints, after I start repo (login), LiveDataCallAdapter fun adapt (where call.enequeue don't want start) debugging don't call
Here is my piece of code, thx
Providing my service instance
#Singleton
#Provides
fun provideRetrofit(): BrizSmartTVService {
return Retrofit.Builder()
.baseUrl(baseUrl)
.addConverterFactory(GsonConverterFactory.create())
.addCallAdapterFactory(LiveDataCallAdapterFactory())
.build()
.create(BrizSmartTVService::class.java)
}
There is my LiveDataCallAdapterFactory and LiveDataCallAdapter
class LiveDataCallAdapterFactory : Factory() {
override fun get(
returnType: Type,
annotations: Array<Annotation>,
retrofit: Retrofit
): CallAdapter<*, *>? {
if (getRawType(returnType) != LiveData::class.java) {
return null
}
val observableType = getParameterUpperBound(0, returnType as ParameterizedType)
val rawObservableType = getRawType(observableType)
if (rawObservableType != ApiResponse::class.java) {
throw IllegalArgumentException("type must be a resource")
}
if (observableType !is ParameterizedType) {
throw IllegalArgumentException("resource must be parameterized")
}
val bodyType = getParameterUpperBound(0, observableType)
return LiveDataCallAdapter<Any>(bodyType)
}
}
class LiveDataCallAdapter<R>(private val responseType: Type) :
CallAdapter<R, LiveData<ApiResponse<R>>> {
override fun responseType() = responseType
override fun adapt(call: Call<R>): LiveData<ApiResponse<R>> {
return object : LiveData<ApiResponse<R>>() {
private var started = AtomicBoolean(false)
override fun onActive() {
super.onActive()
if (started.compareAndSet(false, true)) {
Log.d("TAG", ": onActive Started ");
call.enqueue(object : Callback<R> {
override fun onResponse(call: Call<R>, response: Response<R>) {
Log.d("TAG", ": $response");
postValue(ApiResponse.create(response))
}
override fun onFailure(call: Call<R>, throwable: Throwable) {
Log.d("TAG", ": ${throwable.localizedMessage}");
postValue(ApiResponse.create(throwable))
}
})
}
}
}
}
}
There is my NetworkBoundResourse (work only with Network)
abstract class NetworkBoundResource<RequestType> {
private val result = MediatorLiveData<Resource<RequestType>>()
init {
setValue(Resource.loading(null))
fetchFromNetwork()
}
#MainThread
private fun setValue(newValue: Resource<RequestType>) {
if (result.value != newValue) {
result.value = newValue
}
}
private fun fetchFromNetwork() {
val apiResponse = createCall()
result.addSource(apiResponse) { response ->
result.removeSource(apiResponse)
when (response) {
is ApiSuccessResponse -> {
setValue(Resource.success(processResponse(response)))
}
is ApiErrorResponse -> {
onFetchFailed()
setValue(Resource.error(response.errorMessage, null))
}
}
}
}
protected fun onFetchFailed() {
}
fun asLiveData() = result as LiveData<Resource<RequestType>>
#WorkerThread
protected open fun processResponse(response: ApiSuccessResponse<RequestType>) = response.body
#MainThread
protected abstract fun createCall(): LiveData<ApiResponse<RequestType>>
}
My Repo class
#Singleton
class AuthApiRepo #Inject constructor(
val apiService: BrizSmartTVService
) {
fun authLoginPass(login: String, password: String): LiveData<Resource<AuthResponse>> {
return object : NetworkBoundResource<AuthResponse>() {
override fun createCall(): LiveData<ApiResponse<AuthResponse>> {
val authLogPassBody = AuthLogPassBody(login,password,"password")
Log.d("TAG", ": $authLogPassBody");
return apiService.authLoginPass(authLogPassBody)
}
}.asLiveData()
}
}
And my AuthResponse Class
class AuthResponse {
#SerializedName("token_type")
var tokenType: String? = null
#SerializedName("access_token")
var accessToken: String? = null
#SerializedName("refresh_token")
var refreshToken: String? = null
#SerializedName("user_id")
var userId: String? = null
#SerializedName("expires_in")
var expiresIn: Long = 0
#SerializedName("portal_url")
var portalUrl: String? = null
}
My ViewModel class from where i start calling
class AuthViewModel #Inject constructor(private val authApiRepo: AuthApiRepo) : ViewModel() {
private var _isSigned = MutableLiveData<Boolean>()
val isSigned: LiveData<Boolean>
get() = _isSigned
fun signIn(login: String, password: String) {
authApiRepo.authLoginPass(login, password)
val authRespons = authApiRepo.authLoginPass(login, password)
Log.d("TAG", ": " + authRespons.value.toString());
//here will by always data null and status LOADING
}
override fun onCleared() {
super.onCleared()
}
}
So guys, finaly i found a solution. It's very simple for the peaple experienced in MVVM (live data) subject , but im beginer in MVVM and my brain exploded while I came to this.
So , the problem was I subscribed to Repo livedata from ViewModel , not from View (Fragment in my case). After i locked the chain of livedata observers View - ViewModel - Repo - Service - everything worked. Thx to all
I am trying to show json data using retrofit library in kotlin
This is my Json:
[
{
"login": "mojombo",
"id": 1,
},
{
"login": "defunkt",
"id": 2,
}
]
My Main activity
call.enqueue(object : Callback<UserResponse> {
override fun onResponse(call: Call<UserResponse>, response: Response<UserResponse>) {
Log.e("list","list")
val countrylist = response.body()
for (size in response.body()) {
System.out.println(size.toString())
}
// var listOfMovies: List<UserResponse> = response.body()?.results!!
// myCustomAdapter = UserListAdapter(applicationContext, listOfMovies)
// recyclerView.setAdapter(myCustomAdapter)
progressBar.visibility = View.GONE
}
override fun onFailure(call: Call<UserResponse>?, t: Throwable?) {
progressBar.visibility = View.GONE
Log.e("list", t.toString())
}
})
This an app that I build in kotlin using retrofit and rxjava in the best way possible using a test API.
Model
data class Post( val userID:Int, val title:String, val body: String)
Retrofit Package
IMyApi interface
interface IMyApi {
#get:GET("posts")
val posts: Observable<List<Post>>
}
RetrofitClient Object class
object RetrofitClient {
val instance: Retrofit by lazy {
Retrofit.Builder()
.baseUrl("https://jsonplaceholder.typicode.com/")
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.addConverterFactory(GsonConverterFactory.create())
.build()
}
}
Adapter Package
PostAdapter class
class PostAdapter(private val context: Context, private val postList: List<Post>)
:RecyclerView.Adapter<PostViewHolder>()
{
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int):
PostViewHolder {
val itemView = LayoutInflater.from(parent.context)
.inflate(R.layout.post_item, parent, false)
return PostViewHolder(itemView)
}
override fun getItemCount(): Int {
return postList.size
}
override fun onBindViewHolder(holder: PostViewHolder, position: Int)
{
holder.userId.text = postList[position].userID.toString()
holder.title.text = postList[position].title
holder.body.text = StringBuilder(postList[position].body.substring(0,20))
.append("...").toString()
}
}
PostViewHolder class
class PostViewHolder(itemView: View):RecyclerView.ViewHolder(itemView) {
var userId = itemView.txtID
var title = itemView.txtTitle
var body = itemView.txtBody
}
MainActivity
class MainActivity : AppCompatActivity() {
private lateinit var jsonApi: IMyApi
private var compositeDisposable: CompositeDisposable = CompositeDisposable()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
// Init api
val retrofit = RetrofitClient.instance
jsonApi = retrofit.create(IMyApi::class.java)
// View
recycler_posts.layoutManager = LinearLayoutManager(this)
recycler_posts.setHasFixedSize(true)
fetchData()
}
private fun fetchData() {
compositeDisposable.add(jsonApi.posts
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe { posts->displayData(posts)})
}
private fun displayData(posts: List<Post>?) {
val adapter = PostAdapter(this, posts!!)
recycler_posts.adapter = adapter
}
}
Using this as displayed above should help you solve your issue hopefully. Also when in the code you come across "recycler_posts". This is a id to the recycler added in activity_main. If you need me to include that let me know
That's what we have on our app
object GetFAQsAPI {
private val LOG_TAG = GetFAQsAPI.javaClass.simpleName
interface ThisCallback {
fun onSuccess(getFAQs: GetFAQs)
fun onFailure(failureMessage: String)
fun onError(errorMessage: String)
}
/* POST */
fun postData(jo: JsonObject, callback: GetFAQsAPI.ThisCallback) {
val call = Service.getService().get_faqs(jo)
call.enqueue(object : Callback<JsonObject> {
override fun onResponse(call: Call<JsonObject>, response: Response<JsonObject>) {
//Log.e(LOG_TAG, response.body().toString());
try {
if (response.body()?.get("success")!!.asBoolean) {
val gson = GsonBuilder().setPrettyPrinting().create()
val getFAQs = gson.fromJson(response.body(), GetFAQs::class.java)
callback.onSuccess(getFAQs)
} else {
Log.e(LOG_TAG, "else")
val error = response.body()!!.get("err").asString
callback.onError(error)
}
} catch (e: Exception) {
Log.e(LOG_TAG, "exception" + e.localizedMessage)
callback.onFailure(e.message!!)
}
}
override fun onFailure(call: Call<JsonObject>, t: Throwable) {
Log.e(LOG_TAG, "onFailure: " + t.message)
callback.onFailure(t.message!!)
}
})
}
}
That's how we call it from our fragment - getFAQs is the object parsed.
private fun getFAQsAPI() {
showLoading(true)
val jo = JsonObject().apply {
addProperty("faq_category", "admin")
}
GetFAQsAPI.postData(jo, object : GetFAQsAPI.ThisCallback {
override fun onSuccess(getFAQs: GetFAQs) {
Log.i(LOG_TAG, "onSuccess")
showLoading(false)
updateUI(getFAQs)
}
override fun onFailure(failureMessage: String) {
Log.e(LOG_TAG, failureMessage)
}
override fun onError(errorMessage: String) {
Log.e(LOG_TAG, errorMessage)
}
})
}
Hope that helps.