백 스택에 추가 될 때 어떻게 프래그먼트 상태를 유지할 수 있습니까?


160

두 조각 사이를 전환하는 더미 활동을 작성했습니다. FragmentA에서 FragmentB로 이동하면 FragmentA가 백 스택에 추가됩니다. 그러나 FragmentA로 돌아 가면 (뒤로 누름) 완전히 새로운 FragmentA가 만들어지고 상태가 손실됩니다. 질문 과 같은 것을 겪고 있다는 느낌 들지만 문제를 근절하기 위해 완전한 코드 샘플을 포함 시켰습니다.

public class FooActivity extends Activity {
  @Override public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    final FragmentTransaction transaction = getFragmentManager().beginTransaction();
    transaction.replace(android.R.id.content, new FragmentA());
    transaction.commit();
  }

  public void nextFragment() {
    final FragmentTransaction transaction = getFragmentManager().beginTransaction();
    transaction.replace(android.R.id.content, new FragmentB());
    transaction.addToBackStack(null);
    transaction.commit();
  }

  public static class FragmentA extends Fragment {
    @Override public View onCreateView(LayoutInflater inflater, ViewGroup container,
        Bundle savedInstanceState) {
      final View main = inflater.inflate(R.layout.main, container, false);
      main.findViewById(R.id.next_fragment_button).setOnClickListener(new View.OnClickListener() {
        public void onClick(View v) {
          ((FooActivity) getActivity()).nextFragment();
        }
      });
      return main;
    }

    @Override public void onSaveInstanceState(Bundle outState) {
      super.onSaveInstanceState(outState);
      // Save some state!
    }
  }

  public static class FragmentB extends Fragment {
    @Override public View onCreateView(LayoutInflater inflater, ViewGroup container,
        Bundle savedInstanceState) {
      return inflater.inflate(R.layout.b, container, false);
    }
  }
}

일부 로그 메시지가 추가 된 경우 :

07-05 14:28:59.722 D/OMG     ( 1260): FooActivity.onCreate
07-05 14:28:59.742 D/OMG     ( 1260): FragmentA.onCreateView
07-05 14:28:59.742 D/OMG     ( 1260): FooActivity.onResume
<Tap Button on FragmentA>
07-05 14:29:12.842 D/OMG     ( 1260): FooActivity.nextFragment
07-05 14:29:12.852 D/OMG     ( 1260): FragmentB.onCreateView
<Tap 'Back'>
07-05 14:29:16.792 D/OMG     ( 1260): FragmentA.onCreateView

FragmentA.onSaveInstanceState를 호출하지 않으며 되돌릴 때 새 FragmentA를 만듭니다. 그러나 FragmentA를 사용 중이고 화면을 잠그면 FragmentA.onSaveInstanceState가 호출됩니다. 너무 이상합니다 ... 다시 생성 할 필요가 없도록 백 스택에 조각을 추가 할 것으로 잘못 생각합니까? 문서에서 말하는 내용은 다음과 같습니다 .

조각을 제거 할 때 addToBackStack ()을 호출하면 조각이 중지되고 사용자가 다시 탐색하면 조각이 다시 시작됩니다.


3
@ Jan-Henk 가져와야 할 것은 어떻습니까? 예를 들어,의 스크롤 위치입니다 ListView. 스크롤 리스너를 연결하고 인스턴스 변수를 업데이트하기에는 너무 많은 후프 점핑처럼 보입니다.
Jake Wharton

2
@JakeWharton 더 쉬워야한다는 데 동의하지만 조각이 백 스택에서 복원 될 때 onCreateView가 호출되기 때문에이 문제를 해결할 방법이 없습니다. 그러나 나는 틀릴 수 있었다 :)
Jan-Henk

1
onCreate가 호출되지 않습니다. 따라서 분명히 동일한 인스턴스를 다시 사용하지만 onCreateView를 다시 호출합니까? 절름발이. onCreateView의 결과를 캐시하고 onCreateView가 다시 호출되면 기존보기를 반환 할 수 있다고 생각합니다.
Eric

1
내가 몇 시간 동안 찾고 있었던 것입니다. 인스턴스 변수를 사용하여 어떻게 달성했는지 게시 할 수 있습니까?
Uma

