2014-04-21 15 views
12

Vì vậy, có một số câu hỏi tương tự, nhưng tôi chưa tìm thấy câu hỏi nào giải quyết vấn đề này. Các official android documentation có vẻ trực quan nhưng khi tôi thực hiện một ứng dụng với một công việc phức tạp hơn, các mảnh vỡ backstack được lộn xộn và những thứ kỳ lạ bắt đầu xảy ra. Tôi đã phát triển một bộ xương cho các ứng dụng đơn giản, với ý tưởng về một hoạt động đơn lẻ có thể được truy cập bởi các đoạn của nó để bắt đầu các đoạn khác. Đây là cách tôi đã làm nó:Tìm hiểu các mảnh vỡ backstack

1- Tôi để hoạt động chính của tôi thực hiện một giao diện được gọi là "FragmentDelegate"

public interface FragmentDelegate { 
    public void startFragment(CCFragment fragment, boolean addToBackStack); 
} 

2- Việc thực hiện phương pháp startFrargment:

@Override 
public void startFragment(CCFragment fragment, boolean addToBackStack) { 

    FragmentManager fragmentManager = getSupportFragmentManager(); 

    fragment.setFragmentDelegate(this); 
    FragmentTransaction fragmentTransaction = fragmentManager 
      .beginTransaction(); 

    fragmentTransaction.setCustomAnimations(R.anim.slide_in_right, 
      R.anim.slide_out_left, R.anim.slide_in_left, 
      R.anim.slide_out_right); 

    fragmentTransaction.replace(CONTENT_VIEW_ID, fragment, 
      "callerFragmentClassName"); 
    if (addToBackStack) 
     fragmentTransaction.addToBackStack("callerFragmentClassName"); 
    fragmentTransaction.commitAllowingStateLoss(); 

} 

Các mát về điều này, tôi có thể gọi từ bất kỳ đoạn nào:

mFragmentDelegate.startFragment(aNewFragment, addToBackStack); 

OK bây giờ hãy nghĩ về follo kịch bản trường hợp cánh:

Tôi bắt đầu hoạt động của mình với đoạn ban đầu, cho phép nói đoạn A. Từ đoạn A, tôi gọi cho Hoạt động của máy ảnh. Khi kết quả đến, tôi bắt đầu Fragment B (thêm A vào backstack). Từ B, tôi bắt đầu Fragment C mà không cần thêm B vào hậu trường. Vì vậy, chúng tôi có điều này trong backstack:

[A] [C]

Nếu tôi nhấn nút quay lại, tôi lấy lại cho A. Nếu tôi lặp lại quá trình này, các backstack được điều sai lầm và khi tôi bấm lại, nó sẽ đưa tôi đến đoạn C một lần nữa và một lần nữa ...

Tôi biết điều này rất khó hiểu (và khó khăn hơn để giải thích, vì tiếng Anh không phải là tiếng mẹ đẻ của tôi) nhưng nếu ai đó có thể giải thích tôi làm thế nào để các mảnh vỡ Android trở lại hoạt động thực sự hoặc cung cấp một số loại khung cho ứng dụng, sẽ tuyệt vời.

+0

Bạn đang sử dụng findFragmentByTag (...) để có được một thể hiện của Fragments nếu chúng đã được khởi tạo chưa? Bởi vì có vẻ như bạn có nhiều phiên bản của cùng một đoạn. –

+0

Bạn nói đúng, khi tôi bắt đầu một đoạn, tôi tạo ra một đoạn mới ... nhưng tôi yêu cầu bởi vì đoạn có thể nhận các đối số và khác nhau. –

+0

Bạn luôn có thể đặt đối số mới cho thể hiện của một đoạn. –

Trả lời

17

Giải thích:

FragmentTransactions Khi FragmentManager trở lại trạng lưu (ví dụ người dùng nhấp vào nút Quay lại hoặc bạn gọi một số phương thức pop trên đó), nó thực hiện ngược lại với hành động được lưu trữ trong FragmentTransaction đã lưu. Bạn có thể thấy mã chính xác here, nó khá đơn giản.

Trong trường hợp của bạn, loại hoạt động đã lưu là 'thay thế', do đó, hoàn nguyên có nghĩa là xóa tất cả các trường hợp Phân đoạn đã thêm và thêm lại trường hợp đã xóa. Vì vậy, khi bạn có một đống mảnh như thế này:

[A] [B]

FragmentManager biết, đó là phải loại bỏ các [B] Ví dụ Fragment và thêm [A] khi một hoạt động pop. Vấn đề là, bạn thay thế [B] với [C]:

[A] [C]

Thật không may, sự xâm nhập Fragment BackStack lưu không biết về [C]. Vì vậy, trong một hoạt động pop, FragmentManager sẽ thêm lại [A], sẽ không tìm thấy [B] vì vậy nó không làm gì về điều đó, và để [C] ở đâu.

Giải pháp

