Android架构发展进化详解

目录
  • 一.MVC架构
    • 1.概述
    • 2.例子
  • 二.MVP架构
    • 1.概述
    • 2.例子
  • 三.MVVM架构
    • 1.概述
    • 2.例子
  • 四.Clean架构
    • 1.概述
    • 2.例子
  • 五.MVI架构
    • 1.概述
    • 2.例子
  • 六.总结
    • 1.从MVC架构到MVI架构
    • 2.从clean code到clean coder
    • 3.MVI架构之后

一.MVC架构

1.概述

MVC架构是第一个应用于Android开发的成熟架构,由Model、View、Controller三部分组成:

  • Model:负责数据的存储及相关逻辑。
  • View:负责界面展示。
  • Controller:负责业务逻辑。

MVC架构将代码逻辑分成了数据逻辑、渲染逻辑、业务逻辑三部分,三部分逻辑分别封装在Model层、View层、Controller层。理想条件下,三者呈单向调用,如下图所示:

但实际上,由于Android中负责页面展示的组件(Activity或Fragment)同时承担了View层和Controller层两部分的职责,导致MVC架构在实际使用中退化。退化后的MVC架构如下图所示:

在一些业务场景中,由于View层与Controller层的逻辑耦合在一起,使得二者可以相互调用,进一步衍生出调用关系更加复杂的MVC架构,如下图所示:

此时的MVC架构仅保持了Model层的独立,而View层和Controller层没有得到有效的隔离。

2.例子

点击按钮从网络获取用户信息,经过解析后展示到界面上。

1)Model层

data class UserInfo(
    var name: String,
    var age: Int,
    var height: Int,
    var weight: Int
)
interface NetResponse<T> {
    fun onSuccess(data: T)
    fun onError(e: Throwable)
}
class NetModel {
    fun getUserInfo(callback: NetResponse<UserInfo>) {
        // 模拟网络获取
        val dataStr = getStringFromNet()
        val info = dataStr.parseJson<UserInfo>()
        return callback.onSuccess(info)
    }
}

2)Controller层

class MainActivity : AppCompatActivity() {
    private val netModel = NetModel()
    // Controller调用Model
    private fun getUserInfo(callback: (UserInfo) -> Unit) {
        netModel.getUserInfo(object : NetResponse<UserInfo> {
            override fun onSuccess(data: UserInfo) {
                callback.invoke(data)
            }
            override fun onError(e: Throwable) {
                callback.invoke(getNetErrorData())
            }
        })
    }
    private fun getNetErrorData(): UserInfo {
        return UserInfo(name = "", age = 0, height = 0, weight = 0)
    }
}

3)View层

class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        btnNet?.setOnClickListener {
            // View调用Controller
            getUserInfo {
                tvName?.text = it.name
                tvAge?.text = it.age.toString()
                tvHeight?.text = it.height.toString()
                tvWeight?.text = it.weight.toString()
            }
        }
    }
}

在MVC架构中,Controller实际上就是对Model代码的封装,如果在btnNet的点击回调中调用getUserInfo方法,则是View调用Controller。如果在点击回调中直接调用netModel的getUserInfo方法,那就变成了View调用Model。

二.MVP架构

1.概述

MVP架构是MVC架构的升级版,由Model、View、Presenter三部分组成:

  • Model:负责数据的存储及相关逻辑。
  • View:负责界面展示。
  • Presenter:负责业务逻辑。

MVP架构也将代码逻辑分成了数据逻辑、渲染逻辑、业务逻辑三部分。与MVC架构不同的是,在MVP架构中,负责业务逻辑的Controller层升级为Presenter层。Presenter层不再像Controller层一样耦合在View层中,而是作为独立的类与View层和Model层进行双向的通信,三者调用关系如下图所示:

MVP架构有效的将View层与Model层隔离,同时,由于Presenter层仅持有View层和Model层的接口,因此对于Presenter层逻辑的测试变得更加的方便。而由于所有的逻辑代码都集中到Presenter层中,因此Presenter层变得比原本的Controller层更臃肿。

2.例子

点击按钮从网络获取用户信息,经过解析后展示到界面上。

1)Model层

data class UserInfo(
    var name: String,
    var age: Int,
    var height: Int,
    var weight: Int
)
interface NetResponse<T> {
    fun onSuccess(data: T)
    fun onError(e: Throwable)
}
class NetModel {
    fun getUserInfo(callback: NetResponse<UserInfo>) {
        // 模拟网络获取
        val dataStr = getStringFromNet()
        val info = dataStr.parseJson<UserInfo>()
        return callback.onSuccess(info)
    }
}