1
그래서 최근에 github.com/frostymarvelous/Folio 에서 자체 구현을 시작 하여 문제가 발생했습니다. OOM 충돌이 발생하기 전에 약 5 개의 복잡한 페이지 / 프레임을 생성 할 수 있습니다. 그것이 나를 여기로 이끌었습니다. 숨기고 보여주는 것만으로는 충분하지 않습니다. 보기가 메모리를 너무 많이 사용합니다.
frostymarvelous

답변:


120

당신이 다시 스택에서 단편으로 돌아 경우는 조각을 다시 만듭니다 것이 아니라 함께 같은 인스턴스 시작 재 - 사용 onCreateView()조각 라이프 사이클에서 볼 조각 수명주기를 .

따라서 상태를 저장하려면 인스턴스 변수를 사용해야하며 의존 하지 않아야 합니다 onSaveInstanceState().


32
현재 버전의 설명서가이 주장과 모순됩니다. 흐름도는 상태, 그러나 페이지의 주요 영역의 텍스트가 onCreateView ()를 말한다 단지라는 것을 말한다 첫번째 조각 위치가 표시되는 시간 : developer.android.com/guide/components/fragments.html 나는이 싸움 있어요 지금 문제가 발생하여 백 스택에서 조각을 반환 할 때 호출 된 메소드가 표시되지 않습니다. (Android 4.2)
Colin M.

10
그 행동을 기록하려고했습니다. 조각이 표시 될 때 항상 onCreateView ()가 호출됩니다.
princepiero

4
@ColinM. 문제에 대한 해결책이 있습니까?
블리자드

9
이것은 나를 위해 작동하지 않습니다. 프래그먼트로 돌아올 때 인스턴스 변수가 null입니다! 상태를 어떻게 저장합니까?
Don Rhummy

5
따라서 인스턴스 저장시 릴레이하지 않아야하는 경우 조각 상태 및 데이터를 어떻게 저장해야합니까?
Mahdi

80

Apple UINavigationController과 및에 비해 UIViewControllerGoogle은 Android 소프트웨어 아키텍처에서 잘하지 않습니다. 그리고 안드로이드의 문서 Fragment는별로 도움이되지 않습니다.

FragmentA에서 FragmentB를 입력하면 기존 FragmentA 인스턴스가 삭제되지 않습니다. FragmentB에서 뒤로를 누르고 FragmentA로 돌아 가면 새 FragmentA 인스턴스가 생성되지 않습니다. 기존 FragmentA 인스턴스 onCreateView()가 호출됩니다.

핵심 onCreateView()은 기존 FragmentA의 인스턴스를 사용하고 있기 때문에 FragmentA의 뷰를 다시 팽창시키지 않아야한다는 것입니다 . rootView를 저장하고 재사용해야합니다.

다음 코드는 잘 작동합니다. 조각 상태를 유지할뿐만 아니라 RAM과 CPU 부하도 줄입니다 (필요한 경우 레이아웃 만 팽창시키기 때문). 나는 구글의 샘플 코드와 문서가 그것을 언급하지는 않지만 항상 레이아웃을 팽창 시킨다고 믿을 수 없다 .

버전 1 (버전 1을 사용하지 마십시오. 버전 2를 사용하십시오)

public class FragmentA extends Fragment {
    View _rootView;
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
            Bundle savedInstanceState) {
        if (_rootView == null) {
            // Inflate the layout for this fragment
            _rootView = inflater.inflate(R.layout.fragment_a, container, false);
            // Find and setup subviews
            _listView = (ListView)_rootView.findViewById(R.id.listView);
            ...
        } else {
            // Do not inflate the layout again.
            // The returned View of onCreateView will be added into the fragment.
            // However it is not allowed to be added twice even if the parent is same.
            // So we must remove _rootView from the existing parent view group
            // (it will be added back).
            ((ViewGroup)_rootView.getParent()).removeView(_rootView);
        }
        return _rootView;
    }
}

------ 2005 년 5 월 3 일 업데이트 : -------

언급 한 바와 같이 때때로 _rootView.getParent()에서 null onCreateView이 발생하여 충돌이 발생합니다. dell116이 제안한대로 버전 2는 onDestroyView ()에서 _rootView를 제거합니다. 안드로이드 4.0.3, 4.4.4, 5.1.0에서 테스트되었습니다.

