Why is a for loop causing an infinite loop in retrofit? - kotlin

I'm using MutableLiveData<List> for the backing field. I've tried everything but it will continue to make API calls and it never breaks out of the for loop. I'm not sure whether changing the immutable list value of MutableLiveData triggers this.
fun getTweets(userIDs: List<Long>){
val ids = listOf(1168929753237094400, 3456625696)
viewModelScope.launch {
for(id in ids){
tweetService.getUsername(id).enqueue(object : Callback<TwitterUserResponse> {
override fun onResponse(call: Call<TwitterUserResponse>, response: Response<TwitterUserResponse>) {
val username = response.body()!!.user.username
tweetService.getTweets(id).enqueue(object: Callback<TwitterResponse>{
override fun onResponse(call: Call<TwitterResponse>, response: Response<TwitterResponse>) {
_tweets.value = response.body()!!.tweets.apply { forEach { it.username = username } }
}
override fun onFailure(call: Call<TwitterResponse>, t: Throwable) {}
})
}
override fun onFailure(call: Call<TwitterUserResponse>, t: Throwable) {}
})
}
}
}

Related

mutableListOf() I want to use it globally using lateinit Kotli

private lateinit var participants: mutableListOf<ParticipantDTO>
participants = mutableListOf<ParticipantDTO>()
private fun searchMatchInfoByMatchID(matchId: String,summonerName: String){
lolAPIForMatch.getMatchInfoByMatchID(matchId, API_KEY)
.enqueue(object : Callback<MatchDTO>{
override fun onResponse(call: Call<MatchDTO>, response: Response<MatchDTO>) {
if(response.isSuccessful.not()){
return
}
response.body()?.let {
it.info.participants.filter {
it.summonerName == "${summonerName}"
}.forEach {
participants.add(it)
}
participantAdapter.participants = participants
}
}
override fun onFailure(call: Call<MatchDTO>, t: Throwable) {
}
})
}
participantAdapter.participants = participants
First, declare it as a global variable.
After initialization in onCreate function.
By putting data into participants in the searchMatchInfoByMatchID function
I want to assign participants to participantAdapter.participants, but the data is not being allocated.

I want to use recyclerView, but the view doesn't have any values. kotlin

