Expecting member declaration with kotlin - kotlin

First, I'm sorry to use a translator because I can't speak English.
I tried to implement app server communication through retrofit.
But I got this error for the next code.
service.getinfo()?.enqueue(object : Callback<student> {//22
override fun onResponse(call: Call<student>, response: Response<student>) {
if(response.isSuccessful){
var result: student? = response.body()
Log.d("YMC", "onResponse 성공: " result?.toString())//27
}else{
// 통신이 실패한 경우(응답코드 3xx, 4xx 등)
Log.d("YMC", "onResponse 실패")
}
}
Expecting member declaration :22
Expecting member declaration :22
Expecting member declaration :22
Name expected :22
Unresolved reference: result :27
Expecting an element :27
Expecting an expression :27
Property "service" is never used :20
Variable 'result' is never used :26
I couldn't figure out exactly what the problem was because I wrote the example code without the variable name to learn the basic usage of retrofit.
This is my main activity.
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
}
val retrofit = Retrofit.Builder().baseUrl("myserverURL")
.addConverterFactory(GsonConverterFactory.create()).build()
val service = retrofit.create(StudentService::class.java)
service.getinfo()?.enqueue(object : Callback<student> {
override fun onResponse(call: Call<student>, response: Response<student>) {
if(response.isSuccessful){
var result: student? = response.body()
Log.d("YMC", "onResponse 성공: " result?.toString())
}else{
// 통신이 실패한 경우(응답코드 3xx, 4xx 등)
Log.d("YMC", "onResponse 실패")
}
}
override fun onFailure(call: Call<student>, t: Throwable) {
TODO("Not yet implemented")
}
}
}
This is the content of the student data class.
data class student(
#SerializedName("id") val id:Int,
#SerializedName("hashedPW") val hashedPW:Char,
#SerializedName("hp") val hp:Char,
#SerializedName("name") val name:Char
)
This is an interface to communicate with the server
interface StudentService {
#GET("info/studentList")
fun getinfo(): Call<student>
}

Related

How to make functions wait result

I'm newbie in coding, so I want to ask more experienced programmers how to do it right.
I have 2 functions, first from Facebook SDK and second from AppsFlyerLib.
Can you tell me if there is right option to wait results from this functions please.
Here example of code:
class MainActivity: AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?, persistentState: PersistableBundle?) {
super.onCreate(savedInstanceState, persistentState)
var linkdataPlusApps = ""
//Getting Link Data
val linkdataHandler = object : AppLinkData.CompletionHandler {
override fun onDeferredAppLinkDataFetched(appLinkData: AppLinkData?) {
linkdataPlusApps += appLinkData.toString()
}
}
AppLinkData.fetchDeferredAppLinkData(this, linkdataHandler)
//Gettings Apps
val appsdataHandler = object : AppsFlyerConversionListener {
override fun onConversionDataSuccess(p0: MutableMap<String, Any>?) {
linkdataPlusApps += p0.toString()
}
override fun onConversionDataFail(p0: String?) {}
override fun onAppOpenAttribution(p0: MutableMap<String, String>?) {}
override fun onAttributionFailure(p0: String?) {}
}
AppsFlyerLib.getInstance().init("APPS_KEY", appsdataHandler, this).start(this)
//Here I wanna take this data and put in another activity
val intent = Intent(this, NextActivity::class.java)
intent.putExtra("FetchedData", linkdataPlusApps)
startActivity(intent)
}}
But this code doesn't work because Activity started before data was fetched so string is empty.
I solved this by chaining code, but I'm sure that is dirty-coding.
How I did
class MainActivity: AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?, persistentState: PersistableBundle?) {
super.onCreate(savedInstanceState, persistentState)
var linkdataPlusApps = ""
//Getting Link Data
val linkdataHandler = object : AppLinkData.CompletionHandler {
override fun onDeferredAppLinkDataFetched(appLinkData: AppLinkData?) {
linkdataPlusApps += appLinkData.toString()
val appsdataHandler = object : AppsFlyerConversionListener {
override fun onConversionDataSuccess(p0: MutableMap<String, Any>?) {
linkdataPlusApps += p0.toString()
val intent = Intent(this#MainActivity, NextActivity::class.java)
intent.putExtra("FetchedData", linkdataPlusApps)
startActivity(intent)
}
override fun onConversionDataFail(p0: String?) {}
override fun onAppOpenAttribution(p0: MutableMap<String, String>?) {}
override fun onAttributionFailure(p0: String?) {}
}
AppsFlyerLib.getInstance().init("APPS_KEY", appsdataHandler, this#MainActivity).start(this#MainActivity)
}
}
AppLinkData.fetchDeferredAppLinkData(this, linkdataHandler)
}
}
So code starts from fetching AppLinkData, and when fetched, starting fetching apps, and only then starting second activity with right string.
Can I do it in another way?

andoid studio kotlin - java.lang.IllegalStateException: Expected BEGIN_OBJECT but was BEGIN_ARRAY at line 1 column 2 path $

i am new to kotlin and i'm trying to call an api that has a array form ["value1","value2"] to display in my main activity textView and i keep getting this error
java.lang.IllegalStateException: Expected BEGIN_OBJECT but was BEGIN_ARRAY at line 1 column 2 path $
can someone help i'm using kotlin
this is the Data Class:
data class ApiValuesItem(
val values:Array<String?>
)
this is my interface:
import retrofit2.Call
import retrofit2.http.GET
interface ApiInterface {
#GET("values")
fun getApiValue(): Call<ApiValuesItem?>
}
and this is what i wrote in the mainActivity:
class MainActivity : AppCompatActivity() {
companion object {
const val BASE_URL = "http://xx.xx.xx.xx/sfa/api/"
}
#SuppressLint("ResourceType")
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
get_Api.setOnClickListener {
getApiValues()
}
}
private fun getApiValues() {
val retrofitBuilder = Retrofit.Builder()
.addConverterFactory(GsonConverterFactory.create())
.baseUrl(BASE_URL)
.build()
.create(ApiInterface::class.java)
val retrofitData = retrofitBuilder.getApiValue()
retrofitData.enqueue(object : Callback<ApiValuesItem?> {
override fun onResponse(
call: Call<ApiValuesItem?>,
response: Response<ApiValuesItem?>
) {
val responseBody = response.body()!!
val myStringBuilder = StringBuilder()
for (ApiValues in responseBody){
myStringBuilder.append(ApiValues.values)
myStringBuilder.append(", ")
}
Api_Res.text = myStringBuilder
}
override fun onFailure(call: Call<ApiValuesItem?>, t: Throwable) {
Log.d("MainActivity","onFailure: "+t.message)
Api_Res.text = t.message
}
})
}
}
Your Json:
["value1","value2"]
This is actually json array of strings.
If you define like below, it will be expecting json object. In that object , it will be expecting String Array with key "values"
data class ApiValuesItem(
val values:Array<String?>
)
You model class will be mapped like this.
{"values":["value1","value2"]}
But your root is directly an array.
So instead of Callback<ApiValuesItem?> you should make it as any Iterable<String>. You can use arraylist like below.
Callback<ArrayList<String>?>
Call<ArrayList<String>?>
Response<ArrayList<String>?>

