레이블이 감지인 게시물을 표시합니다. 모든 게시물 표시
레이블이 감지인 게시물을 표시합니다. 모든 게시물 표시

2017년 5월 31일 수요일

안드로이드 Soft Keyboard 상태변화 시점 감지

안드로이드 Soft Keyboard 상태변화 감지하기

발단

안드로이드에서는 소프트키보드 상태를 변경하기 위해, 2가지 방법을 사용할 수 있을 것이다.
  • EditText에 focus를 변경하여(클릭 등) 시스템에서 자동으로 상태변화 수행
  • InputMethodManager의 showSoftInput() / hideSoftInputFromXXX() 메서드를 이용하여 명시적으로 수행
2번째 방법인 InputMethodManager를 이용한다면, 메서드의 파라미터로 ResultReceiver 를 전달하여 상태변화에 따른 콜백을 쉽게 받을수 있다. 하지만, 특별한 케이스가 아니라면 당연히 1번 방법처럼 EditText를 클릭하는 등의 방법으로 시스템이 자동으로 소프트키보드를 제어하도록 구현하는게 일반적이다. 이 때, 소프트키보드의 상태변화와 키보드의 높이를 감지하여 구현해야 할 일이 있다면....??

아이디어

구글에서 검색하던 중, 스택오버플로우에 ViewTreeObserver의 GlobalLayoutListener를 이용하는 방법을 발견했다.
http://stackoverflow.com/questions/4745988/how-do-i-detect-if-software-keyboard-is-visible-on-android-device

코드

// 파라미터로 엑티비티의 가장 최상위 layout을 받는다..
private void registerView(final View rootView) {
    if (mGlobalListener == null) {
        mGlobalListener = new ViewTreeObserver.OnGlobalLayoutListener() {
            @Override
            public void onGlobalLayout() {
                Rect r = new Rect();
                // 해당 루트뷰에서 윈도우가 보이는 영역을 얻어옴
                rootView.getWindowVisibleDisplayFrame(r);

                // 루트뷰의 실제 높이와, 윈도우 영역의 높이를 비교
                // 키보드는 윈도우 영역에 위치하므로 뷰와 윈도우의 높이비교를 통해 키보드의 여부를 알 수 있다.
                int heightDiff = rootView.getRootView().getHeight() - (r.bottom - r.top);

                // keyboardThreshold는 윈도우가 기본적으로 차지하고있는 영역(StatusBar / Soft Back Button)
                int keybordHeight = heightDiff - keyboardThreshold;
                if (heightDiff > keyboardThreshold) {
                    if (!mIsKeyboardVisible) {
                        mIsKeyboardVisible = true;
                        //TODO::Keyboard invisible -> visible
                    }
                } else {
                    if (mIsKeyboardVisible) {
                        mIsKeyboardVisible = false;
                        //TODO::Keyboard visible -> invisible
                    }
                }
            }
        };
    }
    // ViewTreeObserver에 리스너 등록
    rootView.getViewTreeObserver().addOnGlobalLayoutListener(mGlobalListener);
}

2017년 1월 13일 금요일

[안드로이드] Activity Leak 확인 툴 - LeakCanary

엑티비티 Leak

엑티비티의 참조가 남아있어서 Destroy 후에도 GC되지 않는 증상으로, 안드로이드에서 메모리 누수의 주 원인으로 꼽힌다. 엑티비티 인스턴스는 다른 인스턴스에 비해서 메모리를 많이 차지하고, 일반적으로 뷰 등 여러가지 멤버필드를 가지고있기 때문에 엑티비티 Leak이 발생하면 자칫 치명적인 성능저하를 유발할 수도 있다.

LeakCanary

Square 사(BetterKnife 만든 회사)에서 만든 무료 라이브러리로, 그나마 쉽게 엑티비티 Leak을 감지할 수 있도록 도와준다.

적용방법

  1. app의 build.gradle에 다음의 dependancy를 추가한다.
dependencies {
    //Debug용 컴파일
   debugCompile 'com.squareup.leakcanary:leakcanary-android:1.5'
   //Release용 컴파일 - Release시에는 아무 동작도 안하도록
   releaseCompile 'com.squareup.leakcanary:leakcanary-android-no-op:1.5'
}
2.Application의 onCreate() 메서드에서 초기화한다.
public class ExampleApplication extends Application {

  @Override public void onCreate() {
    super.onCreate();
    if (LeakCanary.isInAnalyzerProcess(this)) {
      // This process is dedicated to LeakCanary for heap analysis.
      // You should not init your app in this process.
      return;
    }
    LeakCanary.install(this);
    // 앱 초기화 로직
  }
}

이용방법

앱을 테스트하다보면 다음 이미지와 같이, 추가한적 없는 아이콘이 보이는 경우가 있는데, 저 아이콘이 보이고 Notification이 존재한다면 현재 앱은 엑티비티 Leak이 존재하는 것이다.
Notification을 클릭하면, 왜 Leak이 발생했는지를 보여주는 화면이 나타난다.

장/단점

  • 장점
    • 적용이 매우 쉽다.
    • Leak이 발생하면 시각적으로 알 수 있어서 직관적이다.
  • 단점
    • Activity Leak를 확인하는 것만 가능하다. - 다른 메모리 Leak은 불가능
    • Activity의 Destroy 시점에서 검사를 진행하므로 화면 전환속도가 조금 느리다. - release 버전에서는 LeakCanary가 동작하지 않도록 빈 라이브러리를 컴파일하거나, 라이브러리를 제거해야 한다.

참고자료