协程加载文件
ASK
我的这个下面的协程加载读取文件的jetpack compose不能应用,你能帮我看看为什么吗
package com.linkdom.readbook
import android.annotation.SuppressLint
import android.content.Context
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.material.Button
import androidx.compose.material.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.MutableState
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.tooling.preview.Preview
import kotlinx.coroutines.*
import java.io.BufferedReader
import java.io.File
import java.io.InputStreamReader
@OptIn(DelicateCoroutinesApi::class)
@Composable
fun Test() {
val context = LocalContext.current
val text = remember { mutableStateOf("") }
Column (
modifier = Modifier.fillMaxSize(),
horizontalAlignment = Alignment.CenterHorizontally
){
Button(onClick = {
GlobalScope.launch(Dispatchers.Main) {
readFile(context){
text.value = it
}
}
}) {
Text("读取文件")
}
Text(text = text.value)
}
}
@SuppressLint("CoroutineCreationDuringComposition")
@OptIn(DelicateCoroutinesApi::class)
private fun readFile(
context: Context,
onRead: (String) -> Unit
) {
GlobalScope.launch(Dispatchers.IO) {
// println("${Thread.currentThread().name}执行文件读取任务。\n")
val inputStream = File("app/src/main/res/tmp.txt").inputStream()
val bufferedReader = BufferedReader(InputStreamReader(inputStream))
var line: String? = bufferedReader.readLine()
while (line != null) {
onRead(line)
line = bufferedReader.readLine()
}
}
}
@Preview(showBackground = true)
@Composable
fun Test4() {
Test()
}
报错如下:
E/AndroidRuntime: FATAL EXCEPTION: DefaultDispatcher-worker-1
Process: com.linkdom.readbook, PID: 31890
java.io.FileNotFoundException: app/src/main/res/tmp.txt: open failed: ENOENT (No such file or directory)
at libcore.io.IoBridge.open(IoBridge.java:496)
at java.io.FileInputStream.<init>(FileInputStream.java:159)
at com.linkdom.readbook.TestReadRes4Kt$readFile$1.invokeSuspend(TestReadRes4.kt:53)
at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:106)
at kotlinx.coroutines.internal.LimitedDispatcher.run(LimitedDispatcher.kt:42)
at kotlinx.coroutines.scheduling.TaskImpl.run(Tasks.kt:95)
at kotlinx.coroutines.scheduling.CoroutineScheduler.runSafely(CoroutineScheduler.kt:570)
at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.executeTask(CoroutineScheduler.kt:750)
at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.runWorker(CoroutineScheduler.kt:677)
at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.run(CoroutineScheduler.kt:664)
Suppressed: kotlinx.coroutines.DiagnosticCoroutineContextException: [StandaloneCoroutine{Cancelling}@555505, Dispatchers.IO]
Caused by: android.system.ErrnoException: open failed: ENOENT (No such file or directory)
at libcore.io.Linux.open(Native Method)
at libcore.io.ForwardingOs.open(ForwardingOs.java:167)
at libcore.io.BlockGuardOs.open(BlockGuardOs.java:252)
at libcore.io.ForwardingOs.open(ForwardingOs.java:167)
at android.app.ActivityThread$AndroidOs.open(ActivityThread.java:7255)
at libcore.io.IoBridge.open(IoBridge.java:482)
... 10 more
I/Process: Sending signal. PID: 31890 SIG: 9
请用中文回答我。
GPT(顺利解决,代码在完整demo中)
从您提供的错误日志来看,问题出在找不到文件app/src/main/res/tmp.txt
,具体错误为java.io.FileNotFoundException
。
在Android应用中,您不能直接使用项目文件结构中的路径。您需要将文件放在应用的assets
文件夹中,并使用AssetManager
来读取文件。请按照以下步骤修改您的代码:
- 将
tmp.txt
文件移动到app/src/main/assets
文件夹下(如果没有该文件夹,请创建一个)。 - 修改
readFile
函数如下:
private fun readFile(
context: Context,
onRead: (String) -> Unit
) {
GlobalScope.launch(Dispatchers.IO) {
val assetManager = context.assets
val inputStream = assetManager.open("tmp.txt")
val bufferedReader = BufferedReader(InputStreamReader(inputStream))
var line: String? = bufferedReader.readLine()
while (line != null) {
onRead(line)
line = bufferedReader.readLine()
}
}
}
这样就可以正确读取tmp.txt
文件了。
另外,虽然在这个示例中使用GlobalScope
可能不会产生问题,但是并不推荐在实际项目中使用GlobalScope
,因为它可能导致内存泄漏和其他问题。建议使用rememberCoroutineScope
取代GlobalScope
。这里是使用rememberCoroutineScope
的修改示例:
@Composable
fun Test() {
val context = LocalContext.current
val text = remember { mutableStateOf("") }
val coroutineScope = rememberCoroutineScope()
Column (
modifier = Modifier.fillMaxSize(),
horizontalAlignment = Alignment.CenterHorizontally
){
Button(onClick = {
coroutineScope.launch {
readFile(context) {
text.value = it
}
}
}) {
Text("读取文件")
}
Text(text = text.value)
}
}
这样您的代码应该可以正常工作了。如果您还有其他问题,请随时向我提问。