버전 2

public class FragmentA extends Fragment {
    View _rootView;
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
            Bundle savedInstanceState) {
        if (_rootView == null) {
            // Inflate the layout for this fragment
            _rootView = inflater.inflate(R.layout.fragment_a, container, false);
            // Find and setup subviews
            _listView = (ListView)_rootView.findViewById(R.id.listView);
            ...
        } else {
            // Do not inflate the layout again.
            // The returned View of onCreateView will be added into the fragment.
            // However it is not allowed to be added twice even if the parent is same.
            // So we must remove _rootView from the existing parent view group
            // in onDestroyView() (it will be added back).
        }
        return _rootView;
    }

    @Override
    public void onDestroyView() {
        if (_rootView.getParent() != null) {
            ((ViewGroup)_rootView.getParent()).removeView(_rootView);
        }
        super.onDestroyView();
    }
}

경고!!!

이것은 해킹입니다! 내 앱에서 사용하고 있지만 주석을주의 깊게 테스트하고 읽어야합니다.


38
전체 조각의 루트 뷰에 대한 참조를 보유하는 것은 나쁜 아이디어 IMO입니다. 백 스택에 여러 조각을 지속적으로 추가하고 모든 조각이 루트 뷰를 보유하고 있다면 (여기서 메모리 공간이 매우 큼) 모든 조각에 루트 뷰 참조가 있고 GC 캔트가 없기 때문에 OutOfMemoryError가 발생할 가능성이 높습니다 그것을 수집하십시오. 더 좋은 방법은 항상 뷰를 팽창시키고 안드로이드 시스템이 뷰 생성 / 파괴를 처리하게하고 onActivityCreated / onViewCreated가 데이터가 null인지 확인하는 것입니다. 그렇다면 데이터를로드하고 그렇지 않으면 데이터를보기로 설정하십시오.
traninho

15
이러지 마! 프래그먼트의 뷰 계층 구조가 생성되면 해당 프래그먼트를 보유한 액티비티에 대한 내부 참조가 포함됩니다. 구성 변경이 발생하면 활동이 종종 다시 작성됩니다. 기존 레이아웃을 다시 사용하면 좀비 활동이 참조하는 모든 객체와 함께 메모리에 유지됩니다. 이와 같이 메모리를 낭비하면 성능이 저하되고 포 그라운드에 있지 않을 때 앱이 즉시 종료 될 수있는 최고의 후보가됩니다.
Krylez

4
@AllDayAmazing 좋은 지적입니다. 솔직히 말해서 지금 당황합니다. 누구든지 왜 조각의 루트보기에 대한 참조를 유지하는 것이 좋지는 않지만 루트보기의 하위 (어쨌든 루트보기에 대한 참조가있는)에 대해서만 참조를 보유하는 것은 괜찮습니까?
traninho

2
코드에서 버그가있는 부분을 찾는 데 5 시간을 허비하고 싶지 않다면이 문제를 피하십시오. 이 핵을 사용했기 때문에 많은 것들을 리팩토링해야합니다. 다른 부분을 볼 때 조각의 UI를 그대로 유지하려면 fragmentTransaction.add를 사용하는 것이 좋습니다. fragmentTransaction.replace ()는 프래그먼트의 뷰를 파괴하는 것을 의미합니다. ..... 시스템과 싸우지 마십시오.
dell116

2
@VinceYuan-Android 5.1의 최신 v7-appcompat 라이브러리로 테스트했으며 내 활동의 FragmentManager에서 제거해야 할 조각의 6 인스턴스가 남았습니다. GC가 올바르게 처리하더라도 (믿지 않을 것입니다) 이것은 일반적으로 장치뿐만 아니라 앱의 메모리에 불필요한 부담을 유발합니다. .add ()를 사용하면이 모든 해킹 코드가 필요하지 않습니다. 이를 수행하는 것은 FragmentTransaction.replace () 사용이 처음부터 의도 한 것과 반대입니다.
dell116

53

당신이 찾고있는 것을 성취 할 수있는 다른 방법이 있다고 생각합니다. 나는 완전한 해결책을 말하지는 않지만 제 경우에는 목적을 달성했습니다.

