호환 패키지를 사용하여 Fragments를 사용하여 2.2를 타겟팅합니다.
앱에서 프래그먼트를 사용하도록 활동을 레코딩 한 후 방향 변경 / 상태 관리가 작동하지 않아 단일 FragmentActivity와 단일 프래그먼트가있는 작은 테스트 앱을 만들었습니다.
방향 변경의 로그는 조각 OnCreateView에 대한 여러 호출로 이상합니다.
새 인스턴스를 만드는 대신 조각을 분리하고 다시 연결하는 것과 같은 것이 분명하지만 어디에서 잘못 가고 있는지 나타내는 문서를 볼 수 없습니다.
누구든지 내가 여기서 잘못하고있는 일에 대해 밝힐 수 있습니까? 감사
방향 변경 후 로그는 다음과 같습니다.
Initial creation
12-04 11:57:15.808: D/FragmentTest.FragmentTestActivity(3143): onCreate
12-04 11:57:15.945: D/FragmentTest.FragmentOne(3143): OnCreateView
12-04 11:57:16.081: D/FragmentTest.FragmentOne(3143): OnCreateView->SavedInstanceState null
Orientation Change 1
12-04 11:57:39.031: D/FragmentTest.FragmentOne(3143): onSaveInstanceState
12-04 11:57:39.031: D/FragmentTest.FragmentTestActivity(3143): onCreate
12-04 11:57:39.031: D/FragmentTest.FragmentOne(3143): OnCreateView
12-04 11:57:39.031: D/FragmentTest.FragmentOne(3143): OnCreateView->SavedInstanceState not null
12-04 11:57:39.031: D/FragmentTest.FragmentOne(3143): OnCreateView
12-04 11:57:39.167: D/FragmentTest.FragmentOne(3143): OnCreateView->SavedInstanceState null
Orientation Change 2
12-04 11:58:32.162: D/FragmentTest.FragmentOne(3143): onSaveInstanceState
12-04 11:58:32.162: D/FragmentTest.FragmentOne(3143): onSaveInstanceState
12-04 11:58:32.361: D/FragmentTest.FragmentTestActivity(3143): onCreate
12-04 11:58:32.361: D/FragmentTest.FragmentOne(3143): OnCreateView
12-04 11:58:32.361: D/FragmentTest.FragmentOne(3143): OnCreateView->SavedInstanceState not null
12-04 11:58:32.361: D/FragmentTest.FragmentOne(3143): OnCreateView
12-04 11:58:32.361: D/FragmentTest.FragmentOne(3143): OnCreateView->SavedInstanceState not null
12-04 11:58:32.498: D/FragmentTest.FragmentOne(3143): OnCreateView
12-04 11:58:32.498: D/FragmentTest.FragmentOne(3143): OnCreateView->SavedInstanceState null
주요 활동 (FragmentActivity)
public class FragmentTestActivity extends FragmentActivity {
/** Called when the activity is first created. */
private static final String TAG = "FragmentTest.FragmentTestActivity";
FragmentManager mFragmentManager;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
Log.d(TAG, "onCreate");
mFragmentManager = getSupportFragmentManager();
FragmentTransaction fragmentTransaction = mFragmentManager.beginTransaction();
FragmentOne fragment = new FragmentOne();
fragmentTransaction.add(R.id.fragment_container, fragment);
fragmentTransaction.commit();
}
그리고 조각
public class FragmentOne extends Fragment {
private static final String TAG = "FragmentTest.FragmentOne";
EditText mEditText;
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
Log.d(TAG, "OnCreateView");
View v = inflater.inflate(R.layout.fragmentonelayout, container, false);
// Retrieve the text editor, and restore the last saved state if needed.
mEditText = (EditText)v.findViewById(R.id.editText1);
if (savedInstanceState != null) {
Log.d(TAG, "OnCreateView->SavedInstanceState not null");
mEditText.setText(savedInstanceState.getCharSequence("text"));
}
else {
Log.d(TAG,"OnCreateView->SavedInstanceState null");
}
return v;
}
@Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
Log.d(TAG, "FragmentOne.onSaveInstanceState");
// Remember the current text, to restore if we later restart.
outState.putCharSequence("text", mEditText.getText());
}
명백한
<uses-sdk android:minSdkVersion="8" />
<application
android:icon="@drawable/ic_launcher"
android:label="@string/app_name" >
<activity
android:label="@string/app_name"
android:name=".activities.FragmentTestActivity"
android:configChanges="orientation">
<intent-filter >
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
답변
당신은 당신의 조각을 다른 조각 위에 레이어링하고 있습니다.
구성 변경이 발생하면 이전 프래그먼트가 다시 생성 될 때 새 활동에 자신을 추가합니다. 이것은 대부분의 경우 뒤쪽에 엄청난 고통입니다.
새 조각을 다시 만드는 대신 동일한 조각을 사용하여 발생하는 오류를 중지 할 수 있습니다. 다음 코드를 추가하기 만하면됩니다.
if (savedInstanceState == null) {
// only create fragment if activity is started for the first time
mFragmentManager = getSupportFragmentManager();
FragmentTransaction fragmentTransaction = mFragmentManager.beginTransaction();
FragmentOne fragment = new FragmentOne();
fragmentTransaction.add(R.id.fragment_container, fragment);
fragmentTransaction.commit();
} else {
// do nothing - fragment is recreated automatically
}
그러나 경고 : 수명주기가 미묘하게 변경되므로 Fragment 내부에서 활동 뷰에 액세스하려고하면 문제가 발생합니다. (조각에서 부모 활동에서 뷰를 가져 오는 것은 쉽지 않습니다).
답변
이 책 을 인용하자면 “일관된 사용자 경험을 보장하기 위해 Android는 구성 변경으로 인해 활동이 다시 시작될 때 조각 레이아웃과 관련 백 스택을 유지합니다.” (124 쪽)
접근하는 방법은 먼저 Fragment 백 스택이 이미 채워져 있는지 확인하고 그렇지 않은 경우에만 새 조각 인스턴스를 만드는 것입니다.
@Override
public void onCreate(Bundle savedInstanceState) {
...
FragmentOne fragment = (FragmentOne) mFragmentManager.findFragmentById(R.id.fragment_container);
if (fragment == null) {
FragmentTransaction fragmentTransaction = mFragmentManager.beginTransaction();
fragmentTransaction.add(R.id.fragment_container, new FragmentOne());
fragmentTransaction.commit();
}
}
답변
활동의 onCreate () 메서드는 본 것처럼 방향이 변경된 후에 호출됩니다. 따라서 활동의 방향이 변경된 후 Fragment를 추가하는 FragmentTransaction을 실행하지 마십시오.
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (savedInstanceState==null) {
//do your stuff
}
}
조각은 변경되지 않아야하며 변경되지 않아야합니다.
답변
을 @Override
사용하여 FragmentActivity를 수행 할 수 있습니다 onSaveInstanceState()
. super.onSaveInstanceState()
메서드에서를 호출하지 마십시오 .
답변
항상 nullpointer 예외를 방지해야하므로 먼저 saveinstance 메서드에서 번들 정보를 확인해야합니다. 이 블로그 링크 를 확인하는 간단한 설명
public static class DetailsActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (getResources().getConfiguration().orientation
== Configuration.ORIENTATION_LANDSCAPE) {
// If the screen is now in landscape mode, we can show the
// dialog in-line with the list so we don't need this activity.
finish();
return;
}
if (savedInstanceState == null) {
// During initial setup, plug in the details fragment.
DetailsFragment details = new DetailsFragment();
details.setArguments(getIntent().getExtras());
getFragmentManager().beginTransaction().add(android.R.id.content, details).commit();
}
}
}
답변
프로젝트 만 수행하는 경우 프로젝트 관리자는 전환 기능 화면을 달성해야한다고 말하지만 다른 레이아웃을로드하는 화면 전환을 원하지는 않습니다 (레이아웃 및 레이아웃 포트 시스템을 만들 수 있습니다.
화면 상태를 자동으로 결정하고 해당 레이아웃을로드합니다.) 활동이나 프래그먼트를 다시 초기화해야하기 때문에 사용자 경험이 좋지 않고 화면 스위치에 직접 표시되지 않습니다. Url = YgNfP-vHy-Nuldi7YHTfNet3AtLdN-w__O3z1wLOnzr3wDjYo7X7PYdNyhw8R24ZE22xiKnydni7R0r35s2fOLcHOiLGYT9Qh_fjqtytJki & wd = & eqid = f258719e0001f24000000004585a1082 = & eqid = f258719
전제는 다음과 같이 layout_weight의 레이아웃 방식의 가중치를 사용하는 레이아웃입니다.
<LinearLayout
Android:id= "@+id/toplayout"
Android:layout_width= "match_parent"
Android:layout_height= "match_parent"
Android:layout_weight= "2"
Android:orientation= "horizontal" >
따라서 내 접근 방식은 화면 전환시 뷰 파일의 새 레이아웃을로드 할 필요가없고 onConfigurationChanged 동적 가중치에서 레이아웃을 수정할 필요가 없습니다. 다음 단계는 다음과 같습니다. 1 첫 번째 설정 : 활동 속성의 AndroidManifest.xml : android : configChanges = “keyboardHidden | orientation | screenSize”화면 전환을 방지하려면 다시로드하지 않도록하여 onConfigurationChanged 2 재 작성 활동 또는 onConfigurationChanged 메소드의 프래그먼트를 모니터링 할 수 있습니다.
@Override
Public void onConfigurationChanged (Configuration newConfig) {
Super.onConfigurationChanged (newConfig);
SetContentView (R.layout.activity_main);
if (newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE) {
//On the layout / / weight adjustment
LinearLayout toplayout = (LinearLayout) findViewById (R.id.toplayout);
LinearLayout.LayoutParams LP = new LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, 0, 2.0f);
Toplayout.setLayoutParams (LP);
LinearLayout tradespace_layout = (LinearLayout) findViewById(R.id.tradespace_layout);
LinearLayout.LayoutParams LP3 = new LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, 0, 2.8f);
Tradespace_layout.setLayoutParams (LP3);
}
else if (newConfig.orientation == Configuration.ORIENTATION_PORTRAIT)
{
//On the layout / / weight adjustment
LinearLayout toplayout = (LinearLayout) findViewById (R.id.toplayout);
LinearLayout.LayoutParams LP = new LayoutParams (LinearLayout.LayoutParams.MATCH_PARENT, 0, 2.8f);
Toplayout.setLayoutParams (LP);
LinearLayout tradespace_layout = (LinearLayout) findViewById (R.id.tradespace_layout);
LinearLayout.LayoutParams LP3 = new LayoutParams (LinearLayout.LayoutParams.MATCH_PARENT, 0, 2.0f);
Tradespace_layout.setLayoutParams (LP3);
}
}
답변
구성 변경시 프레임 워크는 조각의 새 인스턴스를 만들고 활동에 추가합니다. 그래서이 대신 :
FragmentOne fragment = new FragmentOne();
fragmentTransaction.add(R.id.fragment_container, fragment);
이 작업을 수행:
if (mFragmentManager.findFragmentByTag(FRAG1_TAG) == null) {
FragmentOne fragment = new FragmentOne();
fragmentTransaction.add(R.id.fragment_container, fragment, FRAG1_TAG);
}
프레임 워크는 setRetainInstance (true)를 호출하지 않는 한 방향 변경시 FragmentOne의 새 인스턴스를 추가합니다.이 경우 FragmentOne의 이전 인스턴스가 추가됩니다.