目录
AndroidSDK开发6我用kotlin协程写了一个简单sdk
1.kotlin的依赖和导包如下:(//如果不使用协程可以去掉协程的导包减少sdk包大小)
6.初始化及管理工具类(WanAndroidManager):
14.具体测试代码如下:(由于之前讲过怎么在新项目中引入aar,这里就不重复了,不懂的小伙伴可以看前几篇)
AndroidSDK开发6我用kotlin写了一个简单sdk
由于前面几篇文章讲解了sdk初始化、sdk设计原则、将moule或者项目打成aar、不用第三方库开发一个sdk等,目前市面上很少有使用sdk开发采用kotlin语言,本文讲解使用如何使用kolin开发一个简单sdk,当然这里有2个版本,由于最开始没有使用协程导致使用和代码还是很多,经过之前的经验和sdk使用原则以及对新语言的使用情况,于是产生了使用加入协程的概念,具体使用如下:
1.kotlin的依赖和导包如下:
(如果不使用协程可以去掉协程的导包减少sdk包大小)
//apply plugin: 'com.android.application' apply plugin: 'com.android.library' apply plugin: 'kotlin-android' apply plugin: 'kotlin-android-extensions' apply plugin: 'kotlin-kapt'
dependencies { implementation fileTree(dir: “libs”, include: [“*.jar”]) implementation ‘androidx.appcompat:appcompat:1.1.0’ implementation ‘androidx.constraintlayout:constraintlayout:1.1.3’ implementation “org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version” implementation “org.jetbrains.kotlin:kotlin-reflect:$kotlin_version” implementation “org.jetbrains.kotlinx:kotlinx-coroutines-core:${kotlinx_coroutines_version}” }
2.Application代码如下:
/** * @auth: njb * @date: 2022/4/27 15:56 * @desc: 描述 */ class App : Application() { override fun onCreate() { super.onCreate() context = applicationContext } companion object{ var context: Context by Delegates.notNull() private set } }
3.常量工具类(Constants):
/** * @auth: njb * @date: 2022/4/25 11:43 * @desc: 常量工具类 */ object Constants { const val BASE_URL = "https://www.wanandroid.com" const val DEFAULT_TIMEOUT = 20000 //10秒 const val TAG = "WanHttp" //搜索 const val QUERY_ARTICLE = "/article/query/0/json" //获取首页banner列表 const val BANNER_LIST = "/banner/json" //搜索热词 const val HOT_KEY = "/hotkey/json" }
4.日志工具类(LogUtils):
/** * @auth: njb * @date: 2022/4/26 14:26 * @desc: 日志工具类 */ object LogUtils { const val showLog:Boolean = true fun i(tag: String, msg: String) { if (showLog) Log.i(tag, msg) } fun d(tag: String, msg: String) { if (showLog) Log.d(tag, msg) } fun w(tag: String, msg: String) { if (showLog) Log.w(tag, msg) } fun e(tag: String, msg: String) { if (showLog) Log.e(tag, msg) } }
5.网络状态工具类(NetWorkUtils):
/** * @auth: njb * @date: 2022/4/27 11:45 * @desc: 网络状态工具类 */ class NetWorkUtils { companion object{ @get:RequiresPermission(Manifest.permission.ACCESS_NETWORK_STATE) val isConnected: Boolean get() { val info = activeNetworkInfo return info.isConnected } @get:RequiresPermission(Manifest.permission.ACCESS_NETWORK_STATE) private val activeNetworkInfo: NetworkInfo get() { val cm = App.context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager return cm.activeNetworkInfo!! } } }
6.初始化及管理工具类(WanAndroidManager):
/** * @auth: njb * @date: 2022/4/23 22:39 * @desc: 描述 */ class WanAndroidManager() { var mContext:Context by Delegates.notNull() fun init(app: Application){ mContext = app.applicationContext } }
7.网络请求工具类:
class WanHttpUtils { companion object { lateinit var connection: HttpURLConnection fun doRequestPost(params: Map<String, String>): WanAndroidHttpResult<String> { val result by lazy { WanAndroidHttpResult<String>() } try { runBlocking { withContext(Dispatchers.Default) { val url by lazy { URL(params["url"]) } LogUtils.d(Constants.TAG, "$url --url--") setConnection(url, params) LogUtils.d(Constants.TAG, "$params --params--") val requestParamJsonObject by lazy { params["body"] } if (requestParamJsonObject != null && "" != requestParamJsonObject?.trim { it <= ' ' }) { val bytes by lazy { requestParamJsonObject?.toByteArray() } connection.setRequestProperty("Content-Length", bytes?.size.toString()) val outputStream by lazy { connection.outputStream } outputStream.run { write(bytes) flush() close() } } setResult(responseCode = connection.responseCode, result) } } } catch (e: Exception) { showErrorMsg(result, e) } finally { connection.disconnect() } return result } fun doRequestGet(params: Map<String, String>): WanAndroidHttpResult<String>? { val result by lazy { WanAndroidHttpResult<String>() } runBlocking { withContext(Dispatchers.Default) { try { val url by lazy { URL(params["url"]) } setConnection(url, params) setResult(responseCode = connection.responseCode, result) } catch (e: Exception) { showErrorMsg(result, e) } } } return result } private fun setResult(responseCode: Int, result: WanAndroidHttpResult<String>) { result.run { responseCode.run { if (this == 200) { isBizSucceed(true) setData(getResponseDataString(connection.inputStream)) } else { isBizSucceed(false) setData("") result.errorMsg = "errorCode:" + responseCode + connection.responseMessage } } } } private fun setConnection( url: URL, params: Map<String, String>, ) { connection = (url.openConnection() as HttpURLConnection).apply { readTimeout = DEFAULT_TIMEOUT connectTimeout = DEFAULT_TIMEOUT doOutput = true doInput = true requestMethod = params["Method"] setRequestProperty("Connection", "Keep-Alive") setRequestProperty("Charset", "UTF-8") setRequestProperty("Content-Type", "application/json; charset=UTF-8") setRequestProperty("accept", "application/json") } } private fun showErrorMsg(result: WanAndroidHttpResult<String>, e: Exception) { val msg: Any msg = when { !isConnected -> { "网络连接失败,请检查网络" } e is SocketTimeoutException -> { "网络请求超时,请稍后重试" } e is MalformedJsonException -> { "数据解析失败" } else -> { "请求失败,请稍后重试:" + e.message } } result.errorMsg = msg } private fun getResponseDataString(inputStream: InputStream): String { val inputStreamReader by lazy { InputStreamReader(inputStream) } val bufferedReader by lazy { BufferedReader(inputStreamReader) } val stringBuilder by lazy { StringBuilder() } var temp: String? try { while (bufferedReader.readLine().also { temp = it } != null) { stringBuilder.append(temp) } } catch (e: IOException) { e.printStackTrace() } finally { try { bufferedReader.close() } catch (e: IOException) { e.printStackTrace() } try { inputStreamReader.close() } catch (e: IOException) { e.printStackTrace() } try { inputStream.close() } catch (e: IOException) { e.printStackTrace() } } return stringBuilder.toString() } } }
8.网络请求接口监听:
/** * @auth: njb * @date: 2022/6/10 15:59 * @desc: 描述 */ interface OnResponseListener { suspend fun onResponse(wanAndroidHttpResult: WanAndroidHttpResult<*>?) }
9.网络请求结果解析工具类:
/** * @auth: njb * @date: 2022/4/22 15:53 * @desc: 描述 */ class WanAndroidHttpResult<T> { /** * 记录请求回来的错误状态描述 */ private var errorCode:Int ?=0 /** * 记录请求回来的错误状态描述 */ var errorMsg = "" /** * 记录返回的数据 */ var data: T? = null private set /** * 业务请求是否成功 */ fun isBizSucceed(defaultValue: Boolean): Boolean { return if (null == errorCode) defaultValue else errorCode == 0 } fun setData(data: T) { this.data = data } }
10.网络请求接口回调方法:
/** * @auth: njb * @date: 2022/4/22 15:33 * @desc: 描述 */ interface WanHttpRequestCallBack { fun onResponse(response: String?): Boolean? fun onFailed(message: String?): Boolean? }
11.网络请求线程工具类:
/** * @auth: njb * @date: 2022/6/6 10:06 * @desc: 描述 */ open class WanRequestThread( private val params: Map<String, String>, private val listener: OnResponseListener ) { private val lock by lazy { ByteArray(0) } private var isCancel = false suspend fun run() { val result: WanAndroidHttpResult<String>? = if (params["Method"] == "POST") WanHttpUtils.doRequestPost(params) else WanHttpUtils.doRequestGet(params) if (!isCancel) { listener.onResponse(result) } } suspend fun cancel() { synchronized(lock) { isCancel = true } } }
12.网络请求回调:
/** * @auth: njb * @date: 2022/6/6 10:27 * @desc: 描述 */ class WanRequestListener { companion object{ suspend fun getQueryArticle(responseListener: OnResponseListener, keyWord:String): WanRequestThread { val params by lazy { HashMap<String, String>() } val url by lazy { Constants.BASE_URL + Constants.QUERY_ARTICLE + "?k="+keyWord } params["url"] = url params["Method"] = "POST" val requestThread by lazy { WanRequestThread(params, responseListener) } requestThread.run() return requestThread } } suspend fun getHomeBanner(responseListener: OnResponseListener):WanRequestThread{ val params by lazy { HashMap<String, String>() } val url by lazy { Constants.BASE_URL + Constants.BANNER_LIST } params["url"] = url params["Method"] = "GET" val requestThread by lazy { WanRequestThread(params, responseListener) } requestThread.run() return requestThread } }
13.网络请求封装的具体方法(包含请求参数和结果回调):
/** * @auth: njb * @date: 2022/5/2 22:37 * @desc: 描述 */ object WanHttpRequest { suspend fun queryArticle(callBack: WanHttpRequestCallBack,keyWord:String){ WanRequestListener.getQueryArticle(object : OnResponseListener { override suspend fun onResponse(wanAndroidHttpResult: WanAndroidHttpResult<*>?) { if (wanAndroidHttpResult == null && wanAndroidHttpResult?.data == null) { return } try { val content by lazy { wanAndroidHttpResult.data.toString() } wanAndroidHttpResult.run { callBack.run { if (isBizSucceed(true)) { onResponse(content) } else { val message by lazy { wanAndroidHttpResult.errorMsg } onFailed(message) } } } } catch (e: Exception) { e.printStackTrace() } } },keyWord) } }
14.具体测试代码如下:
(由于之前讲过怎么在新项目中引入aar,这里就不重复了,不懂的小伙伴可以看前几篇)
class MainActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) initView() } private fun initView() { getQueryData() } private fun getQueryData() { GlobalScope.launch(Dispatchers.Main) { WanHttpRequest.queryArticle(object : WanHttpRequestCallBack { override fun onResponse(response: String?): Boolean? { try { val jsonObject by lazy { JSONObject(response) } val jsonObject2 = jsonObject.getJSONObject("data") val jsonArray by lazy { jsonObject2.getJSONArray("datas") } val list: MutableList<ArticleListDataBean> = ArrayList() if (jsonArray.length() > 0) { for (i in 0 until jsonArray.length()) { val datasBean = ArticleListDataBean() val bannerObject: JSONObject = jsonArray.getJSONObject(i) datasBean.run { bannerObject.run { id = bannerObject.getInt("id") link = bannerObject.getString("link") desc = bannerObject.getString("desc") apkLink = bannerObject.getString("apkLink") title = bannerObject.getString("title") chapterName = bannerObject.getString("chapterName") } list.add(this) } } CoroutineScope(Dispatchers.IO).launch { list.forEach { it -> Log.d("---MainActivity---", it.chapterName + " 数据获取成功 ") tvTest.text = it.chapterName } } } } catch (e: Exception) { e.printStackTrace() } return null } override fun onFailed(message: String?): Boolean? { return null } }, "Android") } } }
15.运行效果截图和日志:
15.1 具体实现效果截图如下:
/**
这里使用的是鸿洋的WanAndroidApi,只是写了一个简单的接口测试,没有写具体的逻辑 **
/
15.2 运行日志如下:
16.项目源码地址如下(分支选择dev_kotlin):