ViewPager ไม่ได้วาดเนื้อหาใหม่ แต่ยังคง / ว่างเปล่า


86

เรากำลังประสบปัญหาแปลก ๆ กับ ViewPager ที่นี่ เราฝังรายการในแต่ละหน้า ViewPager และทริกเกอร์ alertDataSetChanged ทั้งบนอะแดปเตอร์รายการและอะแดปเตอร์เพจเจอร์มุมมองเมื่ออัปเดตข้อมูลรายการ

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

ฉันไม่สามารถทำงานนี้โดยใช้โปรแกรมได้ การทำให้มุมมองรายการเป็นโมฆะหรือเพจเจอร์มุมมองทั้งหมดแม้จะไม่มีผลใด ๆ

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

มีใครกำลังประสบปัญหาเหล่านี้ด้วยหรือคุณมีความคิดว่าอะไรเป็นสาเหตุของปัญหานี้

คำตอบ:


44

ในที่สุดเราก็หาทางออกได้ เห็นได้ชัดว่าการดำเนินการของเราประสบปัญหาสองประการ:

  1. destroyItem()อะแดปเตอร์ของเราไม่ได้ลบมุมมองใน
  2. เรากำลังแคชมุมมองเพื่อที่เราจะต้องขยายเลย์เอาต์ของเราเพียงครั้งเดียวและเนื่องจากเราไม่ได้ลบมุมมองdestroyItem()ออกเราจึงไม่ได้เพิ่มเข้าไปinstantiateItem()แต่เพียงแค่ส่งคืนมุมมองแคชที่สอดคล้องกับตำแหน่งปัจจุบัน

ฉันไม่ได้ดูซอร์สโค้ดของโค้ดลึกเกินไปViewPager- และมันก็ไม่ชัดเจนว่าคุณต้องทำเช่นนั้น - แต่เอกสารบอกว่า:

destroyItem ()
ลบเพจสำหรับตำแหน่งที่กำหนด อะแด็ปเตอร์มีหน้าที่ในการลบมุมมองออกจากคอนเทนเนอร์แม้ว่าจะต้องแน่ใจว่าสิ่งนี้เสร็จสิ้นภายในเวลาที่ส่งคืนจาก FinishUpdate (ViewGroup)

และ:

PagerAdapter ที่เรียบง่ายมากอาจเลือกใช้มุมมองของเพจเป็นอ็อบเจกต์หลักโดยส่งคืนจากอินสแตนซ์ไอเท็ม (ViewGroup, int) หลังการสร้างและเพิ่มไปยัง ViewGroup หลัก การใช้งาน destroyItem (ViewGroup, int, Object) ที่ตรงกันจะลบ View ออกจาก ViewGroup หลักและสามารถใช้ isViewFromObject (View, Object) เป็น return view == object;

ดังนั้นข้อสรุปของฉันคือการที่ViewPagerอาศัยอยู่กับอะแดปเตอร์ที่รองรับอย่างชัดเจนเพิ่ม / ลบเด็กใน/instantiateItem() destroyItem()นั่นคือถ้าอะแด็ปเตอร์ของคุณเป็นคลาสย่อยของคลาสย่อยของPagerAdapterคุณต้องใช้ตรรกะนี้

บันทึก Side: จะตระหนักถึงนี้ViewPagerถ้าคุณใช้รายการภายใน


2
ฉันมีปัญหาเดียวกัน แต่กับ FragmentPagerAdapter ซึ่งจัดการ onDestroy ให้ฉัน ไม่มีวิธีแก้ปัญหาอื่นใดที่ใช้ได้ผลเช่นกัน
Greg Ennis

14
สิ่งที่อาจเป็นปัญหาคือมีคนใช้ getFragmentManger แทน GetChildFragmentManager
Boy

@Boy GetChildFragmentManager คืออะไร?
ไฟในหลุม

1
@Boy Wooooow .... ฉันดึงผมออกมาตลอดสองวันพยายามหาสาเหตุว่าทำไมฉันถึงไม่สามารถอัพเดทอะไรได้เลย ขอขอบคุณ! (พวกเขาควรจะแจ้งให้ทราบในเอกสารของ Google จริงๆเพื่อใช้ตัวจัดการส่วนย่อยนั่นไม่ใช่ว่าคุณต้องการผู้จัดการคนอื่น)
user0721090601

