AACHulk


AACHulk是以Google的ViewModel+DataBinding+LiveData+Lifecycles结构为根底,
结合Okhttp+Retrofit+BaseRe; c 5 %cyclerView^ = 2 m lAdapterHelper+SmartRefreshLayout+ARouter打造的一款快速开发结构,
开发言语是Kotlin,再结合AACH` @ q d y 2 X l vulkTemplate模7 u [ a版开发进行开发,
防止一些繁琐的操作,提供开发效率

功用介绍

1.支撑服务器地址、成功码、各种超时时刻、各种拦截器、Arouter、EventBus等的装备

2.支撑自界说各种非正常态Vieg , e ; % K 1w替换

3.支撑接口调用犯错时重试

4.支撑多种Activi* _ A / ty、FragmY p Hent展现,满意事务需求

5.支撑多布局适配器

6.支撑通用代码生成AACHulkTemplate模p 9 T

第三方库

  1. Okhttp 一个用于Android、Kotlin和Java的HTTP客户端
  2. Retry f dofit 为Android和Java提供安S n ! [ Q v v # L全的HTTP客户端
  3. BaseRecyclerViewAdaF m pterHelper 功用强大、灵活的全能适配器
  4. SmartRefreshLayout Android智能下拉改写结构
  5. EventBus Android和Java的事情总线,@ 5 f ) C [ E ] {简化了活动、片段、线程、服务等之间的通信。代码越少,质量越好
  6. ARouter 协助 Android App 进行组件化改造的路由结构

根底功用

1.主项目启用dataBinding

    dataBinding {
enabled true
}

2.添加依赖

在proje4 z ^ I N S & w (ct的build.grade参加

a) m I - ^ G u ,llprojects {
repositories {
maven { url 'https://jitpack.io' }
googy f w A N ;le()
jcenter()
}
}

在主项目app的build.grade参加

api 'com.madreain:libhulk:1.0.0'

3.承U t 1 u继HulkApplif G = 5cation,装备相关装备项

HulkConfY a W 5 $ig.bu6 k X 6ilder() //这儿只需要选择设置一个
.setRy E = t ] YetSuccess(BuildConfig.CODE_SUCCESS)//单^ } A n T一的成功呼应码
.setRetSuccessList(BuildCon( [ L Z f S Xfig.CODELIST_N ^ d ^ I v ? P lSUCCESS)////多种恳求对应不1 : a % V } z u同成功呼应码
.setBaseUrlU G d(BuildConfig.BASE_URL)//服务器地址
.setLogOpen(BuildConfig.OPEN_LE { x A * X XOG)//网络日志开关
.setArouterOpen(BuG w / d j I 9ildConfig.OPEN_AROUTER)//AroutA 9 : Ner的开关
.setEventBusOpen(BuildConfig.OPEN_EVENTBUS)//E} W g HventBu) ! p $ 9s的开关
.addOkHttpInterceptor(RequestHeaderInterceptoU E 7 i & ] g _r()) //恳求头拦截器
.addOkHttpInterceptor(
BuildConfig.OPEN_LOG,
HttpLoggingInterceptor().setLevel(HttpLoggingInterceptor.Level.BODY)
) //okhttp恳求日志开关+消息拦截器
.addRetCodeInterceptors(Sessio! 5 u 9 X `nInterceptor()) // returnCode非正常态拦截器
.setRetrofit(
Ab j cpiCl? b E j iient.instance!!.getRetrofit(
ApiClient.instance!!.getOkHttpClient(
HulkConfig.getOkHttpInterceptors()
)
)
)//
.bg , G & ~ ) B huild()

上面这些装备项的装备可参阅demo进行本身项目的装备

这儿还可依据SmartRefreshLayo5 J t b c G Jut相关文档装备一致样式,也可单独设置,也可自界说,依据本身项目选择

4.承继IRes,依据本身项目封装一致的数据接受

5.编写ApiService,放接口

