preface

Following on from the previous article, ktarmor-MVP plugin is used. We can quickly create basic template code, but when writing business code, we are not familiar with the Ktarmor-MVP framework and do not know how to navigate the magic mech. So this article I start from BaseActivity, introduce the use of KtarMOR-MVP, “deep source code” analysis, take you into ktarmor-MVP.

Activity

The KtarMOR-MVP framework consists of three main activities

  • BaseActivity
  • ToolbarActivity
  • MvpActivity

The inheritance relationship between them is as follows:

MvpActivity > ToolbarActivity > BaseActivity

Then we’ll look at their concrete implementation

BaseActivity

abstract class BaseActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?). {
        super.onCreate(savedInstanceState)

        // Call the initialization window before the interface is initialized
        initWidows()

        if (initArgs(intent.extras)) {
            setContentView(getLayoutId())

            initBefore()
            initView()
            initListener()
            initData()
        } else {
            finish()
        }
    }

    open fun initArgs(bundle: Bundle?).: Boolean = true

    open fun initWidows(a) {}

    abstract fun getLayoutId(a): Int

    open fun initBefore(a) {}

    open fun initView(a) {}

    open fun initListener(a) {}

    open fun initData(a){}}Copy the code

The BaseActivity basic template structure defines the basic Activity initialization methods. You can extend BaseActivity by overwriting the corresponding method. The following is a detailed description of the method:

  • initWidows: In the interface (setContentViewInitialization window method called before initialization
  • initArgs: Initializes the interface parameter method (passing parameters between activities), which returns by defaultTrueDisplay Activity, otherwise return False, do not display Activity.
  • getLayoutId: Initializes the Activity layout
  • initBefore:initView()Before,setContentView()Method after the initialization method.
  • initView: Initializes controller View method.
  • initListener: Initializes the view-related Listener method of the control.
  • initData: Initializes the data method

It can be used in APP startup pages, simple presentation pages, etc., and does not involve Presenter activities

ToolbarActivity

abstract class ToolbarActivity : BaseActivity() {

    var toolbarTitle: String = ""
        set(value) { field = value supportActionBar? .title = value }override fun initView(a) {
        super.initView()
        initToolbar()
    }

    /** * Toolbar id must be toolbar */
    private fun initToolbar(a){ findViewById<Toolbar>(R.id.toolbar)? .let { toolbar -> setSupportActionBar(toolbar) supportActionBar? .let { it.setDisplayHomeAsUpEnabled(true)
                it.setDisplayShowHomeEnabled(true)}}}override fun onOptionsItemSelected(item: MenuItem?).: Boolean {
        when(item? .itemId) {// Display the slider menu
            android.R.id.home -> {
                finish()
                return true}}return super.onOptionsItemSelected(item)
    }
}
Copy the code

ToolbarActivity inherits BaseActivity for displaying toolBars, which are common in projects, so encapsulate the basic use of the Toolbar.

  • Toolbar Title display
  • Toolbar Return key (android.R.id.home).
  • toolbarTitle: You can change the title corresponding to the Toolbar

Introduce the Toolbar control in the Activity’s XML, and the ID must be Toolbar, otherwise the initToolbar initialization method will not be called!!

MvpActivity

abstract class MvpActivity<P : BaseContract.Presenter> : ToolbarActivity(), BaseContract.View {

    lateinit var presenter: P

    override fun initBefore(a) {
        presenter = bindPresenter()
    }

    abstract fun bindPresenter(a): P

    override fun showError(@StringRes msgRes: Int) {
        showError(getString(msgRes))
    }

    override fun showError(msg: String) {
        toast(msg)
        hideLoading()
    }

    override fun showLoading(a) {}

    override fun hideLoading(a) {}

    override fun onDestroy(a) {
        super.onDestroy()

        if (::presenter.isInitialized) {
            presenter.detachView()
        }
    }
}
Copy the code

MvpActivity also inherits ToolbarActivity, implementing basecontract. View and managing the Presenter lifecycle. Subclasses need to implement the bindPresenter() method, passing the corresponding Presenter. Presenter can then be called for subsequent operations.

  • Encapsulates thePresenterInitialize, destroy
  • copyshowError().showLoading().hideLoading()Methods. (Simple toast)

: : presenter. IsInitialized means to determine whether a presenter lazily initialized and prevent uninitialized, throw exceptions. In the future, it may be possible to generate Presenter by reflection via generic T to reduce duplication

Fragment

The implementation of BaseFragment and MvpFragment is similar to that of Activity

Presenter

abstract class BasePresenter<V : BaseContract.View>(view: V) : BaseContract.Presenter{

    val view: V?
        get() = mViewRef.get(a)// View weak reference to interface type
    private var mViewRef = WeakReference(view)

    val presenterScope: CoroutineScope by lazy {
        CoroutineScope(Dispatchers.Main + Job())
    }

    fun launchUI(block: suspend CoroutineScope. () -> Unit, error: ((Throwable) -> Unit)? = null) { presenterScope.launch { tryCatch({ block() }, { error? .invoke(it) ? : view? .showError(it.toString()) }) } }override fun detachView(a) {
        mViewRef.clear()
        // Cancel all coroutines and their children created by presenterScope.
        presenterScope.cancel()
    }
}
Copy the code
  • The bindingViewThe initialization, destruction, using weak reference mode, to prevent memory leaks.
  • launchUIEncapsulate the coroutine, switch to the Main thread method, and tryCatch the exception.
  • presenterScopeIs bound to the corresponding UI interfaceonDestoryMethod to prevent memory leaks.

Model

abstract class BaseModel {

    suspend fun <R> launchIO(block: suspend CoroutineScope. () -> R) = withContext(Dispatchers.IO) {
        block()
    }
}
Copy the code

BaseModel is relatively simple and encapsulates the operation of coroutines switching IO threads.

DB operations may be added later

Retrofit

class MyRetrofitConfig : BaseRetrofitConfig() {

    override val baseUrl: String
        get() = API.BASE_URL
        
    override val readTimeOut: Long
        get() = //TODO

    override val writeTimeOut: Long
        get() = //TODO

    override val connectTimeOut: Long
        get() = //TODO

    override fun initRetrofit(a): Retrofit {
    
        Baseretrofit.init ()
        return Retrofit.Builder()
            .baseUrl(KtArmor.retrofit.baseUrl)
            .addConverterFactory(GsonConverterFactory.create())
            .addCallAdapterFactory(CoroutineCallAdapterFactory())
            .client(KtArmor.retrofit.initOkHttpClient())
            .build()
            
    }

    override fun initOkHttpClient(a): OkHttpClient {
        // You can pass Interceptor to intercept network requests
        return BaseOkHttpClient.init(TokenInterceptor.create())
    }
}
Copy the code

BaseRetrofitConfig (Retrofit) extends the BaseRetrofitConfig class by configuring its own parameters as follows:

  • baseUrl: baseUrl for network requests
  • initRetrofit: Can be returned for initializing Retrofit methodsSet the Retrofit.
    • The default implementationBaseRetrofit.init()
  • initOkHttpClientInitialize the OkHttp method that can be returnedCustomised Okhttp.
    • The default implementationBaseOkHttpClient.init()
    • init()Method can be passed the correspondingInterceptorTo intercept the network.
    • readTimeOut.writeTimeOut.connectTimeOutYou can override the network connection timeout property

SharedPreferences

Ktarmor-mvp encapsulates the basic SharedPreferences operations by proxy.

  • By defining a variable and passingby PreferenceThe agent
  • Transfer of SpkeyAnd the correspondingdefaultValue

For example,

var account by Preference(Key.ACCOUNT, "")
Copy the code

Sp; / / Sp; / / Sp; / / Sp; / / Sp; / / Sp; / / Sp; / / Sp; / / Sp; The following code

account = "123"
Copy the code

tryCatch

        // Traditional tryCatch
        try{
            // TODO
        }catch (e: Exception){
            // TODO 
        }
        
        / / KtArmor - MVP extension
        tryCatch({
            // TODO
        })

        / / KtArmor - MVP extension
        tryCatch({
            // TODO
        }, {
            // TODO
        })
Copy the code

Extension function

  • ToastExtension, do not repeat showToast, multiple clicks will replace
    • support: Context, Activity, Fragment extension
    • Extension parameters:string(or @ StringRes),duration
    • Toasts. Show (xx)
  • sp.dpReciprocal transformation
    • support: Float to Float, Int to Int
  • Log
    • support: string. ShowLog ()
    • The sample:
      "I am the Log".showLog()
      Copy the code
  • R.color.xxx -> Color Int.R.drawable.xxx -> Drawableextension
    • support: Context, View extension
    • The sample:
      val defaultColor: Int = context.getColorRef(R.color.xxx)
      val defaultDrawable: Drawable? = context.getDrawableRef(R.drawable.xxx)
      Copy the code
  • startActivitySee Anko’s startActivity (Fuzhi)
    • support: Context, Fragment extension
    • The sample:
      startActivity<XXXActivity>(key to value)
      Copy the code
  • ViewRelevant extension
    • TextViewextension
      • The sample:
        // Get the text value of the TextView directly
        mTvAccount.str()
        Copy the code
    • View shows the hidden extension
      • The sample:
        mIvImage.visible()
        Copy the code
    • Display, close the soft keyboard extension
      • support: the View, the Activity
      • The sample:
        activity.hideKeyboard()
        Copy the code
  • .

The last

This is all about ktarMOR-MVP. There will be updates to the framework and related documentation.

Again, ktarmor-MVP encapsulates the framework of the basic MVP structure. It is a small but beautiful framework that has all the elements in it. Encapsulate basic functions, small projects, or test projects can be directly used, save time and effort. I hope you enjoy it

Finally, if there is something wrong, hope friends point out.

Kotlin’s Magical Mecha — KtArmor (PART 1)

Kotlin’s Magic Mecha — KtArmor Plugin (part 2)

Ktarmor-mvp source code portal

Thanks for reading, see you next time