動態

詳情 返回 返回

Android 架構之 MVC 架構模式 - 動態 詳情

前言

由於 MVP、MVVM、組件化架構的興起,MVC 架構在 android 中的應用變得越來越少,但 MVC 是基礎,理解好 MVC 才能更好的理解 MVP,MVVM,因為後兩種都是基於 MVC 發展而來的。

有些人認為只要架構好 App 就做得好,這種認識其實是錯誤的,架構的本質一定是服務於業務的。每一種架構一定有它的優點和缺點,能適合自己的需求、提高開發效率的架構就是一個好的架構。

例如一個功能相對比較簡單並且後期也不再擴展的 App,完全可以用 MVC 架構來寫,將邏輯全部寫在 Activity 或者 Fragment 裏,如果你用 MVP 這種架構,相應的你就要增加很多類,可能並不能提高你的開發效率。

Android 中 MVC 模式角色説明

在 Android 中項目中,MVC 中的 View 就是我們的 XML,而邏輯就是我們的 Activity 或者 Fragment 等類,他們的分工是明確的,佈局就負責 UI,Activity 就負責邏輯,Model 負責數據的處理。

類型 定義 表現形式
M(Model) 模型層(數據存儲、邏輯處理) Model 類
V(View) 視圖層(UI 展示) 佈局文件、Activity
C(Controller) 控制層(邏輯處理) Activity

MVC 實例講解

我相信 MVC 架構大家都知道,理論部分我就不講那麼多了,我們通過一個實例來講解 MVC 架構的具體實現。

這個實例的整體功能非常簡單,就是利用 Okhttp 請求一個 url,然後利用 Gson 解析數據,Glide 顯示圖片,RecyclerView 顯示列表,實例效果如下所示,這裏我使用的 API 是從乾貨集中營 上找的,API 是:https://gank.io/api/v2/data/c...

image.png

創建實體類

image.png
通過接口返回的 Json 數據,我們就可以創建實體類了,我們可以手動寫,也可以用工具直接生成,如果是用 Java 語言,我推薦用 GsonFormat,如果是用 Kotlin 語言,就用 JsonToKotlinClass 插件來自動生成,因為我是用 Kotlin 語言來寫的,所以我就用 JsonToKotlinClass 來自動生成實體類代碼,如下所示:

data class DataBean(
        val data: List<Data>,
        val page: Int,
        val page_count: Int,
        val status: Int,
        val total_counts: Int
)

data class Data(
        val _id: String,
        val author: String,
        val category: String,
        val createdAt: String,
        val desc: String,
        val images: List<String>,
        val likeCounts: Int,
        val publishedAt: String,
        val stars: Int,
        val title: String,
        val type: String,
        val url: String,
        val views: Int
)

創建 View 層

視圖層就是我們的佈局文件,代碼很簡單,就是一個全屏的 RecyclerView,如下所示:

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout 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"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <androidx.recyclerview.widget.RecyclerView
        android:id="@+id/recyclerView"
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>

</androidx.constraintlayout.widget.ConstraintLayout>

因為我們這裏用了 RecyclerView,所以我們得創建一個 RecyclerView 的適配器,代碼如下所示:

class MvcRecyclerAdapter(private val dataList: List<Data>, private val context: Context) : RecyclerView.Adapter<MvcRecyclerAdapter.ViewHolder>() {

    inner class ViewHolder(view: View) : RecyclerView.ViewHolder(view) {
        val ivImg: ImageView = view.findViewById(R.id.iv_img)
        val tvDesc: TextView = view.findViewById(R.id.tv_desc)
    }

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder =
            ViewHolder(LayoutInflater.from(parent.context).inflate(R.layout.layout_list_item, parent, false))

    override fun onBindViewHolder(holder: ViewHolder, position: Int) {
        val bean = dataList[position]
        Glide.with(context).load(bean.images[0]).into(holder.ivImg)
        holder.tvDesc.text = bean.desc
    }

    override fun getItemCount() = dataList.size
}