@futtetennista ฉันก็ทำเหมือนกัน .. ประสบปัญหานี้ .. ตรวจสอบได้ไหม .. stackoverflow.com/questions/61727835/…
AskQ

55

หากViewPagerตั้งค่าไว้ใน Fragment ด้วย a FragmentPagerAdapterให้ใช้getChildFragmentManager()แทนgetSupportFragmentManager()พารามิเตอร์เพื่อเริ่มต้นFragmentPagerAdapterไฟล์.

mAdapter = new MyFragmentPagerAdapter(getChildFragmentManager());

แทน

mAdapter = new MyFragmentPagerAdapter(getSupportFragmentManager());

2
จับได้ดีดูเหมือนว่าจะแก้ปัญหาของฉันเมื่อใช้ FragmentPagerAdapter
Tobliug

1
ขอบคุณ - มันได้ผล ฉันพยายามบังคับgetItem()ให้FragmentPagerAdapterซึ่งซ้อนอยู่ใน Fragment ที่สร้างขึ้นใหม่
kosiara - Bartosz Kosarzycki

ว้าวงานนี้เหมือนมีเสน่ห์ ฉันเดาว่าปัญหาเกิดจากการขยาย viewpager ในส่วน
Thecarisma

ช่วงเวลาแบบนี้ฉันหวังว่าเราจะปรบมือแบบ Medium เพื่อให้ฉันได้ปรบมือมากกว่า 1,000 ครั้งสำหรับสิ่งนี้ เยี่ยมมากนี่น่าจะเป็นคำตอบที่ยอมรับ
Codelicious

21

ฉันมีปัญหาเดียวกัน แต่จริงๆแล้วฉันได้ทำลายมุมมองใน destroyItem (ฉันคิดว่า) อย่างไรก็ตามปัญหาคือฉันทำลายมันโดยใช้viewPager.removeViewAt(index);insted ของviewPager.removeView((View) object);

ไม่ถูกต้อง:

@Override
public void destroyItem(ViewGroup viewPager, int position, Object object) {
    viewPager.removeViewAt(position);
}

ขวา:

@Override
public void destroyItem(ViewGroup viewPager, int position, Object object) {
    viewPager.removeView((View) object);
}

ขอบคุณสำหรับคำแนะนำ ได้รับการตรวจสอบปัญหามาระยะหนึ่งแล้ว
Moritz

2
สิ่งนี้ใช้ได้ผลสำหรับฉัน แต่คุณรู้ไหมว่าทำไมข้อแรกถึงเป็นปัญหา
HannahMitt

@HannahMitt removeViewAt จะลบมุมมองใดก็ตามที่อยู่ในตำแหน่งนั้น ๆ ภายในรายการลูกปัจจุบันของ ViewPager และเพจอาจถูกเพิ่มไปยัง ViewPager ในลำดับใดก็ได้ (ดังนั้นหน้า 0 อาจอยู่ใน ViewPager ที่ดัชนี 1 หรืออะไรก็ได้) removeView จะวนซ้ำผ่านรายการชายน์และลบอ็อบเจ็กต์ที่ระบุทั้งหมด

2
ไม่ทำงานสำหรับฉัน: ไม่สามารถส่งมุมมองไปยังส่วนย่อยได้ วัตถุในที่นี้คือส่วนย่อย
FRK

viewpager ต้องคงที่?
Kanagalingam

10

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

public int getItemPosition (Object object) { return POSITION_NONE; }

โดยพื้นฐานแล้วจะบอก ViewPager ว่าทุกอย่างมีการเปลี่ยนแปลง (และบังคับให้สร้างอินสแตนซ์ทุกอย่างอีกครั้ง) นั่นเป็นสิ่งเดียวที่ฉันคิดได้จากด้านบนของหัว


1
ใช่ฉันได้อ่านเกี่ยวกับตัวเลือกนี้ในหัวข้อนี้: stackoverflow.com/questions/7263291/… - อย่างไรก็ตามนี่ดูเหมือนวิธีการใช้ค้อนขนาดใหญ่ มันต้องมีวิธีที่สวยหรูกว่านี้แน่ ๆ ? ฉันสงสัยว่ามันเกี่ยวข้องกับการใช้รายการเป็นเพจเจอร์หรือไม่?
Matthias

เป็นวิธีการค้อนขนาดใหญ่เล็กน้อย แต่คุณสามารถแก้ไขได้ เช่นส่งคืนค่าที่ถูกต้องจากวิธีการ
Chris Banes

