jamiechoo

 

kotlin里可以在整个项目中共享数据和方法,其状态自动更新且可被任何页面调用和继承, 通常可以使用以下模式之一:

 1, 首选:object 单例(Kotlin 特性)

object 是 Kotlin 提供的单例模式实现,天然支持全局访问和状态更新

object AppState {
  var currentUser: String = ""
  var isLoggedIn: Boolean = false

  fun logout() {
  currentUser = ""
  isLoggedIn = false
  }
}

object BluetoothManager {
  var connectedDeviceName by mutableStateOf<String?>(null)

  fun connectTo(deviceName: String) {
  connectedDeviceName = deviceName
  }

  fun disconnect() {
  connectedDeviceName = null
  }
}

2. 抽象类 + ViewModel(可继承 + 自动状态更新)

abstract class BaseUserViewModel : ViewModel() {
  val userName = MutableLiveData<String>()
  val isLoggedIn = MutableLiveData<Boolean>()

  fun login(name: String) {
  userName.value = name
  isLoggedIn.value = true
    }
}

@HiltViewModel
class MyAppViewModel @Inject constructor() : BaseUserViewModel()

调用页面(Jetpack Compose 或 Fragment)

@Composable
fun HomeScreen(viewModel: MyAppViewModel = hiltViewModel()) {
  val userName by viewModel.userName.observeAsState("")
  Text(text = "Welcome $userName")
}

或在 Fragment 中:

  val viewModel: MyAppViewModel by viewModels()
  viewModel.userName.observe(viewLifecycleOwner) {
    name -> textView.text = "Welcome $name"
  }
 

 3. 接口 + 实现类 + Hilt 注入

🔸接口定义

interface SettingsManager {
    var isDarkMode: Boolean fun toggleTheme()
}
class SettingsManagerImpl @Inject constructor() : SettingsManager {
    override var isDarkMode = false
    override fun toggleTheme() {
      isDarkMode = !isDarkMode
    }
  }

🔸Hilt 模块绑定

@Module
@InstallIn(SingletonComponent::class) interface SettingsModule {
  @Binds
  fun bindSettingsManager(impl: SettingsManagerImpl): SettingsManager
  }

🔸注入使用(ViewModel 或 Composable)

@HiltViewModel
class SettingsViewModel @Inject constructor(
  private val settingsManager: SettingsManager ) :
    ViewModel() {
    fun toggle() = settingsManager.toggleTheme()
    fun isDark() = settingsManager.isDarkMode
  }

在页面中使用:

@Composable
fun SettingsScreen(viewModel: SettingsViewModel = hiltViewModel()) {
    val isDark = viewModel.isDark()
    Button(onClick = {
    viewModel.toggle()
    }) {
      Text(if (isDark) "Switch to Light" else "Switch to Dark")
    }
  }
 

4. sealed class 状态机 + StateFlow + collect

🔸状态类 + 管理器

sealed class AuthState {
    object LoggedOut : AuthState()
    data class LoggedIn(val user: String) : AuthState()
    object Loading : AuthState()
  }
class AuthManager {
    private val _authState = MutableStateFlow<AuthState>(AuthState.LoggedOut)
    val authState: StateFlow<AuthState> = _authState
    fun login(user: String) {
      _authState.value = AuthState.Loading
      _authState.value = AuthState.LoggedIn(user)
    }
  }

🔸注入并 collect 状态

@HiltViewModel
class AuthViewModel @Inject constructor(
    val authManager: AuthManager
    ) : ViewModel()

在 Compose 页面中:

@Composable
fun LoginScreen(viewModel: AuthViewModel = hiltViewModel()) {
    val state by viewModel.authManager.authState.collectAsState()
    when (state) {
      is AuthState.Loading -> CircularProgressIndicator()
      is AuthState.LoggedIn -> Text("Welcome ${(state as AuthState.LoggedIn).user}")
      AuthState.LoggedOut -> Text("Please log in")
    }
  }
 

5. CompositionLocal 注入共享对象

🔸Cart 管理器

class CartManager {
  var items = mutableStateListOf<String>()
  fun addItem(item: String) = items.add(item)
}

🔸声明并提供 CompositionLocal

val LocalCartManager = compositionLocalOf<CartManager> {
    error("CartManager not provided")
  }

在根组件中注入:

@Composable
fun App() {
  val cartManager = remember { CartManager() }
  CompositionLocalProvider(LocalCartManager provides cartManager) {
    NavHost(...) // etc.
  }
}

🔸在页面中使用

@Composable
fun CartScreen() {
  val cart = LocalCartManager.current Column {
    cart.items.forEach {
        Text(it)
    }
    Button(onClick = {
      cart.addItem("Apple")
      }) {
        Text("Add Apple")
        }
      }
    }

6. Repository + Flow + 依赖注入

🔸Repository 类

class ThemeRepository
@Inject constructor() {
    private val _isDark = MutableStateFlow(false)
         val isDark: StateFlow<Boolean> = _isDark
    fun toggleTheme() {
            _isDark.value = !_isDark.value
      }
    }

🔸注入并观察状态

