AACHulk


AACHulk is based on Google’s ViewModel+DataBinding+LiveData+Lifecycles framework, Combining Okhttp + Retrofit + BaseRecyclerViewAdapterHelper + SmartRefreshLayout + ARouter to build a fast development framework, development language is Kotlin, Combined with AACHulkTemplate template development for development, to avoid some tedious operations, to provide development efficiency

Function is introduced

1. Supports the configuration of server address, success code, various timeout periods, various interceptors, Arouter, EventBus, etc

2. Support to customize various abnormal state View replacement

3. Retry if the interface invocation fails

4. Supports the display of various activities and fragments to meet business requirements

5. Support multiple layout adapters

6. Support general-purpose code generation AACHulkTemplate template

Third-party libraries

  1. OkhttpAn HTTP client for Android, Kotlin, and Java
  2. RetrofitSecure HTTP client for Android and Java
  3. BaseRecyclerViewAdapterHelperPowerful and flexible universal adapter
  4. SmartRefreshLayoutAndroid Smart pull-down refresh framework
  5. EventBusThe Event bus for Android and Java simplifies communication between activities, fragments, threads, services, and more. The less code, the better quality
  6. ARouterA routing framework to help Android apps perform componentized transformations

Basis function

1. DataBinding is enabled for the master project

    dataBinding {
        enabled true
    }
Copy the code

2. Add a dependency

Add build. Grade in Project

allprojects {
    repositories {
        maven { url 'https://jitpack.io' }
        google()
        jcenter()
    }
}
Copy the code

Add to build.grade in the main project app

api 'com. Madreain: libhulk: 1.0.0'
Copy the code

3. Inherit HulkApplication and configure related configuration items

Hulkconfig.builder () // Here just select to set a.setretSuccess (buildconfig.code_Success)// a single success response code .setretSuccessList (buildconfig.codelist_Success)//// Multiple requests correspond to different success response code.setBaseurl (buildConfig.base_URL)// Server address SetLogOpen (buildconfig.open_log)// Network log switch. SetArouterOpen (buildconfig.open_arouter)// Switch of Arouter .seteventbusopen (buildconfig.open_eventbus)//EventBus switch.addokhttpinterceptor (RequestHeaderInterceptor()) // RequestHeaderInterceptor .addOkHttpInterceptor( BuildConfig.OPEN_LOG, HttpLoggingInterceptor (). SetLevel (HttpLoggingInterceptor. Level. BODY)) / / okhttp request log switch + message interceptor .addRetCodeInterceptors(SessionInterceptor()) //returnSetRetrofit (apiclient.instance!! .getRetrofit( ApiClient.instance!! .getOkHttpClient( HulkConfig.getOkHttpInterceptors() ) ) )// .build()Copy the code

You can refer to Demo to configure the preceding configuration items

Here you can also configure a unified style according to SmartRefreshLayout related documents, or set it separately, or customize it according to your own project

4. Inherit IRes, and accept the unified data encapsulated by its own project

5. Write ApiService, put the interface

6. Write a common Toolbar(optional) because the Kotlin-Android-Extensions plugin may only use the resource file of its own module, so it is not possible to write the common Toolbar. XML in libhulk for your app. Therefore, you can only write the generic Toolbar.xml in your app project

⚠️ if the big guys have a good way to achieve welcome advice

️🔥️🔥️🔥 AACHulkTemplate template. This template must be used to ensure that the ApiService and tooltool. XML are created, and users can modify the template according to their own projects

Rapid development of

The AACHulkTemplate template is pretty tasty to use. Let’s take a look at your own manual steps, using SingleActivity as an example

1. New SingleActivity inherits BaseActivity

class SingleActivity : BaseActivity<BaseViewModel, ViewDataBinding>() {

    override fun getLayoutId(): Int {
        return R.layout.activity_single
    }

    override fun getReplaceView(): View {
        return layout
    }

    override fun init(savedInstanceState: Bundle?) {

    }

