小编Ioa*_* P.的帖子

使用 Jetpack Compose 时如何更好地注入 ViewModel 对象?

我需要使用导航,并且我还需要在每个屏幕中使用SharedViewModel. 这是我尝试过的。

class MainActivity : ComponentActivity() {
    private lateinit var navController: NavHostController
    private val viewModel: SharedViewModel by viewModels()

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            navController = rememberNavController()
            NavGraph(
                navController = navController,
                sharedViewModel = sharedViewModel
            )
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

正如您所看到的,我将navController和传递sharedViewModel 给了NavGraph

fun NavGraph(
    navController: NavHostController,
    sharedViewModel: SharedViewModel
) {
    NavHost(
        navController = navController,
        startDestination = HomeScreen.route
    ) {
        composable(
            route = HomeScreen.route
        ) {
            HomeScreen(
                sharedViewModel = sharedViewModel
            )
        }
        composable(
            route …
Run Code Online (Sandbox Code Playgroud)

android kotlin android-jetpack-navigation android-jetpack-compose dagger-hilt

2
推荐指数
1
解决办法
611
查看次数

为什么 trySend 会发出假数据?

我需要在 MVVM 中获取用户身份验证状态。在存储库中我这样做:

override fun getAuthResponse() = callbackFlow  {
    val listener = AuthStateListener {
        Log.d(TAG, "currentUser: " + (currentUser == null)) //Line2
        trySend(it.currentUser == null)
    }
    auth.addAuthStateListener(listener)
    awaitClose {
        auth.removeAuthStateListener(listener)
    }
}
Run Code Online (Sandbox Code Playgroud)

“Line2”将始终打印,true因为用户未经过身份验证。然后在 ViewModel 中我有:

fun getAuthResponse() = repo.getAuthResponse()
Run Code Online (Sandbox Code Playgroud)

以及内部活动:

setContent {
    //...
    val response = viewModel.getAuthResponse().collectAsState(initial = false).value
    Log.d(TAG, "response: $response") //Line1
}
Run Code Online (Sandbox Code Playgroud)

由于 setContent 是一个可组合函数,因此当我打开应用程序时,它会触发两次。这意味着“Line1”处的日志语句被触发两次。当它第一次点火时,我得到:

response: false
currentUser: true
Run Code Online (Sandbox Code Playgroud)

因此,即使我在前一行调用了 getAuthResponse(),响应也会在之前打印。问题是,由于某种原因,即使当前用户为空,我也会在活动中打印出该用户不为空。当它第二次触发时,我得到了正确的数据:

response: true
currentUser: true
Run Code Online (Sandbox Code Playgroud)

为什么我得到一个非空的用户对象?trySend 会发出假数据吗?

kotlin firebase kotlin-coroutines android-jetpack-compose kotlin-flow

2
推荐指数
1
解决办法
129
查看次数

每次更改位置时,我都要负责读取操作吗?

我有保持100个位置,每一个与所述一个公司的FireStore数据库latlng正确设置。我创建了一个方法来使用回调从数据库中实际读取数据:

public static void readLocations(MyCallback myCallback) {
    locationsRef.get().addOnCompleteListener(task -> {
        if (task.isSuccessful()) {
            List<LocationModel> locationList = new ArrayList<>();
            for (QueryDocumentSnapshot document : task.getResult()) {
                LocationModel locationModel = document.toObject(LocationModel.class);
                locationList.add(locationModel);
            }
            myCallback.onCallback(locationList);
        }
    });
}
Run Code Online (Sandbox Code Playgroud)

我正在使用 aLocationCallback来跟踪当前位置。使用下面的代码,我readLocations()在 LocationCallback 中调用方法来做一些关于某些距离的数学运算:

LocationCallback locationCallback = new LocationCallback() {
    @Override
    public void onLocationResult(LocationResult locationResult) {
        for (Location myLocation : locationResult.getLocations()) {
            currentLocation = myLocation;
            LatLng currentLatLng = new LatLng(currentLocation.getLatitude(), currentLocation.getLongitude());

            readLocations(locationList -> {
                for (LocationModel lm : …
Run Code Online (Sandbox Code Playgroud)

java android firebase google-cloud-firestore

1
推荐指数
1
解决办法
168
查看次数

如何在 Jetpack Compose 中始终将进度条置于屏幕中央?

我正在尝试对从 API 获取的一些项目进行分页。我想一次加载 10 个项目。我需要的是始终在屏幕中央的所有内容之上显示进度。这是我尝试过的:

val items = viewModel.items.collectAsLazyPagingItems()
Box(
    modifier = Modifier.fillMaxSize()
) {
    LazyColumn {
        items(
            items = items
        ) { item ->
            ProductCard(
                item = item
            )
        }
        items.apply {
            when(loadState.refresh) {
                is Loading -> item { ProgressBar() }
                is Error -> //Log error
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

这是我的进度条:

@Composable
fun ProgressBar() {
    Box(
        modifier = Modifier.fillMaxSize(),
        contentAlignment = Alignment.Center
    ){
        CircularProgressIndicator()
    }
}
Run Code Online (Sandbox Code Playgroud)

问题是,当我启动应用程序时,进度条开始在 10 个加载项目的顶部加载。一旦我加载更多内容,它就会停留在现有项目的底部和新 10 个项目的顶部之间。如何让进度条始终位于屏幕中央,无论我加载多少页?

android kotlin android-jetpack-compose

1
推荐指数
1
解决办法
2446
查看次数

如何在 Jetpack Compose 中正确使用 Flow 和 ProgressBar?

我有这段代码可以增加数据库中的值:

override fun incrementQuantity() = flow {
    try {
        emit(Result.Loading)
        heroIdRef.update("quantity", FieldValue.increment(1)).await()
        emit(Result.Success(true))
    } catch (e: Exception) {
        emit(Result.Failure(e))
    }
}
Run Code Online (Sandbox Code Playgroud)

该函数是从 ViewModel 类中调用的,然后从可组合函数中读取如下响应:

when(val response = viewModel.incrementResponse) {
    is Result.Loading -> showProgressBar()
    is Result.Success -> Log.d("TAG", "Quantity incremented.")
    is Result.Failure -> Log.d("TAG", response.e.message)
}
Run Code Online (Sandbox Code Playgroud)

这意味着在流程中我收到两个事件,第一个是Loading,第二个是数据或失败。我的问题是:

建议这样做吗?或者最好不使用流程并使用如下内容:

override fun incrementQuantity(): Result<Boolean> {
    try {
        heroIdRef.update("quantity", FieldValue.increment(1)).await()
        Result.Success(true)
    } catch (e: Exception) {
        Result.Failure(e)
    }
}
Run Code Online (Sandbox Code Playgroud)

在可组合项内部:

showProgressBar()
when(val response = viewModel.incrementResponse) {
    is Result.Success -> {
        hideProgressBar()
        Log.d("TAG", "Quantity incremented.") …
Run Code Online (Sandbox Code Playgroud)

android kotlin kotlin-coroutines android-jetpack-compose kotlin-flow

1
推荐指数
1
解决办法
3300
查看次数

如何在Java中将Map中的key * value相乘?

我有这门课:

\n
class Product {\n    public double price;\n\n    public Product(double price) {\n        this.price = price;\n    }\n}\n
Run Code Online (Sandbox Code Playgroud)\n

还有一张地图:

\n
Map<Product, Integer> products = new HashMap<>();\n
Run Code Online (Sandbox Code Playgroud)\n

其中包含添加的几种产品,如下所示:

\n
products.put(new Product(2.99), 2);\nproducts.put(new Product(1.99), 4);\n
Run Code Online (Sandbox Code Playgroud)\n

我想使用流计算所有乘积的总和乘以值?我试过:

\n
double total = products.entrySet().stream().mapToDouble((k, v) -> k.getKey().price * v.getValue()).sum();\n
Run Code Online (Sandbox Code Playgroud)\n

但它无法编译,我得到 \xe2\x80\x9c无法解析方法getValue()\xe2\x80\x9d。

\n

我预计:

\n
(2.99 * 2) + (1.99 * 4) = 5.98 + 7.96 = 13.94\n
Run Code Online (Sandbox Code Playgroud)\n

java java-8 java-stream

0
推荐指数
1
解决办法
895
查看次数