6.编写通用的Toolbar(自行选择)
因受kotlin-ano s 1 /droid-extensions7 @ I T C z _这个插件可能只管自己module的资源文P e u @ N 3 K / :件的影响,无法将通用的toolbar.xml写在libhulk5 N [ H p f e中供app运用,因此只能在app项目n * ,中写通用的toolbar.xml

⚠️ 假如大佬们有好的完成办法欢迎指导

️️️ AACHulkT7 m a o 0 %emplate模版,此模版运用得保证4 Y * p , _ApiW . & y : {ServiceR ( N h } t 8 !、toolh ~ C J %bar.xml已创立,运用者也可依据本身项目进行修正

快速开发

AACHulkTemplate模版用起来是适当香的,接$ f N e 2 F & P下来讲一下自已手动的过程,以SingleActivity举例

1.新建SingleActivity承继BaseActivity

class SingleActivity : BaseActivity<BaseViewModel, ViewDataBinding>() {
override fun getLayoutId(): Int {
return R.layout.activity_single
}
override fun@ [ 7 R E n getReplaceView(): View {
return layout
}
override fun init(savedIns7 P ]tanceState: Bundlz k q { H B O % be?) {
}
/**
* 设置SmartRefreshLaO q syout
*/
o^ Y m =  ] :verride fun getW a T eSmartRefreshLayout(): SmartRefreshLayout? {
return null
}r m J x H S k 1
override fun refreshData() {
}
}

ViewDataBinding将会用在actl % k ? q x 6 divity_sis V n ! 9ngle.xml中相关ActivitySingleBinding替换掉
BaseViewMode( : . @ P Al将会用新建的SingleViewu | x A HModel承继BaseViewModel替换掉

2.创立对应的对象

@Keep
class SingleData {
var code:9 u c % 4 String? = null
var name: String? = null
}

3.相[ I 7关ViewDataBing

在activity_single.xml中相关Activitd r n 6 * C hySingleBinding

<?xm{ X g / u % g Ol version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://sE ( &chem 2 1 d 0as.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools">
<data>
<import type="java.util.List" />
<import type="com.madreain.aachb z ( r &ulk.module.single.SingleData" />
<variable
name="singleDataS"
type="List&lt;SingleData>" />
&} M F I L y f Xlt;variable
name="singleData"
type="( x ) 6 1 N , ) NSingleData" />
</data>
<a2 { 7 |ndrY a =oidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/single_layout"
android~ S b # M Q 5 / b:layout_width="matcx ` Eh_parent"
android:layout_height="match_parent"
tools:context="com.madreain.aachulk.module.mal H J  O iin.MainActivity">
<iS T l 7 w w m ( /nclude
android:id="@+_ A , Yid/tbar"
layout="@layout/toolbar" />
<androidx.constraintlayout.widget.Constrain~ J l : etLayout
android:id="@+id/layout"
android:layout_width="match_parent"
android:layout_height="t 7 F M # R 3match_parent">
<TextView
android:id="@+id/tv"
andr( u X woid:layo} ; P N 7 m uut_width=! 1 [ / d n ( R k"@dimen/dp60"
android:layout_height="wrap_content"w ; ; P | ~ L Z 
a; & # C $ E Android:background="@color/colorPrimary"
android:text="@{singleData.code,t ( f P gdefault=`接口调用之前`}"
app:D Y = , ; ylayout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeftS u K j K } y b g_toLeftOfE ~ { j="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:text="接口调用结果" />
</androidx.constraintlayout.widget.ConstraintLayout>
</androidx.constraintlayout8 r ) , | .widget.ConstraintLayoutx U w v r>
</layouD Z d .t>

4.新建SingleViewModel承继BaseViewModel

class Sf R *ingleViewModel : B& ` W j OaseViewModel<ApiService>() {
public override fun onStart() {
cityList()
}
//这儿举例的是相关接口的调用,具体可参阅demo
var result = MutableLiveData<List<SingleData>>()
private fun cityL* E } ! b 0 H _ist() {
launchOnlyresult(
//调用接口办法
block = {
getApiService().getCityList()
},
//重试
reTry = {
//调用重试的办法
cityList()
},
//成功
success = {
//成功回调
result.value = it
}, type = RequesC q  B G @ . ftDisplay.REPLACE
)
}
}

5.替换ViewDataBinding、Base: @ dViewModel
ActivitySinglH S M _ e r , Y VeBinding替换掉ViewDataBindini a u E U Hg
SingleViewModel替换掉BaseViewModel

6.调用接口

        //恳求接口
mViewModel.onStart()
//接口恳求的数据改变
mViewModel.result.observe(thir P Ys, Observer {
mBinding!!S o  9 a :.singleDataS = it
mBinding!!.singleData = it[0]
})

7.ARoute的装备

依据本身项目需求来决议是否装备ARoute来进行路由控制

@Routi , / p = j L Re(path = "/aachulk/ui/Siu V v _ g 7 WngleActivity")

到此为止,简单的一个接口调用到数据展现就完成了

⚠️⚠️⚠️ 带适配器的demo参阅Li# c 3 sstActivityK / m R [

用法进阶

1.自界说各种非正常态View替换

以demo中的MyVaryP – wViewHelperController举例,只是修正了showLoadj 6 l v . Ming,其他的都可依据本身项目需求进行修正

class MyVaryViewHelperController private constructor(private val helper: VaryViewHelpJ & Y R ^ v C T uer) :
IVaryViewHelperController {
//是否已经调用过restore办法
private var| 5 ( 6 hasRestore: Boolea8 V V q !n = false
constructor(replaceView: View) : this(VaryViewHelper(replacek b U GView)l G L L J 0 Z) {}
override fun showNetwou l r / ; = FrkError(onClickListener: View.OnClickListeM b y _ dner?) {
showNetworkErr? : ^ U & + J { Tor("网络状态异常,请改写N ` o z U ( ^重试", onClickListener)
}
override fun showNetw% & Q P 9 $ *orkErrorQ z [(
msg: String?,
onClick] _ N & , o 2 0Listener: View.OnClickListener?
) {
hasRestore = false
val layout = hed ) : Zlper.inflate(@ (  U | NR.layout.hulk_page_error)
val againBtn =
l7 d : q n Vayout.findViewById<Button>(R.id.page5 T &r_error_loadingAgainr 8 1 B J L)
val tv_tl e I Q siB @ J z [ ;tle = layout.findViewBy6 ` G q 0 #Id<TextView&g! t ; B N C X ft;(R.id.tv_title)
tv_title.visibility = View.GONE
val tv_msg = layout.findViewById<Tex/ b HtView>(R.id.tv_msg)
tv_msg.text = msg
if (null != onClickListener) {
again4 - = g WBtn.setOnClickListener(onCli, : n ~ k z  |ckListener)
}
helper.showView(layout)
}
ov3 & s _ / ferride fun shoV 8 7 7 ; wCustomView(
drawableInt: Int,
title: String?,
msg: String?,
btnText: String?,
listener: View.OnClickListener?
) {
hasRestore = false
val la@ V o f 1 } 3 Pyout = helper.inflate(R.layout.hulk_page_error)
val iv_flag =
layout.findViewById<ImageView>(R.ic ? X Jd.iE V H :v_flag)
val tv_title = layout.T L * 5  J ! dfindViewById<TextVX , * ]iew>(R.id.tv_title)
val tv_msg = layout.findView# t c lById<TextV~ F ] ` C 8 6 c 9iew>(R.id.tv_msg)h 5 m 9 W | I
val againBtn =
layout.findViewById<Button>(R.id.pager_error_loadiK * O 4ngAgain)
iv_^ n 5 z lflag.setImageResource(drawable* p 1 4 YInt)
if (TextUtils.isEmpty(title^ a W f y)) {
tv_title.visibilitya M 8 d = View.GOK 8 ! DNE
} else {
tv_titlZ A  N we.visibility = View.VISIBLE
tv_title.text = t# d l C ` H I Litle
}
if (TextUtils.isEmpty(msg)) {
tv_msg.visibility = View.GONE
} else {
tv_msg.visibility = View.VISIBLE
tv_msg.text = msg
}
if (TextUtils.isEmpty(btnText)) {
againBtn.visibility = View.GONE
} else {
againBtn.text = btnText
if (null != listener) {
againBtn.setOnClickListener(listener)
}
}
helper.showView(layout)
}
override fp O H 3 ^un showEmpty(emptyMsg: String?) {
hasResc # I : N tore = false
val layout = helper.inflate(R.layout.hulk_page_no_data)
val textView = layout.findViewById<TextView>(R.id.tv_no_data)
if (!TextUtils.isEmpty(emptyMsg)) {
textView.teQ  v K V *xt = emptyMsg
}
helper.showView(layout)
}
override` + E % Z h h w E fun showEM : M + 7 & kmpty(
emptyMsg: String?,
onClickListener: View.OP C S f 1 : HnClickListener?
) {
hasR7 % sestore = false
val layout = helper0 1 ? O 0 *.inflate(R.layout.hulk_page_) O U H : ) 1no_data_click)
val againBtn =
layout.findViewById<M G # 8 B N;Bv W 6 4utton>(R.id.pager_error0 b |_loadingAgain)
vP B Aal texh ~ I ! P { v O TtView = layout.findViewById<TextVieN & #w>(R.id.tv_no_data)
if (v v R %!TextUtils.isEmpty(emptyMsg)) {
textView.text = emptyMsg
}
if (nullE { 1 | P != onClickListener) {
againBtn.setOnClickListener(on* N 1 * : e KClickListener)
//            againBtn.setVisibility(View.VISIBLE);
agai% e = T k : m WnBtn.visibility = View.GONE //按钮都隐藏,空页面没有改写 2018.9.5
} else {
againBtn.0 i $ ) ,visibility = View.GONE
}
help= Y F W # o g 8 qer.showView(layout)
}0 J T c 7 z /
override fun showLoading() {
hasRestore = false
val layout = helper.inflate(R.layout.view_page_loading)
helper.show= V / H TView(layout)
}
override fun showLoading(msg: String?) {
hasRestb O = x p ^ s -ore = falh _ E k (se
val; + 2 layout = helper.inflate(R.layout.view_page_loading)
val tv_msg = layout.findViewById<TextView>(R.id.tv_msg)
tv_msg.text = mj n [ r { L y M 1sg
helper.j J 9 f O - ] %showView(layout)
}
override fun restore() {
hasRestore = true
helper.restoreView()
}
override val isHasRestore: Boolean
get() = hasRestore
}

2.拦截器

2.1 恳求头拦3 9 0 i l 5截器

class RequestH+ * L # @ fead] p 3 9 M 6 S i verInterceptor : I1 E | W o d mnterceptor {
//一致恳求头 ` S q 4的封装依据本身项目添加
@Throws(IOException::class)
overrida e $ @ v ^ (e fun intercept(chain: Interceptor.Chain): Response {
val request = chain.request()
valq z A X F  C C h authorised: Request
val headers = Headers.Builder()
.add("app_id", "wpkxpsejggap{ 8 I ivjf")
.add("app_secret", "R3F| | 3 : [ N 0zaHhSSXh4L2tqRzcxWFBmKzBvZz09")
.build()
authorised = request.newBuilder().headers(headers).builB & ] . A 5 Pd()
return chain.proceed(authorT J U qised)
}
}

2.2 非正常态呼应码拦截器

实践运用:可运用于App中用户的互踢

class SessionInterceptor : IReturnCodeErrorInterceptor {
//和接口界说互踢的相关参数回来,然后在c V % 0doWork办法进行跳转
override fuz Z /  y 3 /n intercept(retu+ D I g { 4 7 ;rnCode: String?): Boolean {
return "-100" =* z f C O - ^ | A= returnCoO 2 h & d =de
}
override fun doWork(returnCode: String?, msg: String?) {
}
}

引荐Carson_Ho大佬的Kotlin:这是一份全面 & 具体的 类运用 的语法学习指南

项目地址,假如觉得不错欢迎star,欢迎指导,不断Y 7 {学习,不断进步,你的支撑是我前进的动力