상세 컨텐츠

본문 제목

안드로이드 회전시 나타나는 문제.

스마트기기개발관련/안드로이드 개발

by AlrepondTech 2011. 12. 27. 17:11

본문

반응형

 

 

 

=================================

=================================

=================================

 

 

 

 

 

출처: http://blog.kfmes.com/227

안드로이드폰은 화면 회전이 지원된다.

키보드를 열거나 닫으면 가로보기/세로보기로 전환이 되는데,
이때 UI가 새로 그려지면서 Activity의 onDestroy()와 onCreate() 가 수행된다.

위 과정이 수행되고 나면,
Activity 에서 가지고 있었던 변수들(field 도 포함)이 초기 상태로 된다.

만약, 코드에서 Thread를 만들어 돌아가는 중이었다면,
화면 회전을 한 후에는 사라지는 현상이다.

해결방법은 아래를 클릭...

[닫기...]

 

[CODE type="java"]/**
Activity소스코드를 보면, 타입이 HashMap<String, Object>이고, null 을 리턴하고 있다.
유지해야할 데이터가 한개라면 그 Object를 바로 리턴해도 된다. */
@Override
public Object onRetainNonConfigurationInstance() {
[tab]HashMap<String, Object> map = new HashMap<String, Object>();
[tab]map.put("worker", worker);
[tab]map.put("var1", var1);
[tab]map.put("var2", var2);
[tab]return map;
}
}

/**
onCreate의 적당한 부분에 이전 데이터를 복원하는 코드를 넣어준다.
여기에서는 restore() 를 따로 정의했다. */
@Override
public void onCreate(Bundle savedInstanceState) {
[tab]super.onCreate(savedInstanceState);
[tab]...
[tab]...
[tab]restore();
[tab]...
[tab]...
}

/**
이전 데이터를 복원한다 */
@SuppressWarnings("unchecked")
private void restore() {
[tab]Object o = getLastNonConfigurationInstance();
[tab]if(o!=null){
[tab][tab]//Map형태로 리턴했기때문에 casting 해서 사용한다.
[tab][tab]HashMap<String, Object>map = (HashMap<String, Object>) o;
[tab][tab]this.worker = (Thread) map.get("worker");
[tab][tab]this.var1 = (String) map.get("var1");
[tab][tab]this.var2 = (String) map.get("var2");
[tab]}
}[/CODE]


화면이 회전되거나 종료가 될때, onDestroy()가 호출되는데,
다음과 같이 구분해서 종료될때의 처리를 해 줄 수 있다.
[CODE type="java"]@Override
protected void onDestroy() {
[tab]Log.d(tag, "onDestroy" + " isFinishing : " +isFinishing());
[tab]if(isFinishing()){
[tab][tab]//isFinishing()은 진짜로 프로그램이 종료될때는 true 값이다.
[tab][tab]// 회전할때는 당연히 false
[tab][tab]worker.interrupt();
[tab][tab]worker=null;
[tab]}
[tab]super.onDestroy();
}[/CODE]

[닫기...]

 

 

 

=================================

=================================

=================================

 

 


출처: http://starkapin.tistory.com/184

안 드로이드에서 PORTRAIT, LANDSCAPE 두가지 모드로 작업을 진행해야 할 때가 있다. 나는 무조건 단방향모드만 지원할꺼야 라고 기획을 잡아놓으면 이 두가지 상황중 하나만 설정을 해 놓으면 된다. 그러면 조건에 맞춰 어떻게 사용해야 할지를 살펴보자.

 
Manifest에서 처리하는 것만 조사했으니 이것에 대한 내용만 정리해본다면..
 
1
2
3
4
5
6
<activity android:name=".index" android:label="@string/app_name" android:screenorientation="landscape" android:theme="@android:style/Theme.NoTitleBar.Fullscreen">
     <intent-filter>
           <action android:name="android.intent.action.MAIN">
           <category android:name="android.intent.category.LAUNCHER">
     </category></action></intent-filter>
