[AndroidStudio] Unsupported Modules Detected 에러 해결


Unsupported Modules Detected: Compilation is not supported for following modules: [프로젝트 명] Unfortunately you can't have non-Gradle Java modules and Android-Gradle modules in one project.


안드로이드 스튜디오에서 프로젝트 빌드를 했더니 이벤트 로그에 다음과 같은 에러가 났습니다.

더보기

Unsupported Modules Detected: Compilation is not supported for following modules: [프로젝트 명] Unfortunately you can't have non-Gradle Java modules and Android-Gradle modules in one project.

 

아래는 위 에러에 대한 해결 방법입니다. 저는 아래 방법으로 해결 되었습니다.(안드로이드 스튜디오 3.6.2 기준) - Stack overflow 참조 (링크)

1 - 프로젝트를 닫습니다.

2 - 안드로이드 스튜디오 IDE를 닫습니다.

3 - .idea 폴더를 삭제합니다. (프로젝트 위치에 있는 .idea 폴더입니다.)

4 - 모든 .iml 파일을 삭제합니다. (프로젝트 위치에서 .iml 파일을 검색하여 나오는 파일들 전부 삭제하면됩니다.)

5 - 안드로이드 스튜디오를 열고 프로젝트를 import해줍니다.

 


 

위 방법으로 해결이 안된다면, 스택오버플로에 있는 다른 해결방법입니다.

프로젝트 내 setting.gradle로 이동합니다.

--

include ':app'

rootProject.name='<~~~>'  // 제거

--

위 내용에서 rootProject.name='<>' 를 제거해줍니다.

그리고 상단에 나오는 Sync Now 클릭

 

참조

https://stackoverflow.com/questions/30142056/error-unfortunately-you-cant-have-non-gradle-java-modules-and-android-gradle

 

Error: Unfortunately you can't have non-Gradle Java modules and > Android-Gradle modules in one project

I have an IntelliJ 14.1.2 Project consisting of two modules - one is an Android Gradle based module and the other is a Spring Java-based module with Maven. gps-trackman.v1 is my root project and I...

stackoverflow.com

 

버전정보 (v1.0)

 - v1.0 2020.06.29 배포

 

* 저작권에 위반될 수 있는 컨텐츠(이미지, 동영상 등)나 게시글은 삭제되거나 수정될 수 있습니다.

* 문제의 여지가 될 수 있는 컨텐츠의 경우 댓글 달아 주시면 빠른 시일 내에 조치하도록 하겠습니다.

* Karzin은 항상 공부중입니다. 설명이 틀리거나 잘못된 부분이 있다면 의견내주시는대로 수정하도록 하겠습니다.

 

Karzin

abbeea@naver.com


[Java] Activity 화면 방향 회전시 제어하기 (Sensor옵션)


 

지난 시간에 Activity 화면의 방향을 제어하는 방법에 대해서 알아보았습니다. (링크)

 

여기서는 sensor옵션 관련(sensor, fullsensor, sensorLandscape, sensorPortrait) 옵션을 주고 회전시에 화면을 제어하는 방법에 대해서 알아보도록 하겠습니다.

 

Manifest에서 화면의 방향을 제어할 옵션을 준 Activity Class에서 onCreate 함수에

displayManager를 선언해 Listner를 등록해주면 됩니다.

아래는 DisplayManager를 선언하고 Listener를 등록해주는 소스

DisplayManager displayManager = (DisplayManager) getSystemService(Context.DISPLAY_SERVICE);
displayManager.registerDisplayListener(displayListener, null);

 

위 소스를 입력하시면 displayListener가 없다고 에러가 날겁니다.

아래는 우리에게 필요한 Listener(displayListener)를 생성합니다.

DisplayManager.DisplayListener displayListener = new DisplayManager.DisplayListener() {
  @Override
  public void onDisplayAdded(int displayId) {
  	//디스플레이가 시스템에서 추가될 때
  }

  @Override
  public void onDisplayRemoved(int displayId) {
  	//디스플레이가 시스템에서 삭제될 때
  }

  @Override
  public void onDisplayChanged(int displayId) {
  	//디스플레이가 변경될때마다
  }
};