2)Presenter层

class Presenter(private val view: IView) {
    private val model = NetModel()
    fun getUserInfo() {
        model.getUserInfo(object : NetResponse<UserInfo> {
            override fun onSuccess(data: UserInfo) {
                view.setName(data.name)
                view.setAge(data.age)
                view.setHeight(data.height)
                view.setWeight(data.weight)
            }
            override fun onError(e: Throwable) {
                val data = getNetErrorData()
                view.setName(data.name)
                view.setAge(data.age)
                view.setHeight(data.height)
                view.setWeight(data.weight)
            }
        })
    }
    private fun getNetErrorData(): UserInfo {
        return UserInfo(name = "", age = 0, height = 0, weight = 0)
    }
}

3)View层

interface IView {
    fun setName(name: String)
    fun setAge(age: Int)
    fun setHeight(height: Int)
    fun setWeight(weight: Int)
}
class MainActivity : AppCompatActivity(), IView {
    private val presenter = Presenter(this)
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        btnNet?.setOnClickListener {
            presenter.getUserInfo()
        }
    }
    override fun setName(name: String) {
        tvName?.text = name
    }
    override fun setAge(age: Int) {
        tvAge?.text = age.toString()
    }
    override fun setHeight(height: Int) {
        tvHeight?.text = height.toString()
    }
    override fun setWeight(weight: Int) {
        tvWeight?.text = weight.toString()
    }
}

三.MVVM架构

1.概述

MVVM架构最早由微软提出,并在微软的桌面客户端UI框架WPF中实现,由Model、View、ViewModel三部分组成:

  • Model:负责数据的存储及相关逻辑。
  • View:负责界面展示。
  • ViewModel:负责业务逻辑。

MVVM架构是MVP架构的简化版,它同样的解决了View层与Model层的隔离问题。不同于MVP架构中的View层与Presenter层之间的双向通信,MVVM架构采用了一种View层与ViewModel层绑定的方式,当ViewModel层中的UI数据或属性发生变化时,View层的UI会跟随一起变化,这样原本Presenter层中操作View层接口的逻辑通过绑定的方式被简化,层级变得更加轻量,简化后的Presenter层与View层之间只存在数据驱动的关系,Presenter层被简化成了ViewModel层。三个层级的调用关系如下图所示:

在MVVM架构的早期发展中, 开发者们使用谷歌官方的DataBinding框架实现数据与视图的绑定,但DataBinding框架使用复杂,且每当有一处代码需要修改,就会联动修改多处代码。后来,谷歌官方推荐使用Jetpack组件集中的LiveData+ViewModel。通过使用LiveData+ViewModel,大大减少了在使用MVVM架构中模版代码的编写。再后来,为了更好的在协程中使用MVVM架构,以及更方便的编写流式代码,谷歌官方推荐使用StateFlow。

MVVM架构既做到了View层与Model层的隔离,又保证了ViewModel层的简洁不臃肿。View层与ViewModel层的交互完全依赖数据驱动,方便层级的逻辑复用与测试以及多人的协作开发。但同时,由于MVVM架构比MVC架构和MVP架构更抽象,因此在使用时需要编写更多的模版代码。当UI界面复杂时,由于每个UI需要有不同的数据,因此会造成数据过于分散不易维护。

2.例子

点击按钮从网络获取用户信息,经过解析后展示到界面上。

1)Model层

data class UserInfo(
    var name: String,
    var age: Int,
    var height: Int,
    var weight: Int
)
interface NetResponse<T> {
    fun onSuccess(data: T)
    fun onError(e: Throwable)
}
class NetModel {
    fun getUserInfo(callback: NetResponse<UserInfo>) {
        // 模拟网络获取
        val dataStr = getStringFromNet()
        val info = dataStr.parseJson<UserInfo>()
        return callback.onSuccess(info)
    }
}

2)ViewModel层