내가 한 것은 방금 대상 조각을 추가 한 조각을 바꾸는 것입니다. 따라서 기본적으로 add()method 를 사용하게 됩니다 replace().

내가 뭘했는지 현재 조각을 숨기고 백 스택에 추가합니다.

따라서 뷰를 손상시키지 않고 현재 프래그먼트보다 새로운 프래그먼트와 겹칩니다 ( onDestroyView()메서드가 호출되지 않는지 확인하십시오 . 플러그를 추가 backstate하면 프래그먼트를 다시 시작할 수 있다는 이점이 있습니다.

코드는 다음과 같습니다.

Fragment fragment=new DestinationFragment();
FragmentManager fragmentManager = getFragmentManager();
android.app.FragmentTransaction ft=fragmentManager.beginTransaction();
ft.add(R.id.content_frame, fragment);
ft.hide(SourceFragment.this);
ft.addToBackStack(SourceFragment.class.getName());
ft.commit();

AFAIK 시스템 onCreateView()은 뷰가 파괴되거나 생성되지 않은 경우 에만 호출 합니다. 그러나 여기서는 메모리에서 뷰를 제거하지 않고 뷰를 저장했습니다. 따라서 새로운보기를 만들지 않습니다.

그리고 당신이 Destination Fragment에서 돌아 왔을 때 가장 최근에 FragmentTransaction제거 된 Top Fragment가 나타나서 최상위 (SourceFragment) 뷰가 화면 위에 나타납니다.

주석 : 내가 말했듯이 소스 조각의 관점을 제거하지 않으므로 평소보다 더 많은 메모리를 차지하므로 완벽한 솔루션이 아닙니다. 그러나 여전히 목적을 달성하십시오. 또한 기존 방식이 아닌 뷰를 대체하는 대신 완전히 다른 뷰 숨기기 메커니즘을 사용하고 있습니다.

따라서 실제로 상태를 유지 관리하는 방법이 아니라 뷰를 유지 관리하는 방법입니다.


필자의 경우 교체 대신 조각을 추가하면 폴링을 사용할 때 문제가 발생하거나 조각에 다른 종류의 웹 요청이 사용됩니다. Fragment B가 추가되면 Fragment A 에서이 폴링을 일시 중지하고 싶습니다. 이것에 대한 아이디어가 있습니까?
Uma

FirstFragment에서 폴링을 어떻게 사용하고 있습니까? 두 조각 모두 메모리에 남아 있기 때문에 수동으로 수행해야합니다. 따라서 인스턴스를 사용하여 필요한 조치를 수행 할 수 있습니다.이 단서, 두 번째 조각을 추가 할 때 무언가를 수행하는 주요 활동의 이벤트를 생성합니다. 이것이 도움이되기를 바랍니다.
kaushal trivedi

1
실마리 =) 감사합니다. 나는 이것을했다. 그러나 이것이 유일한 방법입니까? 그리고 적절한 방법? 또한 홈 버튼을 누르고 응용 프로그램을 다시 시작하면 모든 조각이 다시 활성화됩니다. 이런 식으로 조각 B에서 Im이라고 가정하자. Activity A{Fragment A --> Fragment B}홈 버튼을 누른 후 응용 프로그램을 다시 시작하면 두 조각이 모두 onResume()호출되므로 폴링이 시작됩니다. 이것을 어떻게 제어 할 수 있습니까?
우마

1
불행히도 시스템은이 방식으로 정상적인 동작으로 작동하지 않으며 두 조각을 모두 활동의 직접적인 자식으로 간주합니다. 조각 상태를 유지하는 목적으로 사용되었지만 다른 정상적인 경우 관리하기가 매우 어려워졌습니다. 이 모든 문제를 발견했습니다. 이제 내 제안은이 길로 가지 않는 것입니다. 죄송합니다.
kaushal trivedi

1
물론 마지막으로 다른 솔루션을 찾을 때 까지이 접근법을 사용하지 말라고 말할 것입니다. 관리하기가 어렵 기 때문입니다.
kaushal trivedi

7

매우 간단한 해결책을 제안합니다.

