'android'에 해당되는 글 36건

  1. 2017.03.30 App이 foreground 인지 background 인지 구별하기 1
  2. 2015.10.14 android face detecting ( FaceDetector vs google-play-vision )
  3. 2014.09.22 [android] View의 LayerType 알아보기
  4. 2014.06.11 외부 library에 소스 경로 추가하기
  5. 2013.12.17 sony tablet s (SGPT12) usb driver 설치
  6. 2013.10.31 [android] loadLibrary 와 CPU 특성
  7. 2013.09.25 [android] AnimationDrawable관련 주의점
  8. 2013.09.09 [android] NDK 개발환경 세팅
  9. 2013.08.21 [android] FFmpeg 빌드 for android with shared-lib
  10. 2013.06.19 [android] CheckBox에서 image와 text 간격

App이 foreground 인지 background 인지 구별하기

android 2017. 3. 30. 22:24

336x280(권장), 300x250(권장), 250x250, 200x200 크기의 광고 코드만 넣을 수 있습니다.

안드로이드 App을 만들다 보면은 App이 background로 내려가는 시점을 알아야 할 때가 있다. 

그런데, 안드로이드에서는 Home 버튼을 눌렀는지 알 수 있는 방법이 없어서 약간의 편법을 사용해야 한다. 



먼저 고전적인 방밥으로는 ActivityManager를 이용하는 방법이다. 

코드로 보면 아래와 같다. 


private boolean isAppIsInBackground(Context context) {
    boolean isInBackground = true;
    ActivityManager am = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
    if (Build.VERSION.SDK_INT > Build.VERSION_CODES.KITKAT_WATCH) {
        List<ActivityManager.RunningAppProcessInfo> runningProcesses = am.getRunningAppProcesses();
        for (ActivityManager.RunningAppProcessInfo processInfo : runningProcesses) {
            if (processInfo.importance == ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND) {
                for (String activeProcess : processInfo.pkgList) {
                    if (activeProcess.equals(context.getPackageName())) {
                        isInBackground = false;
                    }
                }
            }
        }
    } else {
        List<ActivityManager.RunningTaskInfo> taskInfo = am.getRunningTasks(1);
        ComponentName componentInfo = taskInfo.get(0).topActivity;
        if (componentInfo.getPackageName().equals(context.getPackageName())) {
            isInBackground = false;
        }
    }

    return isInBackground;
}


키캣미만에서는 RunningTaksInfo를 이용하고, 키캣이상에서는 RunningAppProcessInfo 를 이용하는 방식이다. 그런데 이 방색을 사용할때는  GET_TASKS 권한을 AndroidManifest.xml에 추가해야 하는데,  GET_TASKS 권한이 deprecated 되었다. 



그래서 다른 방식으로 사용하는것이 Activity의 onStart(), onStop() 함수를 오버라이드(override) 해서 count 하는 방식이다. 대략적인 코드는 아래와 같은 모습이다. 


public class BaseActivity extends Activity {
public static int foregroundCount = 0; // 전역 count 변수

@Override
protected void onStart() {
    super.onStart();
    foregroundCount = foregroundCount+ 1;
}


@Override
protected void onStop() { super.onStop(); foregroundCount = foregroundCount - 1;
} }


Application에서 사용하는 모든 Activity가 BaseActivity를 상속받게 하고, foregroundCount 가 1이상이면 foreground로 볼 수 있는 것이다. 

Activity가 많다면 은근히 작업이 많아 질 수도 있고, 나주에 추가되는 Activity에서 BaseActivity 로부터의 상속을 빼먹으면 버그가 발생하기 쉬운 방식이다. 



그럼 좀 더 안전한 방법은 없을까? 

앱에있는 Application 클래스를 이용하는 방법이 있는데, 

먼저 background에 있는지 체크하는 방법을 알아보자 


public class MyApplication extends Application {
    // ...
    @Override
    public void onTrimMemory(int level) {
        super.onTrimMemory(level);
        if (level == TRIM_MEMORY_UI_HIDDEN) {
           isBackground = true;
           notifyBackground();
        }
    }
}


그런데, onTrimMemory 함수는 screen off 상태일때는 호출이 안되므로, 아래처럼 리시버를 등록해서 체크해야 한다. (screen off 상태는 전원버튼을 눌러서 화면을 끄는것을 말한다. ) 


public class MyApplication extends Application {
  // ...
  @Override
    public void onCreate() {
        super.onCreate();
        // ...
        IntentFilter screenOffFilter = new IntentFilter(Intent.ACTION_SCREEN_OFF);
        registerReceiver(new BroadcastReceiver() {
            @Override
            public void onReceive(Context context, Intent intent) {
              if (isBackground) {
                  isBackground = false;
                  notifyForeground();
              }
            }
        }, screenOffFilter);
      }
}


이렇게 하면 background 상태는 체크가 되는데, foreground 상태는 어떻게 알아 낼 수 있을까?

간단하게 ActivityLifecycleCallback() 함수를 이용하면 된다. 