這個適配器的代碼也不難,就是 RecyclerView 的基本用法。

我們知道在 MVC 架構中 Activity 也承擔了視圖的作用,Activity 需要去初始化佈局,代碼如下所示:

class MainActivity : AppCompatActivity() {

    private lateinit var adapter: MvcRecyclerAdapter
    private val mList = ArrayList<Data>()
 
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        initView()
    }

    private fun initView() {
        val layoutManager = LinearLayoutManager(this)
        recyclerView.layoutManager = layoutManager
        recyclerView.addItemDecoration(DividerItemDecoration(this, DividerItemDecoration.VERTICAL))
        adapter = MvcRecyclerAdapter(mList, this)
        recyclerView.adapter = adapter
    }

}

創建 Model 層

我們需要將在 Model 層去請求數據,然後通過接口的方式將數據傳遞出去,具體代碼如下所示:

class OkhttpModel {

    private val url = "https://gank.io/api/v2/data/category/Girl/type/Girl/page/2/count/10"
    private lateinit var listener : OnOkhttpListener

    fun getData(mListener: OnOkhttpListener) {
        listener = mListener
        thread {
            val okHttpClient = OkHttpClient()
            val request = Request.Builder().get().url(url).build()
            okHttpClient.newCall(request).enqueue(object : Callback {
                override fun onFailure(call: Call, e: IOException) {
                    listener.onFail(e.message.toString())
                }

                override fun onResponse(call: Call, response: Response) {
                    val responseData = response.body?.string()
                    responseData?.let {
                        val dataBean = Gson().fromJson(responseData, DataBean::class.java)
                        listener.onSuccess(dataBean)
                    }

                }

            })
        }

    }

    interface OnOkhttpListener {
        fun onSuccess(bean: DataBean)
        fun onFail(msg: String)
    }
}

創建 Controller 層

Android MVC 架構中 Controller 層就是 Activity 或者 Fragment,所以我們需要在 Activity 中進行邏輯處理,代碼如下所示:

class MainActivity : AppCompatActivity() {

    private lateinit var adapter: MvcRecyclerAdapter
    private var mList = ArrayList<Data>()

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        initView()
    }

    private fun initView() {
        val layoutManager = LinearLayoutManager(this)
        recyclerView.layoutManager = layoutManager
        recyclerView.addItemDecoration(DividerItemDecoration(this, DividerItemDecoration.VERTICAL))
        adapter = MvcRecyclerAdapter(mList, this)
        recyclerView.adapter = adapter

        loadData()
    }

    private fun loadData() {
        val model = OkhttpModel()

        model.getData(object : OkhttpModel.OnOkhttpListener {
            override fun onSuccess(bean: DataBean) {
                bean.data.forEach {
                    mList.add(it)
                }
                runOnUiThread {
                    adapter.notifyDataSetChanged()
                }
            }

            override fun onFail(msg: String) {
                Toast.makeText(this@MainActivity, msg, Toast.LENGTH_SHORT).show()
            }
        })
    }

}

到此為止,一個完整的 MVP 架構的 App 就做完了。

小結

架構永遠是要服務於業務的,不要為了設計而設計,否則反而會降低開發效率,比如一個 App 中只有幾個文件,完全不需要架構,其實上面的例子完全可以把請求網絡數據的代碼放到 Activity 中,這樣我們就不需要 Model 層。我上面加入 Model 層只是為了演示 MVC 架構模式的寫法。

MVC 模式的優點就是簡單方便,但是它的缺點同樣明顯,隨着界面的增多和邏輯複雜度提高,Activity 會顯得十分臃腫,一個 Activity 可能有幾千行代碼,使得維護起來相當困難。

為了解決上述 MVC 模式存在的問題,分離 Activity 中的 View 層和 Controller 層的職責,從而對 Activity 代碼量進行優化、瘦身,所以就出現了 MVP 模式,這個模式我們下次再講。

源碼

源碼 已上傳到 github,有需要的自取。

Add a new 評論

Some HTML is okay.