</activity>
위 소스에서 살펴보면 android Attribute 중 screenOrientation이라는 항목이 보인다. 우리는 이것을 설정해 가로모드인지 세로모드인지를 고정시킬 수 있다.
 
물론 기본적으로 안드로이드에서는 위와 같은 설정을 해주지 않으면 기본적으로 가로, 세로 모드 전환을 시켜준다. 이럴때에는 다음과 같은 상황을 고려해야 한다.
 
"세로, 가로 모드 전환시 레이아웃은 어떻게 변화시켜 줄 것인가?"
 
일반적으로 우리가 주로 사용하는 모드는 세로모드다, 가로폭이 좁고 세로폭이 길어 전체적인 웹의 모습이나 리스트 항목을 보기엔 매우 유리한 편이다. 반대로 가로모드는 넓은 화면을 보기에는 좋지만 세로폭이 좁아 아래로 나열된 항목을 볼땐 불편한 점이 많다.

이 두가지를 다 지원한다고 했을 때 각각 아이템 위젯들은 세로형에서 적합한 크기와 가로모드에서 적합한 크기로 변화되어야 한다. 그래서 우리는 이때 다음 명령어를 통해 현재 상태를 읽어 오고 레이아웃을 적용하는 방법을 사용할 수 있다.
 
1
2
3
WindowManager wm = getWindowManager();
if (wm == null) return;
    setOrientation(wm.getDefaultDisplay().getOrientation()); // 자체 메소드
 
getOrientation 메소드를 이용하면 우리는 현재 모드를 읽어오게 되고 지금 사용자 정의된 setOrientation 메소드 처럼 자신만의 레이아웃을 관리하는 함수를 등록해 사용 할 수 있다.
 
1
2
3
4
5
6
7
8
9
if(m_isLandscape == 0) {
    // Portrait mode, Nothing change previous version
    setContentView(R.layout.reservation_setting_layout);
    mMainlayout = (RelativeLayout)this.findViewById(R.id.MainLayout);
}else {
    // Landscape mode, call another layout
    setContentView(R.layout.reservation_date_land_layout);
    mLMainlayout = (LinearLayout)this.findViewById(R.id.MainLayout);
}
setOrientation 메소드 내부를 일부 살펴보자면 위와 같이 가로와 세로모드에서 각각의 레이아웃을 새로 받아온다. 이를 이용해 우리가 원하는 레이아웃을 입맛에 맞게 변경이 가능하다.
 
문제는 이러한 메소드를 onCreate() 부분에서만 사용하게 만드느냐이다. 답은 '아니다'다. 액티비티 진입시에만 발생하는 onCreate에서만 호출 된다면 액티비티 구동중에서의 변화는 일어나지 않는다. 이럴 때에는 onConfigurationChanged라는 콜백 메소드를 이용하는 방법이 있다. 이를 적용시키기 위해서는 Manifest 파일에서 해당 액티비티에 ConfigChanges 속성을 부여 해준다.
 
android:configChanges="orientation|keyboardHidden" 
 
위와 같은 속성을 추가 해준뒤에, 
 
1
2
3
4
5
6
7
8
9
@Override
public void onConfigurationChanged(Configuration newConfig)
{
    super.onConfigurationChanged(newConfig);
        // 다시 setOrientation()을 호출한다.
        WindowManager wm = getWindowManager();
        if (wm == null) return;
        setOrientation(isLandscape);
}
onConfigurationChanged는 액티비티의 방향전환이 일어날 때 이 메소드를 통해 액티비티를 새로 리셋을 하게된다. 
 
그외에 핸드폰에서 가로모드 방향전환을 막게 되는 경우가 있는데 이러한 설정을 동일하게 맞춰주기 위한 매니페스트 속성으로는 다음이 존재한다.
 
android:screenOrientation="unspecified"
 
위와 같은 내용을 적게 되면 핸드폰 설정값에 따라 방향전환이 일어나게 된다.

 

 

 

=================================

=================================

=================================

 

 

출처: http://komaneko.egloos.com/4374114