class NetViewModel : ViewModel() {
    private val model = NetModel()
    private val name = MutableLiveData<String>("")
    private val age = MutableLiveData<Int>(0)
    private val height = MutableLiveData<Int>(0)
    private val weight = MutableLiveData<Int>(0)
    fun getUserInfo() {
        model.getUserInfo(object : NetResponse<UserInfo> {
            override fun onSuccess(data: UserInfo) {
                name.postValue(data.name)
                age.postValue(data.age)
                height.postValue(data.height)
                weight.postValue(data.weight)
            }
            override fun onError(e: Throwable) {
                val data = getNetErrorData()
                name.postValue(data.name)
                age.postValue(data.age)
                height.postValue(data.height)
                weight.postValue(data.weight)
            }
        })
    }
    private fun getNetErrorData(): UserInfo {
        return UserInfo(name = "", age = 0, height = 0, weight = 0)
    }
    fun name(): LiveData<String> = name
    fun age(): LiveData<Int> = age
    fun height(): LiveData<Int> = height
    fun weight(): LiveData<Int> = weight
}

3)View层

class MainActivity : AppCompatActivity() {
    private lateinit var viewModel: NetViewModel
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        viewModel = ViewModelProvider(this).get(NetViewModel::class.java)
        viewModel.name().observe(this, Observer<String> {
            tvName?.text = it
        })
        viewModel.age().observe(this, Observer<Int> {
            tvAge?.text = it.toString()
        })
        viewModel.height().observe(this, Observer<Int> {
            tvHeight?.text = it.toString()
        })
        viewModel.weight().observe(this, Observer<Int> {
            tvWeight?.text = it.toString()
        })
        btnNet?.setOnClickListener {
            viewModel.getUserInfo()
        }
    }
}

四.Clean架构

1.概述

Clean架构由Robert.C.Martin(Bob大叔)提出,最基础的Clean架构由Entities(实体层)、Use Cases(用例层)、Interface Adapters(接口适配层)、Frameworks & Drivers(框架驱动层)四部分组成:

  • Entities:用于封装企业业务规则,指业务的核心数据模型和接口,一般情况下不会发生变化,只有当业务规则改变才会改变实体层。
  • Use Cases:用于封装软件应用的业务规则,包含实现整个应用所需全部功能的用例,通过调用各种实体的规则实现用例的功能。用例层的改变不会影响实体层,同时外部UI与数据库的改变也不会影响到用例层。
  • Interface Adapters:用于将外部数据转换为实体层与用例层需要的数据结构或将实体层与用例层返回的数据转换为外部需要的数据结构。Clean-MVP中Presenter就是在这一层。
  • Frameworks & Drivers:由一些框架与工具组成,如数据库、UI框架等。这层更多的是用于编写技术细节,而不需要考虑业务逻辑。

Clean架构通过规范层级间的单向依赖关系,从而形成一层包裹一层的层级结构。如下图所示:

Clean架构的层级并不是固定的。根据不同的业务特点,Clean架构也可有更多的层级(最少四层)。由此可见,Clean架构并非传统意义上的架构,它更像是一种理念。Clean架构可以与MVC架构、MVP架构、MVVM架构结合形成Clean-MVC架构、Clean-MVP架构、Clean-MVVM架构。谷歌官方借鉴Clean的理念推出Clean-MVVM架构。

Clean架构具有单向依赖、层级分明、数据驱动的优点。因此在Clean架构中,各个层级的代码逻辑更容易被测试,缺陷与问题更容易被定位,代码的可读性得到显著提升。Clean架构的结构十分复杂。它被称为洋葱架构,不仅是因为它层层包裹的结构,也是因为当你意识到需要写多层模版代码时,Clean架构会让你哭泣。同时,Clean架构还存在用例层代码复用率低、急剧增加的用例导致类膨胀的问题。

2.例子

点击按钮从网络获取用户信息,经过解析后展示到界面上。

1)Entities层

data class UserInfo(
    var name: String,
    var age: Int,
    var height: Int,
    var weight: Int
)

2)Use Cases层

interface UseCase<T, R> {
    fun execute(param: T, callback: R)
}
interface UseCaseCallback<T> {
    fun success(data: T)
    fun fail(e: Throwable)
}
class GetUserInfoUseCase : UseCase<Unit, UseCaseCallback<UserInfo>> {
    private val repository = NetRepository()
    override fun execute(param: Unit, callback: UseCaseCallback<UserInfo>) {
        repository.getUserInfo(object : NetResponse<UserInfo> {
            override fun onSuccess(data: UserInfo) {
                callback.success(data)
            }
            override fun onError(e: Throwable) {
                callback.fail(e)
            }
        })
    }
}

3)Interface Adapters层

