>

recyclerView를 추가하기 전에 두 번 확인한 retrofit 라이브러리를 사용하여 응답을 가져 왔으며 정상적으로 작동하지만 recyclerView 및 어댑터를 추가 한 후 데이터가 표시되지 않습니다.

ApiService.kt

package com.kunalrai.githubtrends
import com.squareup.moshi.Moshi
import retrofit2.Call
import retrofit2.Retrofit
import retrofit2.converter.moshi.MoshiConverterFactory
import com.squareup.moshi.kotlin.reflect.KotlinJsonAdapterFactory
import retrofit2.http.GET
private const val BASE_URL = "https://github-trending-api.now.sh"
val moshi: Moshi = Moshi.Builder()
    .add(KotlinJsonAdapterFactory())
    .build()
private val retrofit = Retrofit.Builder()
    .addConverterFactory(MoshiConverterFactory.create(moshi))
    .baseUrl(BASE_URL)
    .build()
interface ApiService {
    @GET("repositories")
    fun getRepos(): Call<List<Repo>>
}
object Api {
    val RETROFIT_SERVICE : ApiService by lazy { retrofit.create(ApiService::class.java) }
}

ListAdapter.kt

package com.kunalrai.githubtrends
import android.content.Context
import android.util.Log
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.ImageView
import android.widget.TextView
import androidx.recyclerview.widget.RecyclerView
import com.bumptech.glide.Glide
import com.bumptech.glide.request.RequestOptions
class ListAdapter(private val context: Context?, private val repoList: List<Repo>) : RecyclerView.Adapter<ListAdapter.MyViewHolder>() {

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyViewHolder {
        val view = LayoutInflater.from(parent.context).inflate(R.layout.repo_item,parent,false)
        return MyViewHolder(view)
    }
    override fun getItemCount(): Int {
        Log.i("reposize: ",""+repoList.size)
        return repoList.size
    }
    override fun onBindViewHolder(holder: MyViewHolder, position: Int) {
        holder.author.text = repoList[position].author
        holder.repo.text = repoList[position].name
        Glide.with(context!!).load(repoList[position].avatar)
            .apply(RequestOptions().centerCrop())
            .into(holder.image)
    }
    class MyViewHolder(itemView: View?) : RecyclerView.ViewHolder(itemView!!) {
        val author: TextView = itemView!!.findViewById(R.id.owner_name)
        val image: ImageView = itemView!!.findViewById(R.id.owner_image)
        val repo: TextView = itemView!!.findViewById(R.id.repo_name)

    }
}

ListViewModel.kt

package com.kunalrai.githubtrends
import android.util.Log
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import retrofit2.Call
import retrofit2.Callback
import retrofit2.Response
class ListViewModel : ViewModel() {
    var repoList: MutableLiveData<List<Repo>> = MutableLiveData(listOf())
    fun getRepos(): MutableLiveData<List<Repo>>{
            repoList = MutableLiveData()
            loadRepos()
        return repoList
    }
    private fun loadRepos() {
        Api.RETROFIT_SERVICE.getRepos().enqueue( object: Callback<List<Repo>> {
            override fun onFailure(call: Call<List<Repo>>, t: Throwable) {
                Log.i("Failure: ", t.message)
            }
            override fun onResponse(call: Call<List<Repo>>, response: Response<List<Repo>>) {
                if(response.body() != null){
                    repoList.value = response.body()
                    Log.i("response.body :",""+response.body())
                }
            }
        })
    }
}


ListFragment.kt

package com.kunalrai.githubtrends
import androidx.lifecycle.ViewModelProviders
import android.os.Bundle
import android.util.Log
import androidx.fragment.app.Fragment
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.lifecycle.Observer
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.kunalrai.githubtrends.databinding.ListFragmentBinding

class ListFragment : Fragment() {
    companion object {
        fun newInstance() = ListFragment()
    }
    private val viewModel: ListViewModel by lazy {
        ViewModelProviders.of(this).get(ListViewModel::class.java)
    }
    private lateinit var binding: ListFragmentBinding
    var recyclerView: RecyclerView? = null
    lateinit var listAdapter: ListAdapter
    var repoList: List<Repo> = listOf()

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
//        viewModel.getRepos().observe(this,
//            Observer<List<Repo>> {
//                it?.let { repoList ->
//                    this.repoList = repoList
//                    Log.i("inside observe",""+repoList)
//                }
//            })
    }
    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        viewModel.getRepos().observe(this,
            Observer<List<Repo>> {
                it?.let { repoList ->
                    this.repoList = repoList
                    Log.i("inside observe",""+repoList)
                    listAdapter = ListAdapter(context, repoList)
                    recyclerView?.adapter = listAdapter
                }
            })
        recyclerView = view.findViewById(R.id.rv_repo_list)
        recyclerView?.layoutManager = LinearLayoutManager(context)
        recyclerView?.setHasFixedSize(true)

    }
    override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        binding = ListFragmentBinding.inflate(inflater, container, false)
        binding.lifecycleOwner
        binding.viewmodel = viewModel
        setHasOptionsMenu(true)
