Ehtada Jodat
Ehtada Jodat

Reputation: 3

Retrofit does not show any data

I am trying to retrieve/fetch data from server using retrofit and Rxjava to show data in recycler view. The code do not detect any error but still no data is shown. please check my code and help where am I mistaken. Here is my API https://www.testing.albassamapp.com/api/familymembers/v2

Here is my data class Code:

data class Profile(
    @SerializedName("id")
    val id: Int,
    @SerializedName("name")
    val name: String,
    @SerializedName("father_name")
    val fatherName: String,
    @SerializedName("profile_picture_square")
    val profilePicture: String
)

Here is my interface:

interface ProfileApi {
    
    @GET("familymembers/v2")
    //single is observable it emit one variable and then close
    fun getProfiles(): Single<List<Profile>>
}

Here is my service class:

class ProfileService {
   private val BASE_URL = "https://www.testing.albassamapp.com/api/"

    private val api:ProfileApi

    init {
        api = Retrofit.Builder()
            .baseUrl(BASE_URL)
            .addConverterFactory(GsonConverterFactory.create())
            .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
            .build()
            .create(ProfileApi::class.java)
    }

    fun getProfile(): Single<List<Profile>> {
        return api.getProfiles()
    }

}

Here is my listViewModel:

class ListViewModel:ViewModel() {

    private val profileService = ProfileService()
    private val disposable = CompositeDisposable()

    //for live data
    val profiles = MutableLiveData<List<Profile>>()
    val profileLoadingError = MutableLiveData<Boolean>()

    val loading = MutableLiveData<Boolean>()

    fun refresh() {
        fetchProfiles()
    }
    private fun fetchProfiles() {
        loading.value = true
        disposable.add(
            profileService.getProfile()
                .subscribeOn(Schedulers.newThread())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribeWith(object : DisposableSingleObserver<List<Profile>>() {
                    override fun onSuccess(value: List<Profile>?) {
                        profiles.value = value
                        profileLoadingError.value = false
                        loading.value = false
                    }
                    override fun onError(e: Throwable?) {
                        profileLoadingError.value = true
                        loading.value = false
                    }
                })
        )
    }
    override fun onCleared() {
        disposable.clear()
    }
}

Upvotes: 0

Views: 820

Answers (2)

yousef
yousef

Reputation: 1363

You have one mistake serlizable is wrong based on reponse for api, api response is json object contain list of profile you change return in api interface First create object

this your data class

 data class Profile(
@SerializedName("id")
val id: Int,
@SerializedName("name")
val name: String,
@SerializedName("father_name")
val fatherName: String,
@SerializedName("profile_picture_square")
val profilePicture: String
)

Add new class in your data class

    data class Result(
     @SerializedName("Status")
      val status: Int,
      @SerializedName("Message")
      val message: String,
    @SerializedName("Data")
    val data: List<Profile>
     )

your interface will be like this after change

interface ProfileApi {

@GET("familymembers/v2")
//single is observable it emit one variable and then close
fun getProfiles(): Single<Result>
}

your service will be like this

class ProfileService {
 private val BASE_URL = "https://www.testing.albassamapp.com/api/"

 private val api:ProfileApi

 init {
    api = Retrofit.Builder()
        .baseUrl(BASE_URL)
        .addConverterFactory(GsonConverterFactory.create())
        .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
        .build()
        .create(ProfileApi::class.java)
}

fun getProfile(): Single<Result> {
    return api.getProfiles()
}

}

your view model will be like this

class ListViewModel: ViewModel() {

 private val profileService = ProfileService()
 private val disposable = CompositeDisposable()

  //for live data
  val profiles = MutableLiveData<List<Profile>>()
  val profileLoadingError = MutableLiveData<Boolean>()

   val loading = MutableLiveData<Boolean>()

    fun refresh() {
      fetchProfiles()
  }
  private fun fetchProfiles() {
     loading.value = true
     disposable.add(
       profileService.getProfile()
       .subscribeOn(Schedulers.newThread())
       .observeOn(AndroidSchedulers.mainThread())
       .subscribeWith(object : DisposableSingleObserver<Result>() {
         override fun onSuccess(result: Result) {
        if(result.status==200){
          profiles.value = result.data
          profileLoadingError.value = false
        }else{
          // in case exception or message
          profileLoadingError.value = true
        }
        loading.value = false
      }

      override fun onError(e: Throwable) {
        profileLoadingError.value = true
        loading.value = false
      }

    })
  )
  }
 override fun onCleared() {
  disposable.clear()
   }
 }

Upvotes: 1

gtxtreme
gtxtreme

Reputation: 3566

I have modified @yousef's answer above to the following because I could not edit for some reason and the English is a little unclear

You have one mistake the model is wrong based on response for api, api response is json object that contains list of other model object say Profile you must change the returned model in api interface like First create model Result

data class Result(
 @SerializedName("Status")
 val status: Int,
 @SerializedName("Data")
 val data: List<Profile>
)

and then make a Profile class like so

data class Profile(
 @SerializedName("id")
 val id: Int
 @SerializedName("parent_id")
 val parentId: Int // and so on based on the fields you need
)

Just change in your interface for api take object result like this

  fun getProfiles(): Single<Result>.

And then accordingly this will change the other code and you can get the List<Profile> property of the Result class by using getters which are provided by default in the data class of Kotlin

Additionally to reduce the headache while making a model from json, You can use websites like Json2Kotlin

Upvotes: 1

Related Questions