Can't log any data from API call

I'm pretty new to kotlin, and I feel pretty much overwhelmed by it. I'd like to ask - how I can display any data from MutableLiveData? I've tried to Log it, but it doesn't seem to work. I've already added the internet permission to the manifest. Here's the code:
ApiServices
interface ApiServices {
#GET("/fixer/latest/")
fun getRatesData(
#Query("base") base: String,
#Query("apikey") apikey: String
): Call<CurrencyModel>
companion object {
private const val url = "https://api.apilayer.com/"
var apiServices: ApiServices? = null
fun getInstance(): ApiServices {
if (apiServices == null) {
val retrofit = Retrofit.Builder()
.baseUrl(url)
.addConverterFactory(GsonConverterFactory.create())
.build()
apiServices = retrofit.create(ApiServices::class.java)
}
return apiServices!!
}
}
}
Repository
class CurrencyRepository constructor(private val apiServices: ApiServices) {
fun getLatestRates() = apiServices.getRatesData("EUR", "API_KEY");
}
ViewModel
class CurrencyViewModel constructor(private val currencyRepository: CurrencyRepository) :
ViewModel() {
val currencyRatesList = MutableLiveData<CurrencyModel>()
val errorMessage = MutableLiveData<String>()
fun getLatestRates() {
val response = currencyRepository.getLatestRates();
response.enqueue(object : retrofit2.Callback<CurrencyModel> {
override fun onResponse(
call: retrofit2.Call<CurrencyModel>,
response: Response<CurrencyModel>
) {
currencyRatesList.postValue(response.body())
}
override fun onFailure(call: retrofit2.Call<CurrencyModel>, t: Throwable) {
errorMessage.postValue(t.message)
}
})
}
}
FactoryViewModel
class CurrencyViewModelFactory constructor(private val repository: CurrencyRepository) :
ViewModelProvider.Factory {
override fun <T : ViewModel?> create(modelClass: Class<T>): T {
return if (modelClass.isAssignableFrom(CurrencyViewModel::class.java)) {
CurrencyViewModel(this.repository) as T
}else{
throw IllegalArgumentException("Couldn't found ViewModel")
}
}
}
MainActivity
class MainActivity : AppCompatActivity() {
private val retrofitService = ApiServices.getInstance()
lateinit var viewModel: CurrencyViewModel
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
viewModel = ViewModelProvider(this, CurrencyViewModelFactory(CurrencyRepository(retrofitService)))
.get(CurrencyViewModel::class.java)
viewModel.currencyRatesList.observe(this, Observer {
Log.d(TAG, "onCreate: $it")
})
viewModel.errorMessage.observe(this, Observer {
viewModel.getLatestRates()
})
}
}
You never call viewModel.getLatestRates() in your onCreate() to fetch an initial value for your LiveData, so it never emits anything to observe. The only place you have called it is inside your error listener, which won't be called until a fetch returns an error.
Side note, I recommend naming the function "fetchLatestRates()". By convention, "get" implies that the function returns what it's getting immediately rather than passing it to a LiveData later when its ready.
And a tip. Instead of this:
class MainActivity : AppCompatActivity() {
lateinit var viewModel: CurrencyViewModel
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// ...
viewModel = ViewModelProvider(this, CurrencyViewModelFactory(CurrencyRepository(retrofitService)))
.get(CurrencyViewModel::class.java)
//...
}
}
You can do this for the same result:
class MainActivity : AppCompatActivity() {
val viewModel: CurrencyViewModel by viewModels(CurrencyViewModelFactory(CurrencyRepository(retrofitService)))
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// ...
}
}

