2、MVP架构

在MVC框架中套在Android上并不适用,会导致V层和C层代码越来越多,如果在处理复杂的逻辑时,在Activity中(V层)中代码成千上万行,会导致V层越来越臃肿,于是开始剥离V层和C层的代码。

开始将大量的逻辑代码抽取到P层,于是就演化出了MVP架构

View:Activity、Fragment

Presenter: 逻辑层

Model: 数据处理层

在MVP架构中,设计到的内容是通过调用逻辑层的方法和更新UI

那么如何调研逻辑层的方法,如何通知UI更新呢?

首先:View层持有Presenter的引用或者管理类管理Presenter,因此,在View层可以直接拿到Presenter,所以在View层可以直接通过Presenter调用里面的方法

其次:在View层获取/创建Presenter的时候,需要在Presenter中需要注册View层的引用,把接口给到Presenter,这样在P层的逻辑处理中,可以通过接口回调通知UI进行更新

最后,Presenter层持有Model对象,通过Model层去拿数据,隔离了V层和M层,实现了解耦

优点:

剥离了V层C层,实现了解耦,解决了Activity(V层)中代码过于臃肿的问题

缺点:

  1. 更新UI时需要注意线程(P层处理Model层的数据时一般在异步线程,而更新UI需要在主线程)、UI控件的更新有可能在在操作时已经销毁了(需要在用户可视的生命周期范围内进行更新数据)  比如在请求一个数据时,因为是耗时操作,当数据回来时,用户可能将当前的界面关掉了。这个时候更新UI需要判断控件是否存在
  2. 在多个地方使用到同一个Presenter时,可能会存在一些用不上的接口,但还是要去实现,造成了代码的臃肿

测试代码:

逻辑层接口方法:

package com.example.jetpackbysob.mvptest.palyertest

/**
 * Project_name:JetPackBySob
 * Created by:ChenFuXu.
 * Date: 2022/4/30 16:29
 */
interface IPlayerPresenter {
    fun registerViewCallback(callback: IPlayerViewCallback)

    fun unRegisterViewCallback(callback: IPlayerViewCallback)

    /**
     * 根据状态进行播放或则暂停
     */
    fun doPlayOrPause()

    /**
     * 播放上一首
     */
    fun playPre()

    /**
     * 播放下一首
     */
    fun playNext()
}

view层接口方法:

package com.example.jetpackbysob.mvptest.palyertest

/**
 * Project_name:JetPackBySob
 * Created by:ChenFuXu.
 * Date: 2022/4/30 11:20
 */
interface IPlayerViewCallback {
    /**
     * 标题改变
     */
    fun onTitleChange(title: String)

    /**
     * 进度改变
     */
    fun onProgressChange(current: Int)

    /**
     * 播放中
     */
    fun onPlaying()

    /**
     * 暂停
     */
    fun onPausePlay()

    /**
     * 封面改变
     */
    fun onCoverChange(cover: String)
}

P层: 

package com.example.jetpackbysob.mvptest.palyertest

/**
 * Project_name:JetPackBySob
 * Created by:ChenFuXu.
 * Date: 2022/4/30 11:14
 * 通过音乐播放器测试mvp的缺点
 *
 * 播放音乐
 * 暂停音乐
 * 上一首
 * 下一首
 * =================
 * 播放的状态:
 * 通知UI改变成播放的状态
 * 通知UI改变进度的状态
 * 上一首,下一首:
 * 通知UI歌曲标题的变化
 * 通知UI歌曲封面的变化
 * 暂停音乐:
 * 更新UI状态为暂停
 *
 */
class PlayerPresenter private constructor() : IPlayerPresenter {
    companion object {
        val instance by lazy {
            PlayerPresenter()
        }
    }

    // 播放状态的枚举类
    enum class PlayState {
        NONE, LOADING, PLAYING, PAUSE
    }

    private val mCallbacks = arrayListOf<IPlayerViewCallback>()
    private var mCurrentPlayState = PlayState.NONE

