Android 区块链 + CleanArchitecture + MVI 架构实践

Android 区块链 + CleanArchitecture + MVI 架构实践

本文首发地址 https://h89.cn/archives/420.html

前言

在区块链技术快速发展的今天,去中心化应用(DApp)正在重新定义传统的应用开发模式。本文将深入探讨如何在Android 平台上构建一个基于 Solana Mobile SDK 的去中心化电商平台,采用 Clean Architecture 和 MVI架构模式,实现高度解耦、可测试和可维护的现代化应用。

项目源码地址 在结尾

项目概述–核心特性

我们构建的是一个完整的 Web3 去中心化电商平台,集成了购买、销售、收益和治理四大核心功能。该项目不仅展示了区块链技术在电商领域的应用潜力,更重要的是展现了现代 Android 开发的最佳实践:

  • 去中心化交易: 基于 Solana 区块链的安全交易
  • 钱包集成: 无缝集成 Solana Mobile Wallet Adapter
  • 现代 UI: Jetpack Compose + Material Design 3
  • 响应式架构: MVI 模式确保单向数据流
  • 离线支持: Room 数据库提供本地数据持久化
  • 科技美学: 深色主题配合霓虹色彩的未来科技风格

Clean Architecture 架构的三层分离设计理念

我们严格遵循 Uncle Bob 的 Clean Architecture 原则,将应用分为三个独立的层次:

┌─────────────────────────────────────────────────────────┐
│                   Presentation Layer                    │
│  ┌─────────────┐  ┌─────────────┐  ┌─────────────┐     │
│  │   Intent    │  │ ViewModel   │  │    State    │     │
│  │             │  │             │  │             │     │
│  │ UserAction  │→ │ StateFlow   │→ │ UIState     │     │
│  │ SystemEvent │  │ SharedFlow  │  │ Effect      │     │
│  └─────────────┘  └─────────────┘  └─────────────┘     │
└─────────────────────────────────────────────────────────┘
                              ↓
┌─────────────────────────────────────────────────────────┐
│                    Domain Layer                         │
│  ┌─────────────┐  ┌─────────────┐  ┌─────────────┐     │
│  │   Entity    │  │  Use Case   │  │ Repository  │     │
│  │             │  │             │  │ Interface   │     │
│  │ Product     │  │ RegisterMer │  │ IMerchant   │     │
│  │ Order       │  │ chantUseCase│  │ Repository  │     │
│  │ Merchant    │  │ GetProducts │  │ IProduct    │     │
│  └─────────────┘  └─────────────┘  └─────────────┘     │
└─────────────────────────────────────────────────────────┘
                              ↓
┌─────────────────────────────────────────────────────────┐
│                     Data Layer                          │
│  ┌─────────────┐  ┌─────────────┐  ┌─────────────┐     │
│  │ Repository  │  │ DataSource  │  │   Mapper    │     │
│  │ Implement   │  │             │  │             │     │
│  │             │  │ Mock/Room   │  │ DTO ↔ Entity│     │
│  │ ProductRepo │  │ Solana/API  │  │ Serialization│     │
│  └─────────────┘  └─────────────┘  └─────────────┘     │
└─────────────────────────────────────────────────────────┘

Presentation Layer(表现层)

表现层负责 UI 渲染和用户交互,采用 MVI 模式确保单向数据流:

```kotlin
// Intent - 用户意图的抽象表示
sealed class ProductIntent {
    object LoadProducts : ProductIntent()
    data class SearchProducts(val query: String) : ProductIntent()
    data class FilterProducts(val filter: ProductFilter) : ProductIntent()
}

// State - 不可变的 UI 状态
data class ProductState(
    val products: List<Product> = emptyList(),
    val isLoading: Boolean = false,
    val error: String? = null,
    val searchQuery: String = ""
)

// ViewModel - 状态管理和业务逻辑协调
class ProductViewModel @Inject constructor(
    private val getProductsUseCase: GetProductsUseCase
) : ViewModel() {
    private val _state = MutableStateFlow(ProductState())
    val state: StateFlow<ProductState> = _state.asStateFlow()

    fun handleIntent(intent: ProductIntent) {
        when (intent) {
            is ProductIntent.LoadProducts -> loadProducts()
            is ProductIntent.SearchProducts -> searchProducts(intent.query)
            is ProductIntent.FilterProducts -> filterProducts(intent.filter)
        }
    }
}
```