//        recyclerView = view?.findViewById(R.id.rv_repo_list)
//        recyclerView?.layoutManager = LinearLayoutManager(context)
//        recyclerView?.setHasFixedSize(true)
//        listAdapter = ListAdapter(context, repoList)
//        recyclerView?.adapter = listAdapter

        return binding.root
    }
}


Repo.kt

package com.kunalrai.githubtrends
import com.squareup.moshi.Json
data class Repo(
    @Json(name = "author")
    var author: String,
    @Json(name = "name")
    var name: String,
    @Json(name = "description")
    var desc: String,
    @Json(name = "avatar")
    var avatar: String,
    @Json(name = "language")
    var language: String,
    @Json(name = "url")
    var url: String,
    @Json(name = "stars")
    var stars: String,
    @Json(name = "forks")
    var forks: String
)

list_fragment.xml

<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools">
    <data>
        <variable
            name="viewmodel"
            type="com.kunalrai.githubtrends.ListViewModel" />
    </data>
    <FrameLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:context=".ListFragment">
        <androidx.recyclerview.widget.RecyclerView
            android:id="@+id/rv_repo_list"
            android:layout_width="match_parent"
            android:layout_height="match_parent" />
    </FrameLayout>
</layout>

repo_item.xml

<?xml version="1.0" encoding="utf-8"?>
    <RelativeLayout
        xmlns:android="http://schemas.android.com/apk/res/android"
        android:orientation="vertical"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_margin="5dp">
        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="horizontal">
            <de.hdodenhof.circleimageview.CircleImageView
                xmlns:app="http://schemas.android.com/apk/res-auto"
                android:id="@+id/owner_image"
                android:layout_width="96dp"
                android:layout_height="96dp"
                app:civ_border_width="2dp"
                app:civ_border_color="#FF000000"/>
            <LinearLayout
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:orientation="vertical">
                <TextView
                    android:id="@+id/owner_name"
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"/>
                <TextView
                    android:id="@+id/repo_name"
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"/>
            </LinearLayout>
        </LinearLayout>
    </RelativeLayout>

Logcat :

2019-11-29 19:15:15.170 20890-20890/? E/Zygote: isWhitelistProcess - Process is Whitelisted
2019-11-29 19:15:15.187 20890-20890/? E/Zygote: accessInfo : 1
2019-11-29 19:15:18.090 20890-20890/com.kunalrai.githubtrends E/RecyclerView: No adapter attached; skipping layout


매니페스트 파일에서 인터넷 권한을 부여했습니다. recyclerView를 추가하기 전에 가져온 응답을 확인했습니다.

빈 화면은 충돌없이 출력됩니다.


  • 답변 # 1

    몇 가지 변경을 권장합니다.

    ListAdapter에서

    class ListAdapter(private val context: Context?) : RecyclerView.Adapter<ListAdapter.MyViewHolder>() {
      private val repoList = ArrayList<Repo>() //create an empty list first.
      fun resetList(newList: List<Repo>){ //update only when a list is available.
          repoList.clear()
          repoList.addAll(newList)
          notifyDataSetChanged() //you need this part to tell the adapter to redraw the views.
      }
     ... the rest of your List Adapter
    
    

    그런 다음 조각에

    private lateinit var listAdapter: ListAdapter
    override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        binding = ListFragmentBinding.inflate(inflater, container, false)
        binding.lifecycleOwner
        binding.viewmodel = viewModel
        setHasOptionsMenu(true)
    
        listAdapter = ListAdapter(context) //create adapter with emptyList
        recyclerView = view?.findViewById(R.id.rv_repo_list)
        recyclerView?.let{
            it.layoutManager = LinearLayoutManager(context)
            it.setHasFixedSize(true)
            it.adapter = listAdapter //we add the adapter here
        } 
        return binding.root
    }
    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
      super.onViewCreated(view, savedInstanceState)
      viewModel.getRepos().observe(this,
        Observer<List<Repo>> {
            it?.let { repoList ->
                //you just need to repopulate/recycle the views in your adapter.
                //no need to recreate the adapter again.
                listAdapter.resetList(repoList) 
            }
        })
       }
    
    

  • 답변 # 2

    BASE_URL은 / 로 끝나야합니다.  그래서 / 를 추가하십시오  기본 URL의 끝

    BASE_URL = "https://github-trending-api.now.sh/"
    
    

    repoList를 초기화했기 때문에 API가 호출되지 않고 null 인 경우 api를 호출했습니다. api는 전화하지 않으므로 원치 않는 경우를 제거하십시오

       var repoList: MutableLiveData<List<Repo>> = MutableLiveData(listOf())
        if(repoList == null) {
            repoList = MutableLiveData()
            loadRepos()
        }
    
    

    onviewCreated ()에서 API 호출

      override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
          super.onViewCreated(view, savedInstanceState)
          viewModel.getRepos().observe(this,
            Observer<List<Repo>> {
                it?.let { repoList ->
                    listAdapter = ListAdapter(context, repoList)
                    recyclerView?.adapter = listAdapter
                }
            })
           }
    
    

관련 자료

  • 이전 PHP에서 텍스트 파일의 행과 열 읽기
  • 다음 arrays - ARRAYFORMULA가 포함 된 MAXIFS가 Google 스프레드 시트에서 작동하지 않습니다