Tóm tắt vấn đề
Lưu ý: Trong câu trả lời này, tôi sẽ tham khảo FragmentPagerAdaptervà mã nguồn của nó. Nhưng giải pháp chung cũng nên áp dụng cho FragmentStatePagerAdapter.
Nếu bạn đang đọc điều này, bạn có thể đã biết rằng FragmentPagerAdapter/ FragmentStatePagerAdapterđược tạo ra Fragmentscho bạn ViewPager, nhưng khi hoạt động giải trí (cho dù từ xoay thiết bị hoặc hệ thống giết ứng dụng của bạn để lấy lại bộ nhớ), những thứ này Fragmentssẽ không được tạo lại, mà thay vào đó là các phiên bản được truy xuất từFragmentManager . Bây giờ hãy nói Activitynhu cầu của bạn để có được một tham chiếu đến những điều này Fragmentsđể làm việc với chúng. Bạn không có idhoặc tagcho những thứ này được tạo Fragmentsbởi vì FragmentPagerAdapter hãy đặt chúng trong nội bộ . Vì vậy, vấn đề là làm thế nào để có được một tham chiếu đến họ mà không có thông tin đó ...
Vấn đề với các giải pháp hiện tại: dựa vào mã nội bộ
Rất nhiều trong những giải pháp tôi đã nhìn thấy trên này và tương tự như câu hỏi dựa vào nhận được một tham chiếu đến hiện Fragmentbằng cách gọi FragmentManager.findFragmentByTag()và bắt chước các thẻ nội bộ tạo ra:"android:switcher:" + viewId + ":" + id . Vấn đề với điều này là bạn đang dựa vào mã nguồn nội bộ, mà như tất cả chúng ta đều biết không được đảm bảo sẽ giữ nguyên mãi mãi. Các kỹ sư Android tại Google có thể dễ dàng quyết định thay đổi tagcấu trúc sẽ phá vỡ mã của bạn khiến bạn không thể tìm thấy tham chiếu đến cấu trúc hiện có Fragments.
Giải pháp thay thế mà không cần dựa vào nội bộ tag
Dưới đây là một ví dụ đơn giản về cách lấy tham chiếu đến giá trị được Fragmentstrả về FragmentPagerAdaptermà không dựa vào tập nội bộ tagstrên Fragments. Điều quan trọng là ghi đè instantiateItem()và lưu các tham chiếu trong đó thay vì trong getItem().
public class SomeActivity extends Activity {
private FragmentA m1stFragment;
private FragmentB m2ndFragment;
// other code in your Activity...
private class CustomPagerAdapter extends FragmentPagerAdapter {
// other code in your custom FragmentPagerAdapter...
public CustomPagerAdapter(FragmentManager fm) {
super(fm);
}
@Override
public Fragment getItem(int position) {
// Do NOT try to save references to the Fragments in getItem(),
// because getItem() is not always called. If the Fragment
// was already created then it will be retrieved from the FragmentManger
// and not here (i.e. getItem() won't be called again).
switch (position) {
case 0:
return new FragmentA();
case 1:
return new FragmentB();
default:
// This should never happen. Always account for each position above
return null;
}
}
// Here we can finally safely save a reference to the created
// Fragment, no matter where it came from (either getItem() or
// FragmentManger). Simply save the returned Fragment from
// super.instantiateItem() into an appropriate reference depending
// on the ViewPager position.
@Override
public Object instantiateItem(ViewGroup container, int position) {
Fragment createdFragment = (Fragment) super.instantiateItem(container, position);
// save the appropriate reference depending on position
switch (position) {
case 0:
m1stFragment = (FragmentA) createdFragment;
break;
case 1:
m2ndFragment = (FragmentB) createdFragment;
break;
}
return createdFragment;
}
}
public void someMethod() {
// do work on the referenced Fragments, but first check if they
// even exist yet, otherwise you'll get an NPE.
if (m1stFragment != null) {
// m1stFragment.doWork();
}
if (m2ndFragment != null) {
// m2ndFragment.doSomeWorkToo();
}
}
}
hoặc nếu bạn muốn làm việc với tagsthay vì các biến / tham chiếu thành viên của lớp, Fragmentsbạn cũng có thể lấy tagstập hợp FragmentPagerAdaptertheo cách tương tự: LƯU Ý: điều này không áp dụng FragmentStatePagerAdaptervì nó không được đặt tagskhi tạo Fragments.
@Override
public Object instantiateItem(ViewGroup container, int position) {
Fragment createdFragment = (Fragment) super.instantiateItem(container, position);
// get the tags set by FragmentPagerAdapter
switch (position) {
case 0:
String firstTag = createdFragment.getTag();
break;
case 1:
String secondTag = createdFragment.getTag();
break;
}
// ... save the tags somewhere so you can reference them later
return createdFragment;
}
Lưu ý rằng phương pháp này KHÔNG dựa vào việc bắt chước tagtập hợp bên trong FragmentPagerAdaptervà thay vào đó sử dụng các API thích hợp để truy xuất chúng. Bằng cách này, ngay cả khi những tagthay đổi trong các phiên bản tương lai của SupportLibrarybạn, bạn vẫn sẽ an toàn.
Đừng quên rằng tùy thuộc vào thiết kế của bạn Activity, Fragmentsmà bạn đang cố gắng làm việc có thể tồn tại hoặc có thể chưa tồn tại, vì vậy bạn phải tính đến điều đó bằng cách nullkiểm tra trước khi sử dụng tài liệu tham khảo của mình.
Ngoài ra, nếu thay vào đó bạn đang làm việc FragmentStatePagerAdapter, thì bạn không muốn giữ các tham chiếu cứng cho của mình Fragmentsvì bạn có thể có nhiều trong số đó và các tham chiếu cứng sẽ lưu chúng trong bộ nhớ một cách không cần thiết. Thay vào đó, hãy lưu các Fragmenttham chiếu trong WeakReferencecác biến thay vì các tham chiếu chuẩn. Như thế này:
WeakReference<Fragment> m1stFragment = new WeakReference<Fragment>(createdFragment);
// ...and access them like so
Fragment firstFragment = m1stFragment.get();
if (firstFragment != null) {
// reference hasn't been cleared yet; do work...
}