interface NetResponse<T> {
    fun onSuccess(data: T)
    fun onError(e: Throwable)
}
class NetRepository {
    fun getUserInfo(callback: NetResponse<UserInfo>) {
        // 模拟网络获取
        val dataStr = getStringFromNet()
        val info = dataStr.parseJson<UserInfo>()
        return callback.onSuccess(info)
    }
}
interface IView {
    fun setName(name: String)
    fun setAge(age: String)
    fun setHeight(height: String)
    fun setWeight(weight: String)
}
class Presenter(private val view: IView) : UseCaseCallback<UserInfo> {
    private val getUserInfoUseCase = GetUserInfoUseCase()
    fun getUserInfo() =
        getUserInfoUseCase.execute(Unit, this)
    override fun success(data: UserInfo) {
        view.setName(data.name)
        view.setAge(data.age.toString())
        view.setHeight(data.height.toString())
        view.setWeight(data.weight.toString())
    }
    override fun fail(e: Throwable) {
        val data = getNetErrorData()
        view.setName(data.name)
        view.setAge(data.age.toString())
        view.setHeight(data.height.toString())
        view.setWeight(data.weight.toString())
    }
    private fun getNetErrorData(): UserInfo {
        return UserInfo(name = "", age = 0, height = 0, weight = 0)
    }
}

4)Frameworks & Drivers层

class MainActivity : AppCompatActivity(), IView {
    private val presenter = Presenter(this)
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        btnNet?.setOnClickListener {
            presenter.getUserInfo()
        }
    }
    override fun setName(name: String) {
        tvName?.text = name
    }
    override fun setAge(age: String) {
        tvAge?.text = age
    }
    override fun setHeight(height: String) {
        tvHeight?.text = height
    }
    override fun setWeight(weight: String) {
        tvWeight?.text = weight
    }
}

五.MVI架构

1.概述

MVI架构是MVVM架构的升级版,由Model、View、Intent三部分组成:

  • Model:负责存储视图的数据和状态。
  • View:负责界面的展示。
  • Intent:负责封装与发送用户的操作。

MVI架构在MVVM架构的基础上强调数据的单向流动与状态的集中管理,保证数据的唯一性。在MVVM架构中三者的调用关系如下图所示:

在MVVM架构中,View会调用ViewModel执行具体的逻辑操作。而在MVI架构中,用户对View层的交互会被抽象成Intent。当交互发生时,View会发送对应的Intent到ViewModel中处理,通过Intent隔离View对ViewModel的调用。如下图所示:

在MVVM架构中,ViewModel内部对View的数据与属性的维护是分散的,具体表现为每个View都会有一个Data。而在MVI架构中,这些Data将会被整合在一起,形成统一的State,如下图所示:

在MVI架构中,Model层指的就是State。通过引入State,可以更加方便ViewModel的管理。同时隔离ViewModel对View的调用,如下图所示:

这样,原本在MVVM架构中由于双向绑定引起的代码耦合问题,在MVI架构中通过引入Intent与State得以解决。同时,架构整体的数据流向更加清晰,如下图所示:

在MVI架构中,通过状态集中管理减少了模版代码。通过数据单向流动保证了数据流向的一致性,开发者可以更方便的对状态进行跟踪与调试。MVI也存在着一些问题,由于状态集中管理,当页面功能复杂时,State易膨胀。每次更新状态时,都需要更新整体的状态,对内存有一定开销,而且不支持局部刷新。

2.例子

点击按钮从网络获取用户信息,经过解析后展示到界面上。

1)Model层

data class PageState(
    val response: PageResponse = PageResponse.Default,
    val userInfo: UserInfo = UserInfo()
)
sealed class PageResponse {
    class Success<T>(data: T) : PageResponse()
    class Fail(e: Throwable) : PageResponse()
    object Loading : PageResponse()
    object Default : PageResponse()
}
data class UserInfo(
    val name: String = "",
    val age: Int = 0,
    val height: Int = 0,
    val weight: Int = 0
)

2)Intent层

sealed class UserIntent {
    object GetUserInfo : UserIntent()
    object Default : UserIntent()
}

3)ViewModel层

