MVC架构设计与经典的三层模型

Seek first to understand, then to be understood. —— Daily English

在Android项目中,MVC架构设计由于它较高的耦合性,非常容易造成内存泄漏,从而被MVP,MVVM等架构替代。

但作为一种经典的架构设计,MVC在现在的Android项目中,还有很高的占有率。因此我们很有必要去了解一番。

这篇文章将介绍

  • MVC架构设计和这种模式在Android项目中的体现。
  • Android项目中MVC内存泄漏分析,以及为什么会有MVP的演变。

介绍

初探

MVC架构设计
在这里插入图片描述
MVC流程关系:

  1. View接收到用户的操作
  2. View将用户的操作,交给Controller。
  3. Controller完成具体业务逻辑。
  4. 得到结果封装Model,再进行View更新。

从图可看出:
Controller是作为一个媒介,处于Model和View之间。
Model和View之间有紧密的联系,耦合性偏强。

C层处理的东西过多,违反了面向对象编程思想的单一性原则。

但是我们平常在比较的过程中,不能说哪个架构就一定好,要根据项目实际情况,做一定的取舍。

经典的三层模型

在这里插入图片描述

三层模型在Android中的体现

在这里插入图片描述

了解了三层模型在Android项目中的体现之后,我们通过一个Domo来加深印象。


实战

Domo很简单,实现一个网络下载一张图片,并展示的功能。

布局

布局中就一个Button,一个ImageView两个控件。点击按钮后,根据Path下载图片并展示到ImageView上。

代码如下

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <Button
        android:id="@+id/bt_get_image"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:onClick="getImage"
        android:text="获取图片" />

    <ImageView
        android:id="@+id/iv_image"
        android:layout_width="200dp"
        android:layout_height="200dp"
        android:layout_below="@id/bt_get_image" />

</RelativeLayout>
实体类

定义实体类ImageBean,在里面定义两个属性,requestPath用来记录请求的图片地址,bitmap用于接收返回的图片。

代码如下

public class ImageBean {

    // 网络图片地址
    private String requestPath;

    // 结果返回bitmap对象
    private Bitmap bitmap;

    public String getRequestPath() {
        return requestPath;
    }

    public void setRequestPath(String requestPath) {
        this.requestPath = requestPath;
    }

    public Bitmap getBitmap() {
        return bitmap;
    }

    public void setBitmap(Bitmap bitmap) {
        this.bitmap = bitmap;
    }
}
回调接口
public interface Callback {

    /**
     * @param resultCode 请求结果返回标识码
     * @param imageBean Model层数据中bitmap对象(用于C层刷新V)
     */
    void callback(int resultCode, ImageBean imageBean);
}
下载图片工具类
public class ImageDownloader {
    // 成功
    static final int SUCCESS = 200;

    // 失败
    static final int ERROR = 404;

    public void down(Callback callback, ImageBean imageBean) {
        new Thread(new Downloader(callback, imageBean)).start();
    }

    static final class Downloader implements Runnable {

        private final Callback callback;
        private final ImageBean imageBean;

        public Downloader(Callback callback, ImageBean imageBean) {
            this.callback = callback;
            this.imageBean = imageBean;
        }

        @Override
        public void run() {
            try {
                URL url = new URL(imageBean.getRequestPath());
                HttpsURLConnection httpsURLConnection = (HttpsURLConnection) url.openConnection();
                httpsURLConnection.setConnectTimeout(5000);
                httpsURLConnection.setRequestMethod("GET");

                if (httpsURLConnection.getResponseCode() == httpsURLConnection.HTTP_OK) {
                    InputStream inputStream = httpsURLConnection.getInputStream();
                    Bitmap bitmap = BitmapFactory.decodeStream(inputStream);
                    showUi(SUCCESS, bitmap);
                } else {
                    showUi(ERROR, null);
                }
            } catch (Exception e) {
                e.printStackTrace();
                showUi(ERROR, null);
            }
        }

        private void showUi(int resultCode, Bitmap bitmap) {
            if (callback != null) {
                imageBean.setBitmap(bitmap);
                callback.callback(resultCode, imageBean);
            }
        }
    }
}
MainActivity
public class MainActivity extends AppCompatActivity implements Callback {
    private ImageView imageView;
    private final static String PATH = "https://dss1.baidu.com/70cFfyinKgQFm2e88IuM_a/forum/pic/item/9f2f070828381f300704a682a7014c086e06f0f8.jpg";

    private Handler mHandler = new Handler(new Handler.Callback() {
        @Override
        public boolean handleMessage(@NonNull Message msg) {
            switch (msg.what) {
                case ImageDownloader.SUCCESS:// 成功
                    imageView.setImageBitmap(((Bitmap) msg.obj));
                    break;
                case ImageDownloader.ERROR:// 失败
                    Toast.makeText(MainActivity.this, "下载失败", Toast.LENGTH_SHORT).show();
                    break;
            }
            return false;
        }
    });

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        imageView = findViewById(R.id.iv_image);
    }

    // 点击事件
    public void getImage(View view) {
        ImageBean imageBean = new ImageBean();
        imageBean.setRequestPath(PATH);
        new ImageDownloader().down(this, imageBean);
    }

    @Override
    public void callback(int resultCode, ImageBean imageBean) {
        Message message = mHandler.obtainMessage(resultCode);
        message.obj = imageBean.getBitmap();
        mHandler.sendMessageDelayed(message, 500);
    }
}

代码就这么多,加上权限后,我们来看运行效果
在这里插入图片描述
这个例子就是典型的用MVC架构设计搭建的项目。
在这里插入图片描述
V层收到指令(点击事件)后,告知C层去处理(下载图片),C层完成业务逻辑处理之后会将结果(Bitmap)更新到M层,最后M层的结果会返回给V层(展示图片)。

总的来讲就是V——>C——>M——>V的循环过程。


为什么会演变成MVP

我们做一个简单的测试,在MainActivityonCreate()方法中加入以下代码。

new Thread(new Runnable() {
    @Override
    public void run() {
        SystemClock.sleep(50000);
    }
}).start();

启动的一个新的线程,休眠50s。当启动Activity之后,立马按返回键退出应用,并立即回收堆内存之后,我们会发现:
在这里插入图片描述
在这里插入图片描述
会有一个tartget in Thread仍然在运行,还会有一个CallBack在等待执行。这问题非常严重,想必大家都知道,这就是我们所说的存在内存泄露

(对Profiler不熟悉的同学,可以参考我图中标注的1234步棸查看)

这就是MVC架构在Android项目中存在的巨大缺陷。

无论是在MVC,MVP,MVVM架构的项目中,用户最直观的就是Activity。Activity被销毁的时候,能不能非常的干净和纯粹就是我们作为内存泄漏评估的最关键的一个点。

但是我们看见Activity回调destory()要销毁了,并没有真正的被销毁。

主要的原因就是在MVC架构中,作为C层的Activity对M层和V层的交互会非常多,比如开启了一个服务、请求网络或者做其他一些耗时操作,这个时候用户有可能已经把Activity页面关掉了,但是Activity没法真正被销毁,导致这种架构模式会很容易出现内存泄漏。

这也就是后来会慢慢演变用MVP架构去搭建Android项目。

本文完。MVC架构设计就介绍到这里,希望能让大家对MVC的架构有一个了解。MVP架构的介绍文章将在近期发布,欢迎批评指正。


文中Demo下载地址

Android 架构设计模式系列文章索引

MVC架构设计与经典的三层模型

MVVM实现数据双向绑定

DataBinding的使用与原理


架构师系列文章引导页

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

IT小瓯

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值