รายการไม่มีที่สิ้นสุดของ Android


232

ฉันจะสร้างรายการที่เมื่อคุณมาถึงจุดสิ้นสุดของรายการที่ฉันได้รับแจ้งเพื่อให้ฉันสามารถโหลดรายการเพิ่มเติมได้อย่างไร


9
ผมขอแนะนำให้ EndlessAdapter CommonWare ของ: github.com/commonsguy/cwac-endless ผมพบว่ามันมาจากคำตอบนี้คำถามอื่น: stackoverflow.com/questions/4667064/...
Tyler Collier

ฉันต้องการสิ่งเดียวกัน .. สามารถช่วยเหลือคนอื่นได้บ้าง .. stackoverflow.com/questions/28122304/…

คำตอบ:


269

ทางออกหนึ่งคือการใช้OnScrollListenerและทำการเปลี่ยนแปลง (เช่นการเพิ่มรายการ ฯลฯ ) ไปยังสถานะListAdapterที่สะดวกในonScrollวิธีการ

ต่อไปนี้ListActivityจะแสดงรายการของจำนวนเต็มเริ่มต้นด้วย 40 เพิ่มรายการเมื่อผู้ใช้เลื่อนไปที่ส่วนท้ายของรายการ

public class Test extends ListActivity implements OnScrollListener {

    Aleph0 adapter = new Aleph0();

    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setListAdapter(adapter); 
        getListView().setOnScrollListener(this);
    }

    public void onScroll(AbsListView view,
        int firstVisible, int visibleCount, int totalCount) {

        boolean loadMore = /* maybe add a padding */
            firstVisible + visibleCount >= totalCount;

        if(loadMore) {
            adapter.count += visibleCount; // or any other amount
            adapter.notifyDataSetChanged();
        }
    }

    public void onScrollStateChanged(AbsListView v, int s) { }    

    class Aleph0 extends BaseAdapter {
        int count = 40; /* starting amount */

        public int getCount() { return count; }
        public Object getItem(int pos) { return pos; }
        public long getItemId(int pos) { return pos; }

        public View getView(int pos, View v, ViewGroup p) {
                TextView view = new TextView(Test.this);
                view.setText("entry " + pos);
                return view;
        }
    }
}

คุณควรใช้เธรดแยกต่างหากสำหรับการดำเนินการที่ต้องใช้เวลานาน (เช่นการโหลดเว็บข้อมูล) และอาจต้องการระบุความคืบหน้าในรายการสุดท้าย (เช่นตลาดหรือแอพ gmail)


3
ฮะสิ่งนี้จะไม่เรียกขนาดอะแดปเตอร์เพิ่มขึ้นหรือไม่ถ้าคุณหยุดเลื่อนตรงกลางหน้าจอ มันควรโหลด 10 ถัดไปเมื่อมาถึงด้านล่างสุดของรายการ
Matthias

9
ฉันสังเกตเห็นตัวอย่างมากมายเช่นนี้โดยใช้ BaseAdapter ต้องการพูดถึงว่าถ้าคุณใช้ฐานข้อมูลลองใช้ SimpleCursorAdapter เมื่อคุณต้องการเพิ่มลงในรายการอัพเดตฐานข้อมูลของคุณรับเคอร์เซอร์ใหม่และใช้ SimpleCursorAdapter # changeCursor พร้อมกับ informDataSetChanged ไม่ต้องมีคลาสย่อยและทำงานได้ดีกว่า BaseAdapter (อีกครั้งเฉพาะเมื่อคุณใช้ฐานข้อมูล)
brack

1
หลังจากโทรไปที่ AlertDataSetChanged () จะไปอยู่ด้านบนของรายการฉันจะป้องกันได้อย่างไร
วาด

2
หมายเหตุ - ฉันใช้วิธีการนี้ แต่จำเป็นต้องเพิ่มการตรวจสอบเมื่อ visibleCount เป็น 0 สำหรับแต่ละรายการฉันได้รับหนึ่งการเรียกกลับไปยัง onScroll โดยที่ firstVisible, visibleCount และ totalCount ทั้งหมด 0 ซึ่งตรงตามเงื่อนไขทางเทคนิค แต่ไม่ใช่ เมื่อฉันต้องการโหลดเพิ่มเติม
Eric Mill

5
ปัญหาอีกประการของรหัสนี้คือเงื่อนไขfirstVisible + visibleCount >= totalCountตรงตามหลายครั้งด้วยการเรียกหลายครั้งไปยังผู้ฟัง หากฟังก์ชั่นโหลดมากขึ้นเป็นคำขอของเว็บ (ส่วนใหญ่จะเป็นฟังก์ชั่น) ให้เพิ่มการตรวจสอบอีกครั้งว่ามีคำขอเกิดขึ้นหรือไม่ ในอีกทางหนึ่งตรวจสอบว่าจำนวนรวมไม่เท่ากับจำนวนรวมก่อนหน้าเนื่องจากเราไม่ต้องการคำขอหลายรายการสำหรับจำนวนรายการเดียวกันในรายการ
Subin Sebastian