위 선언된 Listener에서 내부 Override된 onDisplayChanged 함수를 이용하시면 Activity가 회전될 때마다 캐치하여 원하는 소스를 실행할 수 있습니다.

 

참조

https://developer.android.com/reference/android/hardware/display/DisplayManager.DisplayListener

 

버전정보 (v1.0)

 - v1.0 2020.06.27 배포

 

* 저작권에 위반될 수 있는 컨텐츠(이미지, 동영상 등)나 게시글은 삭제되거나 수정될 수 있습니다.

* 문제의 여지가 될 수 있는 컨텐츠의 경우 댓글 달아 주시면 빠른 시일 내에 조치하도록 하겠습니다.

* Karzin은 항상 공부중입니다. 설명이 틀리거나 잘못된 부분이 있다면 의견내주시는대로 수정하도록 하겠습니다.

 

Karzin

abbeea@naver.com

 


[Kotlin, Java] Activity 화면 방향 설정


안드로이드의 Activity 설정 시 Orientation을 지정하는 방법을 설명합니다.

 

AndroidManifest.xml에 Orientation 설정을 바꿀 Activity에 대해 특성 한가지만 추가(수정)해주면 됩니다.

 - android:screenOrientation = "옵션값"

  -> screenOrientation 특성은 Activity의 방향을 설정할 수 있습니다.

  -> 단, Activity가 다중창모드(멀티태스킹, 화면 분할)로 실행이 된다면 이 특성은 무시됩니다.

  -> 옵션값 (자주 사용할만한 옵션값에는 Bold 처리)

 

unspecified behind landscape portrait
reverseLandscape reversePortrait sensorLandscape sensorPortrait
userLandscape userPortrait sensor fullSensor
nosensor user fullUser locked

 

-> 자주 사용하는 옵션값만 설명을 하자면,

 landscape는 Activity를 가로방향으로 고정합니다.

 portrait는 Activity를 세로방향으로 고정합니다.

 sensorLandscape는 Activity를 가로방향으로 고정을 하고, sensor의 값에 따라 반전이 될 수 있습니다.

 sensorPortrait는 Activity를 세로방향으로 고정을 하고, sensor의 값에 따라 반전이 될 수 있습니다.

 sensor의 경우 사용자가 들고있는 방향에 따라 Activity의 방향이 결정됩니다.

  -- sensor 사용시 4방향에 대한 설정이 이루어지지 않는다면 fullSensor를 사용해 보세요.

 

 - AndroidManifest.xml에서 설정하는법.

방향 설정을 원하는 Activity 설정 안에 android:screenOrientation 특성을 주어 원하는 옵션값을 부여합니다.

(원하는 옵션값은 상단에서 선택합니다.)

* Android Studio 3.6 이상에서는 사용자가 screenOrientation을 지정하면 에러를 낼 수 있습니다.

 - 이는 unspecified(default -> 시스템이 방향을 선택)와 fullSensor 이외의 옵션값을 사용할 때 일어나는 문제로, tools:ignore="LockedOrientationActivity" 특성과 옵션값을 주어 에러를 무시할 수 있습니다.(오류 무시)

 

<activity
  android:name=".MainActivity"
  android:screenOrientation="portrait"
  tools:ignore="LockedOrientationActivity">
</activity>

 

참조

https://developer.android.com/guide/topics/manifest/activity-element?hl=ko

 

<액티비티>  |  Android 개발자  |  Android Developers

Declares an activity (an Activity subclass) that implements part of the application's visual user interface. All activities must be represented by {@code } elements in the manifest file. Any that are not declared there will not be seen by the system…

developer.android.com

 

버전정보 (v1.0)

 - v1.0 2020.06.26 배포

 