    /**
     * 设置SmartRefreshLayout
     */
    override fun getSmartRefreshLayout(): SmartRefreshLayout? {
        return null
    }

    override fun refreshData() {}}Copy the code

ViewDataBinding will replace the BaseViewModel with an Activity_single.xml binding and will replace the BaseViewModel with the new SingleViewModel inheriting the BaseViewModel

2. Create the corresponding object

@Keep
class SingleData {
    var code: String? = null
    var name: String? = null
}
Copy the code

3. The associated ViewDataBing

Attach an ActivitySingleBinding to activity_single.xml

<? xml version="1.0" encoding="utf-8"? > <layout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools">

    <data>

        <import type="java.util.List" />

        <import type="com.madreain.aachulk.module.single.SingleData" />

        <variable
            name="singleDataS"
            type="List< SingleData>" />

        <variable
            name="singleData"
            type="SingleData" />

    </data>

    <androidx.constraintlayout.widget.ConstraintLayout
        android:id="@+id/single_layout"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:context="com.madreain.aachulk.module.main.MainActivity">

        <include
            android:id="@+id/tbar"
            layout="@layout/toolbar" />

        <androidx.constraintlayout.widget.ConstraintLayout
            android:id="@+id/layout"
            android:layout_width="match_parent"
            android:layout_height="match_parent">

            <TextView
                android:id="@+id/tv"
                android:layout_width="@dimen/dp60"
                android:layout_height="wrap_content"
                android:background="@color/colorPrimary"
                android:text="@{singleData.code,default= 'before interface call'}"
                app:layout_constraintBottom_toBottomOf="parent"
                app:layout_constraintLeft_toLeftOf="parent"
                app:layout_constraintRight_toRightOf="parent"
                app:layout_constraintTop_toTopOf="parent"
                tools:text="Result of interface call" />

        </androidx.constraintlayout.widget.ConstraintLayout>


    </androidx.constraintlayout.widget.ConstraintLayout>
</layout>
Copy the code

4. Create SingleViewModel to inherit BaseViewModel

class SingleViewModel : BaseViewModel<ApiService>() {

    public override fun onStart() {cityList()} demo var result = MutableLiveData<List<SingleData>>() private funcityList() {launchOnlyresult(block = {getApiService().getCityList()}, // Launch the launchOnlyresult(block = {getApiService().getCityList()}, // launch the launchOnlyresult(block = {getApiService().getCityList()}, // launch the launchOnlyresult(block = {getApiService().getCityList()}, // Success = {// success callback result.value = it},type = RequestDisplay.REPLACE
        )
    }
}

Copy the code

5. Replace ViewDataBinding, BaseViewModel ActivitySingleBinding replace ViewDataBinding SingleViewModel replace BaseViewModel

6. Invoke the interface

/ / request interface mViewModel. OnStart () / / interface request data mViewModel change result. Observe (this, the Observer {mBinding!!!!! .singleDataS = it mBinding!! .singleData = it[0] })Copy the code

7. ARoute configuration

Determine whether to configure ARoute for routing control based on your project requirements

@Route(path = "/aachulk/ui/SingleActivity")
Copy the code

At this point, a simple interface call to the data presentation is complete

⚠️⚠️⚠️ Demo with adapter refer to ListActivity

Use the advanced

1. Customize various abnormal state View replacements

In the demo MyVaryViewHelperController, for example, just modify showLoading, other can be modified according to the requirements of their project

class MyVaryViewHelperController private constructor(private val helper: VaryViewHelper) : IVaryViewHelperController {/ / whether the method has been called restore private var hasRestore: Boolean =false

    constructor(replaceView: View) : this(VaryViewHelper(replaceView)) {}

