지난 글 onCreateDialog/onPrepareDialog 에 이어

 

Custom dialog의 위치와 크기 변경에 대해 알아보도록 하겠습니다.

 

이전 글의 맥락을 같이 하기 위해,

onCreateDialog( ... ) 또는 onPrepareDialog( ... ) 메서드에서 변경을 가하도록 합니다.

 

각 dialog id마다 위치/크기가 모두 다르다 하면 각 분기문 안에서 해주시면 될듯하고,

공통분모가 있다면 역시나 맨 끝에 id 구별 없이 해주시면 될듯 합니다.

 

먼저 인자로 넘어온 dialog가 있으니 우린 이 dialog를 잘 요리해주면 됩니다.

자세히 찾아보진 않았지만 Dialog 클래스는 View class를 상속받고 있지 않네요,

View의 계층 구조로 보았을 때 graphics 계열이지만 Dialog는 app 계열입니다.

고로 해당 LayoutParam를 사용하기 위해 View에서는 getLayoutParams() 를 사용했지만,

DIalog의 LayoutParam을 사용하기 위해서는 Dialog의 getWindow()를 통해

해당 window를 참조해서 getAttributes()를 통해 받아와야합니다.

 

복잡해 보이지만 실지론 한줄로 표현이 됩니다.

LayoutParams dialogLP = dialog.getWindow().getAttributes();

 

이렇게 LayoutParam을 받고 나면 조절하는거야 .찍어보면 eclipse의 훌륭한 assist 기능으로 쉽게 알 수 있는데요,

다음을 주의해서 코딩하시면 삽질을 꽤나 많이 줄일 수 있을 것입니다.

 

1. dialog는 width/height가 wrap_content / wrap_content 입니다.

2. dialog는 기본적으로 layout_gravity가 center 정렬입니다.

 

위 주의 사항중 1은 크게 어렵지 않게 해결되었지만 2번 좌표 이동은 생각처럼 잘 안되더라구요(처음엔)

 

모든 기기에 맞는 좌표 이동을 원했기 때문에 y축 이동이 필요했습니다.

(x축은 해상도 따라 비율로 크거나 작아지게만 하면 가운데 정렬이니 좌표를 변경할 필요는 없었습니다.)

 

결국 삽질 끝에 이런 방법이 생겼습니다.

 

1. 기준이 되는 해상도의 이동 좌표를 정함 (예를 들어 1280*720 기준, y축 위로 280px 올라간 dialog)

2. 현재 디바이스의 세로 해상도( deviceHeight ) 를 1280과 비교해 비율을 얻어냄. ( heightRate )

3. 마지막으로 dialogLP.y = Math.round( 280 * heightRate ) - (( deviceHeight - dialogLP.height ) / 2);

 

이렇게 하면 해결이 되더군요 ~_~

 

 


 

한가지 더 중요한 팁이 있는데요, (팁이라기보다는 삽질 미연 방지)

onPrepareDialog( ... ) 에서 크기나 위치를 변경할 경우,

현재 dialog의 값을 참조한 상태로 변경하지 않아야 한다는 것입니다.

 

onCreateDialog에서야 한번 하고 마니 상관 없지만,

onPrepareDialog에서 하면 호출될 때마다 매번 위치/크기가 계속 더해지고 빼지고 하면서 변경되거든요.. ^^;

 


(2016.09.26) 오랜만에 보니 말이 이상하네요 ㅜㅜ 아래 글은 다음에 기회 될 때 올바르게 수정해두겠습니다.

덧붙여 한가지 더!

이렇게 생성된 dialog에서는 onBackPressed 이벤트를 받지 않습니다.

따라서 onBackPressed가 먹히지 않게 하시려면 먹지 않게 할 dialog를 생성할 때

고정적이라면 onCreateDialog에서 dialog.setCancelable( false ) 로 설정해주시면 됩니다.


'Android' 카테고리의 다른 글

Adjusting Touch Area  (0) 2012.10.16
Android GCM 가이드 따라하다 삽질한 기억  (0) 2012.10.09
Avoding memory leaks  (0) 2012.09.10
onCreateDialog/onPrepareDialog  (8) 2012.09.06
안드로이드 성능 개선  (0) 2012.08.31
Posted by 독뽀
,

Avoding memory leaks

Android 2012. 9. 10. 09:49

주로 Context 관련 내용들

 

http://android-developers.blogspot.kr/2009/01/avoiding-memory-leaks.html

'Android' 카테고리의 다른 글