* 저작권에 위반될 수 있는 컨텐츠(이미지, 동영상 등)나 게시글은 삭제되거나 수정될 수 있습니다.

* 문제의 여지가 될 수 있는 컨텐츠의 경우 댓글 달아 주시면 빠른 시일 내에 조치하도록 하겠습니다.

* Karzin은 항상 공부중입니다. 설명이 틀리거나 잘못된 부분이 있다면 의견내주시는대로 수정하도록 하겠습니다.

 

Karzin

abbeea@naver.com





[Kotlin, Java] Android 10에서 파일 엑세스가 되지 않는 문제 해결

- EPERM 오류 해결하기 -


얼마전 개발 테스트 진행중 Android 8이나, Android 9에서 잘만 읽기/쓰기가 되던 파일이 Android 10에서 구동을 하니 에러만 열심히 뿜어내고 저장이 안되는 문제가 있었습니다.

로그창을 확인해보니 EPERM 오류를 뿜어내고 있었고, 저장이 되지않아 곤란해 하고 있었습니다.

특히 테스트를 하며 확인되었지만, READ_EXTERNAL_STORAGE 및 WRITE_EXTERNAL_STORAGE 권한을 유저에게 승인받고 있어서 유독 Android 10에서만 생기는 문제로 파악이 되었죠.

오늘은 이런 Android10으로 올라가면서 파일에 대한 읽기 쓰기가 되지않는 문제에 대해 다뤄보겠습니다.

 - 원인과 해결

Android 10 부터는 외부 저장소 액세스에 대해서 제한을 걸어두는 모양입니다.

해당 제한을 풀기 위해서는 AndroidManifest.xml에 requestLegacyExternalStorage의 값을 true로 설정해주어야합니다. (Android 10 이상을 타겟팅으로 하는 앱의 경우)

<manifest ... >

  <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
  <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
  
  <!-- This attribute is "false" by default on apps targeting
  Android 10 or higher. -->
  <application 
  	android:requestLegacyExternalStorage="true" ... >
    
  ...
  
  </application>
</manifest>

 

* Android 10 이상에서는 외부저장소에 접근을 하기위해 requestLegacyExternalStorage 속성을 꼭 넣어주시기 바랍니다.

** 다만 해당 방법이 완벽히 해결을 할 수 있는 방법은 아니며, 추후 업데이트 되는 Android 버전에서는 동작하지 않을수 있으니 주의해주시기 바랍니다.

 

 - 참조

https://developer.android.com/training/data-storage/files/external-scoped?hl=ko#opt-out-of-scoped-storage

 

범위가 지정된 외부 저장소 액세스 관리하기  |  Android 개발자  |  Android Developers

사용자에게 파일의 더 많은 권한을 제공하고 파일이 복잡해지는 것을 제한하기 위해, Android 10(API 레벨 29) 이상을 타겟팅하는 앱은 외부 저장소로 범위가 지정된 액세스 또는 범위 지정 저장소��

developer.android.com

버전정보 (v1.0)

 - v1.0 2020.06.12 배포

 

* 저작권에 위반될 수 있는 컨텐츠(이미지, 동영상 등)나 게시글은 삭제되거나 수정될 수 있습니다.

* 문제의 여지가 될 수 있는 컨텐츠의 경우 댓글 달아 주시면 빠른 시일 내에 조치하도록 하겠습니다.

 

Karzin

abbeea@naver.com


[Java]안드로이드 권한요청 class


 

어플을 개발하다보면 권한요청을 해야하는 경우가 많이 생깁니다.

특히 센서나, 저장소의 권한을 요청하는 경우가 많은데 이를 조금 더 편하게 사용할 수 있도록 Class로 만들었습니다.

사용방법은 심플합니다.

프로젝트에 .class 파일 넣어주고! 객체 생성해서! 함수한번 실행해주면 끝나게 만들어놨습니다!

(혼자 쓰다가 같이 쓰면 좋을것 같아서..)

 

