Kotlin,Retrofit实现网络数据加载RecyclerView列表

kotlin.jpeg

在上一篇 kotlin实现Recyclerview,ListView列表 里面实现了静态数据的加载,静态数据和网络数据还是有一定的区别的,在这儿还是踩了很多的坑,慢慢在网上查一些相关的操作慢慢实现的。

基于豆瓣Top250做的一个列表展示

豆瓣API地址:https://developers.douban.com/wiki/?title=api_v2

网络请求使用:Retrofit

Json解析:原生解析(虽然Gson解析一步到位,或者Retrofit直接生成Bean都可以,但是了解原生数据解析,绝对没错,也可以多了解Kotlin的语法)

直接上代码,慢慢解释:

object NetUtils{
var url="http://api.douban.com/"
fun getService() :NetService{
    var service=Retrofit.Builder().baseUrl(url).build().create(NetService::class.java)
    return service
    }
 }

Retrofit的使用,不用过多的解释,和java没有太大的区别,多一个object修饰,Kotlin的特点,外部要调用

interface NetService {
@GET("v2/movie/top250")
fun getTopMovies(@Query("start") start:Int, @Query("count")count:Int): Call

}

接口的实现,Retrofit的使用还是和以前一样。

之后就是数据了,写了一个CustomCallBack做了一个简单的封装,这里需要根据数据结构做一个简单的方法分类,豆瓣数据还是有点多,需要手动解析的话,估计没有几百行解析不了,这里解析了三个数据,在数据不同的地方,title,name,image,也算是有代表性的数据,Kotlin的类生成有一个插件可以简单实现这里推荐一下jsontokotlinclass

jsontokotlinclass github地址 和GsonFormat一样的使用方法,里面也有详细的使用方法。

abstract class CustomCallBack : Callback {
abstract fun onGood(data: String)
abstract fun onFailure(msg: String)
abstract fun onFinish()

override fun onResponse(call: retrofit2.Call?, response: retrofit2.Response?) {
    val successful = response!!.isSuccessful
    if(successful){
        try {
            val string = response.body().string()
            val json = JSONObject(string)
            val total = json.optInt("total")
            if(total >= 0){
                onGood(json.optString("subjects"))
            }else{
                onFinish()
            }
        } catch (e: JSONException) {
            e.printStackTrace()
        }
    }
    else{
    }
}
override fun onFailure(call: retrofit2.Call?, t: Throwable?) {
    onFailure(t.toString())
 }
}

数据有点长,这是一条的内容