Android GCM 가이드 따라하다 삽질한 기억  (0) 2012.10.09
Custom dialog 위치/크기 변경하기  (1) 2012.09.26
onCreateDialog/onPrepareDialog  (8) 2012.09.06
안드로이드 성능 개선  (0) 2012.08.31
큰 Bitmap 사용 시 주의점  (0) 2012.08.31
Posted by 독뽀
,

Dialog 사용을 하다보면 Activity에 멤버로 들고다니는 경우가 있어서

관리하기도 어렵고 해서 onCreateDialog/onPrepareDialog를 사용함.

 

※ 개인적으로, 관리하기 어렵다는 내용은 빠르게 이벤트 발생 시 Dialog가 중복해서 뜬다거나..

레이아웃이 전부 달라 멤버 필드로 각 Dialog를 갖고 있으면서 show/hide하면서

위의 중복 문제로 show/hide flag를 두거나 isShow() 등으로 확인하는 번거로움 등을 말함

 

onCreateDialog, onPrepareDialog

1. onCreateDialog 내에서 생성되어 return되는 dialog는 onCreateDialog를 오버라이딩한 액티비티의 소유가 됨.

2. 고정적인 내용(최초 생성 시 1회 호출) vs 유동적인 내용(showDIalog마다 호출) 정도로 요약 가능

3. 호출 흐름

- 최초: showDialog( id ) 호출 → onCreateDialog → onPrepareDialog

- 이후: showDialog( id ) 호출 → onPrepareDialog 만 계속 호출됨

 

정적인 팝업: onCreateDialog에서만 처리해도 됨 (onPrepareDialog 사용 안해도 무방)

동적인 팝업: onCreateDialog에는 정적 내용만 넣고 onPrepareDialog에 동적 내용을 추가한다.

 

onCreateDialog( int id ) 및 onPrepareDialog( int id, Dialog, dialog ) 둘은 deprecated 되었다고 합니다.(인자가 하나씩 적음)

http://developer.android.com/reference/android/app/Activity.html#onCreateDialog(int)

http://developer.android.com/reference/android/app/Activity.html#onPrepareDialog(int, android.app.Dialog)

 


 

final int DIALOG_ID_NOTICE = 0;

@Override
protected Dialog onCreateDialog(int id, Bundle args)
{
    Dialog dialog = null;

 

    switch( id )
    {
        case DIALOG_ID_NOTICE:
        {
            dialog = new Dialog( mContext, R.style.Theme_Dialog );
            dialog.requestWindowFeature( Window.FEATURE_NO_TITLE );
            dialog.setContentView( R.layout.custom_dialog_purchase_house );

 

            TextView title = (TextView) dialog.findViewById( R.id.dialogTitle );

            if( title != null )
                title.setText("Notice");

 

            Button btnCancel = (Button) dialog.findViewById(R.id.dialogCancel );

            if( btnCancel != null )

            {
                btnCancel.setOnClickListener( new View.OnClickListener() {
                    @Override
                    public void onClick(View view) {
                        try {
                            dismissDialog( DIALOG_ID_NOTICE );
                        } catch (Exception e) {
                            Log( "[onCreateDialog] dialog id does not exist" );
                        }
                    }
                });
            }

        }
            break;

        default:
            Log( "[onCreateDialog] dialog id is unknown, dialog will be null." );
            break;

    }

 

    return dialog;
}

 

@Override
protected void onPrepareDialog(int id, Dialog dialog, Bundle args)
{
    super.onPrepareDialog(id, dialog, args);

    switch( id )
    {
        case DIALOG_ID_NOTICE:
        {

            TextView content = (TextView) dialog.findViewById( R.id.dialogMessage );

            if( content != null )

            {

                if( mResult == false )
                    content.setText( "Success!" );

                else

                    content.setText( "Fail!" );

             }
        }
            break;

        default:
            break;
    }
}

 


Dialog를 보여주고 싶은 곳에서 showDialog( DIALOG_ID_NOTICE );

Dialog를 닫을 곳에서 dismissDialog( DIALOG_ID_NOTICE );

 

null 처리 이딴거 다 뺴고싶지만 군데군데 들어갔네요.. 습관 들입시다;

(복붙 하고 색만 입힌거라 수정이 귀찮..)

 

당연한거지만 위에 대응하는 custom dialog xml을 만드실 땐

TextView (@+id/dialogTitle )

TextView (@+id/dialogMessage )

Button (@+id/dialogCancel )

위 세 개 위젯은 반드시 추가해서 만들어주세요~

그리고 Log는 보통 자주들 쓰시는 Log.d( "tag", "msg" ) 를 고친거에요~

이래저래 바꾸는건 상관 없지만 소스 긁어다 하시는 분들은 id 맞춰서..

 

