728x90

일반적으로 안드로이드 폰에서 위치정보를 얻는 방법은 크게 3가지

1) GPS - 위성에서 정보를 받아 삼각측량으로 위치를 계산, 정확하다, 건물 안에서는 안된다

2) 3G망 - 인접된 전화기지국에서오는 전파의 시간 차이로 위치를 계산, 실내에서도 가능

3) WiFi 의 AP

 

 

 

 

1. 위치제공자 확인법

 1) AndroidManifest.xml - 권한설정

<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>

 2) 시스템으로부터 LocationManager 객체 얻어오기

 3) getAllProviders() 메소드로 위치제공자 리스트 가져오기

// 1. 위치관리자 객체 생성
LocationManager lm = (LocationManager)getSystemService(Context.LOCATION_SERVICE);

// 2. 위치제공자 모두 가져오기
List<String> list = lm.getAllProviders(); 


for (int i = 0; i < list.size(); i++) {
 // 위치제공자
 	list.get(i);
 // 해당 제공자 사용가능 boolean 
    lm.isProviderEnabled(list.get(i));
}

/**안드로이드 위치 제공자 관련 상수**/

public static final String GPS_PROVIDER = "gps"
public static final String NETWORK_PROVIDER = "network"
public static final String PASSIVE_PROVIDER = "passive"

 

2. Criteria

// 1. 위치관리자 객체 생성
LocationManager locationManager = (LocationManager)getSystemService(Context.LOCATION_SERVICE);

//2. Criteria 객체 생성(프로바이더의 상세 속성 옵션)
Criteria criteria = new Criteria();
criteria.set(Criteria.ACCURACY_FINE); //위도와 경도에 정확도(정밀도) 설정
criteria.setAccuracy(Criteria.ACCURACY_FINE);
criteria.setPowerRequirement(Criteria.POWER_HIGH);
criteria.setAltitudeRequired(false);
criteria.setSpeedRequired(true);
criteria.setCostAllowed(true);
criteria.setBearingRequired(false);



//3. criteria의 옵션에 해당하는, 현재 위치값을 가져오기 위한 프로바이더
private String bestProvide = locationManager.getBestProvider(criteria, true);

 

4. 위치 정보 취득시의 콜백 - onLocationChanged

//GPS Update 시간은 1초 이상, 반경은 10m 이상이 좋음
//(GPS 송수신하는데 준비 과정에서만 약 1초가 소요 된다고 함)
    
if(!locationManager.isProviderEnabled(provider)
        &&locationManager.getLastKnownLocation(provider)!=null) {

	locationManager.requestLocationUpdates(provider, 1000, 10, this);
    
 }else{

    criteria.setAccuracy(Criteria.ACCURACY_COARSE);
    provider = locationManager.getBestProvider(criteria, true);
    locationManager.requestLocationUpdates(provider, 1000, 10, this);
 
 }

@Override
public void onLocationChanged(Location location) {
// GPS 변경에 따른 코딩 구현.

}

 

 

 

Reference

 

https://developer.android.com/reference/android/location/LocationManager 

 

LocationManager  |  Android Developers

LocationManager public class LocationManager extends Object java.lang.Object    ↳ android.location.LocationManager This class provides access to the system location services. These services allow applications to obtain periodic updates of the device's geog

developer.android.com

https://bitsoul.tistory.com/130

 

안드로이드: 위치제공자 LocationManager 예제 - 현재폰에 제공되는 위치제공자 확인

안드로이드: 위치제공자 LocationManager 예제 - 현재폰에 제공되는 위치제공자 확인 안드로이드를 사용하여 위치기반 앱을 만들때, 현재 톤에 제공되는 위치 제공자 들이 어떠한 것들이 있는지 확인해봐야 합니다..

bitsoul.tistory.com

https://pluu.github.io/blog/android/droidkaigi/2017/12/30/droidkaigi-location/

 

Pluu Dev - [번역] DroidKaigi 2017 ~ 위치 정보를 정확하게 트래킹하는 기술