@ChrisBanes อย่างที่คุณบอกว่าโทรreturn POSITION_NONE;มาforces it to re-instantiate everythingแต่ในกรณีของฉันฉันไม่ต้องการสร้างอินสแตนซ์ทุกอย่างอีกครั้งดังนั้นจะเป็นไปได้ไหมที่จะลบviewโดยไม่ล้างข้อมูลที่มีอยู่ โปรดแจ้งให้เราทราบ
Ritesh Adulkar

คุณคือกลิ่นชีวิต
หน้ากาก 8

2

พยายามแก้ไขปัญหามากเกินไปโดยไม่คาดคิด แต่viewPager.post()ทำงาน

 mAdapter = new NewsVPAdapter(getContext(), articles);
    viewPager.post(new Runnable() {
        @Override
        public void run() {
            viewPager.setAdapter(mAdapter);
        }
    });

1
พระเจ้า. ทำไมไม่มีใครโหวตเรื่องนี้? ฉันมีพฤติกรรมแปลก ๆ เมื่อฉันป้อนชิ้นส่วนอีกครั้งและ viewpager ข้างในไม่แสดงผลตัวเองและการหน่วงเวลาเล็กน้อยเช่นนี้จะช่วยแก้ปัญหาได้จริง!
Fugogugo

0

ไลบรารีการสนับสนุน Android มีกิจกรรมการสาธิตที่มี ViewPager พร้อม ListView ในทุกหน้า คุณควรจะได้ดูและดูว่ามันทำอะไร

ใน Eclipse (พร้อม Android Dev Tools r20):

  1. เลือก New > Android Sample Project
  2. เลือกระดับ API เป้าหมายของคุณ (ขอแนะนำใหม่ล่าสุดที่มี)
  3. เลือก Support4Demos
  4. คลิกขวาที่โปรเจ็กต์แล้วเลือก Android Tools > Add Support Library
  5. เรียกใช้แอพและเลือกFragmentจากนั้นPager

src/com.example.android.supportv4.app/FragmentPagerSupport.javaสำหรับเรื่องนี้ก็คือใน โชคดี!


ขอบคุณ - ฉันจะดูให้! บางทีฉันอาจจะสังเกตเห็นบางสิ่งที่เรากำลังทำผิด
Matthias

0

ฉันพบปัญหานี้และมีปัญหาที่คล้ายกันมาก ฉันถามมันด้วยซ้ำในสแต็กล้น

สำหรับผมในแม่ของแม่ของคนที่มุมมองของฉัน subclassed LinearLayoutและลบล้างโดยไม่ต้องโทรrequestLayout() super.requestLayout()สิ่งนี้ป้องกันonMeasureและไม่ให้onLayoutถูกเรียกใช้บน ViewPager ของฉัน (แม้ว่า hierarchyviewer จะเรียกสิ่งเหล่านี้ด้วยตนเอง) หากไม่มีการวัดจะแสดงเป็นช่องว่างใน ViewPager

ดังนั้นตรวจสอบมุมมองของคุณ ตรวจสอบให้แน่ใจว่าคลาสย่อยจาก View และไม่ลบล้าง requestLayout หรือสิ่งที่คล้ายกัน


0

มีปัญหาเดียวกันซึ่งเป็นสิ่งที่ต้องทำListView(เนื่องจากมุมมองว่างของฉันแสดงขึ้นได้ดีหากรายการว่างเปล่า) ฉันเรียกว่าเพียงแค่ในปัญหาrequestLayout() ListViewตอนนี้ใช้ได้ดี!


0

ฉันพบปัญหาเดียวกันนี้เมื่อใช้ ViewPager และ FragmentStatePagerAdapter ฉันลองใช้ตัวจัดการที่มีความล่าช้า 3 วินาทีเพื่อโทรไม่ถูกต้อง () และ requestLayout () แต่มันไม่ได้ผล สิ่งที่ทำได้คือการรีเซ็ตสีพื้นหลังของ viewPager ดังต่อไปนี้:

