#kotlin #ktor
Вопрос:
Я создал API-интерфейс flask, который может принимать изображение в качестве входных данных в виде строки Base64. Теперь я хочу отправить запрос на этот API из приложения для Android с помощью Ktor. Я использую Jetpack Compose для пользовательского интерфейса здесь. Мне удалось отправить запрос в этот api, но есть проблема, строка Base64 отправляется в api как пустая строка. Теперь, чтобы преобразовать изображение в base64, я использую этот код.
if (imageUri.value!=null){
val file = File(imageUri.value.toString()).readBytes()
imageStr = Base64.encodeToString(file, Base64.DEFAULT)
println(imageStr)
}
Может ли кто-нибудь сказать, что этот код правильный или нет. Я хочу выбрать изображение из галереи и преобразовать его в строку base64. Я также даю код файла MainActivity.kt и свой код файла составной функции.
Основная активность.тыс. т
class MainActivity : ComponentActivity() {
private var imageUri = mutableStateOf<Uri?>(null)
private var imageStr: String = ""
private var post: ImageResponse? = null
private var cropActivityResultContracts = object : ActivityResultContract<Any?, Uri?>() {
override fun createIntent(context: Context, input: Any?): Intent {
return CropImage.activity()
.getIntent(this@MainActivity)
}
override fun parseResult(resultCode: Int, intent: Intent?): Uri? {
return CropImage.getActivityResult(intent)?.uri
}
}
private val launcher = registerForActivityResult(cropActivityResultContracts) { uri ->
imageUri.value = uri
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
if (imageUri.value!=null){
val file = File(imageUri.value.toString()).readBytes()
imageStr = Base64.encodeToString(file, Base64.DEFAULT)
println(imageStr)
}
setContent {
val scope = rememberCoroutineScope()
UploadImageTheme {
ImagePickerDesign(
onSelect = {
launcher.launch("image/*")
},
imageUri = imageUri,
onUpload = {
scope.launch {
post = service.postImage(
ImageRequest(imageStr)
)
}
},
result = post.pred_percentage
)
}
}
}
}
и еще кое-что! может ли кто-нибудь сказать, как отобразить ответ с сервера в приложении. В приведенном выше коде параметр result примет ответ от сервера и отобразит его. Но по какой-то причине я не могу обновить это значение в пользовательском интерфейсе. пожалуйста, помогите в этом случае.
ImagePickerDesign.kt
package com.example.uploadimage
import android.net.Uri
import androidx.compose.foundation.Image
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.*
import androidx.compose.material.Button
import androidx.compose.material.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.MutableState
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.ColorFilter
import androidx.compose.ui.unit.dp
import com.skydoves.landscapist.glide.GlideImage
import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.unit.sp
@Composable
fun ImagePickerDesign(
imageUri: MutableState<Uri?>,
onUpload: () -> Unit,
onSelect: () -> Unit,
result: String
) {
Column(
modifier = Modifier
.fillMaxSize()
.padding(16.dp),
verticalArrangement = Arrangement.SpaceEvenly,
horizontalAlignment = Alignment.CenterHorizontally
) {
if (imageUri.value != null) {
GlideImage(
imageModel = imageUri.value,
modifier = Modifier
.size(350.dp)
.clickable(onClick = onSelect),
contentScale = ContentScale.Fit
)
}else{
Image(
painter = painterResource(id = R.drawable.placeholder_image),
contentDescription = "placeholder",
modifier = Modifier
.size(350.dp)
.clickable(onClick = onSelect),
colorFilter = ColorFilter.tint(Color.Black)
)
}
Text(text = result, fontSize = 16.sp)
Button(onClick = onUpload) {
Text(text = "Upload Image")
}
}
}
Я с нетерпением жду вашего ответа.
вы также можете ознакомиться с моим проектом по этой ссылке https://github.com/srang992/Pancard-Tampering-app
это выводится при запуске приложения для Android
Install successfully finished in 6 s 709 ms.
$ adb shell am start -n "com.example.uploadimage/com.example.uploadimage.MainActivity" -a android.intent.action.MAIN -c android.intent.category.LAUNCHER
Connected to process 32033 on device 'xiaomi-m2010j19si-6686ff050321'.
Capturing and displaying logcat messages from application. This behavior can be disabled in the "Logcat output" section of the "Debugger" settings page.
I/ple.uploadimag: Late-enabling -Xcheck:jni
E/ple.uploadimag: Unknown bits set in runtime_flags: 0x48000
I/Perf: Connecting to perf service.
I/FeatureParser: can't find lime.xml in assets/device_features/,it may be in /vendor/etc/device_features
E/libc: Access denied finding property "ro.vendor.df.effect.conflict"
E/libc: Access denied finding property "ro.vendor.knock.type"
W/ple.uploadimage: type=1400 audit(0.0:18925): avc: denied { read } for name="u:object_r:vendor_default_prop:s0" dev="tmpfs" ino=16328 scontext=u:r:untrusted_app:s0:c35,c257,c512,c768 tcontext=u:object_r:vendor_default_prop:s0 tclass=file permissive=0
type=1400 audit(0.0:18926): avc: denied { read } for name="u:object_r:vendor_default_prop:s0" dev="tmpfs" ino=16328 scontext=u:r:untrusted_app:s0:c35,c257,c512,c768 tcontext=u:object_r:vendor_default_prop:s0 tclass=file permissive=0
W/Looper: PerfMonitor looperActivity : package=com.example.uploadimage/.MainActivity time=273ms latency=938ms running=224ms procState=2 ClientTransaction{ callbacks=[android.app.servertransaction.LaunchActivityItem] lifecycleRequest=android.app.servertransaction.ResumeActivityItem } historyMsgCount=1 (msgIndex=1 wall=997ms seq=2 running=873ms runnable=46ms io=17ms late=2ms h=android.app.ActivityThread$H w=110)
W/Looper: PerfMonitor looperActivity : package=com.example.uploadimage/.MainActivity time=0ms latency=1216ms running=0ms procState=2 ClientTransaction{ callbacks=[android.app.servertransaction.TopResumedActivityChangeItem] } historyMsgCount=2 (msgIndex=1 wall=997ms seq=2 running=873ms runnable=46ms io=17ms late=2ms h=android.app.ActivityThread$H w=110) (msgIndex=2 wall=273ms seq=3 running=224ms runnable=4ms io=20ms late=938ms h=android.app.ActivityThread$H w=159)
I/AdrenoGLES-0: QUALCOMM build : 243b6bc, I98aee2b40e
Build Date : 12/08/20
OpenGL ES Shader Compiler Version: EV031.29.00.16
Local Branch :
Remote Branch : refs/tags/AU_LINUX_ANDROID_LA.UM.8.15.R1.10.00.00.643.066
Remote Branch : NONE
Reconstruct Branch : NOTHING
Build Config : S P 8.0.16 AArch64
Driver Path : /vendor/lib64/egl/libGLESv2_adreno.so
I/AdrenoGLES-0: PFP: 0x016ee188, ME: 0x00000000
I/OpenGLRenderer: Davey! duration=902ms; Flags=1, IntendedVsync=17962622634853, Vsync=17962905968175, OldestInputEvent=9223372036854775807, NewestInputEvent=0, HandleInputStart=17962922546739, AnimationStart=17962922639291, PerformTraversalsStart=17962922843354, DrawStart=17963416902364, SyncQueued=17963440580541, SyncStart=17963440964031, IssueDrawCommandsStart=17963441058406, SwapBuffers=17963524637156, FrameCompleted=17963525914447, DequeueBufferDuration=106000, QueueBufferDuration=392000,
W/Looper: PerfMonitor doFrame : time=605ms vsyncFrame=646397 latency=300ms procState=2 historyMsgCount=4 (msgIndex=1 wall=997ms seq=2 running=873ms runnable=46ms io=17ms late=2ms h=android.app.ActivityThread$H w=110) (msgIndex=2 wall=273ms seq=3 running=224ms runnable=4ms io=20ms late=938ms h=android.app.ActivityThread$H w=159)
I/Choreographer: Skipped 34 frames! The application may be doing too much work on its main thread.
W/Looper: PerfMonitor doFrame : time=11ms vsyncFrame=646410 latency=576ms procState=2 historyMsgCount=5 (msgIndex=1 wall=605ms seq=6 running=461ms late=300ms h=android.view.Choreographer$FrameHandler c=android.view.Choreographer$FrameDisplayEventReceiver)
I/ple.uploadimag: ProcessProfilingInfo new_methods=5563 is saved saved_to_disk=1 resolve_classes_delay=8000
I/Timeline: Timeline: Activity_launch_request time:17970735
W/ActivityThread: handleWindowVisibility: no activity for token android.os.BinderProxy@8f28626
W/ple.uploadimag: Accessing hidden method Landroid/view/View;->computeFitSystemWindows(Landroid/graphics/Rect;Landroid/graphics/Rect;)Z (greylist, reflection, allowed)
W/ple.uploadimag: Accessing hidden method Landroid/view/ViewGroup;->makeOptionalFitsSystemWindows()V (greylist, reflection, allowed)
I/Timeline: Timeline: Activity_launch_request time:17970975
W/Glide: Failed to find GeneratedAppGlideModule. You should include an annotationProcessor compile dependency on com.github.bumptech.glide:compiler in your application and a @GlideModule annotated AppGlideModule implementation or LibraryGlideModules will be silently ignored
I/System.out: 20:44:19.969 [main] INFO io.ktor.client.HttpClient - REQUEST: https://pancard-fraud.herokuapp.com/
20:44:19.978 [main] INFO io.ktor.client.HttpClient - METHOD: HttpMethod(value=POST)
I/System.out: 20:44:19.978 [main] INFO io.ktor.client.HttpClient - COMMON HEADERS
I/System.out: 20:44:19.981 [main] INFO io.ktor.client.HttpClient - -> Accept: application/json
20:44:19.982 [main] INFO io.ktor.client.HttpClient - -> Accept-Charset: UTF-8
I/System.out: 20:44:19.982 [main] INFO io.ktor.client.HttpClient - CONTENT HEADERS
20:44:19.983 [main] INFO io.ktor.client.HttpClient - -> Content-Length: 18
20:44:19.983 [main] INFO io.ktor.client.HttpClient - -> Content-Type: application/json
I/System.out: 20:44:19.984 [main] INFO io.ktor.client.HttpClient - BODY Content-Type: application/json
I/System.out: 20:44:20.024 [main] INFO io.ktor.client.HttpClient - BODY START
20:44:20.025 [main] INFO io.ktor.client.HttpClient - {"imageString":""}
20:44:20.025 [main] INFO io.ktor.client.HttpClient - BODY END
D/NetworkSecurityConfig: No Network Security Config specified, using platform default
I/DpmTcmClient: RegisterTcmMonitor from: $Proxy0
I/System.out: 20:44:41.745 [main] INFO io.ktor.client.HttpClient - RESPONSE: 503 Service Unavailable
20:44:41.746 [main] INFO io.ktor.client.HttpClient - METHOD: HttpMethod(value=POST)
I/System.out: 20:44:41.747 [main] INFO io.ktor.client.HttpClient - FROM: https://pancard-fraud.herokuapp.com/
I/System.out: 20:44:41.747 [main] INFO io.ktor.client.HttpClient - COMMON HEADERS
I/System.out: 20:44:41.748 [main] INFO io.ktor.client.HttpClient - -> cache-control: no-cache, no-store
I/System.out: 20:44:41.749 [main] INFO io.ktor.client.HttpClient - -> connection: keep-alive
I/System.out: 20:44:41.750 [main] INFO io.ktor.client.HttpClient - -> content-length: 506
I/System.out: 20:44:41.751 [main] INFO io.ktor.client.HttpClient - -> content-type: text/html; charset=utf-8
I/System.out: 20:44:41.752 [main] INFO io.ktor.client.HttpClient - -> date: Wed, 03 Nov 2021 15:14:40 GMT
I/System.out: 20:44:41.753 [main] INFO io.ktor.client.HttpClient - -> server: Cowboy
I/System.out: 20:44:41.754 [main] INFO io.ktor.client.HttpClient - -> x-android-received-millis: 1635952481690
I/System.out: 20:44:41.755 [main] INFO io.ktor.client.HttpClient - -> x-android-response-source: NETWORK 503
I/System.out: 20:44:41.756 [main] INFO io.ktor.client.HttpClient - -> x-android-selected-protocol: http/1.1
I/System.out: 20:44:41.757 [main] INFO io.ktor.client.HttpClient - -> x-android-sent-millis: 1635952461008
I/System.out: 20:44:41.769 [ktor-android-dispatcher-worker-3] INFO io.ktor.client.HttpClient - BODY Content-Type: text/html; charset=utf-8
I/System.out: 20:44:41.770 [ktor-android-dispatcher-worker-3] INFO io.ktor.client.HttpClient - BODY START
I/System.out: 20:44:41.771 [ktor-android-dispatcher-worker-3] INFO io.ktor.client.HttpClient - <!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta charset="utf-8">
<title>Application Error</title>
<style media="screen">
html,body,iframe {
margin: 0;
padding: 0;
}
html,body {
height: 100%;
overflow: hidden;
}
iframe {
width: 100%;
height: 100%;
border: 0;
}
</style>
</head>
<body>
<iframe src="//www.herokucdn.com/error-pages/application-error.html"></iframe>
</body>
</html>
I/System.out: 20:44:41.772 [ktor-android-dispatcher-worker-3] INFO io.ktor.client.HttpClient - BODY END
I/System.out: Error: Service Unavailable
Комментарии:
1. Не могли бы вы поделиться кодом для клиента Ktor, который отправляет запрос, и примером ответа сервера?
2. извините за поздний ответ. Я включил свою ссылку на github в свой вопрос, а также в ответ.
3. Вы проверили, что
E/libc: Access denied...
означают эти ошибки?4. Ваш код для получения строки с кодировкой base64 неверен. Вам нужно использовать
getContentResolver().openInputStream(imageUri.value!!)!!.readBytes()
для чтения байтов из файла изображения. Кроме того,imageStr
свойство должно быть обновлено непосредственно перед загрузкой или при обрезке изображения, потому что вonCreate
методеimageUri
всегда естьnull
значение.5. Спасибо за вашу помощь. Теперь это работает. Ты спас меня.