Fragment ใน ViewPager โดยใช้ FragmentPagerAdapter จะว่างเปล่าในครั้งที่สองที่ดู


99

ฉันมีอินเทอร์เฟซแฟรกเมนต์พร้อมแท็บที่ด้านล่างซึ่งเปิดส่วนต่างๆในมุมมองหลัก

ฉันมีส่วนหนึ่งโดยเฉพาะซึ่งเป็นรายการของรายการ หากผู้ใช้เลือกรายการใดรายการหนึ่งในรายการนี้ส่วนอื่นจะเปิดขึ้นซึ่งมี viewpager ซึ่งเลื่อนตามแนวนอนระหว่างรายการทั้งหมดในรายการในส่วนก่อนหน้า ใช้งานได้ดี

viewpager ใช้ FragmentPagerAdapter เพื่อแสดงรายการ

ปัญหาเกิดขึ้นเมื่อผู้ใช้เลือกรายการในรายการดูรายการจากนั้นกดปุ่มบนแถบแท็บเพื่อกลับไปที่รายการจากนั้นเลือกรายการอื่น ครั้งที่สองที่เลือกรายการหน้าจอว่างจะปรากฏขึ้นแทน viewpager ฉันไม่ได้รับข้อผิดพลาดใน LogCat ของฉันเมื่อสิ่งนี้เกิดขึ้น

เหตุใด viewpager จึงปรากฏในครั้งแรกเท่านั้น

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);
    }
}

คำตอบ:


222

ฉันมีปัญหาเดียวกัน การเปลี่ยนคลาสแม่ของ PageAdapter ของฉันandroid.support.v4.app.FragmentPagerAdapterเพื่อandroid.support.v4.app.FragmentStatePagerAdapterแก้ปัญหาการViewPagerแสดงผลของฉันใน "ครั้งที่สอง"!


2
ไม่ได้ล้อเล่น? ฉันไม่มีรหัสนี้อีกแล้วมิฉะนั้นฉันจะทดสอบ บางทีคำตอบนี้อาจช่วยคนอื่นได้
howettl

10
สิ่งที่มนุษย์! ฉันมองหาวิธีแก้ปัญหานี้มาหลายวันแล้ว! ขอบคุณผู้ชายตันทำงานได้อย่างมีเสน่ห์ แต่นักพัฒนาในตัวฉันกำลังถามว่าการเปลี่ยนแปลงนั้นสร้างผลกระทบอะไรบ้าง? ฉันหมายความว่าทำไมมันไม่ทำงานมาก่อนและทำไมใน StatePagerAdapter
Anand Sainath

1
นอกจากนี้คุณต้อง @Override public int getItemPosition (Object object) {return POSITION_NONE; }
Helin Wang

1
ทำงานให้ฉันด้วย นี่คือลิงค์ ดูเหมือนว่าจะบันทึกสถานะแฟรกเมนต์ซึ่งสร้างความแตกต่างทั้งหมด developer.android.com/reference/android/support/v4/app/…
Tjaart

1
มันบังเอิญได้ผลคำตอบที่ถูกต้องคือ @Daniel F's one อย่างไรก็ตามเพื่อความสะดวกของผู้แสดงความคิดเห็นที่นี่ความแตกต่างระหว่างFragmentPagerAdapterและFragmentStatePagerAdapterในอดีตนั้นเหมาะสมกว่าสำหรับสองสามหน้ามันยังคงเก็บชิ้นส่วนทั้งหมดไว้ในหน่วยความจำดังนั้นจึงมีการแสดงที่ดีที่สุดในการสลับหน้าในขณะที่ส่วนหลังเหมาะสำหรับจำนวนมาก หน้ามันทำลายชิ้นส่วนโดยรักษาสถานะไว้เท่านั้นหน่วยความจำมีประสิทธิภาพมากกว่า แต่ช้ากว่าเล็กน้อยในการสลับหน้า
Cristina De Rito

88

ฉันจัดการเพื่อแก้ปัญหานี้โดยการแทนที่getFragmentManager()ด้วยgetChildFragmentManager()ในส่วนของผู้ปกครอง ส่วนผู้ปกครองนี้ถูก instancing android.support.v4.app.FragmentPagerAdapterในการสั่งซื้อเพื่อให้มีเพจ (slideable) เศษซึ่งจะต้องมีผู้จัดการส่วนในการสร้าง สำหรับตัวสร้างนี้ฉันส่งคืนค่าของgetChildFragmentManager().