class NetViewModel : ViewModel() {
    private val model = NetRepository()
    private val state = MutableStateFlow(PageState())
    private val intent = MutableStateFlow<UserIntent>(UserIntent.Default)
    init {
        handleUserIntent()
    }
    fun state() =
        state.asStateFlow()
    fun sendIntent(userIntent: UserIntent) =
        viewModelScope.launch { intent.emit(userIntent) }
    private fun handleUserIntent() =
        intent.onEach {
            when (it) {
                is UserIntent.GetUserInfo -> getUserInfo()
                else -> {}
            }
        }.launchIn(viewModelScope)
    private fun getUserInfo() {
        state.value = state.value.copy(response = PageResponse.Loading)
        model.getUserInfo(object : NetResponse<UserInfo> {
            override fun onSuccess(data: UserInfo) {
                state.value =
                    state.value.copy(response = PageResponse.Success(data), userInfo = data)
            }
            override fun onError(e: Throwable) {
                state.value =
                    state.value.copy(response = PageResponse.Fail(e), userInfo = getNetErrorData())
            }
        })
    }
    private fun getNetErrorData(): UserInfo {
        return UserInfo(name = "", age = 0, height = 0, weight = 0)
    }
}
interface NetResponse<T> {
    fun onSuccess(data: T)
    fun onError(e: Throwable)
}
class NetRepository {
    fun getUserInfo(callback: NetResponse<UserInfo>) {
        // 模拟网络获取
        val dataStr = getStringFromNet()
        val info = dataStr.parseJson<UserInfo>()
        return callback.onSuccess(info)
    }
}

4)View层

class MainActivity : AppCompatActivity() {
    private lateinit var viewModel: NetViewModel
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        viewModel = ViewModelProvider(this).get(NetViewModel::class.java)
        viewModel.state().onEach {
            when (it.response) {
                is PageResponse.Success<*> -> {
                    tvName?.text = it.response
                    tvAge?.text = it.userInfo.age.toString()
                    tvHeight?.text = it.userInfo.height.toString()
                    tvWeight?.text = it.userInfo.weight.toString()
                }
                else -> {}
            }
        }.launchIn(lifecycleScope)
        btnNet?.setOnClickListener {
            viewModel.sendIntent(UserIntent.GetUserInfo)
        }
    }
}

六.总结

1.从MVC架构到MVI架构

开发者们在早期就意识到数据逻辑、业务逻辑、渲染逻辑要分离,因此引入了MVC架构。但由于Android页面组件的特殊性,导致在实际使用中MVC架构的数据逻辑、业务逻辑与渲染逻辑并没有完美分离,因此产生了MVP架构。MVP架构虽然解决了渲染逻辑与数据逻辑的隔离问题,但由于Presenter层需要与View层和Model层双向通信,导致承载业务逻辑的Presenter层过于臃肿,因此引入了MVVM架构。MVVM架构通过绑定的通信方式,解决了业务逻辑层由于层级间通信而过于臃肿的问题。随着时间推移,绑定框架也在不断发展:从DataBinding到LiveData,再从LiveData到StateFlow。由于当界面UI复杂时,MVVM架构的数据过于分散不易维护,因此产生了MVI架构。MVI架构引入了虚拟的“用户层”,框架的数据流动从“用户层”开始,到“用户层”结束,单方向流动。

2.从clean code到clean coder

纵观Android架构的发展历程,数据逻辑、业务逻辑与渲染逻辑的分离关注点正在从代码逐渐转移到用户,这是一种由“物”向“人”的转变。

这种转变在Clean架构也中有所体现。Clean架构的提出者Bob大叔早年间一直致力于保持代码的整洁与条理清晰,于是出版了《Clean Code》。后来,经过探索研究发现,想要保持代码的“干净”,最重要的还是要提升开发者的自身素质,于是诞生了《 The Clean Coder》。Clean架构通过复杂细致的分层设计,规范每个层级的功能,通过依赖关系保证了代码的整洁。但每层内代码的整洁,仍然需要开发者通过代码素养来保证。只有保持每一层代码的整洁,整体代码才能整洁。

3.MVI架构之后

谷歌官方最早推荐开发者使用MVVM架构,在MVI架构推出后,转而推荐使用MVI架构。那么,在MVI架构之后的下一个主流框架又将是什么呢?这一点恐怕无人知晓。但通过分析可以发现,谷歌官方推荐使用MVI架构,本质上是在推荐状态集中管理和单向数据流动的开发思想,而这一开发思想正好是响应式编程的基础。因此可以合理预测下一个主流架构可能就是某个响应式框架。谷歌官方这几年也一直在开发响应式开发框架Compose,但Compose框架在未来能否取代MVI框架仍然是个未知数。

