I am working on one project where I am not able to get json response in my recyclerview but getting response in Viewmodel.
Following is my code. I tried to use debug pointer but I am not getting any information in logcat or debug tab.
class MainActivity : AppCompatActivity() {
private val TAG = "MainActivity"
private lateinit var binding: ActivityMainBinding
lateinit var viewModel: MainViewModel
private val retrofitService = RetrofitService.getInstance()
val adapter = MainAdapter()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
binding = ActivityMainBinding.inflate(layoutInflater)
setContentView(binding.root)
viewModel = ViewModelProvider(this, MyViewModelFactory(MainRepository(retrofitService))).get(MainViewModel::class.java)
binding.recyclerview.adapter = adapter
viewModel.movieList.observe(this, Observer {
Log.d(TAG, "onCreate: $it")
adapter.setMovieList(it)
})
viewModel.errorMessage.observe(this, Observer {
})
viewModel.getAllMovies()
}
}
Models
data class MobileProducts(
val products: List<Product>
)
data class Product(
val image_url: String,
val name: String,
val price: String,
val rating: Int
)
Retrofit
interface RetrofitService {
#GET("/nancymadan/assignment/db")
fun getAllMovies() : Call<List<MobileProducts>>
companion object {
var retrofitService: RetrofitService? = null
fun getInstance() : RetrofitService {
if (retrofitService == null) {
val retrofit = Retrofit.Builder()
.baseUrl("https://my-json-server.typicode.com")
.addConverterFactory(GsonConverterFactory.create())
.build()
retrofitService = retrofit.create(RetrofitService::class.java)
}
return retrofitService!!
}
}
}
Viewmodel
class MainViewModel constructor(private val repository: MainRepository) : ViewModel() {
val movieList = MutableLiveData<List<MobileProducts>>()
val errorMessage = MutableLiveData<String>()
fun getAllMovies() {
val response = repository.getAllMovies()
response.enqueue(object : Callback<List<MobileProducts>> {
override fun onResponse(call: Call<List<MobileProducts>>, response: Response<List<MobileProducts>>) {
movieList.postValue(response.body())
}
override fun onFailure(call: Call<List<MobileProducts>>, t: Throwable) {
errorMessage.postValue(t.message)
}
})
}
}
JSON RESPONSE
{
"products": [
{
"name": "test",
"price": "34999",
"image_url": "url",
"rating": 4
},
{
"name": "test2",
"price": "999",
"image_url": "url",
"rating": 4
},
{
"name": "test",
"price": "34999",
"image_url": "url",
"rating": 4
},
{
"name": "test2",
"price": "999",
"image_url": "url",
"rating": 4
}
,]}
What is missing can anyone help me.
May be you forgot set LayoutManager for your recyclerview
place this line before set adapter
binding.recyclerview.layoutManager = LinearLayoutManager(context)
You have not set any LayoutManager for the RecyclerView, and RecyclerView will not work without LayoutManger. so you should
add this to your code :
binding.recyclerview.setLayoutManager(LinearLayoutManager(this))
and it will work if your MainAdapter class and the data have no problems.
First thing you set layout manager for Recyclerview.
binding.recyclerview.setLayoutManager(LinearLayoutManager(this))
If you set in XML then no need by programmatically.
After getting response of Viewmodel livedata when you observe list data.
You have set list in adapter but use notify.
Use this.
adapter.notifyDataSetChange()
Or You can use DiffUtill for notifying data in adapter it's good way.
If all this not work then try this one time:::::::::
class MainActivity : AppCompatActivity() {
private val TAG = "MainActivity"
private lateinit var binding: ActivityMainBinding
lateinit var viewModel: MainViewModel
private val retrofitService = RetrofitService.getInstance()
val adapter = MainAdapter()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
binding = ActivityMainBinding.inflate(layoutInflater)
setContentView(binding.root)
viewModel = ViewModelProvider(this, MyViewModelFactory(MainRepository(retrofitService))).get(MainViewModel::class.java)
//call api first
viewModel.getAllMovies()
//then observe
viewModel.movieList.observe(this, Observer {
Log.d(TAG, "onCreate: $it")
adapter.setMovieList(it)
//after set data in adapter then set recyclerview adapter
binding.recyclerview.adapter = adapter
})
viewModel.errorMessage.observe(this, Observer {
})
}
}
Related
Recently, I decided to learn a bit about how to write android apps. After read book and checked many codes, blogs etc. I prepared small code which should get a list of data from rest service and present them on a screen in recyclerView. It worked with "hardcoded data", after added retrofit I have seen the data in Log, because I used enqueue with onResponse method. But it is async call, therefore I added Flow with emit and collect methods to handle incoming data. Unfortunately, still it does not work, now even Log is empty.
interface ApiInterface {
#GET("/api/v1/employees")
fun getEmployees() : Call<ResponseModel>
}
object ServiceBuilder {
private val client = OkHttpClient.Builder()
.addInterceptor(HttpLoggingInterceptor(HttpLoggingInterceptor.Logger.DEFAULT)
.setLevel(HttpLoggingInterceptor.Level.BODY))
.build()
private val retrofit: Retrofit = Retrofit.Builder()
.baseUrl(BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
.client(client)
.build()
fun<T> buildService(service: Class<T>): T{
return retrofit.create(service)
}
}
class EmployeeRepository() {
fun getEmployees(): Flow<ResponseModel?> = flow {
val response = ServiceBuilder.buildService(ApiInterface::class.java)
Log.d("restAPI",response.getEmployees().execute().body()!!.toString() )
emit( response.getEmployees().execute().body() )
}
}
class MainViewModel(private val savedStateHandle: SavedStateHandle): ViewModel() {
init {
viewModelScope.launch {
EmployeeRepository().getEmployees().collect {
Log.d("restAPI", it.toString())
}
}
}
}
class MainActivity : AppCompatActivity() {
private val mainModel: MainViewModel by viewModels()
private lateinit var binding: ActivityMainBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityMainBinding.inflate(layoutInflater)
setContentView(binding.root)
binding.recyclerView.layoutManager = LinearLayoutManager(this)
val employee = EmployeeModel(id = 1, employee_age = 11, employee_salary = 12,
employee_name = "ABCD", profile_image = "")
var employeeList = mutableListOf(employee)
val adapter = EmployeeListAdapter(employeeList)
binding.recyclerView.adapter = adapter
}
}
Maybe I missed something in the code or in logic, I cannot find helpful information in internet. Can anyone tell me what and how should I change my code?
UPDATE:
Thank you ho3einshah!
For everyone interested in now and in the future I'd like inform that change from Call to Response:
interface ApiInterface {
#GET("/api/v1/employees")
suspend fun getEmployees() : Response<ResponseModel>
}
and change init to getData method:
fun getData() = repository.getEmployees()
were clue to solve the issue.
Moreover I called livecycleScope one level above - in AppCompatActivity for passing data directly to adapter:
lifecycleScope.launch {
repeatOnLifecycle(Lifecycle.State.STARTED) {
mainModel.getData().collect { employeeList ->
Log.d("restAPI", employeeList.toString() )
val adapter = EmployeeListAdapter(employeeList)
binding.recyclerView.adapter = adapter
}
}
}
Now I see the list on screen with incoming data.
Hi I hope this answer help you.
first because of using GsonConverterFactory add this dependency to your build.gradle(app):
implementation 'com.squareup.retrofit2:converter-gson:2.9.0'
now change your api service to below code:
import retrofit2.Response
import retrofit2.http.GET
interface ApiInterface {
#GET("/api/v1/employees")
suspend fun getList() : Response<ResponseModel>
Please pay attention Response must be from retrofit2.Response
I have used the api you are using it. as a response you have a list with "data" json key. Create a Response model according to Json Response :
data class ResponseModel(
var status : String?,
var data : ArrayList<EmployeeModel>
)
Now this is EmployeeModel :
data class EmployeeModel(
var d:Long,
var employee_age:Long,
var employee_salary:Long,
var employee_name:String,
var profile_image:String
)
class EmployeeRepository {
fun getEmployees() = flow<Response<EmployeeModel>> {
val response = RetrofitBuilder.buildService(MainService::class.java).getEmployees()
Log.e("response",response.body()?.data.toString())
}
}
and for your viewModel its better to call repository from a method and not in init block :
class MainViewModel : ViewModel() {
private val repository = EmployeeRepository()
fun getData() {
viewModelScope.launch(Dispatchers.IO) {
val a = repository.getEmployees()
.collect{
}
}
}
}
and in your MainActivity initialize MainViewModel like this and call MainViewModel method:
class MainActivity : AppCompatActivity() {
lateinit var mainViewModel: MainViewModel
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
mainViewModel = ViewModelProvider(this)[MainViewModel::class.java]
mainViewModel.getData()
}
}
I am creating one Android app and trying to set the data in Recyclerview, I am using MVVM architecture pattern with kotlin, I can see data in logcat but when app loads I am not seeing any data in my recyclerview. Following is my code.
MainActivity
class MainActivity : AppCompatActivity() {
lateinit var productViewModel: ProductViewModel
private lateinit var binding: ActivityMainBinding
val adapter = ProductAdapter()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityMainBinding.inflate(layoutInflater)
setContentView(binding.root)
val productService = RetrofitHelper.getInstance().create(ProductService::class.java)
val productRepository = ProductRepository(productService)
productViewModel = ViewModelProvider(this, ProductViewModelFactory(productRepository)).get(ProductViewModel::class.java)
binding.recyclerview.adapter = adapter
productViewModel.products.observe(this,{
Log.d("TEST",it.toString())
adapter.notifyDataSetChanged()
})
}
}
ProductAdapter
class ProductAdapter : RecyclerView.Adapter<ProductViewHolder>() {
var movies = mutableListOf<MobileList>()
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ProductViewHolder {
val inflater = LayoutInflater.from(parent.context)
val binding = AdapterLayoutBinding.inflate(inflater, parent, false)
return ProductViewHolder(binding)
}
override fun onBindViewHolder(holder: ProductViewHolder, position: Int) {
val movie = movies[position]
holder.binding.name.text = movie.products.get(position).name
Glide.with(holder.itemView.context).load(movie.products.get(position).image_url).into(holder.binding.imageview)
}
override fun getItemCount(): Int {
return movies.size
}
}
class ProductViewHolder(val binding: AdapterLayoutBinding) : RecyclerView.ViewHolder(binding.root) {
}
Repository class
class ProductRepository (private val productService: ProductService) {
private val productLiveData = MutableLiveData<MobileList>()
val products:LiveData<MobileList>
get() = productLiveData
suspend fun getProducts(){
val products = productService.getQuotes()
if(products?.body()!=null)
{
productLiveData.postValue(products.body())
}
}
}
ViewModel
class ProductViewModel (private val productRepository: ProductRepository ) :ViewModel() {
init {
viewModelScope.launch(Dispatchers.IO){
productRepository.getProducts()
}
}
val products : LiveData<MobileList>
get() = productRepository.products
}
Factory
class ProductViewModelFactory (private val productRepository: ProductRepository) : ViewModelProvider.Factory {
override fun <T : ViewModel?> create(modelClass: Class<T>): T {
return ProductViewModel (productRepository) as T
}
}
Model
data class MobileList(
val products: List<Product>
)
data class Product(
val image_url: String,
val name: String,
val price: String,
val rating: Int
)
JSON Response
{
"products": [
{
"name": "test",
"price": "34999",
"image_url": "url",
"rating": 4
},
{
"name": "test2",
"price": "999",
"image_url": "url",
"rating": 4
},]}
First of all make sure you have layoutManager set on the RecyclerView.
The problem here is Your ProductAdapter never had the data . notifyDataSetChanged is not a magic stick to notify the adapter you modify/add/update the dataset and then You will call notifyDataSetChanged . that's how it works .
In your case You have movies list your adapter but you never assigned anything to it its always empty .
There are several ways to it. Just to make it work You can have a method to add the data in your adapter and then notify it.
fun addData(data:List<MobileList>){
movies.addAll(data)
notifyDataSetChanged()
}
Now when you get the data inside on change you call this method .
productViewModel.products.observe(this,{
it?.let{ items ->
adapter.addData(items)
}
})
This should work .
Update on type fix - Seems like your type is messed up . Why is your repo returns a object of MobileList? While you are using a list of MobileList in adapter . Your adapter should hold var movies = mutableListOf<Products>().
productViewModel.products.observe(this,{
it?.let{ item ->
adapter.addData(item.products)
}
})
I'm currently making a sample project about diagrams. I'm starting to use MVVM architecture recently, and I got stuck when the response is null. I also checked the Mutable Live Data to make sure that it is calling the API. Here's some of my code and the error-tag:
Model.kt
data class Model(
#SerializedName("FID") val FID: Int,
#SerializedName("region") val region: String,
#SerializedName("positive") val positive: Float
) {
}
ModelWrap.kt
data class ModelWrap(#SerializedName("samplesAPI") val attributes: Model){
}
ApiClient.kt
object ApiClient {
var retrofitService: ApiInterface? = null
const val BASE_URL = "https://sampleapi.../"
fun getApiSample() : ApiInterface {
if (retrofitService == null){
val retrofit = Retrofit.Builder()
.baseUrl(BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
.build()
retrofitService = retrofit.create(ApiInterface::class.java)
}
return retrofitService!!
}
}
ApiInterface.kt
interface ApiInterface {
#GET("samples")
fun getSampleData(): Call<List<ModelWrap>>
}
MainViewModel.kt
class MainViewModelconstructor(private val repository: ModelRepository) : ViewModel(){
val sampleList= MutableLiveData<List<ModelWrap>>()
val errorMessage = MutableLiveData<String>()
fun getSampleData(pieChart: PieChart){
val response = repository.getSampleData()
response.enqueue(object : Callback<List<ModelWrap>> {
override fun onResponse(
call: Call<List<ModelWrap>>,
response: Response<List<ModelWrap>>
) {
sampleList.postValue(response.body())
}
override fun onFailure(call: Call<List<ModelWrap>>, t: Throwable) {
errorMessage.postValue(t.message)
}
})
}
}
MainViewModelFactory.kt
class MainViewModelFactoryconstructor(private val repository: MainRepository) : ViewModelProvider.Factory {
override fun <T : ViewModel?> create(modelClass: Class<T>): T {
return if (modelClass.isAssignableFrom(MainViewModel::class.java)){
MainViewModel(this.repository) as T
} else {
throw IllegalArgumentException("Sample ViewModel Not Found")
}
}
}
MainRepository.kt
class MainRepository constructor(private val retrofitService: ApiInterface){
fun getSampleData() = retrofitService.getSampleData()
}
MainActivity.kt
class MainActivity : AppCompatActivity() {
private lateinit var pieChart: PieChart
lateinit var sampleViewModel: MainViewModel
private val sampleService = ApiClient.getApiSample()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
pieChart = findViewById(R.id.PieChart)
sampleViewModel= ViewModelProvider(this, MainViewModelFactory(MainRepository(sampleService))).get(MainViewModel::class.java)
getPieChart(pieChart)
}
private fun getPieChart(pieCharts: PieChart) {
mainViewModel.mainList.observe(this, Observer {
Log.d("TAG sample" , "onCreate PieChart: $it")
Log.d("Tag Samples Response" , response.body().toString())
if (it != null) {
val sampleEntries: List<PieEntry> = ArrayList()
for ((attributes) in it!!) {
sampleEntries.toMutableList()
.add(PieEntry(attributes.positive, attributes.region))
//........................................................................
val description = Description()
description.text = "Samples Data"
pieChart.description = description
pieChart.invalidate()
}
}
})
mainViewModel.errorMessage.observe(this, Observer { })
mainViewModel.getSampleData(pieCharts)
}
}
and Lastly, here's some or log message:
V/InputMethodManager: Starting input: tba=android.view.inputmethod.EditorInfo#8b795c0 nm : com.example.diargram ic=null
D/Tag Sample Response: null
D/TAG Sample: onCreate PieChart: null
E/libc: Access denied finding property "ro.serialno"
V/StudioTransport: Agent command stream started.
V/StudioTransport: Transport agent connected to daemon.
I would appreciate it if someone can help me :D, Thank you
Finally, I found a solution for my problem:
I type the wrong endpoint inside the interface class and it should be like this:
interface ApiInterface {
#GET("sample")
fun getSampleData(): Call<List> }
When it comes to assigning the livedata to the view, based on my JSON I should call ArrayList instead of List
List item
Before :
val sampleEntries: List = ArrayList()
After :
val sampleEntries: ArrayList<PieEntry> = ArrayList()
I want to take data from API using AsyncHttpClient(), after that, I show the data to recycle view. but when trying to debug my code is run show the data to recycle view which is no data because not yet finish setData using AsyncHttpClient(). my question is how to run setData recycle view adapter after my setLeague is finish getting data? Sorry, I am a newbie and I put my code below. Please help, I already try using async-await but doesn't work.
This is my ViewModel Class
val footballLeagueList = MutableLiveData<ArrayList<league>>()
internal fun setLeague(){
val client = AsyncHttpClient()
val client2 = AsyncHttpClient()
val listItems = ArrayList<league>()
val leagueListUrl = "https://www.thesportsdb.com/api/v1/json/1/all_leagues.php"
val leagueDetailUrl = "https://www.thesportsdb.com/api/v1/json/1/lookupleague.php?id="
client.get(leagueListUrl, object : AsyncHttpResponseHandler(){
override fun onSuccess(
statusCode: Int,
headers: Array<out Header>?,
responseBody: ByteArray?
) {
try{
val result = String(responseBody!!)
val responseObject = JSONObject(result)
for(i in 0 until 10){
val list = responseObject.getJSONArray("leagues")
val leagues = list.getJSONObject(i)
val leaguesItems = league()
val detailUrl = leagueDetailUrl + leagues.getString("idLeague")
leaguesItems.id = leagues.getString("id")
leaguesItems.name = leagues.getString("strLeague")
leaguesItems.badgeUrl = leagues.getString( "https://www.thesportsdb.com/images/media/league/badge/dqo6r91549878326.png")
listItems.add(leaguesItems)
}
footballLeagueList.postValue(listItems)
}catch (e: Exception){
Log.d("Exception", e.message.toString())
}
}
override fun onFailure(
statusCode: Int,
headers: Array<out Header>?,
responseBody: ByteArray?,
error: Throwable?
) {
Log.d("Failed", "On Failure")
}
})
}
internal fun getLeague(): LiveData<ArrayList<league>> {
return footballLeagueList
}
And this is my MainActivity
class MainActivity : AppCompatActivity() {
private lateinit var mainViewModel: MainViewModel
private lateinit var adapterLeague: leagueAdapter
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
adapterLeague = leagueAdapter()
adapterLeague.notifyDataSetChanged()
verticalLayout {
lparams(matchParent, matchParent)
recyclerView {
layoutManager = GridLayoutManager(context, 2)
adapter = adapterLeague
}
}
mainViewModel = ViewModelProvider(this, ViewModelProvider.NewInstanceFactory())
.get(MainViewModel::class.java)
mainViewModel.setLeague()
mainViewModel.getLeague().observe(this, Observer { leaguesItems ->
if(leaguesItems != null){
adapterLeague.setData(leaguesItems)
}
})
}
}
i am beginner in android dev (both java or kotlin). I am trying to populate spinner from json with retrofit and moshi but I have no idea how to populate it into spinner. to be honest I dont know whether the return of Json data is correct or not, since Log.d() return is not detail as dump() laravel or php.
script in activity onCreate (Please read the comment of the script, i put debug result of Log.d() there):
val task = object : AsyncTask<Void, Void, Response<List<ProductTypeResponse>>>() {
override fun doInBackground(vararg params: Void): Response<List<ProductTypeResponse>> {
val typeAPI = RestAPI()
val callResponse = typeAPI.getNews()
val response = callResponse.execute()
return response
}
override fun onPostExecute(response: Response<List<ProductTypeResponse>>) {
if (response.isSuccessful) {
val news = response.body()
Log.d("test:", news!![0].data.toString()) // method 'java.lang.String com.example.mockie.tigaer.api.TypeDataResponse.toString()' on a null object reference
Log.d("test:", news!!.size.toString()) // it says 67 but the data from the url is 63 array of json object
Log.d("test:", news!![0].toString()) // com.example.mockie.tigaer.api.ProductTypeResponse#f17fd5e
}
}
RestApi.kt
import retrofit2.Call
import retrofit2.Retrofit
import retrofit2.converter.moshi.MoshiConverterFactory
class RestAPI() {
private val tigaerApi: TigaerApi
init {
val retrofit = Retrofit.Builder()
.baseUrl("http://app.tigaer.id/laravel/")
.addConverterFactory(MoshiConverterFactory.create())
.build()
tigaerApi = retrofit.create(TigaerApi::class.java)
}
fun getNews(): Call<List<ProductTypeResponse>> {
return tigaerApi.getTop()
}
}
ApiModel.kt
package com.example.mockie.tigaer.api
class ProductTypeResponse(val data: TypeDataResponse)
class TypeDataResponse(
val children: List<ProductTypeChildrenResponse>
)
class ProductTypeChildrenResponse(val data: ProductTypeDataResponse)
class ProductTypeDataResponse(
val productType: String,
val readable: String
)
TigaerApi.kt
import retrofit2.Call
import retrofit2.http.GET
import retrofit2.http.Query
interface TigaerApi {
#GET("api/type")
fun getTop(): Call<List<ProductTypeResponse>>
}
return Json: https://jsoneditoronline.org/?id=ce90c41b859218e746e41d64eddb4c30
so my questions are :
is there any function to debug object/array as detail as in laravel ?
how to populate my json return data into spinner?
Here is code for same, I modified and integrate in your code only:
"MainActivity.kt" class:
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
var spinner: Spinner = findViewById(R.id.spinner)
val task = object : AsyncTask<Void, Void, Response<List<ProductTypeDataResponse>>>() {
override fun doInBackground(vararg params: Void): Response<List<ProductTypeDataResponse>> {
val typeAPI = RestAPI()
val callResponse = typeAPI.getNews()
val response = callResponse.execute()
return response
}
override fun onPostExecute(response: Response<List<ProductTypeDataResponse>>) {
if (response.isSuccessful) {
val news: List<ProductTypeDataResponse>? = response.body()
var adapter: SpinnerAdapter = SpinnerAdapter(this#MainActivity, news!!);
spinner.adapter=adapter
}
}
}.execute()
}
}
Now Layout "activity_main":
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.example.ankitpatidar.checkkotlin.MainActivity">
<Spinner
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="#+id/spinner"></Spinner>
</LinearLayout>
Now Spinner Adapter as "SpinnerAdapter":
class SpinnerAdapter internal constructor(internal var context: Context, internal var list: List<ProductTypeDataResponse>) : BaseAdapter() {
override fun getCount(): Int {
return list.size
}
override fun getItem(i: Int): Any? {
return null
}
override fun getItemId(i: Int): Long {
return 0
}
override fun getView(i: Int, view: View?, viewGroup: ViewGroup): View {
var view = view
if (view == null) {
val inflater = LayoutInflater.from(context)
view = inflater.inflate(R.layout.item, viewGroup, false)
}
val textView = view!!.findViewById<TextView>(R.id.textView)
textView.text = list[i].productType + " " + list[i].readable
return textView
}
}
Spinner item layout as "item":
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/textView"/>
</LinearLayout>
Now some changes in your existing files:
"ApiModel.kt":
class TypeDataResponse(
val children: List<ProductTypeChildrenResponse>
)
class ProductTypeChildrenResponse(val data: ProductTypeDataResponse)
class ProductTypeDataResponse(
val productType: String,
val readable: String
)
"RestAPI.kt"
class RestAPI() {
private val tigaerApi: TigaerApi
init {
val retrofit = Retrofit.Builder()
.baseUrl("http://app.tigaer.id/laravel/")
.addConverterFactory(MoshiConverterFactory.create())
.build()
tigaerApi = retrofit.create(TigaerApi::class.java)
}
fun getNews(): Call<List<ProductTypeDataResponse>> {
return tigaerApi.getTop()
}
}
Hence it will work for you.
is there any function to debug object/array as detail as in laravel ?
Go through this to run your app in debug mode. https://developer.android.com/studio/debug/index.html
You can always use breakpoints to evaluate expressions while the app is running. Instead of logging put a breakpoint at this line.
val news = response.body()
so when you'll receive a response from server, app will stop at this point and you can check what you are getting in response in detail.
how to populate my json return data into spinner?
If you are getting response from server in Json format as shown in provided link, you'll have to parse the data into a list of objects(POJO).
And then you have to forward this data(maybe you'll have to iterate over list to get the required data because you have two fields in each object) into an adapter and set that adapter to your spinner. It is explained very clearly at following link.
https://developer.android.com/guide/topics/ui/controls/spinner.html
I got an idea in this post, maybe my logic can help anyone in here
this is my JSON
{
"success": 1,
"dataset": [
{
"id": "3",
"nama": "Rush"
},
{
"id": "5",
"nama": "Avanza"
},
{
"id": "6",
"nama": "Innova"
},
{
"id": "14",
"nama": "Sienta"
},
{
"id": "15",
"nama": "Alphard"
},
{
"id": "16",
"nama": "Calya"
}
],
"sql_duration": 0.0013179779052734375,
"auth_duration": 1.9073486328125e-6,
"req_duration": 0.004480123519897461,
"debug_duration": []
}
this is my API Service
ApiMain.kt
class ApiMain : Application(){
private var BASE_URL = "your url in here"
private val client = OkHttpClient().newBuilder()
.addInterceptor(HttpLoggingInterceptor().apply {
level = if (BuildConfig.DEBUG) HttpLoggingInterceptor.Level.BODY else HttpLoggingInterceptor.Level.NONE
})
.readTimeout(30, TimeUnit.SECONDS)
.writeTimeout(30, TimeUnit.SECONDS)
.build()
private val retrofit = Retrofit.Builder()
.baseUrl(BASE_URL)
.client(client)
.addConverterFactory(GsonConverterFactory.create())
.build()
val services: ApiServices = retrofit.create(ApiServices::class.java)
}
and this is my API service
ApiServices.kt
interface ApiServices {
#GET("yourlink")
fun MerkKendaraan():Call<MerkKendaraan>
}
and this is my model
kendaraan.kt
data class MerkKendaraan(
#SerializedName("success")
#Expose
var success: Int? = null,
#SerializedName("dataset")
#Expose
var dataset: List<MerkMobil>? = null,
#SerializedName("sql_duration")
#Expose
var sql_duration: String? = null,
#SerializedName("auth_duration")
#Expose
var auth_duration: String? = null,
#SerializedName("req_duration")
#Expose
var req_duration: String? = null
)
data class MerkMobil(
#SerializedName("id")
#Expose
var id: String? = null,
#SerializedName("nama")
#Expose
var nama: String? = null
)
and this is my main activity
AddKendaraan
class AddKendaraan : AppCompatActivity() {
private var merk : ArrayList<MerkMobil> = ArrayList()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_add_kendaraan)
configspinnermobil()
}
private fun configspinnermobil() {
val spinner: Spinner = findViewById(R.id.spinnerMerk)
ApiMain().services.MerkKendaraan().enqueue(object :
Callback<MerkKendaraan> {
override fun onResponse(call: Call<MerkKendaraan>, response: Response<MerkKendaraan>) {
//Tulis code jika response sukses
Log.d("data api", "data masuk")
if(response.code() == 200){
merk = response.body()?.dataset as ArrayList<MerkMobil>
var data : MutableList<String> = ArrayList()
merk.forEach {
data.add(0,it.nama.toString())
}
spinner.adapter = ArrayAdapter<String>(this#AddKendaraan, R.layout.support_simple_spinner_dropdown_item, data)
}else{
}
}
override fun onFailure(call: Call<MerkKendaraan>, t: Throwable){
//Tulis code jika response fail
Toast.makeText(applicationContext, t.message, Toast.LENGTH_LONG).show()
Log.d("data api", "data tidak masuk")
}
})
}