Как показать результаты вызова API на экране Jetpack ComposeAndroid

Форум для тех, кто программирует под Android
Ответить
Anonymous
 Как показать результаты вызова API на экране Jetpack Compose

Сообщение Anonymous »

Это код для Home.kt

Код: Выделить всё

package com.example.littlelemonandroid

import androidx.compose.foundation.Image
import androidx.compose.foundation.background
import androidx.compose.foundation.clickable
import androidx.compose.foundation.gestures.detectTapGestures
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.absoluteOffset
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.wrapContentSize
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.outlined.Search
import androidx.compose.material3.Icon
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.material3.TextField
import androidx.compose.material3.TextFieldDefaults
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.draw.scale
import androidx.compose.ui.focus.FocusManager
import androidx.compose.ui.focus.FocusRequester
import androidx.compose.ui.focus.focusRequester
import androidx.compose.ui.focus.onFocusChanged
import androidx.compose.ui.input.pointer.pointerInput
import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.platform.LocalFocusManager
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import androidx.navigation.NavHostController
import androidx.room.Room
import com.example.littlelemonandroid.ui.theme.Black
import com.example.littlelemonandroid.ui.theme.DarkGray
import com.example.littlelemonandroid.ui.theme.Green
import com.example.littlelemonandroid.ui.theme.LittleLemonAndroidTheme
import com.example.littlelemonandroid.ui.theme.White
import com.example.littlelemonandroid.ui.theme.Yellow
import io.ktor.client.HttpClient
import io.ktor.client.call.body
import io.ktor.client.engine.android.Android
import io.ktor.client.plugins.contentnegotiation.ContentNegotiation
import io.ktor.client.request.get
import io.ktor.serialization.kotlinx.json.json

//@Preview(showBackground = true)
@Composable
fun Home(navController: NavHostController)  {

val searchPhrase = remember {
mutableStateOf("")
}

val focusManager:  FocusManager = LocalFocusManager.current
var isAnyTextFieldFocused by remember { mutableStateOf(false) }
var isFocused by remember { mutableStateOf(false) }
val focusRequester = remember { FocusRequester() }

val context = LocalContext.current
val database by lazy {
Room.databaseBuilder(context, AppDatabase::class.java, "database").build()
}

LittleLemonAndroidTheme {

Column(
modifier = Modifier
.fillMaxSize()
.background(White)
.pointerInput(Unit) {
detectTapGestures {
if (isAnyTextFieldFocused) {
focusManager.clearFocus()
}
}
}
) {
Row(
horizontalArrangement = Arrangement.SpaceAround,
modifier = Modifier
.fillMaxWidth()
.padding(start = 110.dp)
) {
Box(
modifier = Modifier
.size(100.dp)
.wrapContentSize(unbounded = true)
) {
Image(
painter = painterResource(id = R.drawable.logo),
contentDescription = "Little Lemon Logo",
modifier = Modifier
.size(150.dp)
)
}
Box(
modifier = Modifier
.size(100.dp)
.wrapContentSize(unbounded = true)
.clip(CircleShape)
.padding(start = 30.dp)
.clickable {
navController.navigate(Profile.route)
}
) {
Image(
painter = painterResource(id = R.drawable.profile),
contentDescription = "Little Lemon Logo",
modifier = Modifier
.size(60.dp)
.clip(CircleShape)
.scale(2.0f)
.absoluteOffset(y = 7.dp)
)
}
}
Column(
modifier = Modifier
.background(Green)
.fillMaxWidth()
.padding(start = 15.dp, end = 15.dp, bottom = 20.dp)
) {
Text(
text = stringResource(id = R.string.app_title),
style = MaterialTheme.typography.titleMedium,
color = Yellow,
modifier = Modifier
.fillMaxWidth()
.size(50.dp)
)
Text(
text = stringResource(id = R.string.app_city),
style = MaterialTheme.typography.titleSmall,
color = White,
)
Row(
horizontalArrangement = Arrangement.SpaceBetween,
modifier = Modifier
.fillMaxWidth()
)   {
Text(
text = stringResource(id = R.string.app_description),
color = White,
style = MaterialTheme.typography.bodyMedium,
fontSize = 15.sp,
fontWeight = FontWeight.Bold,
textAlign = TextAlign.Left,
modifier = Modifier
.weight(0.7f)
.padding(top = 20.dp)
)
Image(
painter = painterResource(id = R.drawable.hero_image),
contentDescription = "Hero Image",
contentScale = ContentScale.Crop,
modifier = Modifier
.size(height = 130.dp,  width = 150.dp)
.weight(0.5f)
.clip(RoundedCornerShape(10.dp))
)
}
TextField(
value = searchPhrase.value,
onValueChange = {searchPhrase.value = it},
placeholder = {
Text(
text = "Enter search phrase",
style = MaterialTheme.typography.labelMedium,
color = DarkGray,
fontSize = 18.sp,
)
},
leadingIcon = {
Icon(
imageVector = Icons.Outlined.Search,
contentDescription = "Search Icon",
tint = Black
)
},
colors = TextFieldDefaults.colors(
unfocusedContainerColor = White,
focusedContainerColor = White
),
textStyle = MaterialTheme.typography.labelMedium,
singleLine = true,
modifier = Modifier
.fillMaxWidth()
.padding(
top = 15.dp,
)
.size(50.dp)
.clip(RoundedCornerShape(6.dp))
.focusRequester(focusRequester)
.onFocusChanged { focusState ->
isFocused = focusState.isFocused
isAnyTextFieldFocused = isFocused
}
)
}
}
}
}

