Phân mảnh trong ViewPager sử dụng FragmentPagerAdapter bị trống khi nó được xem lần thứ hai


98

Tôi có một giao diện phân mảnh với các tab ở phía dưới mở các phân mảnh khác nhau trong chế độ xem chính.

Tôi có một phân đoạn cụ thể là danh sách các mục. Nếu người dùng chọn một trong các mục trong danh sách này, thì một phân đoạn khác sẽ mở ra, trong đó có một khung nhìn sẽ cuộn theo chiều ngang giữa tất cả các mục trong danh sách trong phân đoạn trước đó. Điều này hoạt động tuyệt vời.

Viewpager sử dụng FragmentPagerAdapter để hiển thị các mục.

Vấn đề xảy ra khi người dùng chọn một mục trong danh sách, xem nó, sau đó nhấn nút trên thanh tab để quay lại danh sách, sau đó chọn một mục khác. Lần thứ hai một mục được chọn, một màn hình trống sẽ xuất hiện thay vì máy ngắm. Tôi không nhận được lỗi nào trong LogCat của mình khi điều này xảy ra.

Tại sao viewpager chỉ xuất hiện lần đầu tiên?

FragmentPagerAdapter:

public class ViewPagerAdapter extends FragmentPagerAdapter {
    Cursor mCursor;

    public ViewPagerAdapter(FragmentManager fm, Cursor c) {
        super(fm);
        mCursor = c;
    }

    public void changeCursor(Cursor c) {
        mCursor = c;
        this.notifyDataSetChanged();
    }

    @Override
    public int getCount() {
        if (mCursor == null) return 0;
        else return mCursor.getCount();
    }

    @Override
    public Fragment getItem(int position) {
        mCursor.moveToPosition(position);
        return TeamCardFragment.newInstance(mCursor, position);
    }
}

PagerFragment:

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
    Bundle bundle = getArguments();
    mCursorPosition = bundle.getInt(TeamCardCommon.BUNDLE_KEY_CURSOR_POSITION);

    View mView = inflater.inflate(R.layout.team_card_master, container, false);
    mViewPager = (ViewPager)mView.findViewById(R.id.team_card_master_view_pager);

    mAdapter = new ViewPagerAdapter(getFragmentManager(), cursor);
    new setAdapterTask().execute();

    return mView;
}

private class setAdapterTask extends AsyncTask<Void, Void, Void> {
    protected Void doInBackground(Void... params) {
        return null;
    }

    @Override
    protected void onPostExecute(Void result) {
        mViewPager.setAdapter(mAdapter);
        mViewPager.setCurrentItem(mCursorPosition);
    }
}

Câu trả lời:


221

Tôi gặp vấn đề tương tự. Thay đổi lớp cha của PageAdapter của tôi từ android.support.v4.app.FragmentPagerAdapterđể android.support.v4.app.FragmentStatePagerAdaptergiải quyết ViewPagervấn đề hiển thị của tôi vào "lần thứ hai"!


2
Không đua đâu? Tôi không có mã này nữa nếu không tôi sẽ kiểm tra nó. Có lẽ câu trả lời này sẽ giúp ích cho người khác.
howettl

10
Đúng là một người đàn ông! Tôi đã theo dõi giải pháp này trong nhiều ngày! Cảm ơn một người đàn ông tấn công, làm việc như một sự quyến rũ. Nhưng nhà phát triển trong tôi đang hỏi rằng thay đổi đó tạo ra tác động gì? Ý tôi là tại sao không cho nó hoạt động trước và lý do tại sao trong StatePagerAdapter
Anand Sainath

1
bạn cũng cần phải @Override public int getItemPosition (Đối tượng đối tượng) {return POSITION_NONE; }
Helin Wang,

1
Làm việc cho tôi quá. Đây là một liên kết. Nó dường như lưu trạng thái phân mảnh, điều này tạo nên sự khác biệt. developer.android.com/reference/android/support/v4/app/…
Tjaart

1
Thật trùng hợp khi điều này hoạt động, câu trả lời đúng là @Daniel F. Dù sao, để thuận tiện trong những bình luận ở đây, sự khác biệt giữa FragmentPagerAdapterFragmentStatePagerAdapterlà vào sự hiện hữu cựu hơn phù hợp cho vài trang, nó giữ lại tất cả các mảnh vỡ trong bộ nhớ do đó có màn trình diễn tốt nhất trên switch trang, trong khi sau này là phù hợp hơn cho rất nhiều trang, nó phá hủy các mảnh, chỉ giữ lại trạng thái của chúng, bộ nhớ hiệu quả hơn nhưng chuyển trang chậm hơn một chút.
Cristina De Rito

87