@HiltViewModel
class ThemeViewModel @Inject constructor(
    private val themeRepository: ThemeRepository ) : ViewModel() {
      val isDark = themeRepository.isDark
    fun toggleTheme() = themeRepository.toggleTheme()
  }

页面中使用:

@Composable
fun ThemeScreen(viewModel: ThemeViewModel = hiltViewModel()) {
    val isDark by viewModel.isDark.collectAsState()
      Text("Theme: ${if (isDark) "Dark" else "Light"}")
      Button(onClick = {
        viewModel.toggleTheme()
        }) {
        Text("Toggle Theme")
        }
      }

/// PROJECT STRUCTURE: GlobalStateDemo

// ========== build.gradle (Module) ==========
// Add required dependencies
// implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:2.6.2"
// implementation "androidx.hilt:hilt-navigation-compose:1.0.0"
// implementation "androidx.compose.runtime:runtime-livedata:1.6.0"
// kapt "com.google.dagger:hilt-compiler:2.44"

// ========== Application.kt ==========

@HiltAndroidApp
class GlobalStateDemoApp : Application()


// ========== MainActivity.kt ==========

@AndroidEntryPoint
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
  super.onCreate(savedInstanceState)
  setContent {
    val cartManager = remember { CartManager() }
  CompositionLocalProvider(LocalCartManager provides cartManager) {
    NavHostControllerExample()
        }
      }
    }
}


// ========== 1. ViewModel (Base + Inheritance) ==========

abstract class BaseUserViewModel : ViewModel() {
    val userName = MutableLiveData<String>()
    fun login(name: String) { userName.value = name }
}

@HiltViewModel
class MyAppViewModel @Inject constructor() : BaseUserViewModel()

@Composable
fun UserInfoScreen(viewModel: MyAppViewModel = hiltViewModel()) {
    val name by viewModel.userName.observeAsState("")
    Text("Hello, $name")
}


// ========== 2. Interface + Hilt ==========

interface SettingsManager {
    var isDarkMode: Boolean
    fun toggleTheme()
}

class SettingsManagerImpl @Inject constructor() : SettingsManager {
  override var isDarkMode = false
  override fun toggleTheme() { isDarkMode = !isDarkMode }
}

@Module
@InstallIn(SingletonComponent::class)
interface SettingsModule {
@Binds
fun bindSettingsManager(impl: SettingsManagerImpl): SettingsManager
}

@HiltViewModel
class SettingsViewModel @Inject constructor(private val settings: SettingsManager) : ViewModel() {
  fun toggle() = settings.toggleTheme()
  fun isDark() = settings.isDarkMode
}

@Composable
fun SettingsScreen(viewModel: SettingsViewModel = hiltViewModel()) {
    val dark = remember { viewModel.isDark() }
    Button(onClick = { viewModel.toggle() }) { Text(if (dark) "Light" else "Dark") }
}


// ========== 3. Sealed Class State + Flow ==========

sealed class AuthState {
object LoggedOut : AuthState()
  data class LoggedIn(val user: String) : AuthState()
  object Loading : AuthState()
}

class AuthManager @Inject constructor() {
    private val _authState = MutableStateFlow<AuthState>(AuthState.LoggedOut)
    val authState: StateFlow<AuthState> = _authState
  fun login(user: String) {
  _authState.value = AuthState.Loading
  _authState.value = AuthState.LoggedIn(user)
  }
}

@HiltViewModel
class AuthViewModel @Inject constructor(val authManager: AuthManager) : ViewModel()

@Composable
fun AuthScreen(viewModel: AuthViewModel = hiltViewModel()) {
    val state by viewModel.authManager.authState.collectAsState()
  when (state) {
    is AuthState.Loading -> CircularProgressIndicator()
    is AuthState.LoggedIn -> Text("Welcome ${(state as AuthState.LoggedIn).user}")
    AuthState.LoggedOut -> Button(onClick = { viewModel.authManager.login("User") }) {
  Text("Login")
        }  
    }
}


// ========== 4. CompositionLocal Example ==========

class CartManager {
  val items = mutableStateListOf<String>()
  fun addItem(item: String) = items.add(item)
}

  val LocalCartManager = compositionLocalOf<CartManager> { error("No cart manager") }

@Composable
fun CartScreen() {
  val cart = LocalCartManager.current
Column {
    Button(onClick = { cart.addItem("Banana") }) { Text("Add") }
    cart.items.forEach { Text(it) }
  }
}


// ========== 5. Repository + Flow ==========

class ThemeRepository @Inject constructor() {
    private val _dark = MutableStateFlow(false)
    val dark: StateFlow<Boolean> = _dark
  fun toggle() { _dark.value = !_dark.value }
}

@HiltViewModel
class ThemeViewModel @Inject constructor(private val repo: ThemeRepository) : ViewModel() {
    val dark = repo.dark
  fun toggle() = repo.toggle()
}

@Composable
fun ThemeScreen(viewModel: ThemeViewModel = hiltViewModel()) {
    val dark by viewModel.dark.collectAsState()
  Column {
  Text("Dark Mode: $dark")
  Button(onClick = { viewModel.toggle() }) { Text("Toggle") }
  }
}

posted on 2025-05-09 18:18  jamiechoo  阅读(11)  评论(0)    收藏  举报

导航