정확히는 Url이 돌아온 게 아니라, 화면을 회전했을 뿐인데 해당 Activity는 onDestroy()를 거쳐 onCreate()를 다시 실행합니다. .....제정신입니까? 
(아, 물론 제 착각이었습니다. 제정신인건 알고 있어요. 미안해요.)
 
 
곧 해결법을 찾아보기로 하였습니다.
Activity에 onRetainNonConfigurationInstance() 가 있더군요!
 
1.
Configuration이 변경 될 때 onRetainNonConfigurationInstance()가 호출 되고, 여기에서 넘겨줄 Object를 설정. 뭐, Url String정도 넘겨 줄까요?
 
2. onCreate 에서 앞서 넘겨준 Object를 getLastNonConfigurationInstance()로 받아서 loadUrl... 물론 getLastNonConfigurationInstance()에서 아무 값도 반환 되지 않는다면 화면 회전이 아니라 처음 Activity가 start했다는 뜻이니 예외 처리를 잘 해줍시다.
 
 
이 런. 이렇게 해두고 보니 문제가 있습니다. Url만 띄운다고 되는 게 아니거든요. 화면에 입력중인 값, 웹페이지의 자바스크립트에서 가지고 있는 값... 그래서 그냥 WebView 자체를 넘겨줬습니다. getLastNonConfigurationInstance()를 통해 WebView를 받아서 addChild() 해주는 편법을 썼죠. 주의할점은 View는 하나의 Parent만 가질 수 있으므로, onRetainNonConfigurationInstance()에서 WebView를 Parent에서 remove 해줘야 합니다. 
 
결과는 만족스러웠습니다. 그리고 아예 Object를 넘겨줄 때 HashMap으로 넘겨서 WebView와 필요한 몇 가지 변수들의 값을 추가로 넘겨줬습니다. 음. 잘 동작하는군. 화면이 좀 깜박여 보인다는 것을 제외한다면...
넘겨줘야하는 변수가 엄청나게 늘어난다고 해도 수고만 조금 더 들어갈 뿐, 별 문제는 없어 보입니다. Intent처럼 제한 없이 Object를 넘겨 줄 수 있으니까요.
 
 
...여기까지, 코드 없이 설명만 읽기에 괴로우셨을 겁니다. 코드 몇 줄이면 될 것을 이런 게으름뱅이!
하지만 말로 설명하는 게 더 귀찮아요. 코드를 쓰지 않은 것은 일부러 그런 겁니다. 
이건 잘못된 방법이거든요.
이런식으로 구현한 경우를 몇 번 본적이 있어서 무심코 따라했는데, 이 포스팅을 보시는 분들은 따라하지 않도록 주의하시길 바랍니다. 100%의 경우라고는 말 못하지만 대부분의 경우는 위와 같이 하는 게 헛수고일 것입니다.
 
 
제대로 된 해결법은 다음과 같습니다.
 
1. AndroidManifest.xml 파일을 열어줍시다.
2. Activity에 다음 Attribute를 추가해 줍니다. 
 
  android:configChanges="orientation|keyboard"
 
Activiti가 10개라면 각각 전부 다 추가해 주시면 됩니다. 아, 물론 적용하고 싶은 Activity들이요. -끝-
 
 
이 렇게 하면 Activity가 재생성 되지 않습니다. 넵. Object따위 넘겨줄 필요 없습니다. 따로 구현 할 필요가 없다는 뜻입니다. 추가로, onRetainNonConfigurationInstance() 이후 정상적으로 onConfigurationChanged()가 호출 되고요.
물론 각 View들도 정상적으로 onMeasure()후 onDraw() 됩니다.

 

 

 

 

=================================

=================================

=================================

 

 

 

출처: 여기

메인부분에서 화면 고정을 해도 기기에 따라 기기에 설정된 로테이트가 설정된뒤

화면이 바끼는 경우가 있다 특히 메인 액티브티 화면뷰어 같은경우 문제가 된다.

그러므로 회전에 영향이 가는 뷰어부분은 onDestroy()와 onCreate() 에 안의 api

들이 있다면 신경써주어야 한다.



 

=================================

=================================

=================================

 

 


 

반응형


관련글 더보기

댓글 영역