Retrofit - Enqueue - Kotlin

class MainActivity : AppCompatActivity() {
private val fizzUrl = "https://s3-us-west-1.amazonaws.com/fizzup/files/public/"
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
}
//Instance Retrofit
val retrofit = Retrofit.Builder()
.baseUrl(fizzUrl)
.addConverterFactory(MoshiConverterFactory.create())
.build()
//Instance Api
val service = retrofit.create(ExerciseService::class.java)
//Get Request
val call = service.listExercises()
//Get execution
call.enqueue(object: Callback<List<Exercise>> {
override fun onResponse(call: Call<List<Exercise>>, response: Response<List<Exercise>>) {
val allExercise = response.body()
if (allExercise!= null) {
println("All exercises are loaded :")
for (c in allExercise)
println(" one exercise : ${c.name}")
}
}
override fun onFailure(call: Call<List<Exercise>>, t: Throwable) {
error("KO")
}
})
}
Here is my main activity. I have a data model : Exercise
and i have an interface ExerciceService.
But i have an issue with the enqueue method that tell me : Expecting member declaration
Therefore I have an other issue on the object : name expected.
But I've looked how to use enqueue and all I see is what I've done.
Thank for reading me and sorry for bad english.
#Xetiam,
Check if have imported correctly Callback class.
You can also check here. They have great documentation.
https://site-valley.com/2021/02/17/retrofit-android-tutorial-in-kotlin/

Kotlin: How to fetch data from web service and display it in app?

