Android 项目架构

🔥 什么是架构 🔥

在维基百科里是这样定义的: 软件架构是一个系统的轮廓 . 软件架构描述的对象是直接构成系统的抽象组件. 各个组件之间的连接则明确和相对细致地描述组件之间的通讯 . 在实现阶段,  这些抽象组件被细化为实际组件 , 比如具体某个类或者对象 . 

面试的过程中会问到如何设计架构 ?  应用从哪几方面进行考虑 ?  架构的职责是什么 ?  你会发现这样的问题并不好回答 . 这里可以通过如下三点回答 : 

● 为了解决特定的问题而提出 .

有特定的原则将系统整体进行角色划分 .

● 约定角色间的沟通机制 (有分层、有联系才能形成框架 ; 就像mvp、mvc、mvvm为解决特定问题而提出来的 .

所谓的架构 , 其实更多的是一种思想 , 一种机制 .

🔥 如何理解架构设计 🔥 

在进行学习框架的时候都要从下面三个方面进行考虑 : 

● 架构解决了什么问题

● 架构模式如何划分角色的

● 角色是如何建立联系的

当我们在查看框架框架源码的时候会去查看框架里面的当前类的作用 , 类与类之间会存在什么联系 .  平常设计框架的时候, 可以从 上面三个方面 进行考虑 . 

🔥 什么是 MVC 🔥 

其实我们日常开发中的Activity , Fragment和XML界面就相当于一个MVC的架构模式 , 但往往Activity中需要处理绑定UI , 用户交互 , 以及数据处理 . 

这种开发方式的缺点就是业务量复杂的时候一个Activity过于臃肿 . 但是页面机构不复杂的情况下使用这种方式就会显得很简单. 

MVC架构模式本来并不属于Android的开放模式 , 而且来自于Web前端 . 在Android开始发展的时候并没有什么架构 , 就直接照搬了Web前端这套模式 . 

MVC架构模式在前端的作用是为了分离数据和视图 , 但是在Android上面进行使用就不是那么灵光了 . 

🔥 MVC实现 🔥 

创建案例的 Android Studio 版本

下载案例

package com.kotlin.testmvc;

import androidx.appcompat.app.AppCompatActivity;

import android.os.Bundle;
import android.widget.TextView;


class User {
    String tvHelloWorldValue;

    public User(String tvHelloWorldValue) {
        this.tvHelloWorldValue = tvHelloWorldValue;
    }
}

interface HiCallBack<User> {
    void onSuccess(User user);
}

interface IHomeModel {
    void getUserInfo(HiCallBack<User> callback);
}

class HomeModel implements IHomeModel {
    @Override
    public void getUserInfo(HiCallBack<User> callback) {
        // 获取到数据并回传给callback
        User user = new User("设置 tvHelloWorld 的值");
        callback.onSuccess(user);
    }
}

/**
 * MVC Controller
 */
public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        /**
         *  MVC Model
         */
        HomeModel model = new HomeModel();
        model.getUserInfo(new HiCallBack<User>() {
            @Override
            public void onSuccess(User user) {
                /**
                 * MVC View
                 */
                ((TextView) findViewById(R.id.tvHelloWorld)).setText(user.tvHelloWorldValue);
            }
        });
    }
}

项目架构 MVC 案例

🔥 什么是 MVP 架构 🔥

为了解决Activity任务过于繁重 , 数据层和视图层交织在一起的问题就此诞生了mvp架构模式 . 

● 让宿主专注UI逻辑和用户交互的处理 . 把宿主中的业务逻辑分离出来 , 所有跟Android API无关的业务逻辑由Presenter 层来完成 . 但是缺点就是增加了代码量 . 

● Activity 和 Fragment 视为View 层 , 负责处理UI和用户交互

Presenter 为业务处理层 , 负责处理业务逻辑 , 发起请求数据 . 

Model 层中包含着具体的数据请求 , 数据源. 但是这一层在 retrofit , restful 的场景下可以被弱化 .  三层之间调用顺序为 view -> presenter -> model , 为了调用安全着想不可反向调用 ! 不可跨级调用 !

●  BaseView : 一般特指Activity和/Fragment , 可以定义一些通用方法 . 

interface BaseView{
    /**
     * 判断宿主是否还存活,避免NPE
     * @return
     */
    boolean isAlive();
}

●  Presenter : 用于处理业务数据逻辑 , 并通过持有View接口吧数据回传到View层

class BasePresenter <IView extends BaseView>{
    /**
     * 根据MVP的模型,Presenter需要持有View对象,才能将处理好的数据回调出去
     */
    public IView mView;
    public void attach(IView mView){
        this.mView=mView;
    }

    public void detach(){
        this.mView=null;
    }
}

🔥 MVP 架构实现 🔥 

● HomeContract 业务接口的定义

