configuration 의 종류
- display dock 에 연결
- 폰트 크기 변경
- 기본 언어 변경
- 화면전환
- 기타 등등...
이 경우 모든 현재 동작하는 Activity 는 그 Activity 를 다시 사용 하려고 할 때 destroy 되고 recreate 된다.
android:configChagnes
AndroidManifest.xml 에 사용하는android:configChanges방법은 권장하지 않는다. 이 방법은 개발자가 직접 configuration 변경에 대한 관리를 해야 한다. 그리고 이 방법은 개발자가 생각하는 만큼 완벽하게 orientation change(화면 방향 전환) 에 대한 처리를 해주지 않는다.[ref. 1]
onRetainNonConfigurationInstance, getLastNonConfigurationInstance
HoneyComb 이전에 사용됐던
- onRetainNonConfigurationInstance()
- getLastNonConfigurationInstance()
는 deprecated 됐으며,
Fragment 의
- setRetainInstance(boolean)
로 대체되었다.
setRetainInstance(true)
기본적으로 Activity 가 destroy 되고 recreate 될 때 Fragment 도 같이 destroy 되고 recreate 된다. 하지만 이때setRetainInstance(true)를 사용하면 fragment 가 destroy, recreate 되지 않게 할 수 있다.
Fragment 의 onCreate(),
이것은 running Threads, AsyncTasks, Sockets 등을 갖고 있는 Fragment 가 있다면 매우 유용하다.[ref. 1]
onAttach()
onAttach() 에서 Activity 값을 얻을 수 있다.setRetainInstance(true) 를 설정하고 onCreate() 에 code 를 놓아둘 때는 한 번만 실행될 녀석을 놓아두게 된다. 이 때 이 code 가 activity reference 를 필요로 하는 경우라고 가정하자.
이런 경우에 orientation change(화면전환) 이 일어나면, reference 를 다시 설정 해 줘야 하는데, onCreate() 는 setRetainInstance(true) 일때는 다시 실행되지 않기 때문에, activity의 reference 를 onCreate 이전에 설정을 해줘야 한다. 그 때 onAttach() 를 사용할 수 있다. 이런 방법을 이용한 예가 ref. 1 이다.
onCreate()
onCreate() 부분에는 단 한 번 만들어지면 좋을 녀석을 넣어놓자.Configuration 이 바뀌는 경우가 여러가지가 있겠지만, 가장 많은 경우인 orientation 이 바뀌는 경우(화면전환)를 고려해 보면서, 화면이 바뀌어도 값이 변하지 않아서 그대로 사용해도 될 값들과 관련된 사항들을 이 곳에 넣자.
예를 들면 context 같은 것은 이곳에 넣으면 안된다. context 값이 새로 setting 될 것인데, 이때 기존의 context 와는 다른 object 가 된다. (쉽게 얘기하면 새로운 주소값을 가지게 된다.) 그러므로 context 를 그대로 사용하면 잘못된 주소를 access 하게 되는 것이기 때문에 안된다.
참고로, setRetainInstance(true) 도 onCreate() 에 들어간다.
onCreateView()
화면이 바뀌면 당연히 화면에 그려진 GUI 와 관련된 부분들은 다시 그려져야 한다. 간단하게 생각하면 가로, 세로값등 많은 값들이 달라졌기 때문에 기존의 값을 그대로 유지 할 수 없다.화면이 바뀌게 되면, 이 화면을 다시 그려야 하기 때문에 inflate 를 해줘야 한다. 그러므로 화면이 바뀌어서 다시 돌아오게 되면 onCreateView() 부터 시작하게 된다. 그러니 이부분에는 화면을 inflate 하는 부분, inflate 를 set 하는 부분등 inflation 과 관계있는 code를 넣어줘야 한다.
LoaderManager.initLoader()
setRetainInstance(true) 라고 해도 만약 onStart() 같은 곳에서 LoaderManager.initLoader() 를 호출하게 되면 onLoadFinished() 는 호출된다.그러므로 orientation rotate 등이 발생할 때를 위해 아래같은 처리가 필요하다.
LoaderManager loaderManager = getActivity().getSupportLoaderManager();좀 더 자세한 이야기는 아래 글에서 확인 해 보자.
final Loader<Cursor> loader = loaderManager.getLoader(LOADER_ID);
if(loader == null || loader.isReset()){
loaderManager.initLoader(LOADER_ID, null, this);
}
Scenario where initLoader() does not call onLoadFinished()
Code example
public class MainFragment extends Fragment implements LoaderManager.LoaderCallbacks<Cursor> { private static final String TAG = "MainFragment"; private static final int LOADER_ID = 1; private PullToRefreshListView mPullRefreshListView; private MMiniNoteListAdapter mNoteAdapter; private HorizontalListView mPodList; private PodListAdapter mPodListAdapter; private LoadFeedAsyncTask mLoadFeed = null; /** * Hold a reference to the parent Activity so we can report the * task's current progress and results. The Android framework * will pass us a reference to the newly created Activity after * each configuration change. */ @Override public void onAttach(Activity activity) { super.onAttach(activity); //mCallbacks = (TaskCallbacks) activity; } /** * This method will only be called once when the retained * Fragment is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // Retain this fragment across configuration changes. setRetainInstance(true); // Put objects which you do not want to be created again. // ie. run once. mPodListAdapter = new PodListAdapter(); mNoteAdapter = new MMiniNoteListAdapter(); mLoadFeed = new LoadFeedAsyncTask(mPodListAdapter); mLoadFeed.execute(getActivity()); // Though getActivity is changed after orientation change, // this statement is ok because it is run only once. Log.d(TAG, "LoadFeedAsyncTask is invoked with Activity " + getActivity()); } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View fragment = inflater.inflate(R.layout.main_fragment, container, false); mPodListAdapter.setInflater(inflater); mNoteAdapter.setInflater(inflater); NoteLoadSingleton nls = NoteLoadSingleton.getInstance(); mPullRefreshListView = getNoteListView(fragment, nls); mPodList = getPodListView(fragment); nls.init(getActivity(), mPullRefreshListView); return fragment; } @Override public void onActivityCreated(Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); } /** * Called when the activity is first created. */ @Override public void onStart() { super.onStart(); initLoader(); } @Override public void onResume() { // restore the first items super.onResume(); initBroadcastReceiver(); } @Override public void onPause() { if (mBroadcastReceiver != null) { getActivity().unregisterReceiver(mBroadcastReceiver); mBroadcastReceiver = null; } try { saveFirstPageOfNotes(); } catch (RemoteException e) { e.printStackTrace(); } catch (OperationApplicationException e) { e.printStackTrace(); } super.onPause(); } ... private void initLoader() { LoaderManager loaderManager = getActivity().getSupportLoaderManager(); final Loader<Cursor> loader = loaderManager.getLoader(LOADER_ID); if (loader == null || loader.isReset()) { loaderManager.initLoader(LOADER_ID, null, this); } // @note : showLastNotes() is run in the onLoadFinished() } ... }
References
- MONDAY, APRIL 29, 2013, Handling Configuration Changes with Fragments from http://www.androiddesignpatterns.com/2013/04/retaining-objects-across-config-changes.html
- Handling Runtime Changes | Android Developers from http://developer.android.com/guide/topics/resources/runtime-changes.html#HandlingTheChange
댓글 없음:
댓글 쓰기