public class MyApplication extends Application {
    // ...
    @Override
       public void onCreate() {
           super.onCreate();

     registerActivityLifecycleCallbacks(new Application.ActivityLifecycleCallbacks() {
               // ...
               @Override
               public void onActivityResumed(Activity activity) {
                 if (isBackground) {
                     isBackground = false;
                     notifyForeground();
                 }
               }
               // ...
           });
       }
       // ...
}



이상으로 App이 foreground에 있는지, background에 있는지 체크하는 방법에 대해서 

1. ActivityManager를 이용하는 고전적인 방법 

2. Activity의 onStart(), onStop() 을 활용한 방법

3. Application의 onTrimMemory(), registerActivityLifecycleCallbacks() 를 활용하는 방법

으로 알아 보았습니다. 





:

android face detecting ( FaceDetector vs google-play-vision )

android 2015. 10. 14. 15:02

336x280(권장), 300x250(권장), 250x250, 200x200 크기의 광고 코드만 넣을 수 있습니다.

 

먼저 혼동하기 쉬운 얼굴인식과 얼굴검출에 대해서 간단하게 짚고 넘어가면..

얼굴검출(face detect)은 이미지에서 얼굴이 어느 영역에 있는지 찾는 것이고

얼굴인식(face recognize)A라는 얼굴과 B라는 얼굴이 유사한지 또는 같은 사람인지 판별하는 것이다.

 

안드로이드에서 face dectect을 하기 위해서는 2가지 방식이 있다.

첫번째는 , Image 소스에서 얼굴을 검출(dectect)하는 android.media.FaceDetector 를 이용하는 방법

두번째는, live stream 소스에서 얼굴을 검출하는 Camera.FaceDetectionListener 를 이용하는 방법

 

Android 에서 얼굴검출을 위해서 3rd party library를 사용하지 않는다면 어쩔수 없이 사용하는 FaceDetector API level 1 부터 사용가능하데, 그래서 그런지 결과나 성능에서 상당히 떨어진다. 그리고 FaceDetector를 사용할때는 한가지 주의 할점이 입력 Bitmap RGB_565 타입을 넘겨야 한다. 대략적인 코드는 아래와 같다.

 

android.media.FaceDetector.Face[] scaledFaces = new android.media.FaceDetector.Face[1]; // 얼굴 1개만 인식
Bitmap inputBitmap = buildScaledFace565Bitmap(imageBitmap);
android.media.FaceDetector faceDetector = new android.media.FaceDetector(inputBitmap.getWidth(), inputBitmap.getHeight(), 1);
faceDetector.findFaces(inputBitmap, scaledFaces);

 

그리고 입력 bitmap의 크기가 커질수로 수행시간이 기하급수적으로 늘어난다. 그리고 detecting된 정보도 두 눈사이의 중점 Point, 중점 Point에서 눈사이의 거리 정보만 준다. 즉 얼굴영역(Rect)는 알려주지 않는다.

 

그래서 2015 8월에 google에서 google-play-vision library를 발표했는데, 무척이나 좋다.

간단하게 media.FaceDetector와 비교해본 테스트 성능은 아래와 같다.

 

갤럭시 S4단말

사진크기

FaceDetector 시간

Vision 시간

460 * 560

224ms

154ms

960 * 960

705ms

305ms

1920 * 1200

2380ms

350ms

 

성능도 좋지만 결과 품질도 상당히 좋다. 주요한 장점을 설명하면 아래와 같다.

 

1.     얼굴영역(left/right 정보, width, height)를 알려준다.

 

·                     getPosition() - Returns the top left coordinates of the area where a face was detected

·                     getWidth() - Returns the width of the area where a face was detected

·                     getHeight() - Returns the height of the area where a face was detected

 

 

2.     얼굴이 기울어저 있어도 검출된다.



위그림처럼 y축 기준으로 60도 회전된 얼굴과, xy평면을 기준으로 45도 회전된 얼굴까지 검출이가능하다. 기존 android.media.FaceDetector에 비하면 비약적인 발전으로 보인다. ^^;

 

3.     얼굴의 다양한 특징 포인트를 알려준다.

얼굴의 특징 포인트를 Landmark로 부르는데, 코드에 아래처럼 정의 되어 있다.

public static final int BOTTOM_MOUTH = 0;
public static final int
LEFT_CHEEK = 1;
public static final int
LEFT_EAR_TIP = 2;
public static final int
LEFT_EAR = 3;
public static final int
LEFT_EYE = 4;
public static final int
LEFT_MOUTH = 5;
public static final int
NOSE_BASE = 6;
public static final int
RIGHT_CHEEK = 7;
public static final int
RIGHT_EAR_TIP = 8;
public static final int
RIGHT_EAR = 9;
public static final int
RIGHT_EYE = 10;
public static final int
RIGHT_MOUTH = 11;

 

두눈위치, 입위치, 볼위치, 코위치, 귀위치 등 얼굴에 대해서 상세한 정보를 줄 수 있는데, 물로 검출에 성공한 경우에만 Landmark 위치를 알 수 있다. 실제로 테스트 해보면 귀위치는 잘 안나온다.

 