{
"count": 1,
"start": 1,
"total": 250,
"subjects": [{
    "rating": {
        "max": 10,
        "average": 9.5,
        "stars": "50",
        "min": 0
    },
    "genres": ["剧情", "爱情", "同性"],
    "title": "霸王别姬",
    "casts": [{
        "alt": "https:\/\/movie.douban.com\/celebrity\/1003494\/",
        "avatars": {
            "small": "http://img3.doubanio.com\/view\/celebrity\/s_ratio_celebrity\/public\/p67.webp",
            "large": "http://img3.doubanio.com\/view\/celebrity\/s_ratio_celebrity\/public\/p67.webp",
            "medium": "http://img3.doubanio.com\/view\/celebrity\/s_ratio_celebrity\/public\/p67.webp"
        },
        "name": "张国荣",
        "id": "1003494"
    }, {
        "alt": "https:\/\/movie.douban.com\/celebrity\/1050265\/",
        "avatars": {
            "small": "http://img7.doubanio.com\/view\/celebrity\/s_ratio_celebrity\/public\/p46345.webp",
            "large": "http://img7.doubanio.com\/view\/celebrity\/s_ratio_celebrity\/public\/p46345.webp",
            "medium": "http://img7.doubanio.com\/view\/celebrity\/s_ratio_celebrity\/public\/p46345.webp"
        },
        "name": "张丰毅",
        "id": "1050265"
    }, {
        "alt": "https:\/\/movie.douban.com\/celebrity\/1035641\/",
        "avatars": {
            "small": "http://img3.doubanio.com\/view\/celebrity\/s_ratio_celebrity\/public\/p1399268395.47.webp",
            "large": "http://img3.doubanio.com\/view\/celebrity\/s_ratio_celebrity\/public\/p1399268395.47.webp",
            "medium": "http://img3.doubanio.com\/view\/celebrity\/s_ratio_celebrity\/public\/p1399268395.47.webp"
        },
        "name": "巩俐",
        "id": "1035641"
    }],
    "collect_count": 910492,
    "original_title": "霸王别姬",
    "subtype": "movie",
    "directors": [{
        "alt": "https:\/\/movie.douban.com\/celebrity\/1023040\/",
        "avatars": {
            "small": "http://img7.doubanio.com\/view\/celebrity\/s_ratio_celebrity\/public\/p1451727734.81.webp",
            "large": "http://img7.doubanio.com\/view\/celebrity\/s_ratio_celebrity\/public\/p1451727734.81.webp",
            "medium": "http://img7.doubanio.com\/view\/celebrity\/s_ratio_celebrity\/public\/p1451727734.81.webp"
        },
        "name": "陈凯歌",
        "id": "1023040"
    }],
    "year": "1993",
    "images": {
        "small": "http://img7.doubanio.com\/view\/photo\/s_ratio_poster\/public\/p1910813120.webp",
        "large": "http://img7.doubanio.com\/view\/photo\/s_ratio_poster\/public\/p1910813120.webp",
        "medium": "http://img7.doubanio.com\/view\/photo\/s_ratio_poster\/public\/p1910813120.webp"
    },
    "alt": "https:\/\/movie.douban.com\/subject\/1291546\/",
    "id": "1291546"
}],
"title": "豆瓣电影Top250"
}

下面来看看Activity里面的实现

class GridActivity : AppCompatActivity() {
var page:Int=1
var count:Int=15
var movieList : ArrayList  = ArrayList()
lateinit var adapter : GridRVAdapter
override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_grid)
    initUI()
    getInfo()
   setListener()
}

private fun initUI() {

    var manager=GridLayoutManager(this,1)
    rv.layoutManager= manager
    adapter = GridRVAdapter(this@GridActivity,movieList);
    rv.adapter=adapter

//       rv!!.setOnScrollListener(object : RecyclerView.OnScrollListener(){
//
//            @Override
//            override fun onScrollStateChanged(recyclerView: RecyclerView?, newState: Int) {
//                super.onScrollStateChanged(recyclerView, newState)
//
//            }
//
//
//            override fun onScrolled(recyclerView: RecyclerView?, dx: Int, dy: Int) {
//                super.onScrolled(recyclerView, dx, dy)
//                val itemPosition = lm.findLastCompletelyVisibleItemPosition()
//                if(itemPosition==lm.itemCount-1){
//                    addinfo()
//                    adapter.notifyDataSetChanged()
//                }
//            }
//        })
}

private fun setListener(){}

private fun getInfo() {
    var net=NetUtils.getService()
    var call=net.getTopMovies(page,count)

    call.enqueue(object : CustomCallBack() {
        override fun onGood(data: String) {

            //这是集合的直接生成
            var gson = Gson()
            var moviesData:List = gson.fromJson>(data,
                    Array::class.java).toMutableList()

             //单个类解析的方法,News为这个实体类
             //val newsResponse = gson.fromJson(response, News::class.java)

            //这里就是手动解析数据,对照着数据结构可以看到每一条数据是如何得到的,这里就获取了三条数据
            var titles : String
            var name : String=""
            var cover : String
            var json=JSONArray(data)
            for (i in 0 until json.length()-1){
                val optJSONObject = json.optJSONObject(i)
                titles=optJSONObject.optString("title")
                val casts = optJSONObject.optJSONArray("casts")
                for(j in 0 until casts.length()-1){
                    val nameObj = casts.optJSONObject(j)
                    name=nameObj.optString("name")
                }
                val images=optJSONObject.optJSONObject("images")
                cover=images.optString("large")
                var movie=Movies.DataBean(
                        name,
                        titles,
                        cover
                )
                movieList.add(movie)
            }
          //adapter的刷新
            adapter.notifyDataSetChanged()
        }

        override fun onFinish() {

        }

        override fun onFailure(msg: String) {

        }

    })
  }
}