Một giải pháp khả thi cho vấn đề này là sử dụng những mảnh nhỏ. Fragment-A là một Fragment cấp cao nhất, nhưng Fragment-B và Fragment-C là các mảnh con của một WrapperFragment.

Về cơ bản, khi bạn điều hướng đến fragment-B, bạn thay thế Fragment-A với WrapperFragment trong một giao dịch đã lưu:

[A] [[B]]

Sau đó, khi người dùng điều hướng tới Fragment-C, bạn chỉ thay thế của WrapperFragment [B] với [C]:

[A] [[C]]

Khi người dùng nhấn vào nút Quay lại, chúng ta sẽ nhận được một cách chính xác trở lại Fragment- A:

[A]

Demo

tôi đã tập hợp một GitHub project để chứng minh kỹ thuật này.

+0

Cảm ơn, tôi sẽ cố gắng sử dụng giải pháp của bạn. Các wrapperfragment trông rất hứa hẹn :) –

+0

thực sự hữu ích để hiểu được quá trình chính xác. –

0

Trước hết hãy nhớ rằng:

.replace() = .remove().add() 

một số giải pháp khả thi

public void onBackPressed(){ 
    // here you have to remove your last fragment. 
    super.onBackPressed(); 
} 

//////////////////////// ////////////////////////////////////////////////// /////////////////////

@Override 
public boolean onKeyDown(int keyCode, KeyEvent event) { 
if (keyCode == KeyEvent.KEYCODE_BACK) { 
    if (getSupportFragmentManager().getBackStackEntryCount() == 0) { 
     this.finish(); 
     return false; 
    } else { 
     getSupportFragmentManager().popBackStack(); 
     removeCurrentFragment(); 
     return false; 
    } 
} 

    return super.onKeyDown(keyCode, event); 
} 


public void removeCurrentFragment() { 
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction(); 
Fragment currentFrag =  getSupportFragmentManager().findFragmentById(R.id.detailFragment); 

if (currentFrag != null) 
    transaction.remove(currentFrag); 

transaction.commit(); 
} 

//////////////////// ////////////////////////////////////////////////// ////////////////

để biết thêm thông tin về backstack của mảnhCheck HereHere

1

tôi không thể tìm ra cách bạn kết thúc với popping mảnh C một lần nữa và một lần nữa mà không bức tranh toàn cảnh về những gì bạn đã làm, nhưng ở đây những gì bạn đã sai lầm về backstack:

  • BackStack nhập thực sự tiết kiệm các trạng thái hiện tại của toàn bộ FragmentManager, không chỉ là một đoạn duy nhất. I E. nếu bạn thực hiện nhiều thao tác với nhiều đoạn trong một giao dịch và gọi addToBackStack(), bạn sẽ lưu trạng thái của tất cả các đoạn trong giao dịch sắp tới.

  • Khi bạn gọi addToBackStack() bạn thực sự thêm tiếp theo bang đến backstack, tức là trên thực tế, nếu bạn đã gọi addToBackStack() khi bạn đã thêm một đoạn, bạn thực sự có một trạng thái với B và một nhà nước với A đằng sau nó - [A] [B], không phải [A] [C].

tôi khuyên bạn nên sử dụng mã này và thử tất cả mọi thứ với debugger nhìn vào tình trạng FragmentManager đối tượng:

int count = fragmentManager.getBackStackEntryCount(); 
    fragmentTransaction.addToBackStack(String.valueOf(count)); 

Bằng cách này bạn sẽ có thể theo dõi những gì đang thực sự xảy ra trong ứng dụng của bạn.

0

Điều này có vẻ không phải là giải pháp nhưng tôi nghĩ tốt hơn nếu bạn không sử dụng phân đoạn trong các tình huống như thế này. Lúc đầu chỉ có một Hoạt động và thay thế các mảnh theo yêu cầu có vẻ như là một ý tưởng tuyệt vời nhưng khi bạn cố gắng xây dựng ứng dụng của bạn theo cách này mọi thứ trở nên hỗn độn. (Tôi đã ở đó và tôi đang nói từ kinh nghiệm). Tự quản lý BackStack chỉ là một trong những vấn đề. Khi bạn đi xa hơn bạn kết thúc với một hoạt động với rất nhiều mã liên quan bên trong nó mà không phải là mát cả!

Tôi khuyên bạn nên tạo một hoạt động cho từng đoạn bạn đã có và chỉ cần đặt đoạn của bạn bên trong nó. Các hoạt động của bạn vẫn có thể có nhiều đoạn trong một số trường hợp (cho phép nói máy tính bảng hoặc chế độ ngang) và một trong một số trường hợp khác (như chế độ dọc) Nhưng bạn không phải sử dụng phương thức thay thế nữa.

Các hoạt động có thể có hoạt động của phụ huynh nên vấn đề BackStack sẽ được giải quyết theo cách tốt nhất có thể như nhiều vấn đề khác. Đây chỉ là một gợi ý dựa trên kinh nghiệm tôi đã có với các mảnh vỡ. Làm những gì bạn nghĩ tốt nhất.

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