Image에서 얼굴검출할 때 사용하면 상당히 유용할 듯 한다. 추가로 FaceTracking(live로 얼굴을 검출하고 얼굴이 이동하면 따라가면서 계속 검출하는)도 가능하다. 하지만 FaceTrackinginput 크기가 클 경우 FPS가 잘 안나온다.

 

[관련자료]

https://developers.google.com/vision/face-detection-concepts

http://android-developers.blogspot.kr/2015/08/google-play-services-78-lets-see-whats.html

https://github.com/googlesamples/android-vision


 

 


 

 

 



:

[android] View의 LayerType 알아보기

android 2014. 9. 22. 15:09

336x280(권장), 300x250(권장), 250x250, 200x200 크기의 광고 코드만 넣을 수 있습니다.

Android 3.0 ( 허니컴 : API level 11 ) 부터 하드웨어 가속 (hardwareAccelerated )  옵션으로 2D rendering pipeline 의 사용여부를 설정 할 수 있도록 하였다. hardwareAccelerated 을 설정하면 CPU가 할 일을 GPU가 대신 처리해서 그런지 체감 속도가 많이 빨라진다.

 

설정하기

ApplicationManifest.xml에서 설정할수 있다.

앱 전체에 설정하려면 아래처럼 application tag에 설정하면 된다.

<application

android:hardwareAccelerated="true"

또는 Activity 단위로도 설정할 수 있다.

<activity

android:hardwareAccelerated="true"

 

코드를 이용해서 동적으로 Activity에 설정하려면 아래와 같이 하면 된다. ( 동적으로 application 전체를 설정하는 방법은 없다. 동적으로 하려면 모든 activity에 아래의 방법을 적용하면 된다. )

코드로 할 때 주의할점은 setContent 전에 설정해야 한다.

@Override