Emulator 29.2.2 Canary에서 Location 사용하기 Posted on 28 Sep 2019 [요약] Demystifying Android Accessibility Development (Google I/O '19) Posted on 23 Sep 2019 Android Studio Tips #2 Posted on 24 Jul 2019 Android Studio Tips #1 Posted on 13 Jul 2019

pluu.github.io

 https://gogorchg.tistory.com/entry/Android-실시간-GPS-사용

 

[Android] 실시간 GPS 사용

실시간으로 위치 추적을 할 때, 여러 Test와 조사 결과 다음과 같이 나왔다. 1. 강제적으로 Update를 시키지 말고, LocationListener를 통하여 받도록 하자. 2. GPS Update 시간은 1초 이상, 반경은 10m 이상이 좋..

gogorchg.tistory.com

 

728x90
728x90

SurfaceView View를 상속받은 클래스로 Video Memory로 바로 접근하기 때문에 일반 View에서의 랜더링 

속도보다 빠르다.

일반 View는 많은 그리기 작업을 하면 메인 스레드의 자원을 다 잡아먹어버리기때문에 상당히 느려지게 되는데

이러한 단점을 보완하기 위한 클래스라고 보면 된다

 

 

SurfaceView로부터 상속받을 경우 디폴트로 구현해야 할 메소드가 있다.

 

  • public void onDraw (Canvas canvas) : 화면을 그린다.
  • public void surfaceChanged() : 뷰가 변경될 때 호출된다.
  • public void surfaceCreated() : 뷰가 생성될 때 호출된다.
  • public void surfaceDestroyed() : 뷰가 종료될 때 호출된다.

 

그럼 셋팅은 끝. 사용되는건 surfaceCreated surfaceDestoryed 정도가 되겠다.

surfaceCreated는 처음 서피스뷰가 생성될 때 호출되는데, 주의할점은 백그라운드 상태로 내려갔다가, 다시 올라오게 되면

surfaceview가 다시 created된다는점이다. created에서 thread를 실행시키는 작업을 할 경우

반드시 스레드가 동작중인지 여부를 먼저 확인해야한다. 그렇지않으면 익셉션 발생

 

surfaceChanged는 업데이트를 대비해 만들었다, 뭐라뭐라 하던데 잘 모르겠다. 사용하지않는듯하다.

 

이제 SurfaceView 구성은 하였고, 실시간으로 그리기를 실행하려면 Thread를 구동해야한다.

 

private Class PaintThread extends Thread {

public void run() {

while(!this.isInterrupted()){    //스레드가 인터럽트 될 때까지 반복 실행.

if (그리기 실행조건) {

//그리기 실행

doDraw();

}

}

}

}


Reference

- https://biig.tistory.com/23

 

SurfaceView 구현 / 사용법

SurfaceView는 View를 상속받은 클래스로 Video Memory로 바로 접근하기 때문에 일반 View에서의 랜더링 속도보다 빠르다. 일반 View는 많은 그리기 작업을 하면 메인 스레드의 자원을 다 잡아먹어버리기때문에 상..

biig.tistory.com

https://blog.naver.com/muri1004/221054311714

 

[Android] SurfaceView 개념 및 예제

SurfaceView 란?SurfaceView는 View를 상속받는 클래스이다.일반 View는 onDraw 메소드를 시스템에...

blog.naver.com

 

728x90
728x90

 

 

Title: Build a Modular Android App Architecture

Speaker(s): Yigit Boyar, Florina Muntenescu

 

 

1. 어떻게 모듈화된 안드로이드 앱 아키텍쳐를 구축할 것인가?

1) 왜 우리는 이를 구축해야하는가?

  (1) Scale 문제

      - 한두명이 아닌, 여러명이 공통 개발을 할 때, 각자의 담당하는 바를 간섭하지 않고 개발하기란(without stepping on each other's toes) 어렵다. 그래서 이를 방지하고자 이런 모듈들로 나눠서 만들 수 밖에 없다는 의미.

 

  (2) maintainability 유지보수성

      - 만약 monolithic application, 즉 하나의 거대한 아키텍쳐를 가진 앱을 마주하게 된다면? 안드로이드 개발자가 수십 수백개의 레이어들을 마주하게 되고 이를 파악하고 분석하는 것은 매우 어려운 일이다. 대신에, 만약 이 레이아웃들을 각 특징(feature)에 기반하여 그룹화 한다면, 용도의 파악이 용이진다. 또한 굉장히 길고 이상한 이름(weird name)으로 목록이 생기지 않는다. 

 

 

 

  (3) Faster compilation 빠른 컴파일

      - 왼쪽은 monolithic application의 예, 오른쪽은 modulaized application된 예다. 만약 '(designer_news_)comment.xml'라는 파일을 1개 수정했다고 가정 했을때, 컴파일시 커버 범위는 다음과 같다.

      

  (4) Faster CI(Continuous Integration) 빠른 지속적 통합

      - 만약 다음과 같은 모듈 구조를 가진 앱이 있다고 가정하자.

 

      - 이 중에서 module5를 수정 한다고 했을때, 변화가 올바른지 확인하기 위해서 테스트를 해야하는 부분은 오로지, module5가 depend 하고 있는 app부분만 확인하면 된다. 따라서 테스트를 할 때, 연관되지 않은 다른 부분들을 실행할 필요가 없다. 

      - 이에 대해서 '우리는 incremental CI이 없다!'라고 말할 수 있다. 그래서 AndroidX 개발에서 의존성 그래프에 대한 플러그인, 파일들이 변화된 위치와 해당 파일들이 포함된 모듈이 무엇인지에 대한 Git History를 알 수 있도록 하는 플러그인들을 작성했다. 그리고 영향받은 모듈들에 대한 모든 테스트를 실행하였다. 해당 작업에 대한 링크는 다음과 같다. http://goo.gle/androidx-dependency-tracker 

 

 

  (5) Good for business

      - APK 사이즈가 작아지는 장점이 있다. Play store의 통계에 따르면, APK 사이즈에 따라 사람들이 설치를 시작하고 중단하는 비율이 다음과 같다. 즉 앱의 사이즈가 작으면 보다 많은 이용자를 끌어들일 수 있다.

      - 또한 PM이 "내가 정말 멋진 라이브러리를 찾아가지고 왔어!"라고 아이디어를 들고 와도, 이것이 좋은지 안좋은지 싸울 필요가 없다. 다이나믹하게 개발하고 A/B 테스트를 진행하면 됨.

 

 

2) 그렇다면 어떻게 모듈화 할 것인가? feature or layer?

  (1) feature modularization

 


     + 참고: https://developer.android.com/studio/projects/android-library?hl=ko

      - 앱 모듈을 라이브러리 모듈로 변환할 때, 기존 앱 모듈의 build.gradle 파일을 열면 맨 위에 다음과 같이 표시 되어 있다.