Github 권한요청 Class : https://github.com/dawon-karzin/Android_PermissionCheck_Java

 

dawon-karzin/Android_PermissionCheck_Java

안드로이드 권한 요청 클래스입니다.(java). Contribute to dawon-karzin/Android_PermissionCheck_Java development by creating an account on GitHub.

github.com

 -> 버그등은 이슈로 남겨주시면 빠른시일내에 수정토록하겠습니다.

 

 - 구조

  • 클래스명 : PermissionCheck
  • 생성자 파라미터 : Activity
  • 내부 함수 :
    •   check(List<String>)
    •   permissionGranted()
  • 실행 방식 :
    • PermissionCheck 객체 생성(생성시 현 Activity를 매개변수로 전달)
    • 권한 요청을 받아야하는 List를 전달하여 check함수 실행
    • check함수 내에서 매개변수로 전달받은 List를 확인하여 권한이 부여되지 않은(Denied) 권한을 List로 생성
    • 이후 permissionGranted 함수를 실행하여 권한이 부여되지 않은(Denied) 권한에 대하여 요청(request)을 함
  • 사용 방법 :
    •   permission처리를 할 activity 상속 클래스에서 PermissionCheck 클래스 선언.
    •   check함수(파라미터로 permission 리스트를 전달) 사용함으로써 유저에게 권한요청 실행
//권한요청을 받을 List 생성
List myPermission = Arrays.asList( new String[]{ Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.READ_EXTERNAL_STORAGE});

//권한요청 class 생성 (생성시 지금의 Activity를 매개변수로 전달)
PermissionCheck permissionCheck = new PermissionCheck(this); 

//권한요청 시작(권한요청을 받아야하는 List를 매개변수로 전달)
permissionCheck.check(myPermission);

 

-> 개인적으로 개발할때 class 옮겨가며 사용하는 중인데, 생각해보니 permissionDeniedList 변수를 왜 전역으로 선언 했는지 기억이 안나네요;; 무언가 이유가 있었던 것 같은데....... 졸면서 해서그런가;;; (나중에 생각나면 업데이트 해놓겠습니다.)

 

 

* 저작권에 위반될 수 있는 컨텐츠(이미지, 동영상 등)나 게시글은 삭제되거나 수정될 수 있습니다.

* 문제의 여지가 될 수 있는 컨텐츠의 경우 댓글 달아 주시면 빠른시일내에 조치하도록 하겠습니다.

 

Karzin

abbeea@naver.com

 


[Kotlin, JAVA]

밀리세컨드 단위 시간 구하기


간혹 파일명을 만든다던가하는 특수한 경우마다 중복이 일어나지 않기 위해 밀리세컨드 단위의 시간을 구해야하는 경우가 있습니다.

(키값이 중복되지 않는다는 점에선 가장 편한 방법일지도 모르겠지요. 주요 예로는 파일의 저장(영상, 사진) 등)

 

 - Kotlin 현재 시간 구하기

System.currentTimeMillis()

val testTime = "${System.currentTimeMillis()}"

 

 - JAVA 현재 시간 구하기

System.currentTimeMillis();

String testTime = String.valueOf(System.currentTimeMillis());

 

return type는 long형입니다.

 

 *** Reference : https://developer.android.com/reference/java/lang/System#currentTimeMillis()

 

System  |  Android 개발자  |  Android Developers

System public final class System extends Object java.lang.Object    ↳ java.lang.System The System class contains several useful class fields and methods. It cannot be instantiated. Among the facilities provided by the System class are standard input, stand

developer.android.com

 *** 소스에 문제가 있을 시 댓글달아주시면 최신화하도록 하겠습니다. 감사합니다

 


[Kotlin]Handler 이용하여 메인 UI 건드리기

(메인 쓰레드 제어하기)


Timer등을 설정해서 로직을 돌리다보면 이벤트에 따라 UI가 변경되어야하는 경우가 있습니다.

 