View 참조 변수를 가져 와서 OnCreateView에서보기를 설정하십시오. 이 변수에 뷰가 이미 있는지 확인한 다음 동일한 뷰를 반환하십시오.

   private View fragmentView;

   public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        super.onCreateView(inflater, container, savedInstanceState);

        if (fragmentView != null) {
            return fragmentView;
        }
        View view = inflater.inflate(R.layout.yourfragment, container, false);
        fragmentView = view;
        return view;
    }

1
onDestroy ()에서 'fragmentView'변수를 제거하지 않으면 메모리 누수가 발생할 수 있습니다.
Arun PM

@ArunPM 그래서 onDestroy ()에서 fragmentView를 제거하는 방법은 무엇입니까? if (_rootView.getParent() != null) { ((ViewGroup)_rootView.getParent()).removeView(_rootView); }메모리를 지우는 데 적합합니까?
Mehmet Gür

1
@ MehmetGür이 솔루션을 여러 번 사용하고 있습니다. 지금까지 메모리 누수 오류가 발생하지 않았습니다. 그러나 원하는 경우 ArunPM 솔루션을 사용할 수 있습니다. 그가 OnDestroy () Methods에서 fragmentView를 null로 설정하고 있다고 생각합니다.
Mandeep Singh

1
이 방법을 따를 때 LeakCanary 를 사용하여 메모리 누수와 해당 누수 문제를 감지하고 있습니다. 그러나 @Mandeep Sigh가 주석에서 언급했듯이 메소드 null에서 fragmentView 변수에 할당 하여이 문제를 극복 할 수 있습니다 onDestroy().
Arun PM

1
내 지식에 따라 조각이 제거되면 조각과 관련된보기가 지워집니다 onDestroyView(). 이 지우기는 백업보기 변수 (여기서는 fragmentView )에서 발생하지 않으며 조각이 다시 쌓이거나 파괴 될 때 메모리 누수가 발생합니다. LeakCanery 소개의 [메모리 누수의 일반적인 원인] ( square.github.io/leakcanary/fundamentals/… )에서 동일한 참조를 찾을 수 있습니다 .
Arun PM

6

저장 / 다시로드 할 설정 정보가 너무 많은 맵이 포함 된 조각에서이 문제를 발견했습니다. 내 해결책은 기본적 으로이 조각을 항상 활성 상태로 유지하는 것입니다 (@kaushal이 언급 한 것과 유사).

현재 단편 A가 있고 단편 B를 표시하려고한다고 가정하십시오. 결과 요약 :

  • replace ()-Fragment A를 제거하고 Fragment B로 교체합니다. Fragment A는 다시 전면으로 가져온 후 다시 생성됩니다.
  • add ()-(생성 및) Fragment B를 추가하면 Fragment A와 겹쳐지며 백그라운드에서 여전히 활성화됩니다.
  • remove ()-조각 B를 제거하고 A로 돌아 오는 데 사용할 수 있습니다. 조각 B는 나중에 호출 될 때 다시 작성됩니다.

따라서 두 조각을 모두 "저장 한"상태로 유지하려면 hide () / show ()를 사용하여 조각을 전환하십시오.

장점 : 여러 조각을 계속 실행하는 쉽고 간단한 방법
단점 : 모든 메모리를 계속 사용하려면 더 많은 메모리를 사용하십시오. 많은 큰 비트 맵 표시와 같은 문제가 발생할 수 있음


프래그먼트 b를 제거하고 A로 돌아 가면 프래그먼트 A에서 어떤 메소드가 호출되는지 알려주시겠습니까? 조각 B를 제거 할 때 몇 가지 조치를 취하고 싶습니다.
Google

5

onSaveInstanceState() 구성 변경이있는 경우에만 호출됩니다.

한 프래그먼트에서 다른 프래그먼트로 변경하기 때문에 구성 변경이 없으므로 호출 onSaveInstanceState()이 없습니다. 어떤 상태가 저장되지 않습니까? 지정할 수 있습니까?

EditText에 텍스트를 입력하면 자동으로 저장됩니다. ID가없는 UI 항목은보기 상태가 저장되지 않는 항목입니다.


onSaveInstanceState()시스템에 자원이 부족하여 활동을 파괴 할 때도 호출됩니다.
Marcel Bro

0