94

แค่ต้องการมีส่วนร่วมในการแก้ปัญหาที่ฉันใช้กับแอพ

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

  1. ให้ListFragmentหรือListActivityใช้ของคุณOnScrollListener
  2. เพิ่มวิธีการต่อไปนี้ลงในคลาสนั้น:

    @Override
    public void onScroll(AbsListView view, int firstVisibleItem,
            int visibleItemCount, int totalItemCount) {
        //leave this empty
    }
    
    @Override
    public void onScrollStateChanged(AbsListView listView, int scrollState) {
        if (scrollState == SCROLL_STATE_IDLE) {
            if (listView.getLastVisiblePosition() >= listView.getCount() - 1 - threshold) {
                currentPage++;
                //load more list items:
                loadElements(currentPage);
            }
        }
    }
    

    โดยที่currentPageหน้าของแหล่งข้อมูลของคุณที่ควรถูกเพิ่มลงในรายการของคุณและthresholdเป็นจำนวนรายการ (นับจากตอนท้าย) ที่ควรจะเรียกกระบวนการโหลดหากมองเห็นได้ ถ้าคุณตั้งค่าthresholdไป0ตัวอย่างเช่นผู้ใช้มีการเลื่อนไปที่ปลายสุดของรายการเพื่อโหลดรายการอื่น ๆ

  3. (ไม่บังคับ) ดังที่คุณเห็น "การตรวจสอบโหลดมากขึ้น" จะถูกเรียกเมื่อผู้ใช้หยุดเลื่อน listView.addFooterView(yourFooterView)เพื่อปรับปรุงการใช้งานคุณอาจขยายและเพิ่มตัวบ่งชี้ที่โหลดไปยังจุดสิ้นสุดของรายการผ่านทาง ตัวอย่างหนึ่งสำหรับมุมมองส่วนท้ายดังกล่าว:

    <?xml version="1.0" encoding="utf-8"?>
    
    <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:id="@+id/footer_layout"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:padding="10dp" >
    
        <ProgressBar
            android:id="@+id/progressBar1"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_centerVertical="true"
            android:layout_gravity="center_vertical" />
    
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_centerVertical="true"
            android:layout_toRightOf="@+id/progressBar1"
            android:padding="5dp"
            android:text="@string/loading_text" />
    
    </RelativeLayout>
    
  4. (ไม่บังคับ)สุดท้ายลบตัวบ่งชี้การโหลดนั้นโดยการโทรlistView.removeFooterView(yourFooterView)หากไม่มีรายการหรือหน้า


ฉันลองสิ่งนี้ แต่มันใช้ไม่ได้กับ ListFragment มันสามารถใช้ใน ListFragment ได้อย่างไร
zeeshan

ดีฉันใช้มันด้วยListFragmentเช่นกันโดยไม่มีปัญหา - เพียงทำตามแต่ละขั้นตอนข้างต้นและคุณจะสบายดี;) หรือคุณสามารถให้ข้อความแสดงข้อผิดพลาด?
saschoar

สิ่งที่คุณอาจพลาดได้อธิบายไว้ในคำตอบ SO นี้: stackoverflow.com/a/6357957/1478093 -getListView().setOnScrollListener(this)
TBieniek

7
หมายเหตุ: การเพิ่มและลบส่วนท้ายของ listview นั้นเป็นปัญหา (ส่วนท้ายไม่ปรากฏขึ้นหากเรียกว่า setAdapter ก่อนเพิ่มส่วนท้าย) ฉันสิ้นสุดการแก้ไขการมองเห็นส่วนท้ายของมุมมองโดยตรงโดยไม่ลบออก
dvd

สิ่งที่ต้องเพิ่มใน loadElements (currentPage) ??? ฉันหมายความว่าฉันเรียก AsyncTask หรือเธรดของฉัน
android_developer

20

คุณสามารถตรวจสอบท้ายของรายการด้วยความช่วยเหลือของonScrollListenerรหัสการทำงานจะนำเสนอดังต่อไปนี้:

@Override
public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
    if (view.getAdapter() != null && ((firstVisibleItem + visibleItemCount) >= totalItemCount) && totalItemCount != mPrevTotalItemCount) {
        Log.v(TAG, "onListEnd, extending list");
        mPrevTotalItemCount = totalItemCount;
        mAdapter.addMoreData();
    }
}

