존재하는 경우 BackStack에서 조각을 재개하는 방법 case 3:

조각을 사용하는 방법을 배우고 있습니다. Fragment클래스 상단에 세 개의 인스턴스 가 초기화되어 있습니다. 다음과 같은 활동에 조각을 추가하고 있습니다.

선언 및 초기화 :

Fragment A = new AFragment();
Fragment B = new BFragment();
Fragment C = new CFragment();

교체 / 추가 :

FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
ft.replace(R.id.content_frame, A);
ft.addToBackStack(null);
ft.commit();

이 스 니펫이 제대로 작동합니다. 모든 프래그먼트가 액티비티에 첨부되며 아무런 문제없이 백 스택에 저장됩니다.

그래서 시작할 때 A, C다음과 B같은 스택 외모 :

| |
|B|
|C|
|A|
___

그리고 ‘뒤로’버튼을 누르면 B파괴되고 C다시 시작됩니다.

그러나 A두 번째로 조각 을 시작하면 백 스택에서 다시 시작하는 대신 백 스택의 맨 위에 추가됩니다.

| |
|A|
|C|
|A|
___

그러나 나는 A그 위에있는 모든 조각 을 재개 하고 파괴 하고 싶습니다 (있는 경우). 사실, 나는 기본 백 스택 동작을 좋아합니다.

어떻게하면 되나요?

예상 : ( A다시 시작하고 상단 조각을 파괴해야 함)

| |
| |
| |
|A|
___

편집 : (AC에서 제안)

이것은 내 시도 코드입니다.

private void selectItem(int position) {
        Fragment problemSearch = null, problemStatistics = null;
        FragmentManager manager = getSupportFragmentManager();
        FragmentTransaction ft = manager.beginTransaction();
        String backStateName = null;
        Fragment fragmentName = null;
        boolean fragmentPopped = false;
        switch (position) {
        case 0:
            fragmentName = profile;
            break;
        case 1:
            fragmentName = submissionStatistics;
            break;
        case 2:
            fragmentName = solvedProblemLevel;
            break;
        case 3:
            fragmentName = latestSubmissions;
            break;
        case 4:
            fragmentName = CPExercise;
            break;
        case 5:
            Bundle bundle = new Bundle();
            bundle.putInt("problem_no", problemNo);
            problemSearch = new ProblemWebView();
            problemSearch.setArguments(bundle);
            fragmentName = problemSearch;
            break;
        case 6:
            fragmentName = rankList;
            break;
        case 7:
            fragmentName = liveSubmissions;
            break;
        case 8:
            Bundle bundles = new Bundle();
            bundles.putInt("problem_no", problemNo);
            problemStatistics = new ProblemStatistics();
            problemStatistics.setArguments(bundles);
            fragmentName = problemStatistics;
        default:
            break;
        }
        backStateName = fragmentName.getClass().getName();
        fragmentPopped = manager.popBackStackImmediate(backStateName, 0);
        if (!fragmentPopped) {
            ft.replace(R.id.content_frame, fragmentName);
        }
        ft.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE);
        ft.addToBackStack(backStateName);
        ft.commit();

        // I am using drawer layout
        mDrawerList.setItemChecked(position, true);
        setTitle(title[position]);
        mDrawerLayout.closeDrawer(mDrawerList);
    }

내가 시작할 때 문제는, A다음 B, 다음을 눌러 ‘돌아 가기’ B를 제거하고 A다시 시작됩니다. 다시 ‘뒤로’를 누르면 앱이 종료됩니다. 그러나 그것은 빈 창을 표시하고 그것을 닫으려면 세 번 눌러야합니다.

또한, 나는 시작하면 A, 다음 B, 다음 C, 다음, B다시 …

예상 :

| |
| |
|B|
|A|
___

실제 :

| |
|B|
|B|
|A|
___

onBackPressed()사용자 지정으로 재정의해야합니까, 아니면 뭔가 빠졌습니까?



답변

문서를 읽으면 트랜잭션 이름 또는 커밋이 제공 한 ID를 기반으로 백 스택을 팝업하는 방법이 있습니다. 이름을 사용하면 “고유 백 스택 항목”논리를 변경하고 강화할 수있는 숫자를 추적 할 필요가 없으므로 더 쉬울 있습니다.

당 하나의 백 스택 항목 만 원 Fragment하므로 백 상태 이름을 Fragment의 클래스 이름 (via getClass().getName())으로 지정하십시오. 그런 다음를 교체 할 때이 방법을 Fragment사용하십시오 popBackStackImmediate(). true를 반환하면 백 스택에 Fragment 인스턴스가 있음을 의미합니다. 그렇지 않은 경우 실제로 Fragment replacement 로직을 실행하십시오.