onSaveInstanceState백 스택에 프래그먼트를 추가하면 프래그먼트가 호출되지 않기 때문에 여기에서 . 가기 backstack의 단편 라이프 사이클 복원을 시작할 때 onCreateView와 끝 onDestroyView동안은 onSaveInstanceState사이라고 onDestroyView하고 onDestroy. 내 솔루션은 인스턴스 변수를 만들고 init입니다 onCreate. 샘플 코드 :

private boolean isDataLoading = true;
private ArrayList<String> listData;
public void onCreate(Bundle savedInstanceState){
     super.onCreate(savedInstanceState);
     isDataLoading = false;
     // init list at once when create fragment
     listData = new ArrayList();
}

그리고 그것을 확인하십시오 onActivityCreated:

public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
    super.onViewCreated(view, savedInstanceState);
    if(isDataLoading){
         fetchData();
    }else{
         //get saved instance variable listData()
    }
}

private void fetchData(){
     // do fetch data into listData
}

0
getSupportFragmentManager().addOnBackStackChangedListener(new FragmentManager.OnBackStackChangedListener()
    {
        @Override
        public void onBackStackChanged()
        {
            if (getSupportFragmentManager().getBackStackEntryCount() == 0)
            {
                //setToolbarTitle("Main Activity");
            }
            else
            {
                Log.e("fragment_replace11111", "replace");
            }
        }
    });


YourActivity.java
@Override
public void onBackPressed()
{
 Fragment fragment = getSupportFragmentManager().findFragmentById(R.id.Fragment_content);
  if (fragment instanceof YourFragmentName)
    {
        fragmentReplace(new HomeFragment(),"Home Fragment");
        txt_toolbar_title.setText("Your Fragment");
    }
  else{
     super.onBackPressed();
   }
 }


public void fragmentReplace(Fragment fragment, String fragment_name)
{
    try
    {
        fragmentTransaction = fragmentManager.beginTransaction();
        fragmentTransaction.replace(R.id.Fragment_content, fragment, fragment_name);
        fragmentTransaction.setCustomAnimations(R.anim.enter_from_right, R.anim.exit_to_left, R.anim.enter_from_left, R.anim.exit_to_right);
        fragmentTransaction.addToBackStack(fragment_name);
        fragmentTransaction.commitAllowingStateLoss();
    }
    catch (Exception e)
    {
        e.printStackTrace();
    }
}

0

내 문제는 비슷했지만 조각을 유지하지 않고 나를 극복했습니다. F1과 F2라는 두 개의 조각이있는 활동이 있다고 가정하십시오. F1은 처음에 시작되어 in에 일부 사용자 정보가 포함 된 다음 어떤 조건에 따라 F2가 사용자에게 추가 속성 ( 전화 번호)을 입력하도록 요청하면 팝업됩니다 . 다음으로, 전화 번호가 F1으로 다시 돌아가서 가입을 완료하려고하지만 이전의 모든 사용자 정보가 손실되고 이전 데이터가 없다는 것을 알게됩니다. 프래그먼트는 처음부터 다시 작성되며 onSaveInstanceState번들 에이 정보를 저장 한 경우에도에서 널이 리턴됩니다 onActivityCreated.

솔루션 : 호출 활동에서 필요한 정보를 인스턴스 변수로 저장하십시오. 그런 다음 해당 인스턴스 변수를 조각으로 전달하십시오.

@Override
public void onActivityCreated(@Nullable Bundle savedInstanceState) {
    super.onActivityCreated(savedInstanceState);

    Bundle args = getArguments();

    // this will be null the first time F1 is created. 
    // it will be populated once you replace fragment and provide bundle data
    if (args != null) {
        if (args.get("your_info") != null) {
            // do what you want with restored information
        }
    }
}

F2를 표시하기 전에 콜백을 사용하여 인스턴스 변수에 사용자 데이터를 저장합니다. 그런 다음 F2를 시작하고 사용자가 전화 번호를 입력하고 저장을 누릅니다. 나는 활동에 다른 콜백을 사용하여이 정보를 수집하고, 그것은이 시간 내 조각 F1 교체 내가 사용할 수있는 번들 데이터를.

@Override
public void onPhoneAdded(String phone) {
        //replace fragment
        F1 f1 = new F1 ();
        Bundle args = new Bundle();
        yourInfo.setPhone(phone);
        args.putSerializable("you_info", yourInfo);
        f1.setArguments(args);

        getFragmentManager().beginTransaction()
                .replace(R.id.fragmentContainer, f1).addToBackStack(null).commit();

    }
}