suspend fun fetchMenu() : List  {
val httpClient = HttpClient(Android)    {
install(ContentNegotiation) {
json()
}
}

val dataURL = "https://raw.githubusercontent.com/Meta-Mobile-Developer-PC/Working-With-Data-API/main/menu.json"
val menuNetwork : MenuNetwork = httpClient.get(dataURL).body()

return menuNetwork.menu
}
Это MainActivity.kt

Код: Выделить всё

package com.example.littlelemonandroid

import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.activity.enableEdgeToEdge
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.WindowInsets
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.statusBars
import androidx.compose.foundation.layout.windowInsetsPadding
import androidx.compose.material3.Scaffold
import androidx.compose.ui.Modifier
import androidx.core.view.WindowCompat
import androidx.navigation.compose.rememberNavController
import com.example.littlelemonandroid.ui.theme.LittleLemonAndroidTheme
import com.example.littlelemonandroid.ui.theme.White

class MainActivity : ComponentActivity() {

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
WindowCompat.setDecorFitsSystemWindows(window, false)
enableEdgeToEdge()

setContent {
LittleLemonAndroidTheme {
Scaffold(
modifier = Modifier
.fillMaxSize()
.windowInsetsPadding(WindowInsets.statusBars)
.background(White)
) { innerPadding ->
Box()   {
val navController = rememberNavController()
Navigation(navController = navController)
}
}
}
}
}
}
Это Network.kt

Код: Выделить всё

package com.example.littlelemonandroid

import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable

@Serializable
data class MenuNetwork(
@SerialName("menu")
val menu: List
)

@Serializable
data class MenuItemNetwork(
@SerialName("id")
val id: Int,

@SerialName("title")
val title: String,

@SerialName("description")
val description: String,

@SerialName("price")
val price: Double,

@SerialName("image")
val image: String,

@SerialName("category")
val category: String,
)   {
fun toMenuItemRoom() = MenuItemRoom(id, title, description, price, image, category)
}
Это Database.kt

Код: Выделить всё

package com.example.littlelemonandroid

import androidx.lifecycle.LiveData
import androidx.room.Dao
import androidx.room.Database
import androidx.room.Entity
import androidx.room.Insert
import androidx.room.PrimaryKey
import androidx.room.Query
import androidx.room.RoomDatabase

@Entity
data class MenuItemRoom (
@PrimaryKey val id: Int,
val title: String,
val description: String,
val price: Double,
val image: String,
val category: String,
)

@Dao
interface MenuItemDao   {
@Query("SELECT * FROM MenuItemRoom")
fun getAll(): LiveData

@Insert
fun insertAll(vararg menuItems: MenuItemRoom)

@Query("SELECT (SELECT COUNT(*) FROM MenuItemRoom) == 0")
fun isEmpty(): Boolean
}

@Database(entities = [MenuItemRoom::class], version = 1)
abstract class AppDatabase  : RoomDatabase()    {
abstract fun menuItemDao(): MenuItemDao
}
Как отобразить результат fetchMenu, как показано ниже
Изображение приложения
Это то, что дает вызов API, выполненный в функции fetchMenu :

Код: Выделить всё

{
"menu": [
{
"id": 1,
"title": "Greek Salad",
"description": "The famous greek salad of crispy lettuce, peppers, olives, our Chicago.",
"price": "10",
"image":  "https://github.com/Meta-Mobile-Developer-PC/Working-With-Data-API/blob/main/images/greekSalad.jpg?raw=true",
"category": "starters"
},
{
"id": 2,
"title": "Lemon Desert",
"description": "Traditional homemade Italian Lemon Ricotta Cake.",
"price": "10",
"image": "https://github.com/Meta-Mobile-Developer-PC/Working-With-Data-API/blob/main/images/lemonDessert%202.jpg?raw=true",
"category": "desserts"
},
{
"id": 3,
"title": "Grilled Fish",
"description": "Our Bruschetta is made from grilled bread that has been smeared with garlic and seasoned with salt and olive oil.",
"price": "10",
"image": "https://github.com/Meta-Mobile-Developer-PC/Working-With-Data-API/blob/main/images/grilledFish.jpg?raw=true",
"category": "mains"
},
{
"id": 4,
"title": "Pasta",
"description": "Penne with fried aubergines, cherry tomatoes, tomato sauce, fresh chili, garlic, basil & salted ricotta cheese.",
"price": "10",
"image": "https://github.com/Meta-Mobile-Developer-PC/Working-With-Data-API/blob/main/images/pasta.jpg?raw=true",
"category": "mains"
},
{
"id": 5,
"title": "Bruschetta",
"description": "Oven-baked bruschetta stuffed with tomatoes and herbs.",
"price": "10",
"image": "https://github.com/Meta-Mobile-Developer-PC/Working-With-Data-API/blob/main/images/bruschetta.jpg?raw=true",
"category": "starters"
}
]
}
Попробовал запустить fetchMenu в runBlocking и LaunchedEffect, но это не работает. В основном мне нужно иметь возможность делать следующее: 1.) Вызывать функцию и 2.) Сохранять данные в базе данных и отображать результат. Я новичок в Jetpack Compose, если у вас есть другие предложения, скажите об этом.

Подробнее здесь: https://stackoverflow.com/questions/788 ... ck-compose
Ответить

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

Вернуться в «Android»