Adapter的实现和之前的差不多,这里有两种方式实现,都可以尝试

    class GridRVAdapter (var context:Context,var date : ArrayList) : RecyclerView.Adapter() {

fun notifyDataChange(list: ArrayList) {//更新适配器数据
    this.date = list
    notifyDataSetChanged()
}

override fun getItemCount(): Int {
    return date.size
}

override fun onCreateViewHolder(parent: ViewGroup?, viewType: Int): RecyclerView.ViewHolder {
    val inflate = LayoutInflater.from(parent?.context).inflate(R.layout.grid_item, null)
    return MyHolder(inflate)
}

override fun onBindViewHolder(holder: RecyclerView.ViewHolder?, position: Int) {

    if(holder is MyHolder){
        var movie=date[position]
//            holder.bind(movie)
        holder.tv_name.setText(movie.name)
        holder.tv_title.text=movie.title
        Glide.with(context).load(movie.avatars).into(holder.iv_cover)
    }
}

class MyHolder(itemView: View?) : RecyclerView.ViewHolder(itemView) {
     var tv_name: TextView
     var tv_title:TextView
     var iv_cover: ImageView

//        fun bind(date: Movies.DataBean){
//            itemView.tv_names.text=date.name
//            itemView.tv_title.text=date.title
//            Glide.with(itemView.context).load(date.avatars).into(itemView.iv_cover)
//        }
     init{
        tv_name= itemView!!.findViewById(R.id.tv_names)
        tv_title=itemView!!.findViewById(R.id.tv_title)
        iv_cover=itemView!!.findViewById(R.id.iv_cover)
     }
  }
}

上面注释了的方法也可以实现数据的展示。只是两种不同的方式而已,实体类的实现,这里可以使用之前推荐的那个bean实例化的插件,简单快速

class Movies {
data class DataBean(
        val name:String,
        val title:String,
        val avatars:String
   )
}

之后直接使用Gson来实现json的解析,直接生成实体类集合

Todo :集合的直接生成方法

 var gson = Gson()
 var moviesData:List = gson.fromJson>(data,
                    Array::class.java).toMutableList()

MoviesBean.Subejects类是由jsontokotlinclass 直接生成的

class  MoviesBean {

object data class Subejects(
    var rating: Rating,
    var genres: List,
    var title: String,// 霸王别姬
    var casts: List,
    var collect_count: Int,// 910492
    var original_title: String,// 霸王别姬
    var subtype: String,// movie
    var directors: List,
    var year: String,// 1993
    var images: Images,
    var alt: String,// https://movie.douban.com/subject/1291546/
    var id: String// 1291546
) 


data class Cast(
    var alt: String,// https://movie.douban.com/celebrity/1003494/
    var avatars: Avatars,
    var name: String,// 张国荣
    var id: String// 1003494
)


data class Rating(
    var max: Int,// 10
    var average: Double,// 9.5
    var stars: String,// 50
    var min: Int// 0
)

data class Director(
    var alt: String,// https://movie.douban.com/celebrity/1023040/
    var avatars: Avatars,
    var name: String,// 陈凯歌
    var id: String// 1023040
)

data class Avatars(
    var small: String,
    var large: String,// 
http://img7.doubanio.com/view/celebrity/s_ratio_celebrity/public/p1451727734.81.webp
    var medium: String// 
http://img7.doubanio.com/view/celebrity/s_ratio_celebrity/public/p1451727734.81.webp
)

    data class Images(
    var small: String,//        
http://img7.doubanio.com/view/photo/s_ratio_poster/public/p1910813120.webp
    var large: String,// 
http://img7.doubanio.com/view/photo/s_ratio_poster/public/p1910813120.webp
    var medium: String// 
http://img7.doubanio.com/view/photo/s_ratio_poster/public/p1910813120.webp
)
}

实现的效果图如下:

S80411-18551999.jpg

你可能感兴趣的:(Kotlin,Retrofit实现网络数据加载RecyclerView列表)