    override fun showNetworkError(onClickListener: View.OnClickListener?) {
        showNetworkError("Network status is abnormal, please refresh and try again", onClickListener) } override fun showNetworkError( msg: String? , onClickListener: View.OnClickListener? ) { hasRestore =false
        val layout = helper.inflate(R.layout.hulk_page_error)
        val againBtn =
            layout.findViewById<Button>(R.id.pager_error_loadingAgain)
        val tv_title = layout.findViewById<TextView>(R.id.tv_title)
        tv_title.visibility = View.GONE
        val tv_msg = layout.findViewById<TextView>(R.id.tv_msg)
        tv_msg.text = msg
        if(null ! = onClickListener) { againBtn.setOnClickListener(onClickListener) } helper.showView(layout) } override fun showCustomView( drawableInt: Int, title: String? , msg: String? , btnText: String? , listener: View.OnClickListener? ) { hasRestore =false
        val layout = helper.inflate(R.layout.hulk_page_error)
        val iv_flag =
            layout.findViewById<ImageView>(R.id.iv_flag)
        val tv_title = layout.findViewById<TextView>(R.id.tv_title)
        val tv_msg = layout.findViewById<TextView>(R.id.tv_msg)
        val againBtn =
            layout.findViewById<Button>(R.id.pager_error_loadingAgain)
        iv_flag.setImageResource(drawableInt)
        if (TextUtils.isEmpty(title)) {
            tv_title.visibility = View.GONE
        } else {
            tv_title.visibility = View.VISIBLE
            tv_title.text = title
        }
        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 fun showEmpty(emptyMsg: String?) { hasRestore =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.text = emptyMsg } helper.showView(layout) } override fun showEmpty( emptyMsg: String? , onClickListener: View.OnClickListener? ) { hasRestore =false
        val layout = helper.inflate(R.layout.hulk_page_no_data_click)
        val againBtn =
            layout.findViewById<Button>(R.id.pager_error_loadingAgain)
        val textView = layout.findViewById<TextView>(R.id.tv_no_data)
        if(! TextUtils.isEmpty(emptyMsg)) { textView.text = emptyMsg }if(null ! = onClickListener) { againBtn.setOnClickListener(onClickListener) // againBtn.setVisibility(View.VISIBLE); Againbtn. visibility = view. GONE againbtn. visibility = view. GONE againBtn.else {
            againBtn.visibility = View.GONE
        }
        helper.showView(layout)
    }

    override fun showLoading() {
        hasRestore = false
        val layout = helper.inflate(R.layout.view_page_loading)
        helper.showView(layout)
    }

    override fun showLoading(msg: String?) {
        hasRestore = false
        val layout = helper.inflate(R.layout.view_page_loading)
        val tv_msg = layout.findViewById<TextView>(R.id.tv_msg)
        tv_msg.text = msg
        helper.showView(layout)
    }

    override fun restore() {
        hasRestore = true
        helper.restoreView()
    }

    override val isHasRestore: Boolean
        get() = hasRestore

}
Copy the code

2. The interceptor

2.1 Request header interceptor

class RequestHeaderInterceptor : @throws (IOException::class) Override fun Intercept (chain: Interceptor.Chain): Response { val request = chain.request() val authorised: Request val headers = Headers.Builder() .add("app_id"."wpkxpsejggapivjf")
            .add("app_secret"."R3FzaHhSSXh4L2tqRzcxWFBmKzBvZz09")
            .build()
        authorised = request.newBuilder().headers(headers).build()
        return chain.proceed(authorised)
    }
}
Copy the code

2.2 Abnormal state response code interceptor

Practical application: It can be applied to users’ mutual kicking in the App

The class SessionInterceptor: IReturnCodeErrorInterceptor {/ / and the related parameters in the interface definition and kick back, and then indoOverride Fun Intercept (returnCode: String?) : Boolean {return "100"= =returnCode
    }

    override fun doWork(returnCode: String? , msg: String?) {}}Copy the code

🌟🌟🌟 recommended by Carson_Ho’s Kotlin: This is a comprehensive & detailed grammar guide for class use

The project address, if you think it is good, welcome to STAR, welcome to give advice, keep learning, keep making progress, your support is the motivation for me to move forward