class UserViewModel : ViewModel() {
private val _users = MutableLiveData<List<User>>()
val users: LiveData<List<User>> = _users
fun loadUsers() {
viewModelScope.launch {
val data = repository.getUsers()
_users.value = data
}
}
}
class MainActivity : AppCompatActivity() {
private val viewModel: UserViewModel by viewModels()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
viewModel.users.observe(this) { users ->
}
viewModel.loadUsers()
}
}
class UserViewModel(private val userId: Int) : ViewModel() {
}
class UserViewModelFactory(private val userId: Int) : ViewModelProvider.Factory {
override fun <T : ViewModel> create(modelClass: Class<T>): T {
return UserViewModel(userId) as T
}
}
val viewModel: UserViewModel by viewModels {
UserViewModelFactory(userId)
}
class UserViewModel : ViewModel() {
private val _name = MutableLiveData<String>()
val name: LiveData<String> = _name
fun updateName(newName: String) {
_name.value = newName
}
}
viewModel.name.observe(this) { name ->
textView.text = name
}
val userName: LiveData<String> = Transformations.map(user) {
it.name
}
val users: LiveData<List<User>> = Transformations.switchMap(query) { q ->
repository.searchUsers(q)
}
val result = MediatorLiveData<String>()
result.addSource(source1) { value ->
result.value = value
}
result.addSource(source2) { value ->
result.value = value
}
@Entity(tableName = "users")
data class User(
@PrimaryKey(autoGenerate = true)
val id: Int = 0,
@ColumnInfo(name = "user_name")
val name: String,
val age: Int,
@Ignore
val temp: String? = null
)
@Dao
interface UserDao {
@Query("SELECT * FROM users")
fun getAll(): List<User>
@Query("SELECT * FROM users WHERE id = :userId")
fun getById(userId: Int): User?
@Query("SELECT * FROM users WHERE user_name LIKE :search")
fun search(search: String): List<User>
@Insert
suspend fun insert(user: User): Long
@Update
suspend fun update(user: User)
@Delete
suspend fun delete(user: User)
@Query("DELETE FROM users")
suspend fun deleteAll()
}
@Database(entities = [User::class], version = 1)
abstract class AppDatabase : RoomDatabase() {
abstract fun userDao(): UserDao
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,
"app_database"
).build()
INSTANCE = instance
instance
}
}
}
}
class UserRepository(private val userDao: UserDao) {
suspend fun getAllUsers(): List<User> {
return userDao.getAll()
}
suspend fun insertUser(user: User) {
userDao.insert(user)
}
}
class UserViewModel(private val repository: UserRepository) : ViewModel() {
fun loadUsers() {
viewModelScope.launch {
val users = repository.getAllUsers()
_users.value = users
}
}
}
<navigation xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/nav_graph"
app:startDestination="@id/homeFragment">
<fragment
android:id="@+id/homeFragment"
android:name="com.example.HomeFragment"
android:label="Home">
<action
android:id="@+id/action_home_to_detail"
app:destination="@id/detailFragment" />
</fragment>
<fragment
android:id="@+id/detailFragment"
android:name="com.example.DetailFragment"
android:label="Detail">
<argument
android:name="userId"
app:argType="integer" />
</fragment>
</navigation>
<androidx.fragment.app.FragmentContainerView
android:id="@+id/nav_host_fragment"
android:name="androidx.navigation.fragment.NavHostFragment"
app:navGraph="@navigation/nav_graph"
app:defaultNavHost="true" />
findNavController().navigate(R.id.action_home_to_detail)
val bundle = bundleOf("userId" to 123)
findNavController().navigate(R.id.action_home_to_detail, bundle)
val args: DetailFragmentArgs by navArgs()
val userId = args.userId
findNavController().navigateUp()
class UploadWorker(
context: Context,
params: WorkerParameters
) : CoroutineWorker(context, params) {
override suspend fun doWork(): Result {
return try {
val data = inputData.getString("data")
uploadData(data)
Result.success()
} catch (e: Exception) {
Result.retry()
}
}
}
val uploadRequest = OneTimeWorkRequestBuilder<UploadWorker>()
.setInputData(workDataOf("data" to "content"))
.setConstraints(
Constraints.Builder()
.setRequiredNetworkType(NetworkType.CONNECTED)
.build()
)
.build()
WorkManager.getInstance(context).enqueue(uploadRequest)
val periodicWork = PeriodicWorkRequestBuilder<UploadWorker>(
15, TimeUnit.MINUTES
).build()
WorkManager.getInstance(context).enqueue(periodicWork)
WorkManager.getInstance(context)
.getWorkInfoByIdLiveData(uploadRequest.id)
.observe(this) { workInfo ->
when (workInfo.state) {
WorkInfo.State.SUCCEEDED -> {
}
WorkInfo.State.FAILED -> {
}
WorkInfo.State.RUNNING -> {
}
}
}
val Context.dataStore: DataStore<Preferences> by preferencesDataStore(name = "settings")
suspend fun saveValue(key: String, value: String) {
context.dataStore.edit { preferences ->
preferences[stringPreferencesKey(key)] = value
}
}
val valueFlow: Flow<String> = context.dataStore.data
.map { preferences ->
preferences[stringPreferencesKey(key)] ?: ""
}
syntax = "proto3";
message Settings {
string theme = 1;
bool notifications = 2;
}
val Context.settingsDataStore: DataStore<Settings> by dataStore(
fileName = "settings.pb",
serializer = SettingsSerializer
)
val settingsFlow: Flow<Settings> = context.settingsDataStore.data
suspend fun updateTheme(theme: String) {
context.settingsDataStore.updateData { currentSettings ->
currentSettings.toBuilder()
.setTheme(theme)
.build()
}
}
class UserPagingSource(
private val api: ApiService
) : PagingSource<Int, User>() {
override suspend fun load(params: LoadParams<Int>): LoadResult<Int, User> {
return try {
val page = params.key ?: 1
val response = api.getUsers(page, params.loadSize)
LoadResult.Page(
data = response.data,
prevKey = if (page == 1) null else page - 1,
nextKey = if (response.data.isEmpty()) null else page + 1
)
} catch (e: Exception) {
LoadResult.Error(e)
}
}
override fun getRefreshKey(state: PagingState<Int, User>): Int? {
return state.anchorPosition?.let { anchorPosition ->
state.closestPageToPosition(anchorPosition)?.prevKey?.plus(1)
?: state.closestPageToPosition(anchorPosition)?.nextKey?.minus(1)
}
}
}
class UserViewModel(private val api: ApiService) : ViewModel() {
val users: Flow<PagingData<User>> = Pager(
config = PagingConfig(
pageSize = 20,
enablePlaceholders = false
),
pagingSourceFactory = { UserPagingSource(api) }
).flow.cachedIn(viewModelScope)
}
class UserAdapter : PagingDataAdapter<User, UserViewHolder>(UserComparator) {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): UserViewHolder {
return UserViewHolder()
}
override fun onBindViewHolder(holder: UserViewHolder, position: Int) {
val user = getItem(position)
holder.bind(user)
}
object UserComparator : DiffUtil.ItemCallback<User>() {
override fun areItemsTheSame(oldItem: User, newItem: User): Boolean {
return oldItem.id == newItem.id
}
override fun areContentsTheSame(oldItem: User, newItem: User): Boolean {
return oldItem == newItem
}
}
}
class MainActivity : AppCompatActivity() {
private val viewModel: UserViewModel by viewModels()
private val adapter = UserAdapter()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
recyclerView.adapter = adapter
lifecycleScope.launch {
viewModel.users.collectLatest { pagingData ->
adapter.submitData(pagingData)
}
}
}
}
@HiltAndroidApp
class MyApplication : Application()
@AndroidEntryPoint
class MainActivity : AppCompatActivity()
@AndroidEntryPoint
class HomeFragment : Fragment()
@HiltViewModel
class UserViewModel @Inject constructor(
private val repository: UserRepository
) : ViewModel()
@Module
@InstallIn(SingletonComponent::class)
object AppModule {
@Provides
@Singleton
fun provideDatabase(@ApplicationContext context: Context): AppDatabase {
return Room.databaseBuilder(
context,
AppDatabase::class.java,
"app_database"
).build()
}
@Provides
fun provideUserDao(database: AppDatabase): UserDao {
return database.userDao()
}
@Provides
@Singleton
fun provideRetrofit(): Retrofit {
return Retrofit.Builder()
.baseUrl("https://api.example.com/")
.addConverterFactory(GsonConverterFactory.create())
.build()
}
@Provides
fun provideApiService(retrofit: Retrofit): ApiService {
return retrofit.create(ApiService::class.java)
}
}
@AndroidEntryPoint
class MainActivity : AppCompatActivity() {
@Inject
lateinit var repository: UserRepository
private val viewModel: UserViewModel by viewModels()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
}
}
@Composable
fun Greeting(name: String) {
Text(text = "Hello $name!")
}
@Composable
fun UserCard(user: User) {
Card(
modifier = Modifier
.fillMaxWidth()
.padding(16.dp)
) {
Column(modifier = Modifier.padding(16.dp)) {
Text(
text = user.name,
style = MaterialTheme.typography.h6
)
Text(
text = "Age: ${user.age}",
style = MaterialTheme.typography.body2
)
}
}
}
@Composable
fun Counter() {
var count by remember { mutableStateOf(0) }
Column {
Text("Count: $count")
Button(onClick = { count++ }) {
Text("Increment")
}
}
}
@Composable
fun UserScreen(viewModel: UserViewModel = viewModel()) {
val users by viewModel.users.observeAsState(emptyList())
LazyColumn {
items(users) { user ->
UserCard(user)
}
}
}
@Composable
fun AppNavigation() {
val navController = rememberNavController()
NavHost(navController, startDestination = "home") {
composable("home") {
HomeScreen(
onNavigateToDetail = { userId ->
navController.navigate("detail/$userId")
}
)
}
composable("detail/{userId}") { backStackEntry ->
val userId = backStackEntry.arguments?.getString("userId")
DetailScreen(userId)
}
}
}