/**
 * 定义业务接口
 */
interface HomeContract {

    interface View extends BaseView {
        void onGetuserInfo(Object data, String errorMsg);

        void onSaveUserInfo(Object data, String errorMsg);
    }

    /**
     * 每个接口 都会在View 存在与之对应的callback回调
     */
    abstract class Presenter extends BasePresenter<View> {
        public abstract void getUserInfo();

        public abstract void saveUserInfo();
    }
}

●  业务接口Presenter的实现

class HomePresenter extends HomeContract.Presenter {
    @Override
    public void getUserInfo() {
        if (mView != null && mView.isAlive()) {
            mView.onGetuserInfo(null, null);
        }
    }

    @Override
    public void saveUserInfo() {

    }
}

 ●  业务接口View 的实现


public class MainActivity extends AppCompatActivity implements HomeContract.View {

    private HomePresenter presenter;

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

        presenter=new HomePresenter();
        presenter.attach(this);
        presenter.getUserInfo();
    }

    @Override
    public boolean isAlive() {
        /**
         * 当前Activity(宿主)是否存活
         */
        return (!isDestroyed() && !isFinishing());
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        /**
         * 释放掉IView
         */
        presenter.detach();
    }

    @Override
    public void onGetuserInfo(Object data, String errorMsg) {

    }

    @Override
    public void onSaveUserInfo(Object data, String errorMsg) {

    }
}

🔥 创建 BaseActivity  🔥

避免每次 使用Activity都创建 Presenter 实例、判断当前Activity(宿主) 是否销毁、每次都手动销毁IView

class BaseActivity<P extends BasePresenter> extends AppCompatActivity implements BaseView {

    protected P mPresenter;

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        Type superClass=this.getClass().getGenericSuperclass();
        //具备泛型参数的类型
        if(superClass instanceof ParameterizedType){
            Type[] arguments = ((ParameterizedType) superClass).getActualTypeArguments();
            if(arguments!=null&&arguments[0] instanceof BasePresenter){
                try{
                    mPresenter= (P) arguments[0].getClass().newInstance();
                    mPresenter.attach(this);
                }catch (IllegalAccessException e){
                    e.printStackTrace();
                }catch (InstantiationException e){
                    e.printStackTrace();
                }
            }
        }
    }

    @Override
    public boolean isAlive() {
        return (!isDestroyed() && !isFinishing());
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        if(mPresenter!=null){
            mPresenter.detach();
        }
    }
}

🔥 使用BaseActivity 🔥 

 class MainActivity1 extends BaseActivity<HomePresenter> implements HomeContract.View {

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

        mPresenter.getUserInfo();
    }


     @Override
     public void onGetuserInfo(Object data, String errorMsg) {

     }

     @Override
     public void onSaveUserInfo(Object data, String errorMsg) {

     }
 }

项目架构 MVP 案例

 🔥 什么是MVVM 🔥

●  双向绑定 : 数据变更UI会自动刷新 , UI变化了数据也会自动同步到最新的值 .

●  数据驱动UI :  比如 User中的字段 , 数据变化了, 可以做到自动刷新UI .

●  UI同步数据 :  比如 EditText、checkBox、toggleButton 具有状态的View , 当状态变化后 , 数据模型中与之关联的字段值也会自动同步最新状态 . 

// 开启 databinding

android{

    ......
    
    dataBinding{
        enabled = true
    }
}

🔥 传统的MVVM 🔥 

 ●  定义Bean 类 User

package com.test.mvvm;

public class User{
    String nickName;
    String address;


    public String getNickName() {
        return nickName;
    }

    public void setNickName(String nickName) {
        this.nickName = nickName;
    }

    public String getAddress() {
        return address;
    }

    public void setAddress(String address) {
        this.address = address;
    }
}

●  定义ViewModel用于处理数据相关的业务逻辑。并通过ObservableFiled 观察者把结果回传出去

package com.test.mvvm;
import androidx.databinding.ObservableField;

/**
 * 定义ViewModel用于处理数据相关的业务逻辑。并通过ObservableFiled 观察者把结果回传出去
 */
public class HomeViewModel{
   public ObservableField<User> userFiled=new ObservableField();

    public void queryUserInfo(){
        User user=new User();
        user.nickName="nickName";
        user.address="address";
        //自动通知与之关联的观察者
        userFiled.set(user);
    }

}

●   基于DataBinding 在xml中进行数据绑定, 可以实现数据&UI双向绑定 => 数据变更UI自动刷新 , UI变更自动同步数据

