在上一篇 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
)
}