removeDialog( id ) 같은 경우에 즉시 제거가 되지 않는 경우가 발생할 수 있다고 하네요,

그러니 onCreateDialog 를 강제로 부르려고 removeDialog( id ) 를 사용하고 showDIalog( id )를 호출하면

정말 재수 없으면 무슨 일이 벌어질지 모른다는 글을 본 기억이 있는데 찾기가 귀찮..

 

결론은 onCreateDialog에서는 되도록 정적인 일만 하게 두시고 onPrepareDialog에서 동적인 일들을 처리하여

onPrepareDialog만 불려도 되도록 해주세요.

 

위 예에서는 onCreateDialog 에서 첫 세 줄만 남겨두시고 나머진 onPrepareDialog로 옮겨주심 되겠네요.

 

dialog = new Dialog( mContext, R.style.Theme_Dialog );
dialog.requestWindowFeature( Window.FEATURE_NO_TITLE ); // must request before setContentView
dialog.setContentView( R.layout.custom_dialog_purchase_house );

 

후.. 은근 길어졌네..

 

다음에는 Dialog 위치/크기를 자유자재로 바꾸는걸 보도록 할께요..

'Android' 카테고리의 다른 글

Custom dialog 위치/크기 변경하기  (1) 2012.09.26
Avoding memory leaks  (0) 2012.09.10
안드로이드 성능 개선  (0) 2012.08.31
큰 Bitmap 사용 시 주의점  (0) 2012.08.31
AnimationDrawable 사용 시 주의점  (2) 2012.08.24
Posted by 독뽀
,

http://rags.tistory.com/91

 

요약하자면 가장 많이 나오는 내용이..

 

멤버 필드 접근이 빈번하지 않도록 지역 변수로 값을 복사해서 써라..

멤버 필드나 메서드에 final 키워드를 자주 쓰자. 지역 변수에는 성능상 이득이 없음

한 클래스 내에서의 getter/setter를 되도록 사용하지 말고 필드에 직접 접근하라

(객체 지향적 관점에서의 인터페이스로서는 묵과함)

 

결국 멤버 필드 및 중복 함수 호출로 인한 성능 저하를 피하자는 얘기

 

뭐 대충 이런 비용 차이..

함수를 통한 멤버 필드 접근 > 멤버 필드 접근 > 지역 변수

 

아래는 위 링크에 나와있는 대략적인 도표

행동

시간

지역 변수 더하기

1

멤버 변수 더하기

4

String.length() 호출

5

빈 정적 네이티브 메소드 호출

5

빈 정적 메소드 호출

12

빈 가상 메소드 호출

12.5

빈 인터페이스 메소드 호출

15

HashMap Iterator:next() 호출

165

HashMap put() 호출

600

XML로부터 1 View 객체화(Inflate)

22,000

1 TextView를 담은 1 LinearLayout 객체화(Inflate)

25,000

6개의 View 객체를 담은 1 LinearLayout 객체화(Inflate)

100,000

6개의 TextView 객체를 담은 1 LinearLayout 객체화(Inflate)

135,000

activity 시작

3,000,000

 

잘 안쓰던 for-each 나 HashMap 등도 적극 활용해보아요

for-each의 경우 컴파일러가 인라인화 해주기도 한다니 참고!

'Android' 카테고리의 다른 글

Avoding memory leaks  (0) 2012.09.10
onCreateDialog/onPrepareDialog  (8) 2012.09.06
큰 Bitmap 사용 시 주의점  (0) 2012.08.31
AnimationDrawable 사용 시 주의점  (2) 2012.08.24
System(0) 으로도 죽지 않는 app 종료 시키기  (0) 2012.08.21
Posted by 독뽀
,

http://www.facebook.com/notes/jung-haengs-nexus-one/android-%EA%B0%9C%EB%B0%9C%EC%8B%9C-%ED%81%B0-bitmap%EC%9D%84-%EA%B4%80%EB%A6%AC%ED%95%A0%EB%95%8C-%EC%A3%BC%EC%9D%98%ED%95%B4%EC%95%BC%ED%95%A0-memory-leak-%ED%8F%AC%EC%9D%B8%ED%8A%B8/225201584184632

 

신경 쓴다고 써도 잘 안되는 안드로이드 메모리 관리..

 

특히나 고해상도 게임을 제작하는 경우(이번엔 무려 1280*720 사이즈 대상..)

최대화된 이미지를 가지고 요리조리 크기를 변경해가며 사용하게 되는데..

100% bitmap 사용이 불가한 경우도 있었음.