apply plugin: 'com.android.application'

      - 이를 다음처럼 플러그인 할당을 변경하고 sync를 맞춘다.

apply plugin: 'com.android.library'

      - 모듈의 전체 구조는 동일하게 유지되지만, 이제 Android 라이브러리로 작동하며 빌드에서 이제 APK 대신 AAR 파일이 생성됩니다.

 

 

 

app은 application으로 plugin하고, module은 library로 plugin한다
app은 module1이라는 라이브러리에 의존한다. 즉, app은 module1으로부터 코드와 리소스를 접근한다.
그러나 다른 모듈들은 dynamic feature modules일 수 있다. dynamic feature modules들은 dynamic delivery를 경유하여 로딩되는 on-demand code로 사용될 수 있다. 

 

dynamic feature modules은 app에 의존한다. 즉, app으로부터 코드와 리소스를 접근한다.
app은 이런 모듈들을 build.gradle 파일에 dynamic feature modules로 선언한다.
여기서 중요한 점은, app은 사실 module2와 module3에 의존하지 않는다는 점이다. 이는 이 app 안의 feature module의 메인 제약(restriction)이다. 그래서 app이 실제로는 코드와 리소스를 접근하지 않음에도, 이 옵션은 feature modules의 on-demand delivery를 허용한다. dynamic delivery를 통해서, 사용자는 요구에 따라 동적인 특징들(dynamic features)을 다운로드하고 설치할 수 있다.

 

요구에 의해 꺼지는 modules은 당신의 APK의 부분으로써 자동적으로 추가된다. 그리고 만약 당신이 on-demand delivery를 enable 한다면, 이것은 Google Play Store로부터 해당 모듈의 다운로드를 관리할 필요가 있다는 것을 의미한다.

 

공유된 코드와 리소스는 코어 라이브러리의 부분이 된다. 

 

on-demand delivered modules의 이점은 3rd-party 라이브러리를 의존할 수 있다는 것이다. 그리고 정말로 모듈에 다운로딩 될 때만 다운로드 된다.  이는 APK 사이즈를 줄일 수 있다는 것을 의미한다. 

 