<?xml version="1.0" encoding="utf-8"?>
<layout 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">
    <data>
        <variable
            name="viewModel"
            type="com.test.mvvm.HomeViewModel" />
    </data>

    <LinearLayout
        android:layout_width="match_parent"
        tools:context=".MainActivity"
        android:orientation="vertical"
        android:layout_height="wrap_content">
        <!--单向绑定 @ -->
        <TextView
            android:id="@+id/nick_name"
            android:text="@{viewModel.userFiled.nickName}"
            android:layout_width="match_parent"
            android:gravity="center"
            android:background="@color/purple_200"
            android:textColor="@color/white"
            android:layout_height="100dp"/>

        <!--双向绑定 @= -->
        <EditText
            android:id="@+id/edit_address"
            android:text="@={viewModel.userFiled.address}"
            android:layout_width="match_parent"
            android:gravity="center"
            android:textColor="@color/white"
            android:background="@color/colorPrimary"
            android:layout_height="100dp"/>
    </LinearLayout>
</layout>

 ●   Activity 控制数据的获取

package com.test.mvvm;

import android.os.Bundle;
import android.text.Editable;
import android.text.TextWatcher;
import android.util.Log;
import com.test.mvvm.databinding.ActivityMainBinding;
import androidx.appcompat.app.AppCompatActivity;
import androidx.databinding.DataBindingUtil;


public class MainActivity extends AppCompatActivity {

    ActivityMainBinding mainBinding;

    @Override
    protected void onDestroy() {
        super.onDestroy();
        mainBinding.unbind();
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mainBinding = DataBindingUtil.setContentView(this, R.layout.activity_main);

        HomeViewModel homeViewModel = new HomeViewModel();
        mainBinding.setViewModel(homeViewModel);
        homeViewModel.queryUserInfo();

        mainBinding.editAddress.addTextChangedListener(new TextWatcher() {
            @Override
            public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {

            }

            @Override
            public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {

            }

            @Override
            public void afterTextChanged(Editable editable) {
                Log.e("MainActivity","afterTextChanged:"+homeViewModel.userFiled.get().address);
            }
        });
    }
}

TextView 文本 ( nick_name ) 与 ViewModel实现了单项绑定 , 当改变 ViewModelTextView变化 

EditText 编辑框( edit_address ) 与 ViewModel 实现了双向绑定 , 当改变 ViewModel 时 EditText 变化 ,当操作编辑框时ViewModel 变化 

E/MainActivity: afterTextChanged:addres
E/MainActivity: afterTextChanged:addre
E/MainActivity: afterTextChanged:addr
E/MainActivity: afterTextChanged:add
E/MainActivity: afterTextChanged:ad
E/MainActivity: afterTextChanged:a
E/MainActivity: afterTextChanged:
E/MainActivity: afterTextChanged:第一次
E/MainActivity: afterTextChanged:第一次修改
E/MainActivity: afterTextChanged:第一次修改编辑框

 项目架构 传统MVVM 案例

🔥 JetPack下的MVVM 🔥

JetPack下的MVVM . ViewModel + LiveData 组件结合 . 

这样做的目的既能保证数据不会无缘无故丢失 , 还能自动关联宿主的生命周期 , 避免空指针的问题 . Activity , Fragment UI 逻辑和用户交互控制就可以了 . 数据的绑定可以交给DataBinding . 

 

定义ViewModel2 继承自ViewModel , 通过 MutableLiveData 传递数据

package com.test.jetpack.mvvm;

import androidx.lifecycle.MutableLiveData;
import androidx.lifecycle.ViewModel;

/**
 *
 * @author
 */
public class HomeViewModel2 extends ViewModel {

    public MutableLiveData<User> getUserInfo(){
        MutableLiveData<User> liveData=new MutableLiveData<>();
        User user=new User();
        user.nickName="nickName";
        user.address="address";
        liveData.postValue(user);
        return liveData;
    }
}

 MainActivity2 绑定UI布局和对 ViewModel 数据的观察并进行刷新UI界面

package com.test.jetpack.mvvm;

import android.os.Bundle;
import com.test.mvvm.R;
import com.test.mvvm.databinding.ActivityMain2Binding;
import androidx.appcompat.app.AppCompatActivity;
import androidx.databinding.DataBindingUtil;
import androidx.lifecycle.Observer;
import androidx.lifecycle.ViewModelProvider;


public class MainActivity2 extends AppCompatActivity {


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
       final ActivityMain2Binding binding =DataBindingUtil.setContentView(this,R.layout.activity_main2);
        ViewModelProvider provider=new ViewModelProvider(this,new ViewModelProvider.NewInstanceFactory());
        HomeViewModel2 model2=provider.get(HomeViewModel2.class);
        model2.getUserInfo().observe(this, new Observer<User>() {
            @Override
            public void onChanged(User user) {
                binding.setUser(user);
            }
        });
    }
}

 JetPack MVVM 架构 案例 下载

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

️ 邪神

你自己看着办,你喜欢打赏我就赏

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

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

打赏作者

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

抵扣说明:

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

余额充值