ex) animation-list 로 프레임 애니메이션을 보여줄 때 inSampleSize 사용이 불가했음..(AnimationDrawable이기 때문인지 Drawable로만 생성 가능.. Bitmap으로 생성 불가..)

 

여기에 덧붙여 C와는 다르게 GC가 즉시 100% 수행된다는 보장이 없음..

 

오늘 디버깅하다 본건데 좀 큰 이미지 로드 시 아래와 같은 메시지가 나오던데

아마도 이게 메모리 확보하려고 GC가 돌아가는 로그 같음..

 

dalvikvm GC_EXTERNAL_ALLOC freed x K, x % freed x K/x K, external x K/ x K, paused x ms

반복

 

이게 정말 안드로이드 적응하기 힘든 특징..

특히나 링큰된 글에서처럼 ActivityContext를 참조하고 있는 객체가 있을 때 그 참조 횟수 디버깅에 또 시간을 할애해야한다는게 너무 큰 함정인듯..(적어도 나에겐;)

 

c에서의 smart pointer나 obj-c에서 쓰는 retainCount 같은거 없나..?

어디가서 무식하단 소리 들을라 ㅜ

'Android' 카테고리의 다른 글

onCreateDialog/onPrepareDialog  (8) 2012.09.06
안드로이드 성능 개선  (0) 2012.08.31
AnimationDrawable 사용 시 주의점  (2) 2012.08.24
System(0) 으로도 죽지 않는 app 종료 시키기  (0) 2012.08.21
에뮬레이터 관련 정보  (0) 2012.08.13
Posted by 독뽀
,

http://blog.naver.com/huewu/110081670181

 

 

요약하자면..

 

drawable에 생성한 animation-list 를 ImageView에서 사용하려고 할 때,

AnimationDrawable 객체를 start 시키는 위치는 onCreate/onStart 등이 아니라

onWindowFocusChanged 에서 start()를 해야 애니메이션이 정상 동작한다.

 

또한 AnimationDrawable.start() 메서드는 이미 start 되어 있다면 다시 start() 해도 작동하지 않으니

stop() 후 start() 를 해주자.

Posted by 독뽀
,

링크로 대체 ← 클릭

Posted by 독뽀
,

Max VM application heap size

INSTALL_FAILED_INSUFFICIENT_STORAGE 에러

 

Max VM application heap size의 경우 48 내외로 해도 안죽는다면 굿일듯..

 

http://marga.tistory.com/587

Posted by 독뽀
,

http://javaexpert.tistory.com/333

Posted by 독뽀
,

ViewFlipper 사용 시 View 전환 이외에 또 다른 기능을 추가하고 싶을 때는

Flipping animation이 끝나는 시점 등에 해당 기능을 추가하면 된다.

 

http://stackoverflow.com/questions/3813108/listener-for-viewflipper-widget-flipping-events

 

위의 경우는 Animation을 코드로 삽입한 경우이고..

xml로 설정하고 함수가 호출될때만 해당 anim xml일이 호출되는 경우라면 다음과 같이 ViewFlipper의 터치 이벤트를 핸들하면 된다.

 

mViewFlipper.setOnTouchListener( new View.OnTouchListener() {
            @Override
            public boolean onTouch(View v, MotionEvent event) {
                if (event.getAction() == MotionEvent.ACTION_DOWN) {
                    mPrePosX = (int) event.getX();
                }

                if (event.getAction() == MotionEvent.ACTION_UP) {
                    int nTouchPosX = (int) event.getX();

                    if (nTouchPosX < mPrePosX) {
                        slideToNext();
                    } else if (nTouchPosX > mPrePosX) {
                        slideToPrev();
                    }

                    mPrePosX = nTouchPosX;
                }

                return true;
            }
        });

 

위의 slideToNext() 함수 내부에서는 mViewFlipper.SetInAnimation / SetOutAnimation / showNext 를 호출하고 그 외에 할 일들을 추가하면 될 것이다.

반대로 slideToPrev() 함수는 위와 다 똑같지만 마지막에 showNext 대신 showPrevious를 호출하면 끝.

mPrePosX 는 좌로 슬라이드 했는지 우로 슬라이드 했는지를 판단하기 위함이므로 그대로 사용해도 무방함. (좌: prev, 우: next)

'Android' 카테고리의 다른 글

에뮬레이터 관련 정보  (0) 2012.08.13
화면에 사용된 View가 많을 때 한번에 리스너 등록하기  (0) 2012.08.07
색상 필터  (2) 2012.07.11
Android 메모리 릭 피하기 번역  (0) 2012.06.12
Android code snippets  (0) 2011.05.11
Posted by 독뽀
,