하지만 어떻게 우리는 dynamic feature module인 것과 아닌 것을 결정하는가? 이를 위해, 화자는 80/20 원리(80%의 유저가 app의 20%를 사용한다)를 설명한다.
그렇다면, app의 나머지 80%는 app의 core flow 부분이 아니다. 이를 expert features 혹은 paid features라고 하자. 이 features는 나중에 다운받아질 수 있다.

 

유사하게, OnBoarding과 같이 나중에 삭제될 수 있는 feature도 있을 수 있다. 그래서 onDemand는 fase가 될 것이다. 이처럼 약간의 공간을 청소할 수 있다. 
그렇다면 About Screen과 같은 app의 core flow가 아닌 경우를 이야기 하자. 이 경우는 on demand이어야 하는가, 아니어야하는가? dynamic feature여야 하는가 아닌가? 이에 화자는 이처럼 작은 경우, Aout Screan에 즉각적인 접근이 되는 것을 원한다면 안드로이드 라이브러리쪽인게 보다 좋을 것이라 이야기 한다. 만약 좋은 사용자 경험을 확실하게 하고 싶고, 사용자가 이걸 기다리게 하는 것을 원하지 않는다면 말이다. 물론 간단한 about과 같이 dynamic feature module이 가져오는 모든 트러블이 가치있지는 않다.
이제 다른 접근으로, 격자(Plaid) 화면 형태인 뉴스 어플리케이션 샘플에 대해 이야기 해보자. 이 앱은 3개의 다른 소스(디자이너 뉴스, 디자이너 커뮤니티 dribbble, Product hunt 서비스)부터 데이터를 합친다. 각각의 소스는 각자의 표현방법과 비지니스 로직을 가진다. 우리가 원하는 것은 on-demand delivery에 대한 가능성이다. 우리가 원할 때마다 이와 같은 데이터들을 다운로드하는게 가능 해야하고, 다른 것들이 추가 될 수 있어야한다.   

 

즉 이는 디자이너 뉴스나 dribble이 dynamic feature module임을 의미한다. 

 

하지만 search나 about과 같은 것을 우리는 보게 되는데, 이것들은 on-demand delivery로부터 이득을 볼 수 없다. 그래서 우리는 이걸 library module로 남겨둔다.

 

 

 

  (2) feature modularization

 

앞서 말한 격자(Plaid) 화면의 Features들은 어떤 종류의 사용자 features을 가지고, 어떤 기술을 필요로 하는가? (그림과 같이) 우선 뉴스 스트림에 대한 지속성과 이를 fetch하는 API 클라이언트 및 feed UI가 있어야한다. 복수의 뉴스 프로바이더들, 프로바이더에 따른 커스텀 스타일, 권한, 사람들이 스토리에 대해 투표와 코멘트하는 기능들..... 등이 필요하다. 이에 대한 아키텍쳐는 아래와 같을 것이다.
그렇다면 이와 같은 구조, layering의 종류로부터 어떻게 우리가 이점을 얻을 수 있을까? 한가지 옵션은 isolation이다. 

 

 

모듈에 대하여 말할 때, 어떤 한 모듈이 다른 모듈에 의존적이라면 이는 'API' 혹은 'Implementation'이라고 말할 수 있다. API의 경우: 모듈A에게 모듈B에 의존적인 API가 있다면, 이는 B로부터 제공받는 모든 public 기능들은 B로부터 제공받는다는 것이다. 즉 A에 의존하는 모듈들도 B의 public api에 접근할 수 있다. 하지만 implementation의 경우, A에 의존적인 모듈들은 B를 볼 수 없고, B에 대하여 알아야만 한다.

 

 

+ 내가 해석을 해놓고도 개떡같아서 무슨 말인가 싶어서 차이점에 대해 찾아보았다.

   https://tjandroid.blogspot.com/2018/11/api-implementation.html 블로그에 따르면, 

  • api: 의존 라이브러리 수정시 본 모듈을 의존하고 있는 모듈들 또한 재빌드
    • A(api) <- B <- C 의 경우 C 에서 A 를 접근할 수 있음
    • A 수정시 B 와 C 모두 재빌드
  • implementaion: 의존 라이브러리 수정시 본 모듈까지만 재빌드
    • A(implementation) <- B <- C 의 경우 C 에서 A 를 접근할 수 없음
    • A 수정시 B 까지 재빌드

 

 

- 해석중

 

 

Reference

 

https://www.youtube.com/watch?v=PZBg5DIzNww

 

728x90
728x90

 