class SummonerInfoActivity: AppCompatActivity() {
private lateinit var participantAdapter: ParticipantAdapter
private val recycler: RecyclerView by lazy {
findViewById(R.id.RecyclerView)
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val Summoner = intent.getParcelableExtra<SummonerDTO>("SummonerDTO")
Log.e("Info","${Summoner}")
val retrofit2 = Retrofit.Builder()
.baseUrl("https://asia.api.riotgames.com")
.addConverterFactory(GsonConverterFactory.create())
.build()
lolAPIForMatch = retrofit2.create(lolAPIService::class.java)
setContentView(R.layout.activity_summoner_info)
participantAdapter = ParticipantAdapter()
recycler.adapter = participantAdapter
recycler.layoutManager = LinearLayoutManager(this#SummonerInfoActivity)
getMatchIdBypuuid(Summoner?.puuId.orEmpty(),Summoner?.summonerName.orEmpty())
}
private fun getMatchIdBypuuid(puuid: String,summonerName: String){
lolAPIForMatch.getMatchIdBypuuid(puuid, 0,20, API_KEY)
.enqueue(object : Callback<List<String>> {
override fun onResponse(
call: Call<List<String>>,
response: Response<List<String>>
) {
if(response.isSuccessful.not()){
return
}
response.body()?.let {
it.forEach {
searchMatchInfoByMatchID(it,summonerName)
}
}
}
override fun onFailure(call: Call<List<String>>, t: Throwable) {
}
})
}
private fun searchMatchInfoByMatchID(matchId: String,summonerName: String){
lolAPIForMatch.getMatchInfoByMatchID(matchId, API_KEY)
.enqueue(object : Callback<MatchDTO>{
override fun onResponse(call: Call<MatchDTO>, response: Response<MatchDTO>) {
if(response.isSuccessful.not()){
return
}
response.body()?.let {
it.info.participants.filter {
it.summonerName == "${summonerName}"
}.forEach {
participantAdapter.participants.add(it)
}
}
}
override fun onFailure(call: Call<MatchDTO>, t: Throwable) {
}
})
}
}
class ParticipantAdapter: RecyclerView.Adapter<ParticipantAdapter.ViewHolder>() {
var participants = mutableListOf<ParticipantDTO>()
inner class ViewHolder(itemView: View): RecyclerView.ViewHolder(itemView){
fun bind(participant: ParticipantDTO){
itemView.findViewById<TextView>(R.id.kill).text = participant.kills.toString()
itemView.findViewById<TextView>(R.id.death).text = participant.deaths.toString()
itemView.findViewById<TextView>(R.id.assist).text = participant.assists.toString()
}
}
override fun onCreateViewHolder(
parent: ViewGroup,
viewType: Int
): ParticipantAdapter.ViewHolder {
val inflater = LayoutInflater.from(parent.context)
return ViewHolder(inflater.inflate(R.layout.item_match, parent, false))
}
override fun onBindViewHolder(holder: ParticipantAdapter.ViewHolder, position: Int) {
holder.bind(participants[position])
}
override fun getItemCount(): Int {
return participants.size
}
}
participantAdapter.participants.add(it)
The command is searchMatchInfoByMatchID
In the function, you can check that the value is entered correctly, but
If you check in the onCreate function, the value is not assigned.
I want to use the recycler view by properly assigning a value
I tried to solve this problem, but my skills were not enough.
I desperately need the advice of seniors.
I would really appreciate it if you could show me a code sample if possible

How to retrun a String in Kotlin Initialization

I have the following Firebase Initialization, how can I make it return snapshot so that when I call it I get the val snapshot?
var homeRef_Host_Name: Unit = FirebaseDatabase.getInstance().getReference().child("users").child(firebaseAuth.currentUser.uid)
.child("name")
.addListenerForSingleValueEvent(object: ValueEventListener{
override fun onDataChange(snapshot: DataSnapshot) {
val snapshot = snapshot.value.toString()
}
override fun onCancelled(error: DatabaseError) {
}
})
fun getValue(callback:(String)->Unit){
FirebaseDatabase.getInstance().getReference().child("users").child(firebaseAuth.currentUser.uid)
.child("name")
.addListenerForSingleValueEvent(object: ValueEventListener{
override fun onDataChange(snapshot: DataSnapshot) {
callback(snapshot.value.toString())
}
override fun onCancelled(error: DatabaseError) {
}
})
}
fun main(){
getValue {
var yourvariable = it
//place your further code here
}
}
you cant directly assign it to variable because it async operation

kotlin how to share common retrofit response handler code

Having code to get from two different endpoints, but the response json have same scheme and the response handler code are same.
internal interface DataApi {
#GET("/api/api_1")
fun getData_1(#QueryMap params: Map<String, String>?): Call<DataMpdel>
#GET("/api/api_2")
fun getData_2(#QueryMap params: Map<String, String>?): Call<DataMpdel>
}
private lateinit var dataApi: DataApi
init {
dataApi = createDataApi()
}
private fun createDataApi() : DataApi {
val restAdapter = Retrofit.Builder()
.baseUrl(baseUrl)
.client(okHttpClient)
.addConverterFactory(getGsonConverterFactory())
.build()
return restAdapter.create(DataApi::class.java)
}
It could use if/else to call the different endpoint, but that will duplicate the handler code.
Update: create the handler function and in both onResposne() just call that function.
Any suggestion to be better with shared handler code?
private fun fetchFirst(){
if (!UseDataApi_1) {
//
dataApi. getData_1(getQueryParams()).enqueue(object : Callback<DataModel> {
override fun onResponse(call: Call<DataModel>?, response: Response<DataModel>?) {
// same handler code
}
override fun onFailure(call: Call<DataModel>?, throwable: Throwable?) {
// same error handler code
}
})
} else {
//
dataApi. getData_1(getQueryParams()).enqueue(object : Callback<DataModel> {
override fun onResponse(call: Call<DataModel>?, response: Response<DataModel>?) {
// same handler code
}
override fun onFailure(call: Call<DataModel>?, throwable: Throwable?) {
// same error handler code
}
})
}
}
If you want to minimize the duplicate code, create the callback as a class object and use it for both calls (something like this):
private val callback = object : Callback<DataModel> {
override fun onResponse(call: Call<DataModel>?, response: Response<DataModel>?) {
// handler code
}
override fun onFailure(call: Call<DataModel>?, throwable: Throwable?) {
// error handler code
}
}
private fun fetchFirst() {
if (UseDataApi_1) {
dataApi.getData_1(getQueryParams()).enqueue(callback)
} else {
dataApi.getData_2(getQueryParams()).enqueue(callback)
}
}

subscribing to an observable in the chain and setting the observer to the observable

kotlin 1.2.60
rxJava 2
I have the following code snippet below. I am wondering what is the difference in using the subscribe that is chained to the end of flatmap and printing the results or creating an observer and subscribing to the Observable.
For some reason I was expecting to get the same results. But when I print out the result in the onNext it displays the complete emitted item.
However, for the chained on subscribe it displays what I would expect.
fun main(args: Array<String>) {
val source2 = Observable.just("521934/2342/FOXTROT", "21962/12112/78886/TANGO", "283242/4542/WHISKEY/2348562")
source2.flatMap {
Observable.fromArray(*it.split("/").toTypedArray())
}
.subscribe { println(it) }
val observer = object : Observer<String> {
override fun onComplete() {
}
override fun onSubscribe(d: Disposable) {
}
override fun onNext(t: String) {
println(t)
}
override fun onError(e: Throwable) {
}
}
source2.subscribe(observer)
}
The output is below:
from the chained subscribe:
521934
2342
FOXTROT
21962
12112
78886
TANGO
283242
4542
WHISKEY
2348562
from onNext:
521934/2342/FOXTROT
21962/12112/78886/TANGO
283242/4542/WHISKEY/2348562
source2 is an immutable collection. You are observing it twice. You should capture the result of the flatmap in a new variable and then observe that.
fun main(args: Array<String>) {
val source2 = Observable.just("521934/2342/FOXTROT", "21962/12112/78886/TANGO", "283242/4542/WHISKEY/2348562")
val source3 = source2.flatMap {
Observable.fromArray(*it.split("/").toTypedArray())
}
source3.subscribe { println(it) }
val observer = object : Observer<String> {
override fun onComplete() {
}
override fun onSubscribe(d: Disposable) {
}
override fun onNext(t: String) {
println(t)
}
override fun onError(e: Throwable) {
}
}
source3.subscribe(observer)
}