하나는 "NullPointerException: Cannot invoke "String.length()" because "<parameter1>" is null" 이런 에러인거 같은데....대체 어디서 잘못된걸까요. 에러가 여러개 인건가요? FAILURE: Build completed with 2 failures. 1: Task failed with an exception. ----------- * What went wrong: Execution failed for task ':app:checkDebugAarMetadata'. > A failure occurred while executing com.android.build.gradle.internal.tasks.CheckAarMetadataWorkAction > 5 issues were found when checking AAR metadata: * Try: > Run with --info or --debug option to get more log output. > Run with --scan to get full insights. * Exception is: org.gradle.api.tasks.TaskExecutionException: Execution failed for task ':app:checkDebugAarMetadata'. Caused by: org.gradle.workers.internal.DefaultWorkerExecutor$WorkExecutionException: A failure occurred while executing com.android.build.gradle.internal.tasks.CheckAarMetadataWorkAction Caused by: java.lang.RuntimeException: 5 issues were found when checking AAR metadata: 1. Dependency 'androidx.appcompat:appcompat-resources:1.7.0' requires libraries and applications that depend on it to compile against version 34 or later of the Android APIs. :app is currently compiled against android-33. Also, the maximum recommended compile SDK version for Android Gradle plugin 8.0.0 is 33. Recommended action: Update this project's version of the Android Gradle plugin to one that supports 34, then update this project to use compileSdk of at least 34. Note that updating a library or application's compileSdk (which allows newer APIs to be used) can be done separately from updating targetSdk (which opts the app in to new runtime behavior) and minSdk (which determines which devices the app can be installed on). 2. Dependency 'androidx.appcompat:appcompat:1.7.0' requires libraries and applications that depend on it to compile against version 34 or later of the Android APIs. :app is currently compiled against android-33. Also, the maximum recommended compile SDK version for Android Gradle plugin 8.0.0 is 33. Recommended action: Update this project's version of the Android Gradle plugin to one that supports 34, then update this project to use compileSdk of at least 34. Note that updating a library or application's compileSdk (which allows newer APIs to be used) can be done separately from updating targetSdk (which opts the app in to new runtime behavior) and minSdk (which determines which devices the app can be installed on). 3. Dependency 'androidx.core:core-ktx:1.13.0' requires libraries and applications that depend on it to compile against version 34 or later of the Android APIs. :app is currently compiled against android-33. Also, the maximum recommended compile SDK version for Android Gradle plugin 8.0.0 is 33. Recommended action: Update this project's version of the Android Gradle plugin to one that supports 34, then update this project to use compileSdk of at least 34. Note that updating a library or application's compileSdk (which allows newer APIs to be used) can be done separately from updating targetSdk (which opts the app in to new runtime behavior) and minSdk (which determines which devices the app can be installed on). 4. Dependency 'androidx.core:core:1.13.0' requires libraries and applications that depend on it to compile against version 34 or later of the Android APIs. :app is currently compiled against android-33. Also, the maximum recommended compile SDK version for Android Gradle plugin 8.0.0 is 33. Recommended action: Update this project's version of the Android Gradle plugin to one that supports 34, then update this project to use compileSdk of at least 34. Note that updating a library or application's compileSdk (which allows newer APIs to be used) can be done separately from updating targetSdk (which opts the app in to new runtime behavior) and minSdk (which determines which devices the app can be installed on). 5. Dependency 'androidx.annotation:annotation-experimental:1.4.0' requires libraries and applications that depend on it to compile against version 34 or later of the Android APIs. :app is currently compiled against android-33. Also, the maximum recommended compile SDK version for Android Gradle plugin 8.0.0 is 33. Recommended action: Update this project's version of the Android Gradle plugin to one that supports 34, then update this project to use compileSdk of at least 34. Note that updating a library or application's compileSdk (which allows newer APIs to be used) can be done separately from updating targetSdk (which opts the app in to new runtime behavior) and minSdk (which determines which devices the app can be installed on). ============================================================================== 2: Task failed with an exception. ----------- * What went wrong: Execution failed for task ':app:mergeExtDexDebug'. > Could not resolve all files for configuration ':app:debugRuntimeClasspath'. > Failed to transform appcompat-resources-1.7.0.aar (androidx.appcompat:appcompat-resources:1.7.0) to match attributes {artifactType=android-dex, asm-transformed-variant=NONE, dexing-enable-desugaring=true, dexing-enable-jacoco-instrumentation=false, dexing-is-debuggable=true, dexing-min-sdk=24, org.gradle.category=library, org.gradle.dependency.bundling=external, org.gradle.libraryelements=aar, org.gradle.status=release, org.gradle.usage=java-runtime}. > Execution failed for DexingNoClasspathTransform: C:\Users\abc14\.gradle\caches\transforms-3\c494794d48d9429ce3837ff3d9162578\transformed\appcompat-resources-1.7.0-runtime.jar. > Error while dexing. > Failed to transform appcompat-1.7.0.aar (androidx.appcompat:appcompat:1.7.0) to match attributes {artifactType=android-dex, asm-transformed-variant=NONE, dexing-enable-desugaring=true, dexing-enable-jacoco-instrumentation=false, dexing-is-debuggable=true, dexing-min-sdk=24, org.gradle.category=library, org.gradle.dependency.bundling=external, org.gradle.libraryelements=aar, org.gradle.status=release, org.gradle.usage=java-runtime}. > Execution failed for DexingNoClasspathTransform: C:\Users\abc14\.gradle\caches\transforms-3\d251d80cfc588f74172158875c7b2196\transformed\appcompat-1.7.0-runtime.jar. > Error while dexing. * Try: > Run with --info or --debug option to get more log output. > Run with --scan to get full insights. * Exception is: org.gradle.api.tasks.TaskExecutionException: Execution failed for task ':app:mergeExtDexDebug'. Caused by: java.lang.NullPointerException: Cannot invoke "String.length()" because "<parameter1>" is null Caused by: java.util.concurrent.ExecutionException: com.android.tools.r8.utils.P0: java.lang.NullPointerException: Cannot invoke "String.length()" because "<parameter1>" is null Caused by: [CIRCULAR REFERENCE: java.lang.NullPointerException: Cannot invoke "String.length()" because "<parameter1>" is null] Cause 2: org.gradle.api.internal.artifacts.transform.TransformException: Failed to transform appcompat-1.7.0.aar (androidx.appcompat:appcompat:1.7.0) to match attributes {artifactType=android-dex, asm-transformed-variant=NONE, dexing-enable-desugaring=true, dexing-enable-jacoco-instrumentation=false, dexing-is-debuggable=true, dexing-min-sdk=24, org.gradle.category=library, org.gradle.dependency.bundling=external, org.gradle.libraryelements=aar, org.gradle.status=release, org.gradle.usage=java-runtime}. Caused by: org.gradle.api.internal.artifacts.transform.TransformException: Execution failed for DexingNoClasspathTransform: C:\Users\abc14\.gradle\caches\transforms-3\d251d80cfc588f74172158875c7b2196\transformed\appcompat-1.7.0-runtime.jar. Caused by: com.android.builder.dexing.DexArchiveBuilderException: Error while dexing. at com.android.builder.dexing.D8DexArchiveBuilder.getExceptionToRethrow(D8DexArchiveBuilder.java:189) Caused by: com.android.tools.r8.CompilationFailedException: Compilation failed to complete, origin: C:\Users\abc14\.gradle\caches\transforms-3\d251d80cfc588f74172158875c7b2196\transformed\appcompat-1.7.0-runtime.jar:androidx/appcompat/app/ActionBarDrawerToggle$1.class Caused by: java.lang.NullPointerException: Cannot invoke "String.length()" because "<parameter1>" is null Suppressed: java.lang.RuntimeException: java.util.concurrent.ExecutionException: com.android.tools.r8.utils.P0: java.lang.NullPointerException: Cannot invoke "String.length()" because "<parameter1>" is null Caused by: java.util.concurrent.ExecutionException: com.android.tools.r8.utils.P0: java.lang.NullPointerException: Cannot invoke "String.length()" because "<parameter1>" is null Caused by: com.android.tools.r8.utils.P0: java.lang.NullPointerException: Cannot invoke "String.length()" because "<parameter1>" is null Caused by: [CIRCULAR REFERENCE: java.lang.NullPointerException: Cannot invoke "String.length()" because "<parameter1>" is null]
안녕하세요 강의 잘 보고 있습니다. 저는 현재 스프링 진영에서 백엔드 개발을 하고 있습니다. ktor이라는 것을 들어보긴 했는데, 막상 코드를 보면서 비슷한 부분도 있고 새로운 부분도 많네요! 강의를 보다가 궁금한 점이 있는데, 보통 리액트 서버는 3000번 포트로 띄우고 백엔드는 따로 실행해서 화면 테스트를 진행하곤 했는데, Ktor 강의에서는 인텔리제이 실행 한번으로 리액트 서버도 실행되고 같은 포트에 백엔드 호출이 가능한 것을 보고 어떻게 이게 가능한가 싶어서 질문 남깁니다!
강사님 안녕하세요. 우선, 좋은 강의 감사합니다. 19강.코틀린의 이모저모 학습 중 이해되지 않는 부분이 있어서 질문드립니다. takeIf 을 설명하실 때 getNumberOrNull 함수와 getNumberOrNullV2 함수가 동일한 코드라고 설명해주셨는데요. 강의에서 takeIf 확장 함수는 주어진 조건을 만족하면 그 값을, 만족하지 않는다면 null 을 반환한다고 설명해주셨는데, 그러면 getNumberOrNull 함수의 반환 값이 반대로 된 것이 아닌가요? 오히려 getNumberOrNull 함수는 takeUnless 를 사용하는 getNumberOrNullV3 함수와 동일하다고 생각됩니다. 저는 아래와 같이 이해했는데.. 혹시 제가 잘못 이해한건지, 아니면 강의자료에 오타가 있으신건지 궁금합니다~~ // takeIf 구현 fun getNumberOrNull(): Int? { return if (number <= 0) number // 해당 조건이 맞으면 해당 값을 반환 else null // 아니면 Null을 반환 }
rvAdapter.itemClick = object : RVAdapter.ItemClick{ override fun onClick(view: View, position: Int) { val intent = Intent(baseContext, ViewActivity::class.java) intent.putExtra("url", items[position].url) intent.putExtra("title", items[position].titleText) intent.putExtra("titleImageUrl", items[position].titleImageUrl) startActivity(intent) } } 안녕하세요 개복치개발자님. 항상 강사님의 좋은 강의 감사한 마음으로 잘 듣고 있습니다. 섹션 7 망고플레이트 앱 만들기를 공부하다가 궁금한 부분이 있어서 질문 남깁니다. val intent = Intent(baseContext, ViewActivity::class.java) 이 부분에서 baseContext가 의미가하는게 무엇인지, 그리고 여기서 this를 사용하면 안되고 baseContext를 사용해야 하는 까닭이 궁금합니다. 답변 주시면 감사하겠습니다.
입문자를 위한 Spring Boot with Kotlin - 나만의 포트폴리오 사이트 만들기
안녕하세요. 강의 내용중에 궁금한게 있어서 질문 드립니다. 로그인 폼을 거치지 않고 POST body를 전달해서 바로 로그인 해보면 어떨까 해서 시도 했는데 잘 되지 않네요 ... fun filterChain(httpSecurity: HttpSecurity): SecurityFilterChain { return httpSecurity .authorizeHttpRequests { authorizeHttpRequests -> authorizeHttpRequests .requestMatchers(AntPathRequestMatcher("/admin/**")).authenticated() .anyRequest().permitAll() }.csrf {csrf -> csrf.disable() }.headers { headers -> headers.addHeaderWriter(XFrameOptionsHeaderWriter(XFrameOptionsHeaderWriter.XFrameOptionsMode.SAMEORIGIN)) }.formLogin { formLogin -> formLogin.defaultSuccessUrl("/h2-console") // 추가 ////////////////////////////////////////// formLogin.loginProcessingUrl("/login") formLogin.usernameParameter("email") formLogin.passwordParameter("password") }.logout { logout-> logout.logoutRequestMatcher(AntPathRequestMatcher("/admin/logout")) .logoutSuccessUrl("/") }.build() } 강의 내용중에 제가 주석으로 추가 내용 달았어요... 그리고 Entity는 아래처럼 구성했습니다. class Account(email: String, pw: String): BaseEntity(), UserDetails { ........ @field:NotNull @Column(unique = true) var email: String = email @Column(name = "password") var pw: String = pw 그래서 위에처럼 전달했습니다. 그리고 run accountRepository에 디버깅 브레이크를 걸고 Post 메세지를 쐈습니다. 그런데 디버깅 걸린건 "" 공백이네요. 프론트 엔드에서 시큐리티 로그인페이지를 만들고 아디이 패스워드를 전달해서 제어하려고 시도 했는데 뭔가 문제가 있나봐요... 답변 해주지면 감사하겠습니다. @Service class AdminSecurityService( private val accoutRepository: AccountRepository ) : UserDetailsService { override fun loadUserByUsername(email: String): UserDetails { return accoutRepository.findByEmail(email) .orElseThrow{RuntimeException("사용자 정보를 찾을 수없습니다.") } } } ========= 추가 질문 드려요 지금 시큐리티 로그인은 Spring boot 초기화 스타트 한후 유저의 접근을 막는 방화벽 같은 용도로 사용하는건가요?? 아니면 웹 "react" http://localhost:3000/ 에서 로그인 폼 게발한후에 로그인 정보(이메일, 패스워드 아이디)를 http://localhost:8080/login 에 POST / GET 방식으로 전달하고 시큐리티에 접근해서 로그인 하는 사용자 로그인 목적으로 사용하는건지 ... 이게 intellij IDEA에 웹페이지랑 스프링 부트를 개발해서 강의내용은 이해하는데 프론트 엔드와 백엔드와의 통신으로 본다면 좀 헛깔려요 로그인 페이지는 프론트 엔드에서 만드는게 아니라 백엔드에서 만들어야하나... 그럼 프론트엔드에서 백엔드에 접근해 시큐리티 로그인을 한후 로그인 성공 했다는 메세지를 어떻게 프론트 엔드에 전달해야되는지... 그냥 관리자 페이지(사용자 목록 리스트나 사용자 로그인 접근 정보를 보는 용도)를 사용할때 시큐리티 로그인을 사용하고 user로그인(작성한 글, 좋아요 같은 카운트, 로그인한 전화번호, 사진 정보)은 따로 user 로그인하는 Api Controller에 접근해서 로그인 하는건지 좀 헛깔려요. 현재 구글에서 찾아보면 관리페이지는 시큐리티로 접근 사용자, 게스트튼 로그인 API로 접근해서 관리하는거 같은데 정보 찾는게 어렵네요...
안녕하세요 강의 잘 듣고있습니다. class 에는 setter 와 getter 를 생성하지 않고 data class 에는 var 로 받을경우 setter 와 getter 가 생성되면 이외의 다른 메서들도 자동으로 생성이 된다고 하셨습니다. 그러면 class 는 더이상 사용하지 않나요 ?
안녕하세요 강사님, 좋은 강의 잘 듣고 있습니다. 따라하던 중 토큰을 잘못 입력했을 경우 403 Forbidden 에러가 발생하는데 이 에러의 경우는 RestControllerAdvice 에서 처리를 할 수 없는건가요?? 이 경우에도 Response형태를 통일 시키고 싶은데 어떻게 하면 될까요..?
입문자를 위한 Spring Boot with Kotlin - 나만의 포트폴리오 사이트 만들기
안녕하세요. 몇달간 넘 바빠서 스프링 공부를 못했네요. 프로젝트를 하나 새롭게 생성한다음에 첨부터 강의 하나 하나 보면서 프로젝트에 기능을 추가 하고 있었습니다. 그리고 Repository와 Service를 까지 왔어요.. 이 둘의 차이점도 확인해서 비교 하고 그런데 역시 의존성 주입은 좀 어렵더라구요.. 아마 이부분을 제가 몰라서 아래 설명할 코드에 예상하지 못하는 결과가 나왔을꺼 같은데 흠... 사실 질문 하기 미안 하긴 하지만 그래도 빨리 좀 알아야해서 질문 드립니다. 일단 깃 주소부터 올립니다. justkjy/about-coffee: about coffee server (github.com) https://github.com/justkjy/about-coffee 여기에 test>kotlin>... >service>PresentationServiceTest> fun insertMenuTest() { ............... val testCoffeeMenu = presentationService.coffeeMenuSave(coffeeMenuDto) ............... } 디버깅 타서 src/main/kotlin/com/example/aboutcoffee/service/PresentationService.kt fun coffeeMenuSave(menuDTO: CoffeeMenuDTO):CoffeeMenu? { ................. resultMenu = presentationRepository.coffeeMenuSave(menuSave) ................ } 이 부분 왜 null을 리턴하는지 모르겠어요... 분명 데이터 저장하는게 맞는데 .... mock 설정이 잘못되서 그런거겠죠?? ㅠ.ㅠ 에러를 못잡아서 잠을 못자고 있네요 이 프로젝트 완료하면 react로 작성된 커피 블러그랑 연동 하려 했는데 ... 시간이 꽤 걸릴듯 하네요 ㅠ.ㅠ
섹션5, 네비게이션을 만들어보는 강의에서 네비게이션 버튼을 만들고 프래그먼트로 연결시키는 작업까지 완료하고 실행시켜보았을 때 버튼을 눌렀지만, 2번째 프래그먼트로 넘어가지 않습니다. 로그를 추가해서 살펴보았는데, 버튼이 아예 클릭되지 않는 것 같습니다. 코드는 드라이브 링크를 남기겠습니다. 감사합니다 https://drive.google.com/drive/folders/1ri7_CYyzzRrhdMA7vII7TSMJsR9AIcJE?usp=drive_link
gradle에 groupie 라이브러리를 최신 버전으로 implementation 하였는데도 불구하고 이와 같이 import 되지 않습니다. github 공식 문서대로 해도 지원되지 않는데, 2022년을 마지막으로 업데이트가 없는 걸로 봐서 지원이 종료된 걸로 알고 수강을 종료해야 될까요 ?
실전! 코틀린과 스프링 부트로 도서관리 애플리케이션 개발하기 (Java 프로젝트 리팩토링)
안녕하세요 강사님 강의를 들으면서 이번에 처음 JPA를 알아가고 있는 중입니다. 헌데 궁금한점이 JPA 특성인것인지 아니면 H2 DB 문제인지 그것도 아니면 제 Intellij 설정 문제인지 모르겠지만 select가 두번이 되는 이유가 무엇때문이지 궁금해서 질문 드립니다. 실질적인 동작에 문제가 생기지는 않겠지만 N+1 관련 강의를 듣다보니 불필요하게 쿼리가 호출되면 안좋은것 같아 여쭈어 봅니다. @Test @DisplayName("대출 기록이 없는 유저도 응답에 포함") fun getUserLoanHistoriesTest() { //given userRepository.save(User("A",null)) //when val results = userService.getUserLoanHistories() //then assertThat(results).hasSize(1) assertThat(results[0].name).isEqualTo("A") assertThat(results[0].books).isEmpty() } 위의 코드를 동작시켰을때 Hibernate: insert into user (id, age, name) values (default, ?, ?) Hibernate: select user0_.id as id1_1_, user0_.age as age2_1_, user0_.name as name3_1_ from user user0_ Hibernate: select userloanhi0_.user_id as user_id4_2_0_, userloanhi0_.id as id1_2_0_, userloanhi0_.id as id1_2_1_, userloanhi0_.book_name as book_nam2_2_1_, userloanhi0_.status as status3_2_1_, userloanhi0_.user_id as user_id4_2_1_ from user_loan_history userloanhi0_ where userloanhi0_.user_id=? Hibernate: select user0_.id as id1_1_, user0_.age as age2_1_, user0_.name as name3_1_ from user user0_ Hibernate: select userloanhi0_.user_id as user_id4_2_0_, userloanhi0_.id as id1_2_0_, userloanhi0_.id as id1_2_1_, userloanhi0_.book_name as book_nam2_2_1_, userloanhi0_.status as status3_2_1_, userloanhi0_.user_id as user_id4_2_1_ from user_loan_history userloanhi0_ where userloanhi0_.user_id=? Hibernate: delete from user where id=? 출력 부분에 위에 처럼 뜨는데요 제가 이해한 바로는 insert는 save 때문에 한번인 반면에 getUserLoanHistoreies 부분에 findAll로 한번의 쿼리를 불러오는 거라서 user와 와 userloanhistory 테이블을 각각 한번 씩 조회 해야 하지 않는가 싶어서 질문 드립니다. 추가로 확인해 보보니 LEFT join에 fetch를 추가했을때 위의 select user와 user_loan_history는 left join 쿼리문으로 변한는 반면 아래의 select user와 user_loan_history는 남아 있습니다. 따로 user를 find 하는 곳이 없는 것 같은데 이런 현상이 나오는 이유가 뭘까요?.... 추측 하기로는 AfterEach로 clear할때 deleteAll을 사용해서 사용했던 테이블을 모두 select 하는건가 싶긴 한데... 제가 이해를 잘 못해서 그런건지 이부분이 어렵네요....
안녕하세요 ktor이란 가벼운 백엔드 프로그램이 있어서 반가운 마음에 수강 신청하고 강의 듣고 있습니다. 전 개발 시에 항상 폴더경로와 패키지 경로는 같게 하고 다른 강의나 책에서도 패키지 명은 폴더를 따라 가던데 강의/소스 보니 패키지 명이 폴더를 안따라 가는거 같아서 물어봅니다. 예를 들어서 CafeMenu.kt의 파일은 com>example>model 에 있습니다. 그런데 패키지 명은 package com.example.domain.model 이라고 적혀 있는데 경로에서는 domain이 없어요... 그래서 패키지 명을 수정한다면 domain이 이 빠진 package com.example.model 라 작성하거나 domain 폴더를 생성하는게 맞지 않나요?? 흠 .. 뭐 이건 방식이긴 한데 빈 프로젝트에서 시작하는게 강의 듣는데 안 헛깔렸을꺼 같은데 ... 첫 ktor 샘플인 ktor-sample-world에서 plugins가 config로 변경된거 같아서 좀 당황했어요 ^^;; 원리 아무것도 모르고 시작할 땐 그냥 강사님의 이야기를 졸졸졸 따라 가는게 학생들의 마음이라 ... 뭔가 갑작스럽게 단계를 점프하면 고민을 많이 하거든요 ... 이거 폴더 변경되도 문제 없나 ... 내가 빈프로젝트를 만들어서 프로그램 코딩하는데 나도 config의 폴더를 plugins로 변경해야 돌아가는거 아니야.... 폴더명 변경했는데 안돌아가면 어떻게 하지 이런 생각이 갑자기 들었거든요 .. 어째건 저 패키지명 저렇게 해도 되나요??
개인적으로 변수가 null일 경우 변수?.let { } 이렇게 사용해 왔는데요. 강의에서는 viewModelScope.launch { todoRepository.addTodo(recentlyDeleteTodo ?: return@launch) } 이렇게 사용 하셨는데요. 해당 부분만 보면 뭐가 더 좋다 이럴게 없어 보이기는 하는데요. 혹시 특정한 상황에서 ?: return 으로 하는 것이 필요한(or 더 좋은) 경우가 있을까요?
안녕하세요. Spring MVC 환경에서 코루틴을 사용할 때 질문이 있습니다. (WebFlux 사용 X) 다음과 같은 코드가 있다고 가정하겠습니다. 컨트롤러 @GetMapping("/test") suspend fun test(): ApiResponse<Void> { testService.run() return ApiResponse.success(statusCode = HttpStatus.OK) } 서비스 class TestService( private val userRepository: UserRepository, ) { suspend fun run(): Triple<String, String, Int> { // 외부 API 호출 1 val nicknameDeferred = CoroutineScope(Dispatchers.IO).async { callApiForNickname() } // 외부 API 호출 2 val addressDeferred = CoroutineScope(Dispatchers.IO).async { callApiForAddress() } // Do something business logic // DB 호출 val duplicateCount = userRepository.findDuplicateCountById(1L) return Triple(first = nicknameDeferred.await(), second = addressDeferred.await(), third = duplicateCount) } } (callApiFor~() 메소드는 외부 API 호출이라고 가정하며 suspend function입니다) 서비스 레이어에서는 2개의 외부 API 호출을 수행하고 DB호출을 한 후 리턴해주는 간단한 구조입니다. 질문 초기에는 내부적으로 코루틴을 사용할 지 말지 결정할 수 없는 상황이 있기에 모든 컨트롤러 메소드를 suspend로 선언하는건 어떨까 합니다. (2번 질문의 성능 차이가 크지 않다면요^^) 이 부분에 대해 강사님의 생각과 실무에서는 보통 어떻게 하는지 궁금합니다. 위 질문에 이어서, 코루틴이 전혀 사용되지 않는 상황에서 컨트롤러 메소드를 suspend로 선언하면 일반 메소드로 선언하는것과 성능차이가 어느정도 있을까요? (물론 트래픽 등 기타 상황별로 다르겠지만요) 서비스 레이어를 보면 CoroutineScope을 통해 각 외부 API호출별로 루트 코루틴을 따로 만들고 있습니다. 각 외부 API들은 단순 조회 요청으로써 구조적 동시성이 필요하지 않다고 생각하기 때문인데요. 실무에서도 위와 같이 여러개의 외부 API호출을 병렬로 수행해야하는 경우 각 호출마다 CoroutineScope을 사용하여 개별로 루트 코루틴을 만들어서 사용하는지 궁금합니다. 일반적인 웹 API 서버 개발을 수행할 때 구조적 동시성이 필요한 케이스가 있을까요? 어차피 추후 로직을 통해 반환값에 대한 검증을 수행한다고 생각해서요. 예를 들어 A, B, C를 코루틴으로 호출할 때 A가 실패해서 B, C를 취소하려해도 각 메소드의 레이턴시에 따라 취소될수도, 이미 완료됐을수도 있을 것 같습니다. 실무에서 웹 API 비즈니스 로직 구성 시, 개별 루트 코루틴이 아닌 하나의 루트 코루틴으로 묶어서 구조적 동시성을 보장해야만 하는 상황이 있을지, 있다면 무엇일지 궁금합니다. 감사합니다.
진도가 나가지지 않아서 막막합니다... 도움이 필요합니다... 오류 발생한 것에 대한 내용도 글로 정리된 링크나 안내를 실시간으로 받아볼 수 있는 방법은 없을까요?? ㅠㅠ 지금 한달 내내 같은 곳에서 멈춰있는 듯해서 미칠지경입니다... 한 발 더 딛고 싶은데 같은곳에서 빙빙도니까 정말 정신적으로 너무 힘이드네요.
명언 앱 만들기 강의 수강 중 Type mismatch: inferred type is ViewDataBinding! but ActivityMainBinding was expected 위와 같은 오류가 발생합니다. binding=DataBindingUtil.setContentView(this,R.layout.activity_main) 에 빨간 밑줄이 그어집니다. package com.junho.goodwords import android.content.Intent import android.os.Bundle import androidx.appcompat.app.AppCompatActivity import androidx.databinding.DataBindingUtil import com.junho.goodwords.databinding.ActivityMainBinding class MainActivity : AppCompatActivity() { private lateinit var binding: ActivityMainBinding override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) binding=DataBindingUtil.setContentView(this,R.layout.activity_main) binding.showAllSentencesBtn.setOnClickListener { val intent= Intent(this,SentenceActivity::class.java) startActivity(intent) } } } gradle 에서는 buildFeatures{ dataBinding=true viewBinding=true } 로 설정하였습니다.