private void replaceFragment (Fragment fragment){
  String backStateName = fragment.getClass().getName();

  FragmentManager manager = getSupportFragmentManager();
  boolean fragmentPopped = manager.popBackStackImmediate (backStateName, 0);

  if (!fragmentPopped){ //fragment not in back stack, create it.
    FragmentTransaction ft = manager.beginTransaction();
    ft.replace(R.id.content_frame, fragment);
    ft.addToBackStack(backStateName);
    ft.commit();
  }
}

편집하다

문제는-A를 시작한 다음 B를 시작한 다음 뒤로 버튼을 누르면 B가 제거되고 A가 다시 시작됩니다. 다시 뒤로 버튼을 누르면 앱이 종료됩니다. 그러나 그것은 빈 창을 표시하고 그것을 닫으려면 다시 한 번 눌러야합니다.

이것은 FragmentTransaction나중에 스택을 팝 할 수 있도록 백 스택에 추가 되기 때문 입니다. onBackPressed()백 스택에 1 개만 포함 된 경우 이를위한 빠른 수정 은 활동을 재정의 하고 마무리하는 것입니다.Fragment

@Override
public void onBackPressed(){
  if (getSupportFragmentManager().getBackStackEntryCount() == 1){
    finish();
  }
  else {
    super.onBackPressed();
  }
}

중복 백 스택 항목과 관련하여 조각이 튀어 나오지 않은 경우 조각을 대체하는 조건문은 원래의 코드 스 니펫 명확하게 다릅니다 . 당신이하고있는 일은 백 스택이 터 졌는지 여부에 관계없이 백 스택에 추가하는 것입니다.

이와 같은 것은 원하는 것에 더 가깝습니다.

private void replaceFragment (Fragment fragment){
  String backStateName =  fragment.getClass().getName();
  String fragmentTag = backStateName;

  FragmentManager manager = getSupportFragmentManager();
  boolean fragmentPopped = manager.popBackStackImmediate (backStateName, 0);

  if (!fragmentPopped && manager.findFragmentByTag(fragmentTag) == null){ //fragment not in back stack, create it.
    FragmentTransaction ft = manager.beginTransaction();
    ft.replace(R.id.content_frame, fragment, fragmentTag);
    ft.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE);
    ft.addToBackStack(backStateName);
    ft.commit();
  } 
}

동일한 프래그먼트를 선택하고 표시되는 동안 조건부가 약간 변경되어 중복 항목이 발생했습니다.

이행:

replaceFragment()코드에서와 같이 업데이트 된 메소드를 분리 하지 않는 것이 좋습니다 . 이 방법에는 모든 논리가 포함되어 있으며 부품을 움직이면 문제가 발생할 수 있습니다.

이것은 업데이트 된 replaceFragment()메소드를 클래스에 복사 한 다음 변경 해야한다는 것을 의미합니다

backStateName = fragmentName.getClass().getName();
fragmentPopped = manager.popBackStackImmediate(backStateName, 0);
if (!fragmentPopped) {
            ft.replace(R.id.content_frame, fragmentName);
}
ft.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE);
ft.addToBackStack(backStateName);
ft.commit();

그래서 그것은 단순히

replaceFragment (fragmentName);

편집 # 2

백 스택이 변경 될 때 드로어를 업데이트하려면 Fragment에서 승인하고 클래스 이름을 비교하는 메소드를 작성하십시오. 일치하는 것이 있으면 제목과 선택을 변경하십시오. 또한 OnBackStackChangedListener유효한 Fragment가있는 경우 업데이트 메소드를 추가하고 업데이트 메소드를 호출하십시오.

예를 들어, 활동의에서 onCreate(), 추가

getSupportFragmentManager().addOnBackStackChangedListener(new OnBackStackChangedListener() {

  @Override
  public void onBackStackChanged() {
    Fragment f = getSupportFragmentManager().findFragmentById(R.id.content_frame);
    if (f != null){
      updateTitleAndDrawer (f);
    }

  }
});

그리고 다른 방법 :

private void updateTitleAndDrawer (Fragment fragment){
  String fragClassName = fragment.getClass().getName();

  if (fragClassName.equals(A.class.getName())){
    setTitle ("A");
    //set selected item position, etc
  }
  else if (fragClassName.equals(B.class.getName())){
    setTitle ("B");
    //set selected item position, etc
  }
  else if (fragClassName.equals(C.class.getName())){
    setTitle ("C");
    //set selected item position, etc
  }
}

이제 백 스택이 변경 될 때마다 제목과 확인 된 위치가 visible을 반영합니다 Fragment.


답변

이 방법으로 문제를 해결할 수 있다고 생각합니다.