ลิงก์ของ hackbod เป็นกุญแจสำคัญ ( https://developer.android.com/about/versions/android-4.2.html#NestedFragments ) ซึ่งพบในโพสต์นี้Fragments ภายใน Fragments

ในการซ้อนแฟรกเมนต์เพียงแค่เรียกgetChildFragmentManager()Fragment ที่คุณต้องการเพิ่มแฟรกเมนต์ สิ่งนี้ส่งคืน FragmentManager ที่คุณสามารถใช้ได้เหมือนปกติจากกิจกรรมระดับบนสุดเพื่อสร้างธุรกรรมแฟรกเมนต์


ขอบคุณ ... ฉันมีปัญหาที่คล้ายกันพยายามที่จะสร้างอินสแตนซ์มุมมองแท็บแบบเลื่อนอีกครั้งหลังจาก onresume () ที่มีแฟรกเมนต์เพจradapter ... บทช่วยสอนที่ฉันใช้มาจากปี 2016 และฉันยังคงต้องเปลี่ยนเป็นแฟรกเมนต์สเตทเพจradapterเพื่อให้มันเป็น งาน. หวังว่าฉันจะรู้ว่าทำไม
Nerdy Bunz

คำตอบนี้ช่วยประหยัดเวลาของฉันได้มาก เพราะการใช้เพียงอย่างเดียวFragmentStatePagerAdapterไม่สามารถแก้ปัญหาที่ถามที่นี่ได้ พร้อมกับFragmentStatePagerAdapterในส่วนของผู้ปกครองYourAdapter adapter = new YourAdapter (getChildFragmentManager()); จะต้องมีการเพิ่ม
MMK

17

สำหรับฉันฉันต้องเรียกสิ่งนี้ใน viewpager ของฉัน:

myViewPager.setSaveFromParentEnabled(false);

ฉันมีปัญหาที่ viewpager ไม่รีเฟรชและสิ่งที่ฉันเห็นคือหน้าจอสีขาวว่างเปล่าซึ่งควรมีเศษชิ้นส่วน ฉันผ่าน getChildFragmentManager แต่มันไม่ได้ช่วย


1
ทำไมในโลกถึงได้ผลเช่นนี้? สิ่งนี้ช่วยแก้ปัญหาของฉันได้ แต่ฉันไม่รู้ว่าทำไม
ClayHerendeen

ฉันลบมันออกจากรหัสของฉันแล้ว ตัวจัดการส่วนที่เป็นสาเหตุของปัญหา ลองสลับระหว่าง getchildfragmentmanager และ getfragmentmanager
j2emanue

ฉันได้ลองแล้ว ฉันได้ซ้อนแต่ละแท็บด้วย ViewPagers ที่ปิดใช้งานการปัด ฉันรู้ว่านี่เป็นการออกแบบที่ไม่ดี แต่ลูกค้าไม่ต้องการของฉัน ฉันใช้ childFragmentManager สำหรับแถบแท็บระดับบนสุด การสลับสำหรับแถบระดับล่าง / viewpager ดูเหมือนจะไม่สามารถแก้ไขปัญหาได้ ฉันคิดว่าฉันจะติดกับ setSaveFromParentEnabled (false) ในตอนนี้เนื่องจากมันใช้งานได้
ClayHerendeen

คุณกำลังใช้ไลบรารีสนับสนุนล่าสุดหรือไม่
j2emanue

2
ฉันประสบปัญหาเดียวกันจาก 2 วันที่แล้ว .. วิธีแก้ปัญหาของคุณใช้ได้ผลสำหรับฉัน ขอบคุณ!
brijexecon

11

โดยเฉพาะในกรณีของฉันที่ฉันได้รับการใช้ CoordinatorLayout กับ AppBarLayout และ ViewPager สิ่งที่แก้ไขได้สำหรับฉันคือการเอาหุ่นยนต์: fitsSystemWindows = "true" จากคุณสมบัติ

อย่าถามฉันว่าทำไม ฉันรู้ว่ามันฟังดูไร้สาระไปหน่อยและดูเหมือนว่ามันไม่ควรมีความสัมพันธ์กัน แต่มันเป็นเพียงบรรทัดเดียวที่ทำให้เกิดปัญหาเนื่องจากฉันใช้ getChildFragmentManager () ในอะแดปเตอร์ของฉันอยู่แล้ว ฉันใช้เวลาทั้งวันในการดีบักโค้ดเพื่อค้นหาสิ่งนี้ดังนั้นฉันหวังว่ามันจะช่วยคนอื่นได้บ้าง


3
โอ้มนุษย์ ... ฉันเกือบจะยอมแพ้กับปัญหานี้แล้ว คุณทำให้วันของฉันประหลาด! Geez Google, WTF ผิดกับ AppBarLayout? ฉันดูเกือบร้อยหน้าและใช้เวลาหลายชั่วโมงในการแก้ไขข้อบกพร่องเพื่อพยายามแก้ไขปัญหานี้โดยไม่ต้องโชคดี ฉันรู้สึกขอบคุณจริงๆที่ในที่สุดฉันก็สามารถแก้ปัญหาด้วยความคิดเห็นของคุณได้ ขอบคุณมาก! PS: ฉันหมดหวังมากจนสร้างปัญหาใน AOSP: code.google.com/p/android/issues/… XD
Guillem Roca

ขอบคุณสำหรับคำใบ้ อย่างน้อยก็ช่วยเราในการแก้ไขปัญหา ตอนนี้เรากำลังพยายามหาตัวเลือกในการทำให้เต็มหน้าจอ
Paresh Mayani

คุณคือผู้ช่วยชีวิต! ฉันไม่รู้ว่าทำไมฉันถึงมีปัญหานี้และยังไม่รู้ว่าทำไมมันถึงได้ผล!
nandu

10

ฉันมีปัญหาเดียวกันกับที่ฉันเปลี่ยนอะแดปเตอร์จากFragmentPagerAdapterเป็นFragmentStatePagerAdapterและgetFragmentManager()ในส่วนพาเรนต์เป็นgetChildFragmentManager()

เหตุผลเบื้องหลังสิ่งนี้มีFragmentStatePagerAdapterประโยชน์ในการจัดเก็บเพจจำนวนมากและหน่วยความจำที่เชื่อมโยงกับแต่ละเพจที่เข้าชมนั้นน้อยลงเนื่องจากจะเก็บเฉพาะสถานะที่บันทึกไว้ของแฟรกเมนต์ในขณะที่ไม่สามารถมองเห็นเพจได้ ซึ่งจะช่วยลดค่าใช้จ่ายในขณะที่สลับไปมาระหว่างชิ้นส่วน


4

พยายามที่จะนำsetOffscreenPageLimit (int limit)บนViewPager ผู้ปกครอง

mViewPager.setOffscreenPageLimit(totalPages-1);

สิ่งนี้ได้ผลสำหรับฉันเหมือนมีเสน่ห์

ในกรณีของฉันฉันมีชิ้นส่วนอยู่ข้างในTabLayoutด้วยViewPager.

และอีกViewPagerชิ้นหนึ่งภายในส่วนนั้น ครั้งแรกทุกอย่างทำงานได้ดี แต่เมื่อฉันเปลี่ยนแท็บและย้อนกลับบางส่วนของฉันว่างเปล่า


1
คำตอบที่ดี. มันช่วยฉัน
Thirumalvalavan


1

เราแก้ไขสิ่งนี้ได้โดยการนำรายการเพจเจอร์มุมมองกลับมาใช้เป็นมุมมองมาตรฐานแทนที่จะเป็นส่วนย่อยและเปลี่ยนอะแดปเตอร์ตามนั้น


คุณสามารถลองลบฟังก์ชัน isViewFromObject (View view, Object object)
Mina Samy

มันต้องมีวิธีที่ดีกว่านี้ .... : / แม้ว่ายิ่งฉันขุดคุ้ย Android มากเท่าไหร่ฉันก็รู้ว่ามันเป็นผู้ใหญ่น้อยลง
StackOverflowed

1
ไม่รองรับส่วนที่ซ้อนกันดังนั้นการนำไปใช้ใหม่ด้วยมุมมองมาตรฐานจึงเป็นวิธีที่ดี
Sylphe

ฉันกำลังดิ้นรนกับปัญหาที่คล้ายกัน ฉันลองใช้ PagerAdapter แทน FragmentAdapter ก็ยังพบปัญหาเดียวกัน กรุณาช่วยฉันออกไป !
Gaurav Arora

หากคุณต้องการใช้ชิ้นส่วนที่ซ้อนกันคุณสามารถใช้อะแดปเตอร์ที่ฉันให้ไว้ในคำตอบนี้: stackoverflow.com/questions/7700226/…
Slickelito

1

ฉันได้รับปัญหาเดียวกันนี้ในXamarin Android พร้อมกับหน้าจอว่างเปล่าในครั้งที่สอง .. การตั้งค่าต่อไปนี้ได้รับการแก้ไขสำหรับฉัน

viewPager.SaveFromParentEnabled = false;

0

คุณยังสามารถเริ่มต้นอะแดปเตอร์สำหรับกรณีที่คุณพบข้อผิดพลาดนี้เมื่อแอปของคุณถูกย่อขนาดและเรียกขึ้นมาในภายหลัง

@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

ฉันมีสิ่งเดียวกันในครั้งที่สองที่ฉันเรียกใช้อะแดปเตอร์เพจเจอร์มุมมองเด็กจะส่งคืน NullPointerException และการเปลี่ยนอะแดปเตอร์ใน FragmentStatePagerAdapter ก็ช่วยแก้ปัญหาของฉันได้เช่นกัน


0

เปลี่ยนFragmentPagerAdapterเป็นการFragmentStatePagerAdapter ใช้getChildFragmentManager()แทนgetFragmentManager()

getChildFragmentManager()- เนื่องจากตามเอกสารจะส่งคืน FragmentManager ส่วนตัวสำหรับวางและจัดการ Fragment ภายใน Fragment นี้ ในขณะเดียวกันgetFragmentManager()จะส่งคืน FragmentManager สำหรับการโต้ตอบกับชิ้นส่วนที่เกี่ยวข้องกับกิจกรรมนี้


โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.