쉽게말해 UI를 건드리기 위해 서브쓰레드에서 메인쓰레드를 제어한다는건데, 여기서는 Timer를 실행했을때를 예시로 들겠습니다.

 

 - Timer를 통해 i를 증가시키기

private fun timerTest() {
  var i = 0
  myTimer = timer(period = 1000) {
    i++
    handlerTest(i)
  }
}​

  > 위처럼 타이머를 설정하여 1초(period=1000)마다 i를 증가시킨다는 예시를 들겠습니다.

 

 - Handler를 생성하여 UI를 바꿔주기

private fun handlerTest(msg:Int) {
    val handler : Handler = object : Handler(Looper.getMainLooper()) {
        override fun handleMessage(inputMessage: Message) {
            timer_text.setText(msg)
        }
    }
    handler.obtainMessage().sendToTarget()
}

 

  > timerTest 함수에서는 i를 증가시켜 handlerTest 함수에 해당 i값을 매개변수로 넘겨주어 메인쓰레드(UI)를 제어하는 형식입니다.

  > 위 함수에서는 timer_text(TextView)에 1씩 증가시켜 UI단에서 보이게 해줍니다.

 

 *** Reference : https://developer.android.com/reference/android/os/Handler?hl=en

 

Handler  |  Android 개발자  |  Android Developers

Handler public class Handler extends Object java.lang.Object    ↳ android.os.Handler A Handler allows you to send and process Message and Runnable objects associated with a thread's MessageQueue. Each Handler instance is associated with a single thread and

developer.android.com

 *** 소스에 문제가 있을 시 댓글달아주시면 최신화하도록 하겠습니다. 감사합니다.

 


[Kotlin]Toast 사용하기


간혹 유저에게 간단한 메세지를 전달해주기위해 Toast를 사용하는 경우가 있습니다.

이런 경우를 위해 Kotlin에서의 Toast 사용법을 알아보겠습니다.

 

- 기본 형태

Toast.makeText(context, text, duration).show()

 > context(Context)는 현재 Activity의 context를 전달해주시면 되며,

 > text(String)는 Toast에 띄우고 싶은 String형식의 text를,

 > duration(Int)은 Toast를 얼마나 긴 혹은 짧은 시간동안 보이게하고 싶은지를 의미합니다.

 > duration의 경우 Toast.LENGTH_SHORT 및 Toast.LENGTH_LONG을 사용할 수 있으며 각각 0과 1로 대치됩니다. (즉, 0 혹은 1로 넣어도 동작)

 > SHORT는 4000ms(4초), LONG은 7000ms(7초) 입니다.

 

 > *makeText 후 show를 사용하지 않으면 Toast는 보이지 않습니다.

 

 - 예시

Toast.makeText(this, "토스트 테스트_짧게", Toast.LENGTH_SHORT).show()
Toast.makeText(this, "토스트 테스트_길게", Toast.LENGTH_LONG).show()

위는 비교적 간단한 예시이며, duration부분의 SHORT와 LONG의 차이로 Toast를 짧은 시간 혹은 긴 시간동안 보이게 해주는 예시입니다.

 

 - 간단하게 함수를 이용하여 Text만 받아 사용하기

private fun shortToast(text:String) {
	Toast.makeText(this, text, Toast.LENGTH_SHORT).show()
}

private fun longToast(text:String) {
	Toast.makeText(this, text, Toast.LENGTH_LONG).show()
}

 - 사용법 :

  shortToast("안녕! Karzin!")

  longToast("안녕! Karzin!")

 

 *** Reference : https://developer.android.com/reference/android/widget/Toast

 

Toast  |  Android 개발자  |  Android Developers

Toast public class Toast extends Object java.lang.Object    ↳ android.widget.Toast A toast is a view containing a quick little message for the user. The toast class helps you create and show those. When the view is shown to the user, appears as a floating

developer.android.com

 *** 소스에 문제가 있을 시 댓글달아주시면 최신화하도록 하겠습니다. 감사합니다.

+ Recent posts