    override fun registerViewCallback(callback: IPlayerViewCallback) {
        if (!mCallbacks.contains(callback)) {
            mCallbacks.add(callback)
        }
    }

    override fun unRegisterViewCallback(callback: IPlayerViewCallback) {
        mCallbacks.remove(callback)
    }

    override fun doPlayOrPause() {
        if (mCurrentPlayState != PlayState.PLAYING) {
            // 开始播放音乐
            handlerPlayingState()
        } else {
            // 暂停播放
            handlerPauseState()
        }
    }

    // 处理通知UI进行暂停音乐
    private fun handlerPauseState() {
        mCurrentPlayState = PlayState.PAUSE
        mCallbacks.forEach {
            it.onPausePlay()
        }
    }

    // 处理进行通知界面播放音乐
    private fun handlerPlayingState() {
        mCurrentPlayState = PlayState.PLAYING
        for (mCallback in mCallbacks) {
            mCallback.onPlaying()
        }
    }

    /**
     * 播放上一首
     */
    override fun playPre() {
        // 1.拿到上一首歌曲 --> 变更UI,包括通知标题和封面
        handlerTitleChange("七里香")
        handlerCoverChange("七里香")
        // 2.设置给播放器
        // 3.等待播放的回调通知
    }

    /**
     * 播放下一首歌曲
     */
    override fun playNext() {
        // 1.拿到下一首歌曲 --> 变更UI,包括通知标题和封面
        handlerTitleChange("玫瑰花的葬礼")
        handlerCoverChange("玫瑰花")
        // 2.设置给播放器
        // 3.等待播放的回调通知
    }

    private fun handlerCoverChange(cover: String) {
        mCallbacks.forEach {
            it.onCoverChange(cover)
        }
    }

    private fun handlerTitleChange(title: String) {
        mCallbacks.forEach {
            it.onTitleChange(title)
        }
    }
}

V层:

package com.example.jetpackbysob.mvptest.palyertest

import android.os.Bundle
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import com.example.jetpackbysob.R
import kotlinx.android.synthetic.main.activity_player.*

/**
 * Project_name:JetPackBySob
 * Created by:ChenFuXu.
 * Date: 2022/4/30 16:22
 */
class PlayerActivity : AppCompatActivity(), IPlayerViewCallback {
    private val mPlayerPresenter by lazy {
        PlayerPresenter.instance
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_player)
        initPresenter()
        initListener()
    }

    /**
     * 控件设置点击事件
     */
    private fun initListener() {
        play_or_pause.setOnClickListener {
            // 调用presenter层进行播放或者暂停
            mPlayerPresenter.doPlayOrPause()
        }

        // 播放上一首
        play_pre.setOnClickListener {
            mPlayerPresenter.playPre()
        }

        // 播放下一首
        play_next.setOnClickListener {
            mPlayerPresenter.playNext()
        }
    }

    private fun initPresenter() {
        mPlayerPresenter.registerViewCallback(this)
    }

    override fun onDestroy() {
        super.onDestroy()
        mPlayerPresenter.unRegisterViewCallback(this)
    }

    override fun onTitleChange(title: String) {
        play_title.text = title
    }

    override fun onProgressChange(current: Int) {
        TODO("Not yet implemented")
    }

    override fun onPlaying() {
        // 播放中,图标显示暂停
        play_or_pause.text = "暂停"
    }

    override fun onPausePlay() {
        // 暂停中,图标显示播放
        play_or_pause.text = "播放"
    }

    override fun onCoverChange(cover: String) {
        Toast.makeText(this, "封面变化了--> $cover", Toast.LENGTH_SHORT).show()
    }
}

这里的FlowPlayControllerActivity模拟表示在其他页面播放音乐时的悬浮控制框,PlayerActivity为整个音乐的控制界面,实现的方法不仅有切换上下首歌曲,还有控制音乐的播放状态,而在FlowPlayControllerActivity中只需要控制播放状态,不关心切换上下首歌曲,可是因为其实现了IPlayerViewCallback,它就必须也要去实现相应的方法,这是不科学的

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值