본 글은 AAC의 ViewModel 용 관련 글입니다.

 

 

 

Android ViewModel Scope

 

1. Dependaceise 선언 관련 

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
dependencies {
    def lifecycle_version = "2.0.0"
 
    // ViewModel and LiveData
    implementation "androidx.lifecycle:lifecycle-extensions:$lifecycle_version"
    // alternatively - just ViewModel
    implementation "androidx.lifecycle:lifecycle-viewmodel:$lifecycle_version" // For Kotlin use lifecycle-viewmodel-ktx
    // alternatively - just LiveData
    implementation "androidx.lifecycle:lifecycle-livedata:$lifecycle_version"
    // alternatively - Lifecycles only (no ViewModel or LiveData). Some UI
    //     AndroidX libraries use this lightweight import for Lifecycle
    implementation "androidx.lifecycle:lifecycle-runtime:$lifecycle_version"
 
    annotationProcessor "androidx.lifecycle:lifecycle-compiler:$lifecycle_version" // For Kotlin use kapt instead of annotationProcessor
    // alternately - if using Java8, use the following instead of lifecycle-compiler
    implementation "androidx.lifecycle:lifecycle-common-java8:$lifecycle_version"
 
    // optional - ReactiveStreams support for LiveData
    implementation "androidx.lifecycle:lifecycle-reactivestreams:$lifecycle_version" // For Kotlin use lifecycle-reactivestreams-ktx
 
    // optional - Test helpers for LiveData
    testImplementation "androidx.arch.core:core-testing:$lifecycle_version"
}
 
cs

 

2. 추가시 유의사항

implementation'android.arch.lifecycle:ViewModel:1.1.1' //이 아니라


implementation'android.arch.lifecycle:extensions:1.1.1'  //이쪽으로 추가할 것

==> ViewModel로만 연결하면, ViewModelProviders가 없음 (3번참고)

 

3. ViewModel 초기화 변경사항

  androidx.lifecycle:lifecycle-*:2.2.0-alpha03 부터는 ViewModelProviders.of()로 초기화하던 방식이 deprecated 되었다. (아래 링크 참조)

 

Lifecycle  |  Android 개발자  |  Android Developers

Lifecycle-aware components perform actions in response to a change in the lifecycle status of another component, such as activities and fragments. These components help you produce better-organized, and often lighter-weight code, that is easier to maintain

developer.android.com

  • ViewModelProviders.of() has been deprecated. You can pass a Fragment or FragmentActivity to the new ViewModelProvider(ViewModelStoreOwner) constructor to achieve the same functionality. (aosp/1009889)

 

먼저, 다음과 같은 커스텀 ViewModel 클래스가 있다고 할 때, (JAVA 방식)

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import androidx.lifecycle.MutableLiveData;
import androidx.lifecycle.ViewModel;
 
public class TestViewModel extends ViewModel {
 
    private MutableLiveData<String> test = new MutableLiveData<>();
 
    public MutableLiveData<String> getTest() {
        return test;
    }
 
    public void setTest(MutableLiveData<String> test) {
        this.test = test;
    }
}
 
cs

 

API 변경전 (JAVA 방식)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
 
public class MainActivity extends AppCompatActivity {
 
private TestViewModel viewModel;
 
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main_activity);
      
        //Activity에서 호출시 (ViewModelProvider.AndroidViewModelFactory 사용)        
        viewModel = ViewModelProviders.of(this).get(TestViewModel.class);
    }
    
}
 
 
cs

 

 

API 변경후 (JAVA 방식)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
public class MainActivity extends AppCompatActivity implements ViewModelStoreOwner{
 
    private ViewModelProvider.AndroidViewModelFactory viewModelFactory; 
    private ViewModelStore viewModelStore = new ViewModelStore();
 
    private TestViewModel viewModel;
 
 
 
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main_activity);
      
        if(viewModelFactory == null){            
           viewModelFactory = ViewModelProvider.AndroidViewModelFactory.getInstance(getApplication());
        }
 
        viewModel = new ViewModelProvider(this, viewModelFactory).get(TestViewModel.class);
    }
    
 
 
    @Override
    protected void onDestroy() {
        super.onDestroy();
        viewModelStore.clear();
    }
 
    @NonNull
    @Override
    public ViewModelStore getViewModelStore() {
        return viewModelStore;
    }
 
 
}
 
cs
728x90

+ Recent posts