protected void onCreate(Bundle savedInstanceState) {

       super.onCreate(savedInstanceState);          

       getWindow().addFlags(WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED);

       setContentView(R.layout.my_content_view);

 

View 단위로도 설정할수 있는데, 아래의 방법으로 코드로 설정 할 수 있다. 생성자에서 호출이 되어야 한다.

 

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {

setLayerType(View.LAYER_TYPE_SOFTWARE, null);

}

 

참고로, Applicationmanifest나 코드로 설정안하고, android settings에서 개발자 옵션에서 “GPU 렌더링 강제 실행옵션을 키면 항상 GPU로 렌더링하게 된다.

 

View 단위로 설정하는 코드에서 보듯이, SDK에서 View LayerType 3가지로 제공한다.

l  LAYER_TYPE_NONE

l  LAYER_TYPE_SOFTWARE

l  LAYER_TYPE_HARDWARE

 

Software-base drawing model

소프트웨어 기반의 그리기 모델에서는 다음 2가지 절차를 통해서 그리기를 수행한다.

1.     Invalidate the hierarchy

2.     Draw the hierarchy

예를들어서, TextView의 내용을 변경하고 invalidate() 함수를 호출하면 viewhierarchy를 순회하면서 모든 view invalidate가 호하면서 다시 그려야할 영역을( the dirty regin) 을 구하게 된다. 그리고 viewhierarchy를 순회하면서 다시 그리게 된다.  (View.invalidate 함수를 보면, ViewParent invalidateChild 함수를 호출하는 것을 확인할수 있다. )

Software로 그리는 방식은 간단하지만, 2개의 결점을 가지고 있다. 첫째는 변경되지 않은 view에 대해서도 draw 코드를 수행하게 되는것이고, 두번째는 앱에 버그가 존재할수 있다는 것이다.

  

 

Hardware-base drawing model

하드웨어기반의 그리기 모델에서는 소프트웨어기반의 그리기 모델의 단점을 개선하여서 변경된 viewupdate를 하도록 개선된 모델이다.

1.     Invalidate the hierarchy

2.     Record and update display lists

3.     Draw the display lists

디스플레이 리스트( diplay list)를 가지고 있어서 각각의 view hierarchy에서 update되는 것만 다시 그리는 방식이다.

 

전체적인 구조나 성능면에서 hardware 방식이 더 좋지만 hardware 방식의 문제점도 있다. 바로 모든 api 가 지원하는 것이 아니다.

아래의 표는 Harware 기반 그리기 모델에서 android OS 버전별로 지원되는 api와 지원안되는 api 리스트 이다. 아래의 api를 사용할때는 성능 감소가 되더라도, LayerType을 반드시 software로 설정해야 정성 동작한다.

 

API level

< 16

16

17

18

Canvas

drawBitmapMesh() (colors array)

drawPicture()

drawPosText()

drawTextOnPath()

drawVertices()

setDrawFilter()

clipPath()

clipRegion()

clipRect(Region.Op.XOR)

clipRect(Region.Op.Difference)

clipRect(Region.Op.ReverseDifference)

clipRect() with rotation/perspective

Paint

setAntiAlias() (for text)

setAntiAlias() (for lines)

setFilterBitmap()

setLinearText()

setMaskFilter()

setPathEffect() (for lines)

setRasterizer()

setShadowLayer() (other than text)

setStrokeCap() (for lines)

setStrokeCap() (for points)

setSubpixelText()

Xfermode

AvoidXfermode

PixelXorXfermode

PorterDuff.Mode.DARKEN (framebuffer)

PorterDuff.Mode.LIGHTEN (framebuffer)

PorterDuff.Mode.OVERLAY (framebuffer)

Shader

ComposeShader inside ComposeShader

Same type shaders inside ComposeShader

Local matrix on ComposeShader

 

 

 

참고 : http://developer.android.com/guide/topics/graphics/hardware-accel.html



:

외부 library에 소스 경로 추가하기

android 2014. 6. 11. 13:58

336x280(권장), 300x250(권장), 250x250, 200x200 크기의 광고 코드만 넣을 수 있습니다.

안드로이드를 개발할 때 장점은 java로 되어 있어서 android의 소스를 쉽게 참조 할수 있는 점이다. 그런데, 안드로이드 소스외에 추가로 사용하는 library에 대해서는 소스를 볼 수 없어서 답답하곤 했다. 예를 들어서 android의 하위버전 호환 library android-support-v4.jar를 대부분 사용하는데, 개발하다가 ‘F3’ 키로 따라 들어가다 보면 아래와 같은 화면을 만나게 된다.

 


Android –support-v4 opensource라서 project를 다운받아서 봐도 되지만, 개발 환경과 연동이 안되어서 바로바로 소스보기가 불편하다. 그래서 검색해보니 있구나~

 

Google I/O 2012에서 그 방법을 소개하고 있다. ( 48분 부터 보면 된다. ) 

또는 옆의 링크를 눌러도 된다.  Explanation in Google I/O 2012 video

 

간단하게 설명하면 다음과 같다.

 

1. lib 폴더에 jar 파일이름 + “.properties” 라는 파일을 하나 만든다.

   예를 들어서 gson-2.2.4.jar 이면, gson-2.2.4.jar.properties 로 파일을 하나 만든다.


2. 파일에 src 또는 doc 의 경로를 설정하면 된다. ( 절대경로, 상대경로 모두 된다. )

   예를 들면, src=../libs-sources/gson-2.2.4-sources.jar  이렇게 해주면 된다.

   물론 해당 경로에 gson-2.2.4-source.jar 파일이 있어야 한다.

 



이렇게 하고 설정이 잘 되었는지 확인하려면 환경설정에서

“Java Build path” -> Libraries -> Android Private Libraries 에서 해당 jar 파일을 찾아서 펼친뒤에 Source attachment를 확인하면 된다.



 

설정하고 위에서럼 확인이 안될때는 F5를 눌러서 refresh를 해보면 된다.

그래도 안되면 projectclose 했다가 다시 열면된다.

그래도 안되면 eclipse를 종료했다가 다시 시작해야 한다.

 

참고로 xxx-source.jar 파일은 maven 중앙 repository 등에서 쉽게 구할수 있다.

http://search.maven.org

 

개발환경이 편리해 저서 뿌듯하다~ ㅋㅋ 

 

 



:

sony tablet s (SGPT12) usb driver 설치

android 2013. 12. 17. 13:48

336x280(권장), 300x250(권장), 250x250, 200x200 크기의 광고 코드만 넣을 수 있습니다.

소니에서 나온 tablet s 라는 안드로이드 기반의 타블렛이 있는데, usb driver를 설치하기가 쉽지 않다. 정확한 모델명은 SGPT12 이다. 안드로이드 개발을 위해서 ADB 와 연결하려면 기본 드라이버가 설치되어 있어야 하는데.. 쉽지않군..

 

구글링으로 검색해보니 비슷한 사래가 다반사구나.

http://stackoverflow.com/questions/9006455/how-to-install-a-sony-tablet-s-as-an-adb-device

 

내용을 읽어 보면 아래 소니페이지에서 가이드 하는 대로 하면 된다고 한다.

http://esupport.sony.com/US/perl/support-info.pl?info_id=878

 

.. 이거봐라..

내용을 보니 google usb driver를 사용하고 있는데 windows에서 자동으로 검색이 안되니 sdk에서 android_winusb.inf 파일을 직접 수정하라고 한다. 참 우울하네~

Android SDK를 받은 상태라면 “android_winusb.inf” 파일은 아래 위치에 있다. 

SDK -> extras -> google -> usb_driver

Google usb driver만 받을 수도 있다. (http://developer.android.com/sdk/win-usb.html )


 

아래의 2줄을 자신의 환경에 맞게 추가해주면 된다.

 

;SONY Sony Tablet P

%CompositeAdbInterface% = USB_Install, USB\VID_054C&PID_04D2&MI_01

 

;SONY Sony Tablet S

%CompositeAdbInterface% = USB_Install, USB\VID_054C&PID_05B4&MI_01

 

자신의 컴퓨터가 intel 기반이면 [Google.NTx86] 영역에 추가하면 되고, AMD 기반이면 [Google.NTamd64] 에 추가해주면 된다. 잘 모르겠으면 2군데 다 추가해주면 된다. 

추가해주고 드라이버를 업데이트 하는데 자동 검색이 안된다. ㅠㅠ  

 

아래처럼 수동으로 직접 선택해주면 된다.

장치관리자 -> 미설치 장치 -> 마우스 오른쪽 클릭 ->  드라이버 소프트웨어 업데이트 에서 자동검색말고 아래있는 수동으로 찾기를 선택하다.  그다음 "컴퓨터장치 드라이버 목록에서 직접 선택" 을 누르면 된다. 



 

위와 같은 화면이 안나오면 "디스크 있음"을 선택한 후에 직접 “android_winusb.inf” 파일을 선택해 주면 된다.

 



:

[android] loadLibrary 와 CPU 특성

android 2013. 10. 31. 14:20

336x280(권장), 300x250(권장), 250x250, 200x200 크기의 광고 코드만 넣을 수 있습니다.

Android에서 native 라이브러리를 만들 때 보통은 armeabi / armeabi-v7a 용으로 컴파일 해서 프로젝트의 libs 폴더 밑에 넣어준다. 이는 대부분의 안드로이드 장치가 ARM 기반의 CPU로 만들어 졌기 때문이다. 사실 Android 에서 지원하는 cpu ARM 뿐만 아니라 Interlx86 도 지원하고 MIPS 또한 공식적으로 지원한다. 다만 시장에 아직 제품이 많지 않을 뿐이다.

 

참고 : CPU Architecuture 별 지원 Platforms

Native Code CPU Architecture Used

Compatible Android Platform(s)

ARM, ARM-NEON

Android 1.5 (API Level 3) and higher

x86

Android 2.3 (API Level 9) and higher

MIPS

Android 2.3 (API Level 9) and higher

 

이번에 Intel에서 Xolo-X900 이라는 Intelx86 기반의 안드로이드 폰을 출시했다. 이번이라고 한건 내가 지금 알았기 때문이고, 찾아보니 실체 출시된 날짜는 2012 4월 쯤이었다. ~ 완전 모르고 있었네 ㅎㅎ

 

So 파일을 로딩하기 위해서 보통은 System.loadLibrary() 함수를 호출한다. 그러면 해당 함수가 알아서 CPU를 확인해서 알맞은 so 모듈을 로딩해주는 것으로 알고 있었다. 우연히 xolo 디바이스를 구할 수 있어서 armeabi/armeabi-v7a so 모듈만 있는 프로그램을 실행시켰는데, armeabi-v7aso 가 로딩 되는 것이다. 우와그러나 실행하다가 죽는다. ㅠㅠ  

 

그래서 loadLibrary를 연구해 보기 시작했다. 가장 먼저 developer의 문서를 찾아보면 아래와 같다.

Loads and links the library with the specified name. The mapping of the specified library name to the full path for loading the library is implementation-dependent.

loadLibrary(“foo”) 이렇게 호출하면 이름(foo)과 일치하면서, device의 CPU타입에 따라서 적절한 모듈을 로딩해 준다. 즉 해당 device armeabi-v7a 를 지원하면 lib/armeabi-v7a 경로에 있는 foo.so를 로딩한고 device x86을 지원하면 lib/x86 경로이 있는 foo.so를 로딩하는 것이다. 그리고 full path를 사용하면 해당 so를 직접 로딩한다는 말이다.

 

그럼, loadlibrary(foo)를 호출 했을 때 IntelXolo 단말기는 왜 lib/armeabi-v7a 경로에 있는 모듈을 로딩한걸까? ( lib/x86 폴더는 존재하지 않는 상태임 )

 

궁금증을 해결하기 위해서 일단 Java 레벨에서(NDK가 아닌) CPU 정보를 얻는 방법부터 찾아 보았다. 간단하게 Build 클래스에 정보가 있었다.

Build.CPU_ABI 를 이용하면 되는데, 보다보니 Build.CPU_ABI2가 존재 한다. ~~ 느낌이 온다~

(참고로 ABI는 Application Binary Interface의 약자다. ) 

 

System.loadLibrary  디바이스의 Build.CPU_ABI / Build.CPU_ABI2 의 순서로 so 모듈을 찾는 것이다. Android loadLibrary 내부에서 mapLibraryName을 호출하는 부분이 아마도 이 동작을 하는 것으로 추측된다.

 

해결 하려면 so 파일을 x86용으로 개발해서 빌드한후 추가하면 된다. 또는 모든 기능이 x86을 지원하는 것이 아니라면 아래처럼 Java 코드로 간단하게 막을수 있다.

public static void loadLibrary() {

      if (isLoaded) {

            return;

      }

 

      if (isLoaded == false) {

      if (Build.CPU_ABI.equals(“x86”)) {

            isLoaded = false;

            return;

      }

 

      try {

            System.loadLibrary("foo");

            isLoaded = true;

 

      } catch (Throwable e) {

            isLoaded = false;

}

}

추가로 발견한 내용으로는 프로젝트의 lib/x86 폴더에 해당 모듈이 하나라도 있으면 google play 마켓에서 x86용 디바이스에 노출이 된다는 점이다.

따라서 프로젝트가 x86을 부분적으로 지원 할 수는 없고 모든 so 모듈들을 x86으로 지원하는 것이 좋다.

 

 



:

[android] AnimationDrawable관련 주의점

android 2013. 9. 25. 14:08

336x280(권장), 300x250(권장), 250x250, 200x200 크기의 광고 코드만 넣을 수 있습니다.

android에서 animation은 크게 2가지로 구분된다.

Frame animation :

frame의 이미지를 여러장 준비해서 보여주는 것

장점 : 이미지 제작에 따라서 다양한 에니메이션이 가능하다

단점 : 이미지를 많이 쓰게되면, 저사양 단말에서 OutofMemory 발생 가능성이 높아진다.

Tween animation

시스템이 제공하는 방법으로 첫상태와 마지막 상태를 지정해서 중간의 frame은 계산해서 만드는방식

장점 : 이미지가 필요없어서 가볍고 빠르다.

단점 : 제공되는 animation만 가능하다. ( alpha, scale, translate 등등 )

 

이중에서 Frame Animaton을 이용할 때 AnimationDrawable을 사용하게 되는데 사용시 주의점에 대해서 몇가지 적어본다.

 

[ AnimationDrawable.start() 호출 시점 ]

사용자의 interaction 없이 Activity의 시작과 동시에 animation이 시작되야 할 때 onCreate에서 호출하면 동작을 않한다. 이유는 developer 사이트에서 다음과 같이 설명하고 있다.

It's important to note that the start() method called on the AnimationDrawable cannot be called during the onCreate() method of your Activity, because the AnimationDrawable is not yet fully attached to the window. If you want to play the animation immediately, without requiring interaction, then you might want to call it from the onWindowFocusChanged() method in your Activity, which will get called when Android brings your window into focus.

출처 : http://developer.android.com/guide/topics/graphics/drawable-animation.html

 

쉽게 말하면 onCreate에서는 window에 완전하게 붙은 상태가 아니라서, 완전히 붙은 시점인 onWindowFocusChanged()에서 호출해야 된다는 것이다. 구글링하다보면 아래와 같은 해결방법도 있다 

ImageView rocketImage = (ImageView) layout.findViewById(R.id.animation);

rocketImage.setBackgroundResource(R.drawable.progress_blue_animation);

rocketAnimation = (AnimationDrawable) rocketImage.getBackground();

rocketImage.post(new Runnable(){

    public void run(){

        rocketAnimation.start();

    }

});

 ImageViewpost()를 통해서 호출시점을 조금 뒤로 늦추는 방식인데, 이 방식보다는 developer 페이지에서 언급한 방식이 더 낳아 보인다.

  

[ 3.0 미만에서 OutofMemory 이슈 ]

AnimationDrawable로 몇가지 만든다음에 반복적으로 실행하다보면 memory가 적은 단말에서 OutofMemory가 발생한다. 검색해보니 3.0 미만에서는 명시적으로 이미지리소스를 해제해주어야 한다. 해제하는 방법은 아래와 같다 

ad.stop();

for (int i = 0; i < ad.getNumberOfFrames(); ++i){

    Drawable frame = ad.getFrame(i);

    if (frame instanceof BitmapDrawable) {

        ((BitmapDrawable)frame).getBitmap().recycle();

    }

    frame.setCallback(null);

}

ad.setCallback(null);

 

참고로 3.0 이상에서 AnimationDrawable의 리소스를 해제하게되면 같인 리소스의 Animation을 2번 실행하면 recycledBitmap을 사용했다면서 crash가 발생한다. 아마도 3.0 이상부터는 bitmap이 java 영역의 heap에 할당 되면서 캐시가 되고 있는것 같은 느낌이다. 그래서 강제로 recycle을 호출하면 안된다. 

안드로이드 3.0만 되도 좋을 것 같은데.. 아직도 2.3의 사용비율이 전체에서 30%가 넘는구나..

 

[ 2013-10 에 추가 ] 

위에처럼 명시적으로 해제 할 경우에 문제가 발생한다.  아래의 방법이 더 잘 동작한다.  리소스아이디 0을 넘김으로써 빈   drawable을 선택하게 하면 기존에 가지고 있던 리소스가 자동으로 해제되는 방식으로 안드로이드 버전에 따른 문제도 없다. 

ad.stop();

ad.selectDrawable(0); 




:

[android] NDK 개발환경 세팅

android 2013. 9. 9. 18:04

336x280(권장), 300x250(권장), 250x250, 200x200 크기의 광고 코드만 넣을 수 있습니다.

1. NDK

앱을 개발할 때 보통은 SDK를 이용하여 개발을 한다. 그러나 SDK 에서 지원하지 않거나, 성능상의 이슈를 해결하기 위해서 NDK를 이용한다. NDK로 할 수 있는 것들은 어떤 것이 있을까를 알아보기 위해서 NDK에서 제공하는 것들을 알아보자.

·         libc (C library) headers

·         libm (math library) headers

·         JNI interface headers

·         libz (Zlib compression) headers

·         liblog (Android logging) header

·         OpenGL ES 1.1 and OpenGL ES 2.0 (3D graphics libraries) headers

·         libjnigraphics (Pixel buffer access) header (for Android 2.2 and above).

·         A Minimal set of headers for C++ support

·         OpenSL ES native audio libraries

·         Android native application APIS

많구나~ ㅋㅋ.  근데 이걸로 멀 할 수 있을까? 현실적인 주요 목적은 기존에 작성된  c/c++ 코드로 구현된 코드를 (java로 처리가 느린 image processing 같은것이 좋은 예) 그대로 이식할 수 있게 된다. 물론 필요에 따라서 java 로직을 c/c++으로 개발 할 수도 있다. 

 

2. NDK 설치하기

설치전 필요한것들  (자세한건 http://developer.android.com/tools/sdk/ndk/index.html#Reqs 참고 )

Android SDK  : android 1.5 SDK 이상

지원하는 운영체제 : windows XP 이상, Mac OS X 10.4.8 이상 ( x86 ), Linux ( GLibc 2.7 이상 )

필요한 개발도구 :

OS에 맞는 GNU Make 3.81 이상

최신 버전의 awk

윈도우의경우 Cygwin 1.7 이상

 

아래를 클릭해서 설치한다. ( 자신의 OS에 맞는 걸로 )  나는 window 64bit를 받았다. 

http://developer.android.com/tools/sdk/ndk/index.html

450MB 크기의 zip파일을 받아서 그냥 아무곳에 압축을 해제하면 된다. (해제하니 1GB 헐 ㅠㅠ)

 

3. Cygwin 설치 (윈도우에서)

다음으로 Windows 환경이므로 cygwin을 설치한다.

http://cygwin.com/install.html

여기서 setup.exe를 받아서 설치한다.

설치 중간에 package를 선택하는게 나오는데 아래는 꼭 선택해야 한다.

gcc-core : C compiler

gcc-g++ : C++ Compiler

make : The GNU version of the ‘make’ utility

 

(본인은 make를 선택안 했다가 나중에 구글링을 좀 했었다. )

그러면 dependency가 걸려 있는 다른 모듈들도 같이 설치된다. ( maven 처럼 좋네~ )

 

Cygwin을 실행한 후에 path를 설정하면 편하다.

vi .bashrc

export PATH=$PATH: {여기에 ndk-build경로 추가}

alias ll=’ls –all’

 

 

4. sample build test

Cywin을 실행한 뒤에 NDK sample 폴더로 이동한뒤에 hello-jni로 이동한다.

그러면 jni 폴더에 2개의 파일이 존재한다.

$ tree jni

jni

├── Android.mk

└── hello-jni.c

 

여기서 ndk-build를 실행하면 libhello-jni.so 파일이 생성된다.  생성후 /libs/armeabi/libhello-jni.so에 설치했다고 나온다.

$ ndk-build

Gdbserver      : [arm-linux-androideabi-4.6] libs/armeabi/gdbserver

Gdbsetup       : libs/armeabi/gdb.setup

Install        : libhello-jni.so => libs/armeabi/libhello-jni.so

 

참고로 .so 파일은 apache의 모듈로 자주 보던 형식이었는데 linux share object 파일으로 윈도우의  dll 과 비슷한 것으로 생각하면 된다. Linexstatic library .a 파일이고, shared-library.so 파일이므로 .so 로 빌드해야 한다. Android .so 파일만 로딩할 수 있다.

 

 

 



:

[android] FFmpeg 빌드 for android with shared-lib

android 2013. 8. 21. 23:11

336x280(권장), 300x250(권장), 250x250, 200x200 크기의 광고 코드만 넣을 수 있습니다.

FFmpeg은 동영상을 인코딩/디코딩 해주는 opensource 입니다. 주요 특징은 아래와 같습니다.

라이선스 : LGPL

운영체제 : linux, window, mac-os, android 등 다수 지원 ( 개발은 linux 기반임 )

앞의 FFfast forward를 의미함.

대부분의 동영상 프로그램에서 사용됨. ( 곰플레이어, KMP, MX 플레이어 등 )

 

 

FFmpegandroid 용으로 컴파일 하면서 찾아본 자료 정리와 삽질 내용 정리합니다. 관련 글을 읽어본 후 따라하면 항상 안되는 경우가 발생하는데, 검색해보면 대부분 나오더군요. 제가 격은 문제들은 아래 트러블 슈팅으로 정리 하였습니다.

 

[ 환경 ]

OS : Window에서  Cygwin 으로

Android-NDK : r8e ( 현재는 r9 나와 있네요 )

목적 FFmpegAndroid shared-lib 으로 컴파일 ( static 이었으면 좋았을 것을 )

FFmpeg 버전 : 1.2.2  (http://ffmpeg.org/download.html )

 

[ 관련 글 ]

 

Android 동영상 플레이어 개념

http://helloworld.naver.com/helloworld/8794

 

Android-pub 강좌

http://www.androidpub.com/index.php?mid=android_dev_info&page=1&search_target=tag&search_keyword=FFmpeg&document_srl=1645684

http://www.androidpub.com/index.php?mid=android_dev_info&page=1&search_target=tag&search_keyword=FFmpeg&document_srl=1646144

http://www.androidpub.com/index.php?mid=android_dev_info&page=1&search_target=tag&search_keyword=FFmpeg&document_srl=1646529

http://www.androidpub.com/index.php?mid=android_dev_info&page=1&search_target=tag&search_keyword=FFmpeg&document_srl=1646540

http://www.androidpub.com/1690105

 

*vec.io 의 글 (영문) :

 https://vec.io/posts/how-to-build-ffmpeg-with-android-ndk

 

 

[ 트러블 슈팅 ]

 

l  Config 실패할 경우

원인 : 줄변경하기 위해서 \ 을 사용하는데 \ 뒤에 space 가 있으면 안됨.

이것땜에 시작부터 2~3시간 삽질함.

 

l  config 성공하고 make 실패시

원인 : 생성된 config.h 헤더파일에 줄변경 문자가 포함된 경우가 있음.

참고 : http://stackoverflow.com/questions/14199888/cygwin-make-errors-ffmpeg-compile-with-ndk

Ultra-editor 에서도 않보임. 그냥 eclipse에서 보면 줄변경 되어 있음. 콘솔인경우 VI 에디터로 바로 지우면 편리함. 계속 삽질 ㅠ

 

l  share파일이 libavcodec.so.54 이렇게 생성될 때  

원인 : 1.2.2 버전의 share 모드 스크립트가 그렇게 생겨 먹었음.

참고 :

http://stackoverflow.com/questions/14521588/native-libraries-so-xy-failing-to-link-at-runtime

http://stackoverflow.com/questions/14522510/simple-string-substitution-in-makefile/

수정 : 참고는 그냥 참고일뿐, library.mak 파일에서 link 만드는 부분 수정하면 됨. ( install-lib$(NAME)-shared 로 검색 ) 그리고 configure 파일에서 SLIBNAME_WITH_MAJOR 찾아서 수정하면됨. 삽질은 멈추지 않는다.

 

 

[ 마치면서 ]

윈도우에서 하다가 막혀서 맥에서 해보니 맥이 android NDK 개발하는데 더 좋은 환경인 것 같습니다. 주변에서도 맥에서 android 개발하는 사람들이 꽤 되던데 저도 고려중에 있습니다.

 

[ 기타 참고 ]

https://code.google.com/p/javacv/downloads/list

 

 

 

 



:

[android] CheckBox에서 image와 text 간격

android 2013. 6. 19. 03:51

336x280(권장), 300x250(권장), 250x250, 200x200 크기의 광고 코드만 넣을 수 있습니다.

안드로이드에서 checkbox를 사용할 때 주의점이 있다. Check 이미지와 text의 간격을 조정하기 위해서는 paddingLeft를 사용하는데, XML에서 사용하면 API 16 이하에서는 동작하지 않는다. ( API 17 : 젤리빈 에서 수정되었다. )

 

<CheckBox

android:id="@+id/twitter_connect_checkbox"

android:button="@drawable/ selector_common_checkbox"

android:layout_alignParentLeft="true"

android:layout_marginLeft="10dp"

android:paddingLeft="5dp"

android:text="@string/some_text " />

 

android의 버전별로 호환성을 유지하기 위해서는, 위의 paddingLeft XML에서는 빼고 코드로 처리하는 것이 바람직하다.

final float scale = getResources().getDisplayMetrics().density;

checkBox.setPadding(checkBox.getPaddingLeft() + (int)(30.0f * scale + 0.5f),

checkBox.getPaddingTop(),

checkBox.getPaddingRight(),

checkBox.getPaddingBottom());

                     

다른 방법으로는 drawableLeft 사용하여 이미지를 표시하고, 이미지의 간격 조정은 drawablePadding으로, 텍스트의 간격 조정은 paddingLeft 등으로 처리하는 것이다.

아래는 checkbox 대신 ToggleButton으로 변경하여 처리한 방법이다.

 

<ToggleButton

android:id="@+id/twitter_connect_checkbox"

android:drawableLeft="@drawable/ selector_common_checkbox"

android:drawablePadding="5dp"

android:layout_alignParentLeft="true"

android:layout_marginLeft="10dp"

android:paddingLeft="5dp"

android:text="@string/some_text " />

 

drawableLeft, drawableRight, drawableTop, drawableBottom 등으로 component의 원하는 위치에 이미지를 설정할수 있다.  drawablePadding 값은 컨트롤 내부에서 이미지의 간격을 조정하는 값이다. paddingLeft는 이미지와 텍스트사이의 간격을 설정한다.

 

drawableXXX 기능은 TextView에 있는 기능으로 TextView parent로 하는 Button 계열의 컨트롤에서는 모두 사용가능한 방법이다. CheckBox의 상속 구조는 아래와 같다.

CheckBox -> CompoundButton -> Button -> TextView -> View

 

CheckBox ToggleButton interface가 상당히 유사해서 대부분 서로 대체해서 사용할수 있으므로 checkBox의 에러가 android 4.2에서 수정되었으므로 imagetext를 표시해야 하는 부분에서 checkbox 대신에 ToggleButton을 사용하길 권장한다.

( 안드로이드는 TextView에 참 많은 기능이 들어 있다. )

 

 



: