44

Đã tìm kiếm sự cố này trong một thời gian không có lịch phát sóng ngay bây giờ:Cách xác định phân đoạn được khôi phục từ backstack

Làm cách nào để xác định phân đoạn đang được khôi phục từ backstack? Tôi đang sử dụng thư viện tương thích và một ListFragment bên trong một FragmentActivity. Khi một mục bên trong ListFragment được chọn, một Fragment mới được bắt đầu để thay thế ListFragment.

Tôi nhận thấy rằng khi FragmentActivity bị tạm dừng, hàm onSaveInstanceState của Fragment được gọi. Nhưng khi Fragment được đưa vào ngăn xếp trở lại thông qua FragmentTransaction, onSaveInstanceState không được gọi, sau đó các phương thức vòng đời onCreateView và onActivityCreated được gọi với gói lưu trữ nullInstanceState.

Tôi hỏi điều này vì tôi muốn tải một số dữ liệu khi Phân đoạn được tạo hoặc khôi phục nhưng không phải khi người dùng quay lại. backstack.

Tôi đã xem How to check if Fragment was restored from a backstack? nhưng muốn thêm chi tiết khác với hy vọng điều này sẽ kích động câu trả lời.

Edit: chỉ nhận thấy http://developer.android.com/reference/android/app/Fragment.html#onSaveInstanceState(android.os.Bundle) nói

Lưu ý tuy nhiên: phương pháp này có thể được gọi bất cứ lúc nào trước khi onDestroy(). Có rất nhiều tình huống mà một mảnh có thể bị rách nát (như khi được đặt trên ngăn xếp phía sau không có hiển thị giao diện người dùng), nhưng trạng thái của nó sẽ không được lưu cho đến khi hoạt động sở hữu thực sự cần lưu trạng thái của nó.

Vì vậy onSaveInstanceState chắc chắn là ra câu hỏi ...

+0

Như một chút cập nhật cho câu hỏi này, tôi nghi ngờ ngày càng nhiều đó là do thoái thác thư viện tương thích của. Chưa thử chạy thử nghiệm trên 3.0 thiết bị, sẽ kiểm tra lại khi tôi thực hiện. – dvd

+0

tại sao bạn không đặt cuộc gọi máy chủ của mình để tải dữ liệu trong 'onCreate()'. Có lẽ, điều đó sẽ làm giảm bớt rắc rối của bạn. Tôi tin rằng phương pháp này đặc biệt không được gọi là khi một mảnh được khôi phục từ ngăn xếp trở lại. – Abhijit

Trả lời

34

Tôi nghĩ rằng hầu hết cách đơn giản là thực hiện điều này ví dụ như trong onViewCreated() phương pháp:

if (savedInstanceState == null && !mAlreadyLoaded) { 
    mAlreadyLoaded = true; 

    // Do this code only first time, not after rotation or reuse fragment from backstack 
} 

Bởi vì khi đoạn đặt android trên backstack, nó chỉ phá hủy quan điểm của mình, nhưng đừng giết dụ chính nó, Vì vậy, mAlreadyLoaded sẽ vẫn đúng khi fragment sẽ được khôi phục từ backstack.

+0

Đây là câu trả lời đúng để xác định xem thể hiện phân đoạn đã được khôi phục từ ngăn xếp lại chưa. Cuối cùng tôi đã có cơ hội xem lại chủ đề này và đọc nguồn cho FragmentManager trong thư viện hỗ trợ phiên bản v4 13. Ví dụ phân đoạn như ATom được giữ lại khi thêm vào ngăn xếp ngược. Vì vậy, thiết lập và kiểm tra một lá cờ trong các công trình onViewCreated. – dvd

+5

Điều này chỉ hoạt động nếu bạn gọi 'setRetainInstance (true)', không phải lúc nào cũng là một tùy chọn. –

+1