MyFragment.java

    private Handler mHandler;
    private Runnable mBugUpdater;

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
            Bundle savedInstanceState) {
        View rootView = new ViewPager(getActivity());
        //...Create your adapter and set it here...

        mHandler = new Handler();
        mBugUpdater = new Runnable(){
            @Override
            public void run() {
                mVp.setBackgroundColor(mItem.getBackgroundColor());
                mHandler = null;
                mBugUpdater = null;
            }           
        };
        mHandler.postDelayed(mBugUpdater,50);

        return rootView;
    }

    @Override
    public void onPause() {
        if(mHandler != null){
            //Remove the callback if it hasn't triggered yet
            mHandler.removeCallbacks(mBugUpdater);
            mHandler = null;
            mBugUpdater = null;
        }
        super.onPause();
     }

0

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

ฉันมี ViewPager ที่ใช้ FragmentStatePagerAdapter ซึ่งเคยมีสองส่วน แต่ฉันได้เพิ่มส่วนที่สามในภายหลัง อย่างไรก็ตามฉันลืมไปว่าขีด จำกัด หน้าจอปิดเริ่มต้นคือ 1 ดังนั้นเมื่อฉันเปลี่ยนไปใช้ส่วนที่สามใหม่ชิ้นแรกจะถูกทำลายจากนั้นสร้างขึ้นใหม่หลังจากเปลี่ยนกลับ ปัญหาคือกิจกรรมของฉันรับผิดชอบในการแจ้งชิ้นส่วนเหล่านี้เพื่อเริ่มต้นสถานะ UI สิ่งนี้เกิดขึ้นกับการทำงานเมื่อวงจรชีวิตของกิจกรรมและส่วนเหมือนกัน แต่ในการแก้ไขฉันต้องเปลี่ยนชิ้นส่วนเพื่อเริ่มต้น UI ของตัวเองในช่วงอายุการใช้งานเริ่มต้น ในตอนท้ายฉันยังเปลี่ยน setOffscreenPageLimit เป็น 2 เพื่อให้ทั้งสามชิ้นส่วนยังคงมีชีวิตอยู่ตลอดเวลา (ปลอดภัยในกรณีนี้เนื่องจากไม่ได้ใช้หน่วยความจำมาก)


-1

ฉันมีปัญหาที่คล้ายกัน ฉันแคชมุมมองเพราะฉันต้องการเพียง 3 มุมมองในViewPager. เมื่อฉันเลื่อนไปข้างหน้าทุกอย่างไม่เป็นไร แต่เมื่อฉันเริ่มเลื่อนไปข้างหลังเกิดข้อผิดพลาดมันขึ้นว่า "มุมมองของฉันมีผู้ปกครองอยู่แล้ว" วิธีแก้ไขคือการลบรายการที่ไม่จำเป็นด้วยตนเอง

@Override
    public Object instantiateItem(ViewGroup container, int position) {
        int localPos = position % SIZE;
        TouchImageView view;
        if (touchImageViews[localPos] != null) {
            view = touchImageViews[localPos];
        } else {
            view = new TouchImageView(container.getContext());
            view.setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT));
            touchImageViews[localPos] = view;
        }
        view.setImageDrawable(mDataModel.getPhoto(position));
        Log.i(IRViewPagerAdpt.class.toString(), "Add view " + view.toString() + " at pos: " + position + " " + localPos);
        if (view.getParent() == null) {
        ((ViewPager) container).addView(view);
    }
        return view;
    }

    @Override
    public void destroyItem(ViewGroup container, int position, Object view) {
        //      ((ViewPager) container).removeView((View) view);
        Log.i(IRViewPagerAdpt.class.toString(), "remove view " + view.toString() + " at pos: " + position);
    }

..................

private static final int SIZE = 3;
private TouchImageView[] touchImageViews = new TouchImageView[SIZE];

-1

สำหรับฉันปัญหากำลังกลับมาที่กิจกรรมหลังจากกระบวนการแอปถูกฆ่า ฉันใช้อะแดปเตอร์เพจเจอร์มุมมองแบบกำหนดเองที่แก้ไขจากแหล่งที่มาของ Android เพจเจอร์มุมมองถูกฝังไว้ในกิจกรรม

โทร viewPager.setCurrentItem(position, true);

(พร้อมแอนิเมชั่น) หลังจากตั้งค่าข้อมูลและดูเหมือนว่า alertDataSetChanged () จะใช้งานได้ แต่หากตั้งค่าพารามิเตอร์เป็นเท็จจะไม่ทำและแฟรกเมนต์ว่างเปล่า นี่เป็นกรณีพิเศษที่อาจช่วยใครบางคนได้


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