public static void attachFragment ( int fragmentHolderLayoutId, Fragment fragment, Context context, String tag ) {


    FragmentManager manager = ( (AppCompatActivity) context ).getSupportFragmentManager ();
    FragmentTransaction ft = manager.beginTransaction ();

    if (manager.findFragmentByTag ( tag ) == null) { // No fragment in backStack with same tag..
        ft.add ( fragmentHolderLayoutId, fragment, tag );
        ft.addToBackStack ( tag );
        ft.commit ();
    }
    else {
        ft.show ( manager.findFragmentByTag ( tag ) ).commit ();
    }
}

이 질문 에 원래 게시 된


답변

1 단계 : 활동 클래스와의 인터페이스 구현

public class AuthenticatedMainActivity extends Activity implements FragmentManager.OnBackStackChangedListener{

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        .............
        FragmentManager fragmentManager = getFragmentManager();
        fragmentManager.beginTransaction().add(R.id.frame_container,fragment, "First").addToBackStack(null).commit();
    }

    private void switchFragment(Fragment fragment){
      FragmentManager fragmentManager = getFragmentManager();
      fragmentManager.beginTransaction()
        .replace(R.id.frame_container, fragment).addToBackStack("Tag").commit();
    }

    @Override
    public void onBackStackChanged() {
    FragmentManager fragmentManager = getFragmentManager();

    System.out.println("@Class: SummaryUser : onBackStackChanged "
            + fragmentManager.getBackStackEntryCount());

    int count = fragmentManager.getBackStackEntryCount();

    // when a fragment come from another the status will be zero
    if(count == 0){

        System.out.println("again loading user data");

        // reload the page if user saved the profile data

        if(!objPublicDelegate.checkNetworkStatus()){

            objPublicDelegate.showAlertDialog("Warning"
                    , "Please check your internet connection");

        }else {

            objLoadingDialog.show("Refreshing data...");

            mNetworkMaster.runUserSummaryAsync();
        }

        // IMPORTANT: remove the current fragment from stack to avoid new instance
        fragmentManager.removeOnBackStackChangedListener(this);

    }// end if
   }
}

2 단계 : 다른 조각을 호출 할 때이 메소드를 추가하십시오.

String backStateName = this.getClass().getName();

FragmentManager fragmentManager = getFragmentManager();
fragmentManager.addOnBackStackChangedListener(this);

Fragment fragmentGraph = new GraphFragment();
Bundle bundle = new Bundle();
bundle.putString("graphTag",  view.getTag().toString());
fragmentGraph.setArguments(bundle);

fragmentManager.beginTransaction()
.replace(R.id.content_frame, fragmentGraph)
.addToBackStack(backStateName)
.commit();


답변

나는 이것이이 질문에 대답하기에 상당히 늦다는 것을 알고 있지만,이 문제를 혼자서 해결하고 모든 사람과 공유 할 가치가 있다고 생각했습니다 .`

public void replaceFragment(BaseFragment fragment) {
    FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
    final FragmentManager fManager = getSupportFragmentManager();
    BaseFragment fragm = (BaseFragment) fManager.findFragmentByTag(fragment.getFragmentTag());
    transaction.setCustomAnimations(R.anim.enter_from_right, R.anim.exit_to_left, R.anim.enter_from_left, R.anim.exit_to_right);

    if (fragm == null) {  //here fragment is not available in the stack
        transaction.replace(R.id.container, fragment, fragment.getFragmentTag());
        transaction.addToBackStack(fragment.getFragmentTag());
    } else {
        //fragment was found in the stack , now we can reuse the fragment
        // please do not add in back stack else it will add transaction in back stack
        transaction.replace(R.id.container, fragm, fragm.getFragmentTag());
    }
    transaction.commit();
}

그리고 onBackPressed ()에서

 @Override
public void onBackPressed() {
    if(getSupportFragmentManager().getBackStackEntryCount()>1){
        super.onBackPressed();
    }else{
        finish();
    }
}


답변

getFragmentManager().addOnBackStackChangedListener(new FragmentManager.OnBackStackChangedListener() {

    @Override
    public void onBackStackChanged() {

        if(getFragmentManager().getBackStackEntryCount()==0) {
            onResume();
        }
    }
});


답변

더 쉬운 솔루션은이 줄을 바꿀 것입니다

ft.replace(R.id.content_frame, A);
ft.add(R.id.content_frame, A);

그리고 XML 레이아웃 내부에서 사용하십시오

  android:background="@color/white"
  android:clickable="true"
  android:focusable="true"

Clickable 즉, 포인터 장치로 클릭하거나 터치 장치로 탭할 수 있습니다.

Focusable키보드와 같은 입력 장치에서 포커스를 얻을 수 있음을 의미합니다. 키보드와 같은 입력 장치는 입력 자체를 기반으로 입력 이벤트를 보낼 뷰를 결정할 수 없으므로 포커스가있는 뷰로 보냅니다.


답변