Domain Layer(领域层)

领域层包含纯粹的业务逻辑,不依赖任何框架:

```kotlin
// Entity - 业务实体
data class Product(
    val id: String,
    val name: String,
    val description: String,
    val price: BigDecimal,
    val currency: String,
    val imageUrls: List<String>,
    val sellerId: String,
    val category: String,
    val stock: Int,
    val rating: Float,
    val reviewCount: Int
)

// Use Case - 业务用例
class GetProductsUseCase @Inject constructor(
    private val productRepository: IProductRepository
) {
    suspend operator fun invoke(): Flow<Result<List<Product>>> {
        return productRepository.getProducts()
            .map { products ->
                Result.Success(products.sortedByDescending { it.rating })
            }
            .catch { exception ->
                emit(Result.Error(exception))
            }
    }
}

// Repository Interface - 数据访问抽象
interface IProductRepository {
    suspend fun getProducts(): Flow<List<Product>>
    suspend fun getProductById(id: String): Product?
    suspend fun searchProducts(query: String): Flow<List<Product>>
}
```

Data Layer(数据层)

数据层实现具体的数据访问逻辑,支持多种数据源:

```kotlin
// Repository Implementation
class ProductRepositoryImpl @Inject constructor(
    private val mockDataSource: MockProductDataSource,
    private val roomDataSource: RoomProductDataSource,
    private val solanaDataSource: SolanaProductDataSource
) : IProductRepository {

    override suspend fun getProducts(): Flow<List<Product>> {
        return combine(
            roomDataSource.getProducts(),
            solanaDataSource.getProducts()
        ) { localProducts, blockchainProducts ->
            // 合并本地和区块链数据
            (localProducts + blockchainProducts).distinctBy { it.id }
        }
    }
}

// Data Source Abstraction
interface ProductDataSource {
    suspend fun getProducts(): Flow<List<Product>>
    suspend fun getProductById(id: String): Product?
    suspend fun insertProducts(products: List<Product>)
}
```

MVI 模式深度解析

单向数据流的优势

MVI 模式通过强制单向数据流,解决了传统 MVP/MVVM 模式中状态管理的复杂性:

User Interaction → Intent → ViewModel → State → UI → User Interaction

状态管理策略

我们使用 StateFlow 和 SharedFlow 来管理不同类型的状态:

class MainViewModel @Inject constructor(
    private val solanaWalletConnectUseCase: SolanaWalletConnectUseCase
) : ViewModel() {
   
   

    // UI 状态 - 使用 StateFlow
    private val _uiState = MutableStateFlow(MainUiState())
    val uiState: StateFlow<MainUiState> = _uiState.asStateFlow()

    // 一次性事件 - 使用 SharedFlow
    private val _uiEffect = MutableSharedFlow<UiEffect>()
    val uiEffect: SharedFlow<UiEffect> = _uiEffect.asSharedFlow()

    fun handleIntent(intent: MainIntent) {
   
   
        viewModelScope.launch {
   
   
            when (intent) {
   
   
                is MainIntent.ConnectWallet -> connectWallet()
                is MainIntent.DisconnectWallet -> disconnectWallet()
            }
        }
    }
}

Room 数据库架构设计

数据库设计

我们采用 Room 数据库来提供离线支持和数据缓存:

@Database(
    entities = [ProductEntity::class],
    version = 1,
    exportSchema = false
)
@TypeConverters(StringListConverter::class, StringMapConverter::class)
abstract class AppDatabase : RoomDatabase() {
   
   
    abstract fun productDao(): ProductDao

    companion object {
   
   
        @Volatile
        private var INSTANCE: AppDatabase? = null

        fun getDatabase(context: Context): AppDatabase {
   
   
            return INSTANCE ?: synchronized(this) {
   
   
                val instance = Room.databaseBuilder(
                    context.applicationContext,
                    AppDatabase::class.java,
                    "web3_ecommerce_database"
                ).build
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

清霜辰

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

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

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

打赏作者

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

抵扣说明:

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

余额充值