前言
由于 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...
创建实体类
通过接口返回的 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,有需要的自取。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。