大家好,我是小黑,一个还没秃头的程序员~~~你必须特别努力,才能显得毫不费力。今天的文章是为了前段时间学习kotlin所进行的接口对接,使用的网络数据传输框架为Retrofit,使用的接口为玩Android的开放接口,项目地址:https://gitee.com/fjjxxy/kotlin_retrofit.git
知识体系下的文章https://www.wanandroid.com/article/list/0/json?cid=60方法:GET参数:cid 分类的id,上述二级目录的id 页码:拼接在链接上,从0开始。 获取公众号列表https://wanandroid.com/wxarticle/chapters/json 方法:GET
需要申请的权限<uses-permission android:name="android.permission.INTERNET" />
需要添加的依赖def retrofit_version = '2.6.1'//----------------- retrofit begin -----------------implementation "com.squareup.retrofit2:retrofit:$retrofit_version"implementation "com.squareup.retrofit2:converter-gson:$retrofit_version"implementation "com.squareup.retrofit2:converter-scalars:$retrofit_version"// ---- okhttp ----implementation 'com.squareup.okhttp3:logging-interceptor:3.11.0'// ---- okhttp ----//----------------- retrofit end -----------------implementation 'androidx.recyclerview:recyclerview:1.0.0'
先来看一下效果图效果图中由两个列表组成,上个列表对接第一个接口,下个列表对接第二个接口,好了,接下来是代码展示
(一)定义一个实体类Result,用来接收接口返回的数据
class Result<T> { var errorCode: String? = null var errorMsg: String? = null var data: T? = null}
(二)定义一个接口Api,使用注解的方式为retrofit提供Restful风格的Api,各种注解的使用方式这里就不一一列举了,请大家自行百度interface Api { /** * 微信公众号列表 */ @GET("wxarticle/chapters/json") fun getwxarticle(): Call>> /** * 文章列表 */ @GET("article/list/{page}/json") fun getArticle(@Path("page") page: String, @Query("cid") cid: String): Call>}
(三)封装接口请求工具类HttpHelper,获取 retrofit对象以及Api服务,设置 拦截器以及处理日志 ,代码如下 /** * 接口请求工具类 */class HttpHelper { companion object { private val BASE_URL = "https://www.wanandroid.com/" //服务器地址 private var sHttpClient: OkHttpClient? = null private var sApi: Api? = null /** * 添加拦截器,对返回的数据或者日志进行处理,对请求添加统一头部 */ fun getHttpClient(): OkHttpClient? { if (sHttpClient == null) { synchronized(HttpHelper::class.java) { if (sHttpClient == null) { val builder = OkHttpClient.Builder() //添加拦截器 var interceptor = HttpLoggingInterceptor( HttpLoggingInterceptor.Logger { message -> //对日志进行处理 Log.e("Tag", message) } ) interceptor.setLevel(HttpLoggingInterceptor.Level.BODY) builder.addInterceptor(interceptor) builder.addInterceptor { chain -> val request = chain.request() val compressedRequest = request.newBuilder() //添加头部 .addHeader( "User-Agent", "Android" ) .build() chain.proceed(compressedRequest) } sHttpClient = builder .callTimeout(40, TimeUnit.SECONDS) .connectTimeout(40, TimeUnit.SECONDS) .readTimeout(40, TimeUnit.SECONDS) .writeTimeout(40, TimeUnit.SECONDS) .build() } } } return sHttpClient } /** * 获取接口服务 */ fun getApi(): Api? { if (sApi == null) { synchronized(HttpHelper::class.java) { if (sApi == null) { val retrofit = createRetrofit(BASE_URL) sApi = retrofit.create(Api::class.java) } } } return sApi } /** * 获取Retrofit对象,定义返回类型的转换器 */ private fun createRetrofit(baseUrl: String): Retrofit { val gsonBuilder = GsonBuilder() return Retrofit.Builder() .client(getHttpClient()) .baseUrl(baseUrl) .addConverterFactory(ScalarsConverterFactory.create()) .addConverterFactory(GsonConverterFactory.create(gsonBuilder.create())) .build() } }}
(四)封装接口回调类SingleCallback,处理数据返回成功和失败状态的数据/** * 接口请求基本回调 */abstract class SingleCallback<T : Result>?> : Callback<T> { //接口请求成功 override fun onResponse( call: Call<T>, response: Response<T> ) { val result = response.body() if (result == null) { onFailure("-99", "请求异常", null) } else { if (apiFailure(result)) { onFailure(result.errorCode, result.errorMsg ?: "", result) } else { onSuccess(result) } } } override fun onFailure(call: Call<T>, t: Throwable) { Log.e("SingleCallback", "onFailure: " + t.message, t) } fun successCode(): String { return "0" } fun apiFailure(result: T?): Boolean { return result == null || successCode() != result.errorCode } /** * 失败回调。默认已经将失败信息提示出来 */ fun onFailure(code: String?, message: String, response: T?) { Toast.makeText(App.getContext(), message, Toast.LENGTH_SHORT).show() } abstract fun onSuccess(response: T)}
(五)设计列表界面以及子项布局activity_main.xml<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" tools:context=".MainActivity"> <androidx.recyclerview.widget.RecyclerView android:id="@+id/rv_article_data" android:layout_width="match_parent" android:layout_height="0dp" android:layout_weight="1" /> <androidx.recyclerview.widget.RecyclerView android:id="@+id/rv_user_data" android:layout_width="match_parent" android:layout_height="0dp" android:layout_weight="1" />LinearLayout>
item_article.xml
<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="wrap_content" android:background="#fff"> <TextView android:id="@+id/tv_article" android:layout_width="match_parent" android:layout_height="40dp" android:text="" android:textSize="14dp" />LinearLayout>
item_user.xml
<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="wrap_content" android:background="#fff"> <TextView android:id="@+id/tv_user" android:layout_width="match_parent" android:layout_height="40dp" android:text="" android:textSize="14dp" />LinearLayout>
(六)实体类Article实体类class Article { var datas: List? = null}
ArticleData实体类
val title: String? = null
User实体类
val name: String? = nul
(七)逻辑以及数据适配器代码编写MainActivity.ktclass MainActivity : AppCompatActivity() { private val mUserList: MutableList = ArrayList() private var mArticleList: MutableList = ArrayList(); override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) //或者这里可以不用findViewById,直接用布局中的id作为变量名也可以 var rvArticleData: RecyclerView = findViewById(R.id.rv_article_data) var rvUserData: RecyclerView = findViewById(R.id.rv_user_data) rvArticleData.layoutManager = LinearLayoutManager(this) rvUserData.layoutManager = LinearLayoutManager(this) rvArticleData.adapter = ArticleAdapter(this, mArticleList) var userAdapter = UserAdapter(mUserList) userAdapter.setOnUserClickListener(object : UserAdapter.OnUserClickListener { override fun click(text: String?) { Toast.makeText(applicationContext, text, Toast.LENGTH_SHORT).show() } }) rvUserData.adapter = userAdapter //请求微信公众号接口 var api = HttpHelper.getApi() api!!.getwxarticle()!!.enqueue(object : SingleCallback>>() { override fun onSuccess(response: Result<List<User>>) { if (response.data != null && (response.data?.size ?: 0 > 0)) { mUserList.addAll(response.data!!) rvUserData.adapter?.notifyDataSetChanged() } } }) //请求文章接口 var api1 = HttpHelper.getApi() api1!!.getArticle("1", "60")!!.enqueue(object : SingleCallback>() { override fun onSuccess(response: Result<Article>) { if (response.data != null && response.data?.datas != null && response.data?.datas?.size ?: 0 > 0) { mArticleList.addAll(response.data?.datas!!) rvArticleData.adapter?.notifyDataSetChanged() } } }) }}
ArticleAdapter.kt
class ArticleAdapter(var mContext: Context, var mList: List) : RecyclerView.Adapter() { class ViewHolder(view: View) : RecyclerView.ViewHolder(view) { var mTvArticle: TextView = view.tv_article } override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder { return ViewHolder( LayoutInflater.from(parent.context).inflate( R.layout.item_article, parent, false ) ) } override fun getItemCount(): Int { return mList.size } override fun onBindViewHolder(holder: ViewHolder, position: Int) { holder.mTvArticle.text = mList[position].title //设置点击事件,Lambda 表达式用着真的很舒服 holder.mTvArticle.setOnClickListener { Toast.makeText( mContext, mList[position].title, Toast.LENGTH_SHORT ).show() } }
UserAdapter.kt
class UserAdapter(var mList: List) : RecyclerView.Adapter() { class ViewHolder(view: View) : RecyclerView.ViewHolder(view) { var mTvUser: TextView = view.tv_user } private var mUserClickListener: OnUserClickListener? = null //设置点击事件回调,具体的实现在回调中定义 interface OnUserClickListener { fun click(text: String?) } fun setOnUserClickListener(onUserClickListener: OnUserClickListener) { this.mUserClickListener = onUserClickListener } override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder { return ViewHolder( LayoutInflater.from(parent.context).inflate( R.layout.item_user, parent, false ) ) } override fun getItemCount(): Int { return mList.size } override fun onBindViewHolder(holder: ViewHolder, position: Int) { holder.mTvUser.text = mList[position].name holder.mTvUser.setOnClickListener { mUserClickListener!!.click(mList[position].name) } }
到此为止,Kotlin+Retrofit+Recyclerview的用法就介绍到这里了,功能的效果图如开头展示,代码已上传到码云,地址:https://gitee.com/fjjxxy/kotlin_retrofit.git,最后,祝大家身体健康,万事如意,谢谢大家的支持与阅读!