อีกวิธีในการทำเช่นนั้น (อะแดปเตอร์ภายใน) มีดังต่อไปนี้:

    public View getView(int pos, View v, ViewGroup p) {
            if(pos==getCount()-1){
                addMoreData(); //should be asynctask or thread
            }
            return view;
    }

addMoreData()โปรดทราบว่าวิธีการนี้จะถูกเรียกว่าหลายครั้งดังนั้นคุณจำเป็นต้องเพิ่มเงื่อนไขอื่นเพื่อป้องกันการหลายสายของ

เมื่อคุณเพิ่มองค์ประกอบทั้งหมดลงในรายการโปรดโทรinformDataSetChanged ()ภายในอะแดปเตอร์ของคุณเพื่ออัปเดตมุมมอง (ควรเรียกใช้บนเธรด UI - runOnUiThread )


7
มันเป็นเรื่องที่ดีที่จะทำสิ่งอื่น ๆ getViewนอกเหนือจากมุมมองกลับมาใน ตัวอย่างเช่นคุณไม่รับประกันว่าposผู้ใช้จะดู มันอาจเป็นเพียงเครื่องมือวัด ListView
โทมัส Ahle

ฉันต้องการโหลดรายการเพิ่มเติมหลังจากเลื่อนไป 10 รายการ แต่ฉันสังเกตเห็นว่าการโหลดเริ่มต้นก่อนที่รายการที่ 10 จะปรากฏให้เห็นในรายการที่ 9 วิธีการหยุดนี้
Atul Bhardwaj

4

ที่Ognyan Bankov GitHubฉันพบวิธีที่ง่ายและทำงาน!

มันทำให้การใช้งานVolley HTTP libraryที่ทำให้เครือข่ายสำหรับแอพ Android ง่ายขึ้นและที่สำคัญที่สุดคือเร็วขึ้น วอลเล่ย์มีให้บริการผ่านที่เก็บ AOSP แบบเปิด

รหัสที่กำหนดแสดงให้เห็นถึง:

  1. ListView ซึ่งถูกเติมข้อมูลด้วยคำร้องขอ HTTP paginated
  2. การใช้งาน NetworkImageView
  3. Listless "Endless" แบ่งหน้าดูด้วยการอ่านล่วงหน้า

สำหรับความมั่นคงในอนาคตฉันคดเคี้ยว repo


2

นี่คือวิธีการแก้ปัญหาที่ทำให้การแสดงมุมมองการโหลดในตอนท้ายของ ListView ง่ายขึ้นในขณะที่กำลังโหลด

คุณสามารถดูชั้นเรียนได้ที่นี่:

https://github.com/CyberEagle/OpenProjects/blob/master/android-projects/widgets/src/main/java/br/com/cybereagle/androidwidgets/helper/ListViewWithLoadingIndicatorHelper.java - ช่วยให้สามารถใช้งานได้ ฟีเจอร์โดยไม่ต้องขยายจาก SimpleListViewWithLoadingIndicator

https://github.com/CyberEagle/OpenProjects/blob/master/android-projects/widgets/src/main/java/br/com/cybereagle/androidwidgets/listener/EndlessScrollListener.java - ผู้ฟังที่เริ่มโหลดข้อมูลเมื่อผู้ใช้ ใกล้จะถึงด้านล่างของ ListView

https://github.com/CyberEagle/OpenProjects/blob/master/android-projects/widgets/src/main/java/br/com/cybereagle/androidwidgets/view/SimpleListViewWithLoadingIndicator.java - The EndlessListView คุณสามารถใช้คลาสนี้โดยตรงหรือขยายออกไป


1

อาจจะช้าไปหน่อย แต่วิธีแก้ปัญหาต่อไปนี้เกิดขึ้นมีประโยชน์มากในกรณีของฉัน ในทุกสิ่งที่คุณต้องทำคือเพิ่มใน ListView ของคุณFooterและสร้างมันaddOnLayoutChangeListenerขึ้นมา

http://developer.android.com/reference/android/widget/ListView.html#addFooterView(android.view.View)

ตัวอย่างเช่น:

ListView listView1 = (ListView) v.findViewById(R.id.dialogsList); // Your listView
View loadMoreView = getActivity().getLayoutInflater().inflate(R.layout.list_load_more, null); // Getting your layout of FooterView, which will always be at the bottom of your listview. E.g. you may place on it the ProgressBar or leave it empty-layout.
listView1.addFooterView(loadMoreView); // Adding your View to your listview 

...

loadMoreView.addOnLayoutChangeListener(new View.OnLayoutChangeListener() {
    @Override
    public void onLayoutChange(View v, int left, int top, int right, int bottom, int oldLeft, int oldTop, int oldRight, int oldBottom) {
         Log.d("Hey!", "Your list has reached bottom");
    }
});

