Kotlin语言基于Mvp+Retrofit+RxJava封装的Android项目的基础依赖库
前言
该Library是基于Kotlin语言封装的一个库,主要是用来创建一个kotlin项目时,作为项目的简单封装,使用该Library作为依赖引入,即可进行项目开发,省去一些前期准备工作。
该Library主要进行了一下封装:
- 采用普通MVC架构的方式,对Activity,Fragment,Adapter和一些工具类的封装以及自定义View的实现;
- 采用Retrofit+RxJava 对http请求进行相应的封装,可设置公共参数,并对RX生命周期进行处理;
- 采用MVP架构,对上面封装的Activity,Fragment 进行二次封装;
- 该项目使用了org.jetbrains.anko ,可实现对布局文件的自动依赖注入,kotlin文件中的View名称就是对应布局文件中View的 id;
一、采用普通方式封装的基础文件介绍
1、BaseActivity
package:cn.onestravel.library.kotlin.base.activity
所有Activity的基类,定义一些子类必须实现的和可实现的方法:
/**
* 获取布局ID,子类必须实现
*/
protected abstract fun getLayoutId(): Int
/**
* 初始化 View 的相关操作,若有需要可在子类实现
*/
protected open fun initView() {}
/**
* 初始化 Listener 事件的相关操作,若有需要可在子类实现
*/
protected open fun initListener() {}
/**
* 初始化 Data 数据的相关操作,若有需要可在子类实现
*/
protected open fun initData() {}
/**
* 在主线程弹出Toast 提示
* @param msg 需要弹出的提示信息
*/
protected open fun showToast(msg:String){
runOnUiThread {
toast(msg)
}
}
/**
* 在主线程弹出Toast 提示
* @param stringRes 需要弹出的提示信息的string资源ID
*/
protected open fun showToast(stringRes:Int){
runOnUiThread {
toast(getString(stringRes))
}
}
/**
* 跳转到另一个Activity,并且finish 掉当前Activity
* 需要跳转的Activity必须继承于BaseActivity 或者
* @param params 可变参数,需要通过intent传递的参数 eg:"key" to "value"
*/
inline fun <reified T: BaseActivity> startActivityAndFinish(vararg params: Pair<String, Any?>) {
startActivity<T>(*params)
finish()
}
2、BaseListActivity
package:cn.onestravel.library.kotlin.base.activity
继承自BaseActivity,实现针对RecyclerView实现列表数据的一些配置,简化实现只有一个列表布局的Activity,并且实现上拉加载,下拉刷新操作。
主要方法如下:
protected fun getRecyclerView():LoadMoreRecyclerView{
return mRecyclerView
}
/**
* 获取recyclerView的布局管理器,子类可重写该方法,来更改布局管理器
*/
protected open fun getLayoutManager(): RecyclerView.LayoutManager {
val layoutManager: LinearLayoutManager = LinearLayoutManager(this)
//设置为垂直布局,这也是默认的
layoutManager.orientation = OrientationHelper.VERTICAL
return layoutManager
}
/**
* 设置RecyclerView 的Adapter适配器
* @param adapter 设置的Adapter,必须是BaseRecyclerAdapter的子类
*/
protected fun <T> setAdapter(adapter: BaseRecyclerAdapter<T>) {
mRecyclerView.adapter = adapter
}
/**
* 设置刷新控件的颜色
*/
protected fun setRefreshColorSchemeColors(@ColorInt vararg colors: Int) {
mRefreshLayout.setColorSchemeColors(*colors)
}
/**
* 设置刷新控件的颜色
*/
protected fun setColorSchemeResources(@ColorRes vararg colorIds: Int) {
mRefreshLayout.setColorSchemeResources(*colorIds)
}
/**
* 设置刷新控件是否显示
*/
protected fun isRefresh(isRefresh: Boolean) {
mRefreshLayout.isRefreshing = false
}
/**
* 刷新完成
*/
protected fun refreshComplete() {
mRefreshLayout.isRefreshing = false
}
/**
* 刷新数据,子类实现该方法,进行数据请求
*/
protected open fun refreshDatas() {
}
/**
* 加载更多完成
*/
protected fun loadMoreComplete() {
mRecyclerView.loadMoreComplete(true)
}
/**
* 设置是否可以加载更多
*/
protected fun canLoadMore(canLoadMore: Boolean) {
mRecyclerView.loadMoreEnable = canLoadMore
}
/**
* 设置是否还有更多的数据
*/
protected fun hasLoadMore(hasLoadMore: Boolean) {
mRecyclerView.hasMore = hasLoadMore
}
/**
* 加载新数据,子类实现该方法,进行数据请求
*/
protected open fun loadMoreDatas() {
}
3、BaseRecyclerAdapter
package:cn.onestravel.library.kotlin.base.adapter
针对RecyclerView使用的RecyclerView.Adapter进行封装,实现一些基础的布局(不常变化的)设置的方法,定义一些方法,简化子类的实现,更加有利于缩短开发时间;实现adapter中提示Toast的方法,以及添加、设置数据,或者基础View的设置相关内容的方法;对Item点击和长按的监听事件。
主要方法如下:
abstract class BaseRecyclerAdapter<T> : RecyclerView.Adapter<VH>(), View.OnClickListener, View.OnLongClickListener {
private val mDatas: MutableList<T> = ArrayList<T>()
private lateinit var context: Context
private var clickListener: OnItemClickListener<T>? = null
private var longClickListener: OnItemLongClickListener<T>? = null
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): VH {
context = parent.context
val convertView = LayoutInflater.from(parent.context).inflate(getLayoutId(viewType), parent, false)
convertView.setOnClickListener(this)
convertView.setOnLongClickListener(this)
return VH(convertView)
}
/**
* 设置Item 的点击事件
*/
fun setOnItemClick(listener: OnItemClickListener<T>) {
clickListener = listener
}
/**
* 设置Item 的点击事件
*/
fun setOnItemClick(onClick: (view:View,position:Int,data:T) -> Unit) {
clickListener = object : OnItemClickListener<T> {
override fun onItemClick(view: View, position: Int, data: T) {
onClick(view,position,data)
}
}
}
/**
* 设置Item 的长按事件
*/
fun setOnItemLongClick(listener:OnItemLongClickListener<T>) {
longClickListener = listener
}
/**
* 设置Item 的长按事件
*/
fun setOnItemLongClick(onLongClick: (view:View,position:Int,data:T) -> Boolean) {
longClickListener = object : OnItemLongClickListener<T> {
override fun onItemLongClick(view: View, position: Int, data: T):Boolean {
return onLongClick(view,position,data)
}
}
}
override fun onClick(p0: View?) {
val position:Int = p0?.getTag(R.id.itemViewPosition) as Int
val data:T = mDatas.get(position)
clickListener?.onItemClick(p0,position,data)
}
override fun onLongClick(p0: View?): Boolean {
val position:Int = p0?.getTag(R.id.itemViewPosition) as Int
val data:T = mDatas.get(position)
return longClickListener?.onItemLongClick(p0,position,data) ?: true
}
/**
* 设置数据,并且会清空原数据列表
* @param datas 新的数据列表
*/
open fun setDatas(datas: List<T>) {
mDatas.clear()
mDatas.addAll(datas)
notifyDataSetChanged()
}
/**
* 添加新的数据列表到原数据列表末尾
* @param datas 新的数据列表
*/
open fun addDatas(datas: List<T>) {
mDatas.addAll(datas)
notifyDataSetChanged()
}
/**
* 添加新的数据列表到原数据列表的指定位置
* @param position 需要添加的指定位置
* @param datas 新的数据列表
*/
open fun addDatas(position: Int, datas: List<T>) {
val pos = if (position > mDatas.size) {
mDatas.size
} else position
mDatas.addAll(pos, datas)
notifyDataSetChanged()
}
/**
* 更新数据列表指定位置上的数据
* @param position 需要更新数据的位置
* @param data 更新后的数据
*/
open fun updateData(position: Int, data: T) {
if (position < mDatas.size) {
mDatas.removeAt(position)
mDatas.add(position, data)
notifyItemChanged(position)
}
}
/**
* 添加新的数据到原数据列表末尾
* @param datas 新的数据
*/
open fun addData(data: T) {
mDatas.add(data)
notifyItemInserted(mDatas.size - 1)
}
/**
* 添加新的数据到原数据列表的指定位置
* @param position 需要添加的指定位置
* @param data 新的数据
*/
open fun addData(position: Int, data: T) {
val pos = if (position > mDatas.size) {
mDatas.size
} else position
mDatas.add(pos, data)
notifyItemInserted(pos)
}
/**
* 移除指定位置上的数据
* @param position 需要添加的指定位置
*/
open fun removeDataAt(position: Int) {
if (position < mDatas.size) {
mDatas.removeAt(position)
notifyItemRemoved(position)
}
}
protected open fun showToast(msg: String) {
context.runOnUiThread {
context.toast(msg)
}
}
/**
* 移除指定的数据
* @param data 需要移除的数据实体
*/
open fun removeData(data: T) {
if (mDatas.contains(data)) {
val position = mDatas.indexOf(data)
mDatas.removeAt(position)
notifyItemRemoved(position)
}
}
/**
* 根据View的类型获取对应的Item布局的ID
*/
@LayoutRes
abstract fun getLayoutId(viewType: Int): Int
/**
* 绑定ViewHolder 时执行的方法,在此方法里处理对Item的view的操作
*/
abstract fun onBindVH(holder: VH, position: Int, datas: T)
/**
* 返回数据的数量
*/
override fun getItemCount(): Int {
return mDatas.size
}
override fun onBindViewHolder(holder: VH, position: Int) {
holder.itemView.setTag(R.id.itemViewPosition, position)
onBindVH(holder, position, mDatas.get(position))
}
}
/**
*Item 的点击事件
*/
interface OnItemClickListener<T> {
fun onItemClick(view: View, position: Int, data: T)
}
/**
*Item 的长按事件
*/
interface OnItemLongClickListener<T> {
fun onItemLongClick(view: View, position: Int, data: T):Boolean
}
/**
* 所有的Adapter 使用的ViewHolder
*/
class VH(itemView: View) : RecyclerView.ViewHolder(itemView) {
/**
* 根据View的id获取对应的View
*/
inline fun <reified E : View> getView(@IdRes viewId: Int): E {
return itemView.find<E>(viewId)
}
/**
* 对TextView及其子类设置文本内容
* @param viewId 对应的View 的id
* @param value 需要设置的文本内容
*/
inline fun setText(@IdRes viewId: Int, value: String) {
val view: View = this.getView(viewId)
if (view is TextView) {
val tv: TextView = view
tv.text = value
}
}
/**
* 对TextView及其子类设置文本内容
* @param viewId 对应的View 的id
* @param value 需要设置的文本内容
*/
inline fun setText(@IdRes viewId: Int, value: Spannable) {
val view: View = this.getView(viewId)
if (view is TextView) {
val tv: TextView = view
tv.text = value
}
}
/**
* 对TextView及其子类设置文本内容
* @param viewId 对应的View 的id
* @param stringRes 需要设置的文本资源的id
*/
inline fun setText(@IdRes viewId: Int, @StringRes stringRes: Int) {
val view: View = this.getView(viewId)
if (view is TextView) {
val tv: TextView = view
tv.setText(stringRes)
}
}
/**
* 对ImageView及其子类设置图片
* @param viewId 对应的View 的id
* @param resId 需要设置的图片资源的id
*/
inline fun setImageResource(@IdRes viewId: Int, @DrawableRes resId: Int) {
val view: View = getView(viewId)
if (view is ImageView) {
val iv: ImageView = view
iv.imageResource = resId
}
}
/**
* 对ImageView及其子类设置图片
* @param viewId 对应的View 的id
* @param imgUrl 需要设置的网络图片的地址
*/
inline fun setImageUrl(@IdRes viewId: Int, imgUrl: String) {
val view: View = getView(viewId)
if (view is ImageView) {
val iv: ImageView = view
iv.loadImage(imgUrl)
}
}
/**
* 对View及其子类设置背景图片
* @param viewId 对应的View 的id
* @param resId 需要设置的背景图片的资源地址
*/
inline fun setBackgroundResource(@IdRes viewId: Int, @DrawableRes resId: Int) {
val view: View = getView(viewId)
view.setBackgroundResource(resId)
}
/**
* 对View及其子类设置背景颜色
* @param viewId 对应的View 的id
* @param color 需要设置的背景颜色
*/
inline fun setBackgroundColor(@IdRes viewId: Int, @ColorInt color: Int) {
val view: View = getView(viewId)
view.setBackgroundColor(color)
}
/**
* 对View及其子类设置点击事件
* @param viewId 对应的View 的id
* @param color 需要设置的背景颜色
*/
inline fun setOnClick(@IdRes viewId: Int, crossinline onClick: (View) -> Unit) {
val view: View = getView(viewId)
view.setOnClickListener {
onClick.invoke(it)
}
}
}
4、ImageViewExtend
package: cn.onestravel.library.kotlin.base.extend
改文件是ImageView的扩展方法的文件,主要针对ImageView加载网络图片而新增的一些扩展方法
具体方法如下:
inline fun ImageView.loadImage(imgUrl: String): ImageView {
ImageUtils.loadImageUrl(this.context, imgUrl, this)
return this
}
inline fun ImageView.loadBitmap(imgUrl: String): ImageView {
ImageUtils.loadImageBitmap(this.context, imgUrl, this)
return this
}
inline fun ImageView.loadGif(imgUrl: String): ImageView {
ImageUtils.loadImageGif(this.context, imgUrl, this)
return this
}
inline fun ImageView.loadImgCallBack(imgUrl: String, requestListener: RequestListener<Bitmap>): ImageView {
ImageUtils.loadImageCallBack(this.context, imgUrl, this, requestListener)
return this
}
5、BaseFragment
package: cn.onestravel.library.kotlin.base.fragment
所有Fragment的基类,定义一些子类必须实现的和可实现的方法,具体方法与BaseActivity方法类似。
6、BaseListFragment
package: cn.onestravel.library.kotlin.base.fragment
继承自BaseFragment,实现针对RecyclerView实现列表数据的一些配置,简化实现只有一个列表布局的Fragment,并且实现上拉加载,下拉刷新操作;具体方法与BaseListActivity相同。
7、DensityUtil
package: cn.onestravel.library.kotlin.base.utils
尺寸转换工具类,可以将dip转为px,将px转为dip;获取屏幕宽度和高度。
/**
* dip转换为px
*/
fun dip2px(dp: Int): Int {
return (dp * density).toInt()
}
/**
* px转换为dip
*/
fun px2dip(px: Float): Int {
return (px / density).toInt()
}
/**
* 获取屏幕宽度
*/
fun appWidth(): Int {
return Resources.getSystem().getDisplayMetrics().widthPixels
}
/**
* 获取屏幕高度
*/
fun appHeight(): Int {
return Resources.getSystem().getDisplayMetrics().heightPixels
}
8、CircleTextView
package:cn.onestravel.library.kotlin.base.view
自定义圆形TextView,一满足不同需求
9、EmptyView
package:cn.onestravel.library.kotlin.base.view
自定义 数据为空的页面视图,主要有三个功能类型,分别为:数据为空显示页面(TYPE_EMPTY);加载进度提示页面(TYPE_LOADING);加载失败可点击重试页面(TYPE_RELOAD)
重新定义的一下方法如下:
/**
* 设置页面显示类型
*
* @param type
*/
fun setEmptyType(type: Int) {
_setEmptyType(type, true)
}
/**
* 设置页面显示类型
*
* @param type
*/
private fun _setEmptyType(type: Int, isShow: Boolean) {
this.emptyType = type
when (type) {
TYPE_EMPTY -> {
layoutLoading!!.visibility = View.GONE
layoutReload!!.visibility = View.GONE
layoutEmpty!!.visibility = View.VISIBLE
btnReload!!.visibility = View.GONE
ivEmptyImg!!.visibility = View.VISIBLE
}
TYPE_LOADING -> {
layoutLoading!!.visibility = View.VISIBLE
layoutEmpty!!.visibility = View.GONE
layoutReload!!.visibility = View.GONE
if (tvLoadingMsg != null) {
tvLoadingMsg!!.text = "正在加载..."
}
}
TYPE_RELOAD -> {
layoutLoading!!.visibility = View.GONE
layoutEmpty!!.visibility = View.GONE
layoutReload!!.visibility = View.VISIBLE
btnReload!!.visibility = View.VISIBLE
ivEmptyImg!!.visibility = View.VISIBLE
}
}
if (isShow) {
show()
}
}
/**
* 设置空数据界面的背景色
*
* @param color 背景色
*/
fun setEmptyBackgroundColor(color: Int) {
layoutEmpty!!.setBackgroundColor(color)
}
/**
* 设置错误描述
*
* @param resId
*/
fun setEmptyText(@StringRes resId: Int) {
if (tvEmptyMsg != null) {
tvEmptyMsg!!.text = mContext!!.getString(resId)
}
}
/**
* 设置错误描述
*
* @param text
*/
fun setEmptyText(text: CharSequence?) {
var text = text
if (text == null) {
text = ""
}
if (tvEmptyMsg != null) {
tvEmptyMsg!!.text = text
}
}
/**
* 设置错误描述字体大小
*
* @param size
*/
fun setEmptyTextSize(size: Float) {
if (tvEmptyMsg != null) {
tvEmptyMsg!!.setTextSize(TypedValue.COMPLEX_UNIT_PX, size)
}
}
/**
* 设置错误描述颜色
*
* @param color
*/
fun setEmptyTextColor(color: Int) {
if (tvEmptyMsg != null) {
tvEmptyMsg!!.setTextColor(color)
}
}
/**
* 设置错误描述颜色
*
* @param colors
*/
fun setEmptyTextColor(colors: ColorStateList) {
if (tvEmptyMsg != null) {
tvEmptyMsg!!.setTextColor(colors)
}
}
/**
* 设置页面图片
*
* @param resId
*/
fun setEmptyImgResource(@DrawableRes resId: Int) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
this.noDataImg = mContext!!.getDrawable(resId)
} else {
this.noDataImg = mContext!!.resources.getDrawable(resId)
}
if (ivEmptyImg != null) {
ivEmptyImg!!.setImageResource(resId)
}
}
/**
* 设置页面图片
*
* @param noDataImg
*/
fun setEmptyImg(noDataImg: Drawable) {
this.noDataImg = noDataImg
if (ivEmptyImg != null) {
ivEmptyImg!!.setImageDrawable(noDataImg)
}
}
/**
* 获取加载按钮文字
*/
fun getReloadBtnText(): String? {
return reloadBtnText
}
/**
* 设置重新加载按钮文字
*
* @param resId
*/
fun setReloadBtnText(resId: Int) {
this.reloadBtnText = mContext!!.getString(resId)
if (btnReload != null) {
btnReload!!.text = this.reloadBtnText
}
}
/**
* 设置重新加载按钮文字
*
* @param reloadBtnText
*/
fun setReloadBtnText(reloadBtnText: String) {
this.reloadBtnText = reloadBtnText
if (btnReload != null) {
btnReload!!.text = this.reloadBtnText
}
}
/**
* 设置重新加载按钮文字大小
*
* @param reloadBtnTextSize
*/
fun setReloadBtnTextSize(reloadBtnTextSize: Float) {
this.reloadBtnTextSize = reloadBtnTextSize
if (btnReload != null) {
btnReload!!.setTextSize(TypedValue.COMPLEX_UNIT_PX, this.reloadBtnTextSize)
}
}
/**
* 设置重新加载按钮文字颜色
*
* @param color
*/
fun setReloadBtnTextColor(color: Int) {
this.reloadBtnTextColor = color
if (btnReload != null) {
btnReload!!.setTextColor(this.reloadBtnTextColor)
}
}
/**
* 设置重新加载按钮文字颜色
*
* @param colors
*/
fun setReloadBtnTextColor(colors: ColorStateList) {
if (btnReload != null) {
btnReload!!.setTextColor(colors)
}
}
/**
* 设置加载按钮背景
*
* @param reloadBackground
*/
fun setReloadBtnBackground(reloadBackground: Drawable) {
this.reloadBtnBackground = reloadBackground
if (btnReload != null) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
btnReload!!.background = this.reloadBtnBackground
} else {
btnReload!!.setBackgroundDrawable(this.reloadBtnBackground)
}
}
}
/**
* 设置加载按钮背景
*
* @param color
*/
fun setReloadBtnBackgroundColor(color: Int) {
this.reloadBtnBackground = ColorDrawable(color)
if (btnReload != null) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
btnReload!!.background = this.reloadBtnBackground
} else {
btnReload!!.setBackgroundDrawable(this.reloadBtnBackground)
}
}
}
/**
* 设置加载按钮背景
*
* @param resId
*/
fun setReloadBtnBackgroundResource(resId: Int) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
this.reloadBtnBackground = mContext!!.getDrawable(resId)
} else {
this.reloadBtnBackground = mContext!!.resources.getDrawable(resId)
}
if (btnReload != null) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
btnReload!!.background = this.reloadBtnBackground
} else {
btnReload!!.setBackgroundDrawable(this.reloadBtnBackground)
}
}
}
/**
* 获取加载提示文字
*/
fun getReloadText(): String? {
return reloadText
}
/**
* 设置重新加载提示文字
*
* @param resId
*/
fun setReloadText(resId: Int) {
this.reloadText = mContext!!.getString(resId)
if (tvReloadMsg != null) {
tvReloadMsg!!.text = this.reloadText
}
}
/**
* 设置重新加载提示文字
*
* @param reloadText
*/
fun setReloadText(reloadText: String) {
this.reloadText = reloadText
if (tvReloadMsg != null) {
tvReloadMsg!!.text = this.reloadText
}
}
/**
* 设置重新加载提示文字大小
*
* @param reloadTextSize
*/
fun setReloadTextSize(reloadTextSize: Float) {
this.reloadTextSize = reloadTextSize
if (tvReloadMsg != null) {
tvReloadMsg!!.setTextSize(TypedValue.COMPLEX_UNIT_PX, this.reloadTextSize)
}
}
/**
* 设置重新加载提示文字颜色
*
* @param color
*/
fun setReloadTextColor(color: Int) {
this.reloadTextColor = color
if (tvReloadMsg != null) {
tvReloadMsg!!.setTextColor(this.reloadTextColor)
}
}
/**
* 设置重新加载提示文字颜色
*
* @param colors
*/
fun setReloadTextColor(colors: ColorStateList) {
if (tvReloadMsg != null) {
tvReloadMsg!!.setTextColor(colors)
}
}
/**
* 设置页面图片
*
* @param resId
*/
fun setReloadImgResource(@DrawableRes resId: Int) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
this.reloadImage = mContext!!.getDrawable(resId)
} else {
this.reloadImage = mContext!!.resources.getDrawable(resId)
}
if (ivReloadImg != null) {
ivReloadImg!!.setImageResource(resId)
}
}
/**
* 设置页面图片
*
* @param reloadImage
*/
fun setReloadImg(reloadImage: Drawable) {
this.reloadImage = reloadImage
if (ivReloadImg != null) {
ivReloadImg!!.setImageDrawable(reloadImage)
}
}
/**
* 设置加载提示文字
*
* @param resId
*/
fun setLoadingText(resId: Int) {
this.loadingText = mContext!!.getString(resId)
if (tvLoadingMsg != null) {
tvLoadingMsg!!.text = this.loadingText
}
}
/**
* 设置加载提示文字
*
* @param loadingText
*/
fun setLoadingText(loadingText: String) {
this.loadingText = loadingText
if (tvLoadingMsg != null) {
tvLoadingMsg!!.text = this.loadingText
}
}
/**
* 显示此视图
*/
fun show() {
this.visibility = View.VISIBLE
}
/**
* 隐藏此视图
*/
fun hide() {
this.visibility = View.GONE
}
/**
* 设置重新加载监听事件
*
* @param listener
*/
fun setOnReloadListener(listener: OnReloadListener) {
this.onReloadListener = listener
}
interface OnReloadListener {
fun onReload()
}
companion object {
const val TYPE_EMPTY = 0 // 页面为空,没有数据时展示
const val TYPE_LOADING = 1 // 正在加载视图
const val TYPE_RELOAD = 2 // 加载失败,显示重新加载视图
}
10、ShapeImageView
package:cn.onestravel.library.kotlin.base.view
自定义矩形和圆形ImageView,实现带边框的圆角矩形ImageView或圆形ImageVIew
viewShape的值为:
值 | 说明 |
---|---|
SHAPE_REC | 矩形ImageView |
SHAPE_CIRCLE | 圆形ImageView |
SHAPE_OVAL | 椭圆ImageView |
/**
* 设置ImageView的形式,圆角矩形,圆形,或椭圆
**/
var shape = SHAPE_REC: Int
get() = shape
set(shape) {
this.shape = shape
invalidate()
}
/**
* 设置ImageView边框颜色
**/
var borderColor: Int
get() = mBorderColor
set(mBorderColor) {
this.mBorderColor = mBorderColor
mBorderPaint.color = mBorderColor
invalidate()
}
/**
* 设置ImageView的圆角
**/
var roundRadius: Float
get() = mRoundRadius
set(mRoundRadius) {
this.mRoundRadius = mRoundRadius
invalidate()
}
/**
* 设置ImageView的边框宽度
**/
fun setBorderSize(mBorderSize: Int) {
this.borderSize = mBorderSize.toFloat()
mBorderPaint.strokeWidth = mBorderSize.toFloat()
initRect()
invalidate()
}
/**
* 设置ImageView的图片资源
**/
override fun setImageResource(resId: Int) {
super.setImageResource(resId)
mBitmap = ImageUtils.getBitmapFromDrawable(drawable)
setupBitmapShader()
}
/**
* 设置ImageView的Drawable
**/
override fun setImageDrawable(drawable: Drawable?) {
super.setImageDrawable(drawable)
mBitmap = ImageUtils.getBitmapFromDrawable(drawable)
setupBitmapShader()
}
二、采用RxJava+Retrofit架构封装的关于Http请求以及生命周期处理的文件介绍
1、BaseRxActivity
package:cn.onestravel.library.kotlin.rxrequest.activity
继承自BaseActivity ,针对RxJava处理了相对应的生命周期,同时拥有BaseActivity的所有特性。
生命周期处理:
abstract class BaseRxActivity : BaseActivity(), LifecycleProvider<ActivityEvent> {
private val lifecycleSubject:BehaviorSubject<ActivityEvent> = BehaviorSubject.create()
@CheckResult
override fun lifecycle(): Observable<ActivityEvent> {
return lifecycleSubject.hide()
}
@CheckResult
override fun <T> bindUntilEvent(event: ActivityEvent): LifecycleTransformer<T> {
return RxLifecycle.bindUntilEvent(lifecycleSubject, event)
}
@CheckResult
override fun <T> bindToLifecycle(): LifecycleTransformer<T> {
return RxLifecycleAndroid.bindActivity(lifecycleSubject)
}
@CallSuper
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
lifecycleSubject.onNext(ActivityEvent.CREATE)
}
@CallSuper
override fun onStart() {
super.onStart()
lifecycleSubject.onNext(ActivityEvent.START)
}
@CallSuper
override fun onResume() {
super.onResume()
lifecycleSubject.onNext(ActivityEvent.RESUME)
}
@CallSuper
override fun onPause() {
lifecycleSubject.onNext(ActivityEvent.PAUSE)
super.onPause()
}
@CallSuper
override fun onStop() {
lifecycleSubject.onNext(ActivityEvent.STOP)
super.onStop()
}
@CallSuper
override fun onDestroy() {
lifecycleSubject.onNext(ActivityEvent.DESTROY)
super.onDestroy()
}
}
2、BaseRxListActivity
package:cn.onestravel.library.kotlin.rxrequest.activity
继承自BaseListActivity ,针对RxJava处理了相对应的生命周期,同时拥有BaseListActivity下拉刷新,上拉加载的所有特性。
3、BaseRxFragment
package:cn.onestravel.library.kotlin.rxrequest.fragment
继承自BaseFragment ,针对RxJava处理了相对应的生命周期,同时拥有BaseFragment的所有特性。
生命周期处理:
abstract class BaseRxFragment : BaseFragment(), LifecycleProvider<FragmentEvent> {
private val lifecycleSubject:BehaviorSubject<FragmentEvent> = BehaviorSubject.create()
override fun lifecycle(): Observable<FragmentEvent> {
return lifecycleSubject.hide()
}
@CheckResult
override fun <T> bindUntilEvent(event: FragmentEvent): LifecycleTransformer<T> {
return RxLifecycle.bindUntilEvent(lifecycleSubject, event)
}
@CheckResult
override fun <T> bindToLifecycle(): LifecycleTransformer<T> {
return RxLifecycleAndroid.bindFragment(lifecycleSubject)
}
@CallSuper
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
lifecycleSubject.onNext(FragmentEvent.CREATE)
}
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
lifecycleSubject.onNext(FragmentEvent.CREATE_VIEW)
return super.onCreateView(inflater, container, savedInstanceState)
}
@CallSuper
override fun onStart() {
super.onStart()
lifecycleSubject.onNext(FragmentEvent.START)
}
@CallSuper
override fun onResume() {
super.onResume()
lifecycleSubject.onNext(FragmentEvent.RESUME)
}
@CallSuper
override fun onPause() {
lifecycleSubject.onNext(FragmentEvent.PAUSE)
super.onPause()
}
@CallSuper
override fun onStop() {
lifecycleSubject.onNext(FragmentEvent.STOP)
super.onStop()
}
override fun onDestroyView() {
lifecycleSubject.onNext(FragmentEvent.DESTROY_VIEW)
super.onDestroyView()
}
@CallSuper
override fun onDestroy() {
lifecycleSubject.onNext(FragmentEvent.DESTROY)
super.onDestroy()
}
}
4、BaseRxListFragment
package:cn.onestravel.library.kotlin.rxrequest.fragment
继承自BaseListFragment ,针对RxJava处理了相对应的生命周期,同时拥有BaseListFragment下拉刷新,上拉加载的所有特性。
5、BaseObserver<T: ResponseResult>
package:cn.onestravel.library.kotlin.rxrequest.common
RxJava+Retrofit 请求的观察者,返回特定数据结构的数据,并进行相应的处理。
具体实现如下:
/**
* @name cn.onestravel.library.kotlin.rxrequest.common.BaseObserver
* @description 请求返回结果,返回json数据必须符合 {"code":"0000","msg":""}
* @createTime 2018/12/12 17:00
* @author onestravel
* @version 1.0.0
*/
abstract class BaseObserver<T : ResponseResult> : Observer<T> {
/**
* 请求开始 处理基本的loading框的显示等
*
* @param d
*/
fun onStart(d: Disposable) {
Log.e(
TAG,
"===========单个接口请求开始========="
)
}
/**
* 此方法必须实现
*
* @param result 请求成功的结果
*/
abstract fun onSuccess(result: T)
/**
* 请求失败
*
* @param code 错误码
* @param msg 错误提示语
*/
fun onFailure(code: String, msg: String?) {
Log.e(
TAG,
"接口请求失败===code = " + code + "errorMsg =" + msg
)
}
/**
* 请求都完成时之行此方法
*/
fun onFinish() {
}
override fun onSubscribe(d: Disposable) {
onStart(d)
}
override fun onNext(result: T) {
if (BaseResponse.REQUEST_OK == result.code) {
onSuccess(result)
Log.i(TAG, "请求成功responseBody====" + JSON.toJSONString(result))
} else {
onFailure(result.code, result.msg)
}
}
override fun onError(e: Throwable) {
var errorMsg = ""
var errorCode = 0
if (e is HttpException) {
val httpException = e as HttpException
errorCode = httpException.response().code()
if (404 == errorCode || 500 == errorCode) {
errorMsg = "请求异常,请稍候重试!"
} else {
}
} else {
//todo 设置固定的错误码及错误提示
}
onFailure(errorCode.toString(), errorMsg)
}
override fun onComplete() {
onFinish()
}
companion object {
private val TAG = "request"
}
}
BaseResponse:
/**
* @name cn.onestravel.library.kotlin.rxrequest.common.BaseResponse
* @description 请求返回结果数据基类
* @createTime 2018/12/12 17:00
* @author onestravel
* @version 1.0.0
*/
open class BaseResponse(val code: String = "0000", val msg: String = ""): Serializable {
companion object {
val REQUEST_OK = "0000" //请求成功的code码
val REQUEST_ERROR = "-1" //请求失败的code码
}
}
ResponseResult:
/**
* @name cn.onestravel.library.kotlin.rxrequest.common.ResponseResult
* @description 请求返回结果数据 符合 {"code":"0000","msg":"","data":{},"datas":[]} 的基类
* @createTime 2018/12/12 17:00
* @author onestravel
* @version 1.0.0
*/
class ResponseResult :BaseResponse(), Serializable
6、BaseObserver1<DATA: Serializable>
package:cn.onestravel.library.kotlin.rxrequest.common
RxJava+Retrofit 请求的观察者,返回特定数据结构的数据,并进行相应的处理。
具体实现如下:
/**
* @name cn.onestravel.library.kotlin.rxrequest.common.BaseObserver
* @description 请求返回结果,返回json数据必须符合 {"code":"0000","msg":"","data":{},"datas":[]},data 和 datas 的数据 bean 相同
* @createTime 2018/12/12 17:00
* @author onestravel
* @version 1.0.0
*/
abstract class BaseObserver1<DATA : Serializable> : Observer<ResponseResult1<DATA>> {
/**
* 请求开始 处理基本的loading框的显示等
*
* @param d
*/
fun onStart(d: Disposable) {
Log.e(
TAG,
"===========单个接口请求开始 =========="
)
}
/**
* 此方法必须实现
*
* @param result 请求成功的结果
*/
abstract fun onSuccess(result: ResponseResult1<DATA>)
/**
* 请求失败
*
* @param code 错误码
* @param msg 错误提示语
*/
fun onFailure(code: String, msg: String?) {
Log.e(
TAG,
"接口请求失败============code = " + code + "errorMsg =" + msg )
}
/**
* 请求都完成时之行此方法
*/
open fun onFinish() {
}
override fun onSubscribe(d: Disposable) {
onStart(d)
}
override fun onNext(result: ResponseResult1<DATA>) {
if (BaseResponse.REQUEST_OK == result.code) {
onSuccess(result)
Log.i(TAG, "请求成功responseBody====" + JSON.toJSONString(result))
} else {
onFailure(result.code, result.msg)
}
}
override fun onError(e: Throwable) {
var errorMsg = ""
var errorCode = 0
if (e is HttpException) {
val httpException = e as HttpException
errorCode = httpException.response().code()
if (404 == errorCode || 500 == errorCode) {
errorMsg = "请求异常,请稍候重试!"
} else {
}
} else {
//todo 设置固定的错误码及错误提示
}
onFailure(errorCode.toString(), errorMsg)
}
override fun onComplete() {
onFinish()
}
companion object {
private val TAG = "request"
}
}
ResponseResult1:
/**
* @name cn.onestravel.library.kotlin.rxrequest.common.ResponseResult
* @description 请求返回结果数据 符合 {"code":"0000","msg":"","data":{},"datas":[]} 的基类
* @createTime 2018/12/12 17:00
* @author onestravel
* @version 1.0.0
*/
class ResponseResult1<DATA:Serializable>(
val data: DATA?,
val datas: MutableList<DATA>? = ArrayList()
) :BaseResponse(), Serializable
7、BaseObserver2<DATA : Serializable,ITEM:Serializable>
package:cn.onestravel.library.kotlin.rxrequest.common
RxJava+Retrofit 请求的观察者,返回特定数据结构的数据,并进行相应的处理。
具体实现如下:
package cn.onestravel.library.kotlin.rxrequest.common
import android.util.Log
import io.reactivex.Observer
import io.reactivex.disposables.Disposable
import retrofit2.HttpException
import java.io.Serializable
/**
* @name cn.onestravel.library.kotlin.rxrequest.common.BaseObserver2
* @description 请求返回结果,返回json数据必须符合 {"code":"0000","msg":"","data":{},"datas":[]},data 和 datas 的数据 bean 可以不相同
* @createTime 2018/12/12 17:00
* @author onestravel
* @version 1.0.0
*/
abstract class BaseObserver2<DATA : Serializable,ITEM:Serializable> : Observer<ResponseResult2<DATA,ITEM>>, ObserverResult<ResponseResult2<DATA,ITEM>> {
/**
* 请求开始 处理基本的loading框的显示等
*
* @param d
*/
override fun onStart(d: Disposable) {
Log.e(
BaseObserver2.TAG,
"===========单个接口请求开始 =========="
)
}
/**
* 此方法必须实现
*
* @param result 请求成功的结果
*/
abstract override fun onSuccess(result: ResponseResult2<DATA, ITEM>)
/**
* 请求失败
*
* @param code 错误码
* @param msg 错误提示语
*/
override fun onFailure(code: String, msg: String?) {
Log.e(
BaseObserver2.TAG,
"接口请求失败============code = " + code + "errorMsg =" + msg )
}
/**
* 请求都完成时之行此方法
*/
override fun onFinish() {
}
override fun onSubscribe(d: Disposable) {
onStart(d)
}
override fun onNext(baseObject: ResponseResult2<DATA,ITEM>) {
// Log.i("responseBody====",)
if (BaseResponse.REQUEST_OK == baseObject.code) {
onSuccess(baseObject)
} else {
onFailure(baseObject.code, baseObject.msg)
}
}
/**
*
*/
override fun onError(e: Throwable) {
var errorMsg = ""
var errorCode = 0
if (e is HttpException) {
val httpException = e as HttpException
errorCode = httpException.response().code()
if (404 == errorCode || 500 == errorCode) {
errorMsg = "请求异常,请稍候重试!"
} else {
}
} else {
//todo 设置固定的错误码及错误提示
}
onFailure(errorCode.toString(), errorMsg)
}
override fun onComplete() {
onFinish()
}
companion object {
private val TAG = "RequestBaseObserver2"
}
}
ResponseResult2:
/**
* @name cn.onestravel.library.kotlin.rxrequest.common.ResponseResult
* @description 请求返回结果数据 符合 {"code":"0000","msg":"","data":{},"datas":[]} 的基类
* @createTime 2018/12/12 17:00
* @author onestravel
* @version 1.0.0
*/
class ResponseResult2<DATA:Serializable,ITEM:Serializable>(
val data: DATA?,
val datas: MutableList<ITEM>? = ArrayList()
) :BaseResponse(), Serializable
8、BaseLoader
package:cn.onestravel.library.kotlin.rxrequest.loader
公共的Loader,处理observe针对请求进行线程切换
abstract class BaseLoader<S : BaseService> {
protected val mServiceManager: RetrofitServiceManager by lazy { RetrofitServiceManager.INSTANCE }
protected val mService: S by lazy { createService() }
/**
* 创建 Service 实例
*/
abstract fun createService(): S
/**
* 设置Observable的工作线程
* @param observable
* @param <T>
* @return
</T> */
fun <T> observe(observable: Observable<T>): Observable<T> {
return observable.subscribeOn(Schedulers.io())
.unsubscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
}
}
9、BaseService
package:cn.onestravel.library.kotlin.rxrequest.service
所有 Retrofit 请求的 Service 的接口基类,目前只用于规范子类,可声明对应公用方法
10、RetrofitServiceManager
package:cn.onestravel.library.kotlin.rxrequest.service
生成接口service实例的管理类,初始化Retrofit 实例,设置请求相关的一些拦截器、超时时间等配置,定义Http请求的公共URL
/**
* @name cn.onestravel.library.kotlin.rxrequest.service.RetrofitServiceManager
* @description 生成接口实例的管理类
* @createTime 2018/12/12 17:00
* @author onestravel
* @version 1.0.0
*/
class RetrofitServiceManager private constructor() {
private val mRetrofit: Retrofit
init {
val interceptorBuild = HttpCommonInterceptor.Builder()
val logging = HttpLoggingInterceptor()
logging.level = HttpLoggingInterceptor.Level.BODY
val okHttpClientBuild = OkHttpClient.Builder()
okHttpClientBuild.connectTimeout(CONNECTION_TIMEOUT.toLong(), TimeUnit.SECONDS)
.readTimeout(READ_TIMEOUT.toLong(), TimeUnit.SECONDS)
.writeTimeout(WRITE_TIMEOUT.toLong(), TimeUnit.SECONDS)
.addInterceptor(interceptorBuild.build())//拦截器添加公共请求参数
.addInterceptor(RetryInterceptor(2))//重试三次的拦截
.addInterceptor(logging)//请求日志打印
//初始化Retrofit
mRetrofit = Retrofit.Builder()
.baseUrl(BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.client(okHttpClientBuild.build())
.build()
}
/**
* 生成对应接口的实例
*
* @param service
* @param <T>
* @return
</T> */
fun <T:BaseService> create(service: Class<T>): T {
return mRetrofit.create(service)
}
companion object {
val INSTANCE by lazy { RetrofitServiceManager() }
private const val CONNECTION_TIMEOUT = 5
private const val READ_TIMEOUT = 20
private const val WRITE_TIMEOUT = 10
private const val BASE_URL = "http://192.168.1.12:9090/"
}
}
三、采用Mvp架构封装的文件介绍
1、BaseMvpActivity<V : BaseMvpView, P : BaseMvpPresenter<V>>
package:cn.onestravel.library.kotlin.mvp.activity
所有Mvp架构的 Activity 的基类,自BaseActivity ,拥有BaseActivity的所有特性,处理了P层的相关生命周期。
/**
* @name BaseMvpActivity
* @description 所有Mvp架构的 Activity 的基类
* @createTime 2018/12/12 17:00
* @author onestravel
* @version 1.0.0
*/
abstract class BaseMvpActivity<V : BaseMvpView, P : BaseMvpPresenter<V>> : BaseActivity(), BaseMvpView {
private val presenter by lazy { createPresenter() }
private var mLoadingDialog: LoadingDialog? = null
protected abstract fun createPresenter(): P
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
if (presenter == null) {
throw NullPointerException("Presenter is null! Do you return null in createPresenter()?")
}
presenter.onMvpAttachView(this as V, savedInstanceState)
}
override fun onStart() {
super.onStart()
presenter.let {
it.onMvpStart()
}
}
override fun onResume() {
super.onResume()
presenter.let {
it.onMvpResume()
}
}
override fun onPause() {
presenter.let {
it.onMvpPause()
}
super.onPause()
}
override fun onStop() {
presenter.let {
it.onMvpStop()
}
super.onStop()
}
override fun onSaveInstanceState(outState: Bundle?) {
super.onSaveInstanceState(outState)
presenter?.let {
it.onMvpSaveInstanceState(outState)
}
}
override fun onDestroy() {
presenter?.let {
it.onMvpDetachView(false)
it.onMvpDestroy()
}
mLoadingDialog?.let {
it.destroy()
mLoadingDialog = null
}
super.onDestroy()
}
override fun showLoading(content: String?) {
if (mLoadingDialog == null) {
mLoadingDialog = LoadingDialog.getInstance(this)
mLoadingDialog!!.title = content?:"正在加载..."
if (!mLoadingDialog!!.isShowing) {
mLoadingDialog!!.show()
}
}
}
override fun hideLoading() {
mLoadingDialog?.let {
mLoadingDialog!!.dismiss()
}
}
override fun onResponseError(msg: String?) {
msg?.let {
showToast(msg)
}
}
}
2、BaseMvpListActivity<V : BaseMvpView, P : BaseMvpPresenter<V>>
package:cn.onestravel.library.kotlin.mvp.activity
所有Mvp架构的 ListActivity 的基类,自BaseListActivity ,拥有BaseListActivity的所有特性,并且处理了P层的相关生命周期。
3、BaseRxMvpActivity<V : BaseMvpView, P : BaseMvpPresenter<V>>
package:cn.onestravel.library.kotlin.mvp.activity
所有Mvp架构的 采用RxJava+Retrofit 请求的Activity 的基类,继承自BaseRxActivity ,拥有BaseRxActivity的所有特性,并且处理了P层的相关生命周期。
4、BaseRxMvpListActivity<V : BaseMvpView, P : BaseMvpPresenter<V>>
package:cn.onestravel.library.kotlin.mvp.activity
所有Mvp架构的 采用RxJava+Retrofit 请求的带有列表的Activity,继承自BaseRxListActivity ,拥有BaseRxListActivity的所有特性,并且处理了P层的相关生命周期。
5、Fragment 有与前4个Activity功能相同Fragment,就不多做介绍了。
package:cn.onestravel.library.kotlin.mvp.fragment
6、BaseMvpModel
package:cn.onestravel.library.kotlin.mvp.model
Mvp模式中所有Model层的基类,是一个接口,可以声明共同的方法,交由子类去实现。
7、BaseMvpPresenter
package:cn.onestravel.library.kotlin.mvp.presenter
Mvp模式中所有presenter层的基类,是一个接口,声明了presenter层相关的生命周期方法,由子类去实现。
/**
* @name BaseMvpPresenterImpl
* @description 所有界面presenter的接口类
* @createTime 2018/12/12 16:27
* @author onestravel
* @version 1.0.0
*/
interface BaseMvpPresenter<in V : BaseMvpView> {
fun onMvpAttachView(view: V, savedInstanceState: Bundle?)
fun onMvpStart()
fun onMvpResume()
fun onMvpPause()
fun onMvpStop()
fun onMvpSaveInstanceState(savedInstanceState: Bundle?)
fun onMvpDetachView(retainInstance: Boolean)
fun onMvpDestroy()
}
8、BaseMvpPresenterImpl<V: BaseMvpView>
package:cn.onestravel.library.kotlin.mvp.presenter.impl
Mvp模式中所有presenter层的接口的实现类,对presenter层相关的生命周期方法进行实现;并且实现与View层的绑定,持有View层的引用。
/**
* @name BaseMvpPresenterImpl
* @description 所有界面presenter的接口类
* @createTime 2018/12/12 16:27
* @author onestravel
* @version 1.0.0
*/
interface BaseMvpPresenter<in V : BaseMvpView> {
fun onMvpAttachView(view: V, savedInstanceState: Bundle?)
fun onMvpStart()
fun onMvpResume()
fun onMvpPause()
fun onMvpStop()
fun onMvpSaveInstanceState(savedInstanceState: Bundle?)
fun onMvpDetachView(retainInstance: Boolean)
fun onMvpDestroy()
}
9、BaseMvpView
package:cn.onestravel.library.kotlin.mvp.view
Mvp模式中所有View层的接口类,声明了一些View层常用的加载进度显示与隐藏,请求失败提示等公用的方法。
/**
* @name BaseMvpPresenterImpl
* @description 所有界面presenter的接口类
* @createTime 2018/12/12 16:27
* @author onestravel
* @version 1.0.0
*/
interface BaseMvpPresenter<in V : BaseMvpView> {
fun onMvpAttachView(view: V, savedInstanceState: Bundle?)
fun onMvpStart()
fun onMvpResume()
fun onMvpPause()
fun onMvpStop()
fun onMvpSaveInstanceState(savedInstanceState: Bundle?)
fun onMvpDetachView(retainInstance: Boolean)
fun onMvpDestroy()
}
声明:
针对Kotlin项目的一些常用封装,到这里就介绍完了,后面还会增加MVVM模式的一些封装,敬请期待!!
在封装或者介绍过程中,如有什么不正确或者不明白的地方,期待与您进行交流,共同提高!
联系邮件:server@onestravel.cn
鸣谢!!!
网友评论