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<ResponseBody>

}

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

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

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

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

override fun onResponse(call: retrofit2.Call<ResponseBody>?, response: retrofit2.Response<ResponseBody>?) {
    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<ResponseBody>?, 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<Movies.DataBean>  = 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<MoviesBean.Subejects> = gson.fromJson<Array<MoviesBean.Subejects>>(data,
                    Array<MoviesBean.Subejects>::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<Movies.DataBean>) : RecyclerView.Adapter<RecyclerView.ViewHolder>() {

fun notifyDataChange(list: ArrayList<Movies.DataBean>) {//更新适配器数据
    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<MoviesBean.Subejects> = gson.fromJson<Array<MoviesBean.Subejects>>(data,
                    Array<MoviesBean.Subejects>::class.java).toMutableList()

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

class  MoviesBean {

object data class Subejects(
    var rating: Rating,
    var genres: List<String>,
    var title: String,// 霸王别姬
    var casts: List<Cast>,
    var collect_count: Int,// 910492
    var original_title: String,// 霸王别姬
    var subtype: String,// movie
    var directors: List<Director>,
    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
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,332评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,508评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,812评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,607评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,728评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,919评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,071评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,802评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,256评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,576评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,712评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,389评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,032评论 3 316
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,798评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,026评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,473评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,606评论 2 350

推荐阅读更多精彩内容

  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 171,831评论 25 707
  • 前言 人生苦多,快来 Kotlin ,快速学习Kotlin! 什么是Kotlin? Kotlin 是种静态类型编程...
    任半生嚣狂阅读 26,171评论 9 118
  • 本文是在学习和使用kotlin时的一些总结与体会,一些代码示例来自于网络或Kotlin官方文档,持续更新... 对...
    竹尘居士阅读 3,272评论 0 8
  • 2016-12-31 有朋天下 关于原生个案,对于很多人来说都是一个全新的概念,网上可以收集到一些相关资料,也有很...
    Cinny深圳阅读 493评论 0 0
  • 2016年,夏天。 我们毕业了。 其实,真正意识到要毕业的时候,是你在火车上给我发短信,你说你要回去考特岗了。我劝...
    U木头人阅读 204评论 0 0