เหตุการณ์นี้จะเริ่มขึ้นเมื่อมีส่วนท้ายปรากฏให้เห็นและใช้งานได้อย่างมีเสน่ห์


0

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

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

นี่คือที่อยู่: https://github.com/SphiaTower/AutoPagerRecyclerManager


ลิงก์เสีย
DSlomer64

0

ทางออกที่ดีที่สุดที่ฉันได้เห็นคือในไลบรารีFastAdapterสำหรับมุมมองของนักรีไซเคิล EndlessRecyclerOnScrollListenerแต่ก็มี

นี่คือตัวอย่างการใช้งาน: EndlessScrollListActivity

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


0

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

ความนับถือ.

listView.setOnScrollListener(new OnScrollListener() {

    @Override
    public void onScrollStateChanged(AbsListView view, int scrollState) {
        // TODO Auto-generated method stub
        if(scrollState == SCROLL_STATE_IDLE) {
            if(footerView.isShown()) {
                bottomView.setVisibility(LinearLayout.INVISIBLE);
            } else {
                bottomView.setVisibility(LinearLayout.VISIBLE);
            } else {
                bottomView.setVisibility(LinearLayout.INVISIBLE);
            }
        }
    }

    @Override
    public void onScroll(AbsListView view, int firstVisibleItem,
            int visibleItemCount, int totalItemCount) {

    }
});

0

ฉันรู้ว่ามันเป็นคำถามเก่าและโลก Android ได้ย้ายไปที่ RecyclerViews เป็นส่วนใหญ่ แต่สำหรับใครที่สนใจคุณอาจพบว่าห้องสมุดนี้น่าสนใจมาก

มันใช้ BaseAdapter ที่ใช้กับ ListView เพื่อตรวจสอบเมื่อรายการถูกเลื่อนไปยังรายการสุดท้ายหรือเมื่อมันถูกเลื่อนออกไปจากรายการสุดท้าย

มันมาพร้อมกับโครงการตัวอย่าง (รหัสกิจกรรมเกือบ 100 บรรทัด) ที่สามารถใช้เพื่อให้เข้าใจได้อย่างรวดเร็วว่าทำงานอย่างไร

การใช้งานง่าย:

class Boy{

private String name;
private double height;
private int age;
//Other code

}

อะแดปเตอร์สำหรับเก็บวัตถุ Boy จะมีลักษณะดังนี้:


public class BoysAdapter extends EndlessAdapter<Boy>{




        ViewHolder holder = null;


        if (convertView == null) {
            LayoutInflater inflater = LayoutInflater.from(parent
                    .getContext());

            holder = new ViewHolder();

            convertView = inflater.inflate(
                    R.layout.list_cell, parent, false);


            holder.nameView = convertView.findViewById(R.id.cell);

            // minimize the default image.
            convertView.setTag(holder);
        } else {
            holder = (ViewHolder) convertView.getTag();
        }

        Boy boy = getItem(position);

        try {
            holder.nameView.setText(boy.getName());

            ///Other data rendering codes.

        } catch (Exception e) {
            e.printStackTrace();
        }

        return super.getView(position,convertView,parent);

}

ขอให้สังเกตว่าวิธีการ GetView ของ BoysAdapter ส่งกลับการเรียกไปยังgetViewวิธีการของ EndlessAdapter superclass นี่เป็นสิ่งที่จำเป็น 100%

ตอนนี้เพื่อสร้างอะแดปเตอร์ทำ:

   adapter = new ModelAdapter() {
            @Override
            public void onScrollToBottom(int bottomIndex, boolean moreItemsCouldBeAvailable) {

                if (moreItemsCouldBeAvailable) { 
                    makeYourServerCallForMoreItems();
                } else {
                    if (loadMore.getVisibility() != View.VISIBLE) {
                        loadMore.setVisibility(View.VISIBLE);
                    }
                }
            }

            @Override
            public void onScrollAwayFromBottom(int currentIndex) { 
                loadMore.setVisibility(View.GONE);
            }

            @Override
            public void onFinishedLoading(boolean moreItemsReceived) { 
                if (!moreItemsReceived) {
                    loadMore.setVisibility(View.VISIBLE);
                }
            }
        };

loadMoreรายการเป็นปุ่มหรือองค์ประกอบ UI อื่น ๆ ที่อาจต้องคลิกเพื่อดึงข้อมูลเพิ่มเติมจาก URL เมื่อวางไว้ตามที่อธิบายไว้ในรหัสอะแดปเตอร์รู้ว่าเมื่อใดที่จะแสดงปุ่มนั้นและเมื่อต้องการปิดใช้งาน เพียงแค่สร้างปุ่มใน xml ของคุณและวางไว้ตามที่แสดงในรหัสอะแดปเตอร์ด้านบน

สนุก.

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