到此这篇关于Android架构发展进化详解的文章就介绍到这了,更多相关Android架构内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • Android应用架构思想分析

    算算日子,工作刚好三年了.这篇开始,鄙人就要向着各种以前想起来就头大的方向努力前进了.作为在Android应用层搬砖多年的民工,首篇我想谈谈自己对架构思想的一些看法.如有不妥,还请拍砖. 盖楼的故事(虚构) 有一块地,两个区域,开发商分别让两个包工头负责开发. 包工头A办事干净利落,甩开膀子就开工了.为了省钱雇了一个全能的工人,他既要去采购盖房的材料,又要用这些材料盖房子.起初底层屋子结构简单,还能应付得来,到了后面复杂的设计需求时,忙的不可开交,经常精疲力尽,阻断了盖房子的进程,使得老板很是不

  • Android Jetpack架构组件 ViewModel详解

    前言 前面两篇文章我们已经学习了Lifecycle和DataBind,本篇文章我们来学习Jetpack系列中比较重要的ViewModel,Jetpack的很多很多组件都是搭配使用的,所以单独的知识点可能会有些"无意义"但却是我们项目实战的基础! ViewModel的使用 ViewModel类旨在以注重生命周期的方式存储和管理界面相关的数据.ViewModel类让数据可在发生屏幕旋转等配置更改后继续存在.这句话很好理解,还记得我们在讲解Lifecycle的时候 举的例子吗,我们还是使用那

  • Android 架构之数据库框架搭建

    目录 1.先创建对应相关操作的注解 1.1 bTable 标识表 1.2 DbPrimaryKey 标识主键 1.3 DbFiled 标识成员属性 2.创建对应表操作类Dao层 2.1 建 待实现的基层 IBaseDao 2.2 建已实现的基层 BaseDao 2.3 建对应model 的Dao层 3.创建数据库工厂 4.创建对应model 5.最终使用 前言: 你还在苦恼的写SQL么?你还在为数据库升级而烦恼么?你还在因查询数据而写繁琐不可用的代码么? 在这,这些都将不复存在!在本篇中,将会让

  • Android登录代码MVP架构详解

    登录代码MVP架构的具体实现,分享给大家. MainActivity.java public class MainActivity extends AppCompatActivity implements View.OnClickListener, Mvp.fff { private EditText mUsername; private EditText mPassword; private Button login; private ProgressDialog mProgressDialo

  • 浅谈Android官方MVP架构解读

    综述 对于MVP (Model View Presenter)架构是从著名的MVC(Model View Controller)架构演变而来的.而对于Android应用的开发中本身可视为一种MVC架构.通常在开发中将XML文件视为MVC中的View角色,而将Activity则视为MVC中的Controller角色.不过更多情况下在实际应用开发中Activity不能够完全充当Controller,而是Controller和View的合体.于是Activity既要负责视图的显示,又要负责对业务逻辑的

  • Android Jetpack架构组件Lifecycle详解

    前言 Lifecycle是Jetpack架构组件中用来感知生命周期的组件,使用Lifecycles可以帮助我们写出和生命周期相关更简洁更易维护的代码. 生命周期 生命周期这个简单而又重要的知识相信大家早已耳熟能详.假设我们现在有这样一个简单需求: 这个需求只是一个实例,在真实的开发中当然不可能有这样的需要: 在Activity 可见的时候,我们去做一个计数功能,每隔一秒 将计数加1 ,当Activity不可见的时候停止计数,当Activity被销毁的时候 将计数置为0 OK,So easy~ ,

  • Android 生命周期架构组件使用方法

    Support Library 26.1+ 直接支持生命周期架构组件.使用该组件,Android 生命周期的梦魇已经成为过去.再也不用担心出现 Can not perform this action after onSaveInstanceState 这样的异常了. 笔者封装了一个简化使用该组件的辅助类,大约 70 行代码: public class LifecycleDelegate implements LifecycleObserver { private LinkedList<Runna

  • Android 架构之数据库框架升级

    目录 1.备份原数据库File文件 2.数据库升级XML编写 updateXml.xml 3.创建XML解析器 3.1 对应工具类 DomUtils.class 3.2 对应XML的实体类 4.万事俱备只欠东风: UpdateManager.class 前言: 上一篇讲解了Android 架构之数据框架搭建 ,里面含有数据库最基础的增删改查功能,不过只考虑了单数据库,开发者可以举一反三按照对应思路设计多数据库架构. 在本篇里,将会讲解令开发者比较头疼的数据库升级. 话不多说,先来看代码效果,看看

  • Android分包MultiDex策略详解

    1.分包背景 这里首先介绍下MultiDex的产生背景. 当Android系统安装一个应用的时候,有一步是对Dex进行优化,这个过程有一个专门的工具来处理,叫DexOpt.DexOpt的执行过程是在第一次加载Dex文件的时候执行的.这个过程会生成一个ODEX文件,即Optimised Dex.执行ODex的效率会比直接执行Dex文件的效率要高很多. 但是在早期的Android系统中,DexOpt有一个问题,DexOpt会把每一个类的方法id检索起来,存在一个链表结构里面.但是这个链表的长度是用一

  • Android系统对话框使用详解(最详细)

    在实际应用开发中,用到系统对话框中的情况几乎是没有的.按开发流程来说,UI工程师都会给出每一个弹窗的样式,故而在实际开发中都是自定义弹窗的. 即使用到的地方不多,但是我们也是需要了解并且能熟练的运用它,下面为大家奉上各种系统对话框的实现. 目录 一.系统对话框的几种类型与实现 在项目的实际开发中,用到的系统对话框几乎是没有的.原因大概包含以下几点: 样式过于单一,不能满足大部分实际项目中的需求. 对话框的样式会根据手机系统版本的不同而变化.不能达到统一的样式. 能实现的功能过于简单. 在这里先附

  • Android HandlerThread使用方法详解

    Android HandlerThread使用方法详解 HandlerThread 继承自Thread,内部封装了Looper. 首先Handler和HandlerThread的主要区别是:Handler与Activity在同一个线程中,HandlerThread与Activity不在同一个线程,而是别外新的线程中(Handler中不能做耗时的操作). 用法: import android.app.Activity; import android.os.Bundle; import androi

  • InnoDb 体系架构和特性详解 (Innodb存储引擎读书笔记总结)

    后台线程 •Master Thread 核心后台线程,主要负责将缓冲池的数据异步刷新到磁盘.例如脏页的刷新,插入缓冲的合并,undo 页的回收等. 每秒一次的操作: 1.日志缓冲刷新到磁盘,即使该事务还没有提交.该操作总是会发生,这个就是为了再大的事务,提交时间都很短. 2.当IO压力很小时(1s内发生的IO次数小于5% innodb_io_capacity)合并5% innodb_io_capacity 的插入缓冲. 3.当脏页比例大于 innodb_max_dirty_pages_cnt,

  • Android中menu使用详解

    Menu(菜单)是Android中一定会使用的模块,每个Android项目都会用到Menu来给用户起到选择和导航的作用,提升用户体验,下面通过本文给大家分享android 中menu使用,需要的朋友一起看看吧 很多activity界面中都存在一个菜单栏,就是点击右上角的一个按钮的时候会出现一个下拉列表差不多的东西,这个功能的实现其实只需要下面的两步,每一个activity都可以拥有自己独一无二的menu,具体的格式可以自己进行定义,详细的创建步骤如下 ①在res下的menu中创建file_men

  • Android xml解析实例详解

    Android  xml解析实例详解 实现效果图: XmlActivity package com.Android.xiong.gridlayoutTest; import android.app.Activity; import android.content.res.XmlResourceParser; import android.graphics.Color; import android.graphics.Typeface; import android.os.Bundle; impo

  • Android AOP注解Annotation详解(一)

    Android 注解Annotation 相关文章: Android AOP注解Annotation详解(一) Android AOP之注解处理解释器详解(二) Android AOP 注解详解及简单使用实例(三) Android AOP 等在Android上应用越来越广泛,例如框架ButterKnife,Dagger2,EventBus3等等,这里我自己总结了一个学习路程. - Java的注解Annotation - 注解处理解析器APT(Annotation Processing Tool)

  • Android Tab 控件详解及实例

    Android Tab 控件详解及实例 在桌面应用中Tab控件使用得非常普遍,那么我们经常在Android中也见到以Tab进行布局的客户端.那么Android中的Tab是如何使用的呢? 1.Activity package com.wicresoft.activity; import com.wicresoft.myandroid.R; import android.app.TabActivity; import android.os.Bundle; import android.util.Lo

随机推荐

其他