Hello :) I'm working on app that shows popular movies and some details about each of them. I created a RecyclerView where information should be displayed. I'm stuck with getting and displaying data. I'm using https://www.themoviedb.org/ page for api.
I was following these steps: http://imakeanapp.com/make-a-movies-app-using-tmdb-api-part-4-networking-using-retrofit-library/ , but it's written in Java and I need code in Kotlin. I converted by myself a part of the code, here is what I have:
in Movie.kt
data class Movie (
#SerializedName("id") val id: Int,
#SerializedName("title") val title: String,
#SerializedName("poster_path") val posterPath: String,
#SerializedName("release_date") val releaseDate: String,
#SerializedName("vote_average") val rating: Float
)
in MoviesResponse.kt
data class MoviesResponse (
#SerializedName("page") val page: Int,
#SerializedName("total_results") val totalResults: Int,
#SerializedName("results") val movies: List<Movie>,
#SerializedName("total_pages") val totalPages: Int
)
in TMDbApi.kt
interface TMDbApi {
#GET("movie/popular")
fun getPopularMovies (
#Query("api_key") apiKey: String,
#Query("language") language: String,
#Query("page") page: Int
): Call<List<MoviesResponse>>
}
in OnGetMoviesCallback.kt
interface OnGetMoviesCallback {
fun onSuccess(movies: List<Movie>)
fun onError()
}
in MainAdapter.kt
class MainAdapter: RecyclerView.Adapter<CustomHolder>(){
var movies: List<Movie> = listOf()
fun MainAdapter(movies: List<Movie>) {
this.movies = movies
}
override fun getItemCount(): Int {
return movies.size
}
override fun onBindViewHolder(holder: CustomHolder, position: Int) {
holder.bind(movies.get(position))
holder?.setOnClick()
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): CustomHolder {
val layoutInflater = LayoutInflater.from(parent?.context)
val cellForRow = layoutInflater.inflate(R.layout.movie_row, parent, false)
return CustomHolder(cellForRow)
}
}
class CustomHolder(view: View): RecyclerView.ViewHolder(view){
fun bind(result: Movie){
itemView.title.text = result.title
itemView.release_date.text = result.releaseDate
}
}
in MoviesRepository.kt
val BASE_URL: String = "https://api.themoviedb.org/3/"
val LANGUAGE: String = "en-US"
data class MoviesRepository (
val repositroy: MoviesRepository,
val api: TMDbApi
)
object getInstance{
val retrofit: TMDbApi = Retrofit.Builder()
.addConverterFactory(GsonConverterFactory.create())
.client(OkHttpClient().newBuilder().build())
.baseUrl(BASE_URL)
.build()
.create(TMDbApi::class.java)
}
in AllMoviesActivity.kt
class AllMoviesActivity : AppCompatActivity(), Callback<List<MoviesResponse>> {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_all_movies)
rw_main.layoutManager = LinearLayoutManager(this)
rw_main.adapter = MainAdapter()
getMovies()
}
private fun getMovies() {
getInstance.retrofit.getPopularMovies("2B0b0e8d104f0d6130a4fc67848f89e107", LANGUAGE, 1).enqueue(this)
}
override fun onResponse(call: retrofit2.Call<List<MoviesResponse>>, response: Response<List<MoviesResponse>>) {
val moviesResponse = response.body() ?: listOf()
Log.d("Results", moviesResponse.toString())
}
override fun onFailure(call: retrofit2.Call<List<MoviesResponse>>, t: Throwable) {
Toast.makeText(this, "Failed", Toast.LENGTH_SHORT).show()
}
}
And I have added in Manifest file Internet permission. When I run this, I get 'Failed' Toast and I don't see RecyclerView. Can you tell me what I'm missing or what's wrong? I've been searching on the Internet solutions but with no results. Hope you could help me. Thanks!
Looks like you are missing something small. After making a call to the API on Postman, Here's what you expect on your response body:
{
"page": 1,
"total_results": 10000,
"total_pages": 500,
"results": [...
}
Having brought that up, lets digest your lines, in TMDbApi.kt, you have indicated that your expected response is a List<MoviesResponse> which conflicts the response you receive as it is a JSON of type MoviesResponse,
Fix:
...): Call<List<MoviesResponse>>
}
to:
): Call<MoviesResponse>
}
The rest are small fixes to align your response handling.
Head over to AllMoviesActivity.kt and change the following:
class AllMoviesActivity : AppCompatActivity(), Callback<List<MoviesResponse>> {
to
class MainActivity : AppCompatActivity(), Callback<MoviesResponse>
Then on the callback functions, change signatures like so:
override fun onResponse(call: retrofit2.Call<List<MoviesResponse>>, response: Response<List<MoviesResponse>>) {
val moviesResponse = response.body() ?: listOf() ...
to:
override fun onResponse(call: Call<MoviesResponse>, response:Response<MoviesResponse>
) {
val moviesResponse = response.body()//type will be inferred ...
Then finally,
override fun onFailure(call: retrofit2.Call<List<MoviesResponse>>, t: Throwable) {
to:
override fun onFailure(call: Call<MoviesResponse>, t: Throwable) {
That's the basic to get the response and keep the Failure toast at bay.
Parting shot
Make the logs your friend, they can reveal the messy & smallest misses