@BenoitDuffez Tôi tin rằng chỉ cần thiết nếu bạn đang làm việc với một 'Fragment' có' FragmentTransaction' không được thêm vào ngăn xếp. Nếu giao dịch được thêm vào ngăn xếp lại thì 'Fragment' sẽ được giữ lại tự động (tức là' onDestroy' của nó sẽ không được gọi). [** Từ tài liệu **] (http://developer.android.com/guide/components/fragments.html#Transactions). Nếu bạn không thêm nó vào back stack thì bạn sẽ phải gọi 'setRetainInstance()' như bạn đã nói nếu bạn muốn nó không bị hủy. –

30
getSupportFragmentManager().addOnBackStackChangedListener(new OnBackStackChangedListener() {  
      public void onBackStackChanged() { 
       Log.i(TAG, "back stack changed "); 
       int backCount = getSupportFragmentManager().getBackStackEntryCount(); 
       if (backCount == 0){ 
            // block where back has been pressed. since backstack is zero. 
       } 
      } 
     }); 

sử dụng addOnBackStackChangedListener này.

+4

Tôi chỉ cố gắng này, vấn đề là onBackStackChanged được gọi là sau khi các phương pháp vòng đời mảnh vỡ được gọi. Những gì tôi muốn làm là: tải dữ liệu khi phân đoạn được tạo lần đầu tiên, lưu trữ dữ liệu và khôi phục khi cần thiết (không tải lại). Điều đó đã đạt được với việc tải/phục hồi có điều kiện trong onActivityCreated. Khi đoạn được khôi phục qua popping ngăn xếp lại, không tải lại dữ liệu. Ngay cả khi tôi đặt cờ trong onBackStackChanged, các phương pháp vòng đời sẽ không nhìn thấy nó. – dvd

+0

Hoạt động như một sự quyến rũ! – portfoliobuilder

+0

question.acceptedAnswer = this; – satheeshwaran

0

Trong một số trường hợp, bạn có thể sử dụng phương pháp isVisible để hiểu là lần đầu tiên hiển thị một đoạn hoặc nó được khôi phục từ hậu trường.

8

YẾU EDIT: Oct 15 2013

Lời giải thích trước đó (giữ dưới đây để tham khảo) thất bại khi ứng dụng được đưa vào nền và đưa trở lại phía sau.

Thay vào đó, tốt hơn là so sánh kích thước hiện tại của hậu trường với đoạn khi đoạn được tạo & được đặt vào hậu trường.


Hãy xem tốt ở Hình 2 trong http://developer.android.com/guide/components/fragments.html#Creating

gì con số này cho bạn biết là khi một đoạn được phục hồi từ backstack, onCreate() của nó không được gọi, trong khi onCreateView của nó() Là.


Vì vậy, bạn có thể muốn làm một cái gì đó như thế này:

public class MyFragment extends Fragment { 
    int mBackStackSize = 0; 

    @Override 
    public void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 
     mBackStackSize = getFragmentManager().getBackStackEntryCount(); 
    } 

    public boolean isRestoredFromBackstack() { 
     return mBackStackSize > getFragmentManager().getBackStackEntryCount(); 
    } 
} 
4

Nếu bạn thêm vào đoạn để backstack, và sau một số thao tác bạn giấu nó bằng cách sử fragmentTransaction.hide (fragment) và sau đó khôi phục nó từ backstack như fragmentTransaction.show (fragmentManager.findFragmentByTag (fragment.getName())); bạn có thể ghi đè lên onHiddenChanged (boolean ẩn)

@Override 
public void onHiddenChanged(boolean hidden) { 
    // TODO Auto-generated method stub 
    super.onHiddenChanged(hidden); 
    if (!hidden) { 
     //fragment became visible 
     //your code here 
    } 
} 
+0

Đó chính xác là những gì tôi đang tìm kiếm. Cảm ơn! Chỉ cần lưu ý rằng nó sẽ là 'if (! Hidden) {' – crubio

0
Fragment.getFragmentManager() == null 

trước khi thêm vào và sau popped

12

Khi một đoạn đi vào back-đống onDestroyView() gọi. Không phải onDestroy().

Và khi một đoạn xuất hiện từ phía sau ngăn xếp onCreateView() được gọi. Không phải onCreate().

Vì vậy, thêm một boolean mIsRestoredFromBackstack để phân mảnh và làm theo như sau:

@Override 
public void onCreate(Bundle savedInstanceState) 
{ 
    super.onCreate(savedInstanceState); 
    mIsRestoredFromBackstack = false; 
} 

@Override 
public void onResume() 
{ 
    super.onResume(); 
    if(mIsRestoredFromBackstack) 
    { 
     // The fragment restored from backstack, do some work here! 
    } 
} 

@Override 
public void onDestroyView() 
{ 
    super.onDestroyView(); 
    mIsRestoredFromBackstack = true; 
} 
+0

onDestroyView đang được gọi từ khóa màn hình, vì vậy hành động của tôi được gọi hai lần sau khi quay trở lại từ backstack – ldrrp

+1

Nó hoạt động. Cảm ơn bạn đã trả lời. –

Các vấn đề liên quan