Android架构模式推荐及分析和MVC架构模式制作一个简单的底部tab切换
目录
主流架构模式对比
适用场景
MVP:团队协作开发,需要高可测试性的项目
MVC架构模式制作一个简单的底部tab切换
(Model-View-Controller)结构
代码
效果
主流架构模式对比
对比维度 | MVC | MVP | MVVM | MVI |
---|---|---|---|---|
学习曲线 | 最低(基础分层清晰) | 中等(需接口抽象) | 较高(依赖数据绑定框架) | 最高(状态流管理复杂) |
代码复杂度 | 低(但易导致Controller臃肿) | 中等(分层明确) | 高(双向绑定调试难度大) | 极高(单向数据流逻辑严密) |
可测试性 | 差(业务与UI耦合) | 优秀(Presenter独立测试) | 良好(ViewModel可单元测试) | 优秀(状态隔离测试友好) |
适用项目规模 | 小型原型项目(<10个页面) | 中小型项目(10-50个页面) | 中大型项目(50+页面) | 高交互复杂项目(如金融交易) |
使用率 | 传统项目遗留较多(约25%) | 企业级应用常见(约35%) | 主流框架推荐(约40%) | 新兴趋势上升(约15%) |
- 小型简单项目:优先选择MVC,Android自带支持无需额外架构代码
- 中型交互项目:MVVM通过数据绑定技术可减少约40%的UI同步代码
- 测试驱动开发:MVP虽代码量较多但分层更清晰,便于单元测试
适用场景
- MVC:原生支持无需额外框架,推荐用于教学演示或超简易工具类App开发
-
MVP:团队协作开发,需要高可测试性的项目
- MVVM:响应式编程模式,适合长期维护的中大型项目(需搭配DataBinding或Jetpack Compose)
- MVI:适用于强状态管理需求(如实时聊天、股票交易系统)
MVC架构模式制作一个简单的底部tab切换
(Model-View-Controller)结构
src/
├── main/
│ ├── java/com/ys/autoapp/
│ │ ├── MainActivity.java <-- Controller(主控制逻辑)
│ │ ├── HomeFragment.java <-- Controller(首页页面逻辑)
│ │ ├── RulesFragment.java <-- Controller(规则页面逻辑)
│ │ └── ProfileFragment.java <-- Controller(我的页面逻辑)
│ │
│ ├── res/
│ │ ├── layout/
│ │ │ ├── activity_main.xml <-- View(主界面布局)
│ │ │ ├── fragment_home.xml <-- View(首页页面)
│ │ │ ├── fragment_rules.xml <-- View(规则页面)
│ │ │ └── fragment_profile.xml <-- View(我的页面)
│ │ │
│ │ └── menu/
│ │ └── bottom_navigation_menu.xml <-- View(底部导航菜单定义)
│ │
│ └── drawable/
│ ├── ic_home.xml
│ ├── ic_rules.xml
│ └── ic_profile.xml <-- View(图标资源)
代码
MainActivity
import android.os.Bundle;
import android.util.Log;import androidx.appcompat.app.AppCompatActivity;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentManager;
import androidx.fragment.app.FragmentTransaction;
import com.google.android.material.bottomnavigation.BottomNavigationView;
import com.google.android.material.navigation.NavigationBarView;public class MainActivity extends AppCompatActivity {private static final String TAG = "MainActivity";// 定义常量以替代资源 IDprivate static final int NAVIGATION_HOME = R.id.navigation_home;private static final int NAVIGATION_RULES = R.id.navigation_rules;private static final int NAVIGATION_PROFILE = R.id.navigation_profile;private FragmentManager fragmentManager;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);fragmentManager = getSupportFragmentManager();// 初始化底部导航栏BottomNavigationView bottomNavigationView = findViewById(R.id.bottom_navigation);bottomNavigationView.setOnItemSelectedListener(new NavigationBarView.OnItemSelectedListener() {@Overridepublic boolean onNavigationItemSelected(android.view.MenuItem item) {Log.d(TAG, "切换" + String.valueOf(item.getItemId()));Fragment selectedFragment = null;// 使用 if-else 替代 switch-case,避免变量重复赋值if (item.getItemId() == NAVIGATION_HOME) {selectedFragment = new HomeFragment();} else if (item.getItemId() == NAVIGATION_RULES) {selectedFragment = new RulesFragment();} else if (item.getItemId() == NAVIGATION_PROFILE) {selectedFragment = new ProfileFragment();}if (selectedFragment != null) {FragmentTransaction transaction = fragmentManager.beginTransaction();transaction.replace(R.id.fragment_container, selectedFragment);transaction.commit();}return true;}});// 默认显示首页bottomNavigationView.setSelectedItemId(NAVIGATION_HOME);}
}
HomeFragment
import android.os.Bundle;
import androidx.fragment.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;public class HomeFragment extends Fragment {@Overridepublic View onCreateView(LayoutInflater inflater, ViewGroup container,Bundle savedInstanceState) {return inflater.inflate(R.layout.fragment_home, container, false);}
}
ProfileFragment
import android.os.Bundle;
import androidx.fragment.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;public class ProfileFragment extends Fragment {@Overridepublic View onCreateView(LayoutInflater inflater, ViewGroup container,Bundle savedInstanceState) {return inflater.inflate(R.layout.fragment_profile, container, false);}
}
RulesFragment
import android.os.Bundle;
import androidx.fragment.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;public class RulesFragment extends Fragment {@Overridepublic View onCreateView(LayoutInflater inflater, ViewGroup container,Bundle savedInstanceState) {return inflater.inflate(R.layout.fragment_rules, container, false);}
}
bottom_navigation_menu.xml
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"><itemandroid:id="@+id/navigation_home"android:icon="@drawable/ic_home"android:title="首页" /><itemandroid:id="@+id/navigation_rules"android:icon="@drawable/ic_rules"android:title="规则" /><itemandroid:id="@+id/navigation_profile"android:icon="@drawable/ic_profile"android:title="我的" />
</menu>
activity_main.xml
<?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"android:layout_width="match_parent"android:layout_height="match_parent"><FrameLayoutandroid:id="@+id/fragment_container"android:layout_width="match_parent"android:layout_height="0dp"app:layout_constraintTop_toTopOf="parent"app:layout_constraintBottom_toTopOf="@id/bottom_navigation" /><com.google.android.material.bottomnavigation.BottomNavigationViewandroid:id="@+id/bottom_navigation"android:layout_width="match_parent"android:layout_height="wrap_content"app:layout_constraintBottom_toBottomOf="parent"app:menu="@menu/bottom_navigation_menu" /></androidx.constraintlayout.widget.ConstraintLayout>
fragment_home.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="match_parent"android:orientation="vertical"android:gravity="center"android:background="#FFFFFF"><TextViewandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:text="首页"android:textSize="24sp"android:textColor="#000000" /><!-- 新增一行文本,标识当前页面 --><TextViewandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:text="这是首页页面"android:textSize="16sp"android:textColor="#000000"android:layout_marginTop="16dp" /></LinearLayout>
fragment_rules.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="match_parent"android:orientation="vertical"android:gravity="center"android:background="#FFFFFF"><TextViewandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:text="规则"android:textSize="24sp"android:textColor="#000000" /><!-- 新增一行文本,标识当前页面 --><TextViewandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:text="这是规则页面"android:textSize="16sp"android:textColor="#000000"android:layout_marginTop="16dp" /></LinearLayout>
fragment_profile.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="match_parent"android:orientation="vertical"android:gravity="center"android:background="#FFFFFF"><TextViewandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:text="我的"android:textSize="24sp"android:textColor="#000000" /><!-- 新增一行文本,标识当前页面 --><TextViewandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:text="这是我的页面"android:textSize="16sp"android:textColor="#000000"android:layout_marginTop="16dp" /></LinearLayout>
ic_home.xml
<vector xmlns:android="http://schemas.android.com/apk/res/android"android:width="24dp"android:height="24dp"android:viewportWidth="24"android:viewportHeight="24"><pathandroid:fillColor="#000000"android:pathData="M10 20v-6h4v6h5v-8h3L12 3 2 12h3v8z" />
</vector>
ic_rules.xml
<vector xmlns:android="http://schemas.android.com/apk/res/android"android:width="24dp"android:height="24dp"android:viewportWidth="24"android:viewportHeight="24"><pathandroid:fillColor="#000000"android:pathData="M12 2L2 22h20L12 2z" />
</vector>
ic_profile.xml
<vector xmlns:android="http://schemas.android.com/apk/res/android"android:width="24dp"android:height="24dp"android:viewportWidth="24"android:viewportHeight="24"><pathandroid:fillColor="#000000"android:pathData="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm0 3c1.66 0 3 1.34 3 3s-1.34 3-3 3-3-1.34-3-3 1.34-3 3-3zm0 14.2c-2.5 0-4.71-0.98-6.29-2.58C4.59 15.72 4 13.55 4 11c0-1.66 0.59-3.22 1.57-4.42C5.16 6.21 6.42 5 8 5c1.58 0 3.04 1.21 3.92 2.59C11.96 6.78 13.22 5 14.8 5c1.58 0 3.04 1.21 3.92 2.59C19.41 7.78 20 9.34 20 11c0 2.55-0.59 4.72-1.57 6.22C17.71 19.02 15.5 20 12 20z" />
</vector>
效果
ending
人的一生 必须要学会做一件事 而且要做到透彻 才不枉此生...共勉 💪。