콜백에 대한 자세한 내용은 https://developer.android.com/training/basics/fragments/communicating.html 에서 확인할 수 있습니다.


0

먼저 : FragmentTransaction 클래스의 replace 메소드 대신 add 메소드를 사용하고 addToBackStack 메소드로 스택에 secondFragment를 추가해야합니다

두 번째 : 다시 클릭하면 popBackStackImmediate ()를 호출해야합니다.

Fragment sourceFragment = new SourceFragment ();
final Fragment secondFragment = new SecondFragment();
final FragmentTransaction ft = getChildFragmentManager().beginTransaction();
ft.add(R.id.child_fragment_container, secondFragment );
ft.hide(sourceFragment );
ft.addToBackStack(NewsShow.class.getName());
ft.commit();
                                
((SecondFragment)secondFragment).backFragmentInstanceClick = new SecondFragment.backFragmentNewsResult()
{
        @Override
        public void backFragmentNewsResult()
        {                                    
            getChildFragmentManager().popBackStackImmediate();                                
        }
};

0

다음 코드를 사용하여 조각을 교체하십시오.

Fragment fragment = new AddPaymentFragment();
getSupportFragmentManager().beginTransaction().replace(R.id.frame, fragment, "Tag_AddPayment")
                .addToBackStack("Tag_AddPayment")
                .commit();

활동의 onBackPressed ()는 다음과 같습니다.

  @Override
public void onBackPressed() {
    android.support.v4.app.FragmentManager fm = getSupportFragmentManager();
    if (fm.getBackStackEntryCount() > 1) {

        fm.popBackStack();
    } else {


        finish();

    }
    Log.e("popping BACKSTRACK===> ",""+fm.getBackStackEntryCount());

}

0
Public void replaceFragment(Fragment mFragment, int id, String tag, boolean addToStack) {
        FragmentTransaction mTransaction = getSupportFragmentManager().beginTransaction();
        mTransaction.replace(id, mFragment);
        hideKeyboard();
        if (addToStack) {
            mTransaction.addToBackStack(tag);
        }
        mTransaction.commitAllowingStateLoss();
    }
replaceFragment(new Splash_Fragment(), R.id.container, null, false);

1
이 코드 스 니펫은 제한적이고 즉각적인 도움이 될 수 있습니다. 적절한 설명은 크게 장기 가치를 향상 할 보여줌으로써 이 문제에 대한 좋은 해결책이고, 다른 유사한 질문을 미래의 독자들에게 더 유용 할 것입니다. 제발 편집 당신이 만든 가정 등 일부 설명을 추가 할 답변을.
행동

0

스택에서 오래된 조각을 찾아 스택에있는 경우로드하는 완벽한 솔루션입니다.

/**
     * replace or add fragment to the container
     *
     * @param fragment pass android.support.v4.app.Fragment
     * @param bundle pass your extra bundle if any
     * @param popBackStack if true it will clear back stack
     * @param findInStack if true it will load old fragment if found
     */
    public void replaceFragment(Fragment fragment, @Nullable Bundle bundle, boolean popBackStack, boolean findInStack) {
        FragmentManager fm = getSupportFragmentManager();
        FragmentTransaction ft = fm.beginTransaction();
        String tag = fragment.getClass().getName();
        Fragment parentFragment;
        if (findInStack && fm.findFragmentByTag(tag) != null) {
            parentFragment = fm.findFragmentByTag(tag);
        } else {
            parentFragment = fragment;
        }
        // if user passes the @bundle in not null, then can be added to the fragment
        if (bundle != null)
            parentFragment.setArguments(bundle);
        else parentFragment.setArguments(null);
        // this is for the very first fragment not to be added into the back stack.
        if (popBackStack) {
            fm.popBackStack(null, FragmentManager.POP_BACK_STACK_INCLUSIVE);
        } else {
            ft.addToBackStack(parentFragment.getClass().getName() + "");
        }
        ft.replace(R.id.contenedor_principal, parentFragment, tag);
        ft.commit();
        fm.executePendingTransactions();
    }

처럼 사용

Fragment f = new YourFragment();
replaceFragment(f, null, boolean true, true); 
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.