Tôi đã quản lý để giải quyết điều này bằng cách thay thế getFragmentManager()bằng getChildFragmentManager()trong phân đoạn mẹ. Phân đoạn mẹ này đang cài đặt một android.support.v4.app.FragmentPagerAdapter để chứa các phân đoạn có thể phân trang (có thể trượt), yêu cầu trình quản lý phân đoạn trong phương thức khởi tạo. Đối với hàm tạo này, tôi đã chuyển giá trị trả về của getChildFragmentManager().

liên kết của hackbod là chính ( https://developer.android.com/about/versions/android-4.2.html#NestedFragment ), được tìm thấy trong bài đăng này Các mảnh trong các mảnh

Để lồng một đoạn, chỉ cần gọi getChildFragmentManager()Fragment mà bạn muốn thêm một đoạn vào. Điều này trả về FragmentManager mà bạn có thể sử dụng giống như bạn thường làm từ hoạt động cấp cao nhất để tạo các giao dịch phân đoạn.


Cảm ơn bạn ... tôi đã gặp sự cố tương tự khi cố gắng khởi tạo lại chế độ xem tab trượt sau onresume () có chứa một phân mảnh ... hướng dẫn mà tôi đã sử dụng là từ năm 2016 và tôi vẫn cần phải thay đổi nó thành segmentstatepageradapter để chuyển sang công việc. ước gì tôi biết TẠI SAO.
Nerdy Bunz

câu trả lời này đã tiết kiệm rất nhiều thời gian của tôi. Bởi vì chỉ sử dụng FragmentStatePagerAdapterkhông giải quyết được câu hỏi được hỏi ở đây. cùng với FragmentStatePagerAdapterphân đoạn mẹ YourAdapter adapter = new YourAdapter (getChildFragmentManager()); phải được thêm vào
MMK

17

đối với tôi, tôi phải gọi điều này trên máy xem của tôi:

myViewPager.setSaveFromParentEnabled(false);

Tôi đã gặp sự cố trong đó máy ngắm không được làm mới và tất cả những gì tôi thấy là một màn hình trắng trống, nơi có các mảnh vỡ. Tôi đã chuyển trong getChildFragmentManager nhưng nó không giúp được gì.


1
Tại sao trên thế giới đã làm việc này? Điều này đã khắc phục sự cố của tôi nhưng tôi không có manh mối tại sao.
ClayHerendeen

Tôi đã xóa nó khỏi mã của mình ngay bây giờ. Trình quản lý phân mảnh đã gây ra sự cố. Hãy thử chuyển đổi giữa getchildfragmentmanager và getfragmentmanager
j2emanue

Tôi đã thử điều đó. Tôi đã lồng nhau các Tab với ViewPager đã tắt tính năng vuốt. Tôi biết đây là thiết kế kém nhưng khách hàng không mong muốn của tôi. Tôi đang sử dụng childFragmentManager cho thanh tab cấp cao nhất. Việc chuyển đổi cho thanh tab / chế độ xem cấp thấp hơn dường như không khắc phục được sự cố. Tôi cho rằng tôi sẽ gắn bó với setSaveFromParentEnabled (false) ngay bây giờ vì nó đang hoạt động.
ClayHerendeen

Bạn đang sử dụng mới nhất thư viện hỗ trợ
j2emanue

2
Tôi đã gặp phải vấn đề tương tự từ 2 ngày trước .. Giải pháp của bạn đã hiệu quả với tôi. cảm ơn !
brijexecon

11

Trong trường hợp rất cụ thể của tôi, khi tôi đang sử dụng CoordinatorLayout với AppBarLayout và ViewPager, điều đã giải quyết được vấn đề đó cho tôi là xóa android: fitSystemWindows = "true" khỏi thuộc tính xml AppBarLayout của tôi .

Đừng hỏi tôi tại sao. Tôi biết nó nghe có vẻ hơi nực cười và giống như nó không nên có mối tương quan, nhưng chính dòng đơn này là thứ duy nhất gây ra sự cố khi tôi đã sử dụng getChildFragmentManager () trong bộ điều hợp của mình. Tôi đã dành cả ngày để gỡ lỗi mã của mình chỉ để tìm ra điều này, vì vậy tôi hy vọng nó sẽ tiết kiệm thời gian cho người khác.


3
Ôi trời ... tôi gần như sẽ đầu hàng với vấn đề này. Bạn đã làm cho tôi ngày kỳ lạ! Geez Google, WTF bị lỗi với AppBarLayout? Tôi đã xem gần trăm trang và dành hàng tấn giờ để gỡ lỗi để cố gắng giải quyết vấn đề này mà không gặp may. Tôi thực sự biết ơn vì cuối cùng tôi đã giải quyết được vấn đề với nhận xét của bạn. Cảm ơn rất nhiều! Tái bút: Tôi đã rất tuyệt vọng đến mức tôi thậm chí đã tạo ra sự cố trong AOSP: code.google.com/p/android/issues/… XD
Guillem Roca

Cảm ơn cho gợi ý. Ít nhất nó đã giúp chúng tôi giải quyết vấn đề. Bây giờ chúng tôi đang cố gắng tìm ra tùy chọn để làm cho nó toàn màn hình
Paresh Mayani

Bạn là một cứu cánh! Tôi hoàn toàn không biết tại sao tôi lại gặp phải vấn đề này và vẫn không biết tại sao nó lại hoạt động!
nandu 17/07/19

10

Tôi đã gặp vấn đề tương tự mà tôi đã thay đổi bộ điều hợp từ FragmentPagerAdaptersang FragmentStatePagerAdaptergetFragmentManager()trong phân đoạn mẹ thànhgetChildFragmentManager()

Lý do đằng sau điều này là FragmentStatePagerAdapterhữu ích trong việc lưu trữ một số lượng lớn các trang và bộ nhớ liên quan đến mỗi trang được truy cập sẽ ít hơn vì nó chỉ giữ trạng thái đã lưu của phân đoạn trong khi trang không hiển thị. Điều này làm giảm chi phí trong khi chuyển đổi giữa các phân đoạn.


4

Cố gắng đưa setOffscreenPageLimit (int limit)vào ViewPager mẹ.

mViewPager.setOffscreenPageLimit(totalPages-1);

Điều này làm việc cho tôi như một sự quyến rũ.

Trong trường hợp của tôi, tôi đã có trong đoạn TabLayoutvớiViewPager.

Và một cái khác ViewPagerbên trong mảnh vỡ đó. Lần đầu tiên tất cả đều hoạt động tốt nhưng khi tôi thay đổi tab và quay lại, một số đoạn của tôi bị trống.


1
Câu trả lời tốt. Nó đã giúp tôi.
Thirumalvalavan


1

Chúng tôi đã giải quyết vấn đề này bằng cách triển khai lại các mục máy nhắn tin chế độ xem dưới dạng các chế độ xem tiêu chuẩn thay vì phân đoạn và thay đổi bộ điều hợp cho phù hợp.


bạn có thể thử gỡ bỏ các isViewFromObject (Xem xem, đối tượng Object) chức năng
Mina Samy

Phải có một cách tốt hơn ....: / mặc dù tôi càng đào sâu vào Android, tôi càng nhận ra điều đó kém thành thục hơn.
StackOverflowed

1
Các phân đoạn lồng nhau không được hỗ trợ , vì vậy việc triển khai lại với chế độ xem chuẩn có vẻ là cách tốt.
Sylphe

Tôi đang đấu tranh với vấn đề tương tự. Tôi đã thử sử dụng PagerAdapter thay vì FragmentAdapter vẫn gặp sự cố tương tự. Hãy giúp tôi ra !
Gaurav Arora

Nếu bạn muốn sử dụng mảnh vỡ lồng nhau bạn có thể sử dụng adapter tôi cung cấp trong câu trả lời này: stackoverflow.com/questions/7700226/...
Slickelito

1

Tôi gặp sự cố tương tự này trên Xamarin Android với màn hình trống lần thứ hai .. Thiết lập sau đây đã khắc phục sự cố cho tôi.

viewPager.SaveFromParentEnabled = false;

0

Bạn cũng có thể khởi tạo bộ điều hợp cho các trường hợp gặp phải lỗi này khi ứng dụng của bạn được thu nhỏ và sau đó được gọi lên.

@Override 
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
    Bundle bundle = getArguments();
    mCursorPosition = bundle.getInt(TeamCardCommon.BUNDLE_KEY_CURSOR_POSITION);
    View mView = inflater.inflate(R.layout.team_card_master, container, false);
    mViewPager = (ViewPager)mView.findViewById(R.id.team_card_master_view_pager);
    initViewPagerAdapter();
    return mView;
}
private void initViewPagerAdapter(){
    mAdapter = new ViewPagerAdapter(getFragmentManager(), cursor);
    new setAdapterTask().execute();
}

@Override
public void onResume(){
    super.onResume();
    initViewPagerAdapter();
}

0

Tôi đã gặp điều tương tự, trong lần thứ hai tôi gọi Bộ điều hợp máy nhắn tin, chế độ xem con trả về một NullPointerException. Và việc thay đổi trình điều hợp trong FragmentStatePagerAdapter cũng giải quyết được vấn đề của tôi.


0

Đổi FragmentPagerAdapterthành FragmentStatePagerAdapter Sử dụng getChildFragmentManager()thay vìgetFragmentManager()

getChildFragmentManager()- bởi vì theo tài liệu, nó sẽ trả về một FragmentManager riêng để đặt và quản lý các Fragment bên trong Fragment này. Trong khi đó getFragmentManager()sẽ trả về FragmentManager để tương tác với các phân đoạn được liên kết với hoạt động này


0

class ViewPagerAdapter mở rộng FragmentStatePagerAdapter công việc này cho tôi, hãy thử cái này

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.