簡體   English   中英

Android LoadMore-ListView

[英]Android LoadMore-ListView

我有很多條目的內部數據庫(SQLite)。 因此,我決定在用戶​​開始活動時在列表視圖中加載前20個條目,並且當他向下滾動時,如果還有條目,每次按下按鈕時,他可以加載更多20個條目。

編輯

//onCreate()
acceptedLogs = helper.getLogsRange(0, LOAD_AMOUNT);
        loadedEntriesCounter = LOAD_AMOUNT;

        logAdapter = new LogAdapter(acceptedLogs);
        logRecyclerView.setAdapter(logAdapter);
        logRecyclerView.setHasFixedSize(false);
        linearLayoutManager = new LinearLayoutManager(getContext());
        logRecyclerView.setLayoutManager(linearLayoutManager);




@Override
            public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
                super.onScrolled(recyclerView, dx, dy);
                visibleItemCount = logRecyclerView.getChildCount();
                totalItemCount = logRecyclerView.getLayoutManager().getItemCount();
                int firstVisibleItemPosition = linearLayoutManager.findFirstVisibleItemPosition();
                if (loading) { // boolean set to true if you are already loading and false after you will update adaptor
                    if (totalItemCount > previousTotalCount) {
                        previousTotalCount = totalItemCount;
                    }
                }
                if (!loading && (totalItemCount - visibleItemCount) <= (firstVisibleItemPosition + VISIBLE_THRESHOLD)) {
                    loading = true;
                    List<Log> newLogs = helper.getLogsRange(loadedEntriesCounter, LOAD_AMOUNT);
                    loadedEntriesCounter += LOAD_AMOUNT;
                    logAdapter.logs.addAll(newLogs);
                    logAdapter.notifyDataSetChanged();

                }
            }

加載只會發生! 在哪里必須將加載設置為false?

首先,最好將RecyclerView與Viewholder配合使用,其次,最好在滾動偵聽器上加載數據,並采取一些技巧,例如,您已加載20個項目,然后在滾動列表時滾動列表和滾動至例如可以很好地加載數據。底部的18個項目,您將在此處開始異步任務,滾動到20時,加載將完成,並且列表將更新20個,因此用戶什至看不到何時加載。

mVisibleThreshold = 2 // this is count items to bottom of current list when load will start.

這是我的recyclerview的滾動偵聽器(可以調整為您的listview):

mProductsResultsList.setOnScrollListener(new RecyclerView.OnScrollListener() {
            @Override
            public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
                super.onScrollStateChanged(recyclerView, newState);
            }

            @Override
            public void onScrolled(RecyclerView recyclerView, int dx, int dy) {


                super.onScrolled(recyclerView, dx, dy);
                mVisibleItemCount = mProductsResultsList.getChildCount();
                mTotalItemCount = mProductsResultsLayoutManager.getItemCount();
                mFirstVisibleItem = mProductsResultsLayoutManager.findFirstVisibleItemPosition();

                if (mLoadingInProgress) { // boolean set to true if you are already loading and false after you will update adaptor
                    if (mTotalItemCount > mPreviousTotal) {

                        mPreviousTotal = mTotalItemCount;
                    }
                }
                if (!mLoadingInProgress && (mTotalItemCount - mVisibleItemCount)
                        <= (mFirstVisibleItem + mVisibleThreshold)) {
                    mLoadingInProgress = true;
                        mLastPageRequest++; // current page to load and add
                        // Here you load data and update adapter
                        // if in async task then start it here and set mLoadingInProgress to true and onPostExecute add to list result and make notifyDatasetChanged on adapter then mLoadingInProgress to false.


                }
            }
        });

另一點:請勿在后台任務中觸摸任何視圖(否則,您將卡住主線程),使用RunOnUIThread在onPostExecute中的任務代碼之后進行所有更新和通知。

好的,因為您對此解決方案感興趣,因此可以改善答案:

mLastPageRequest-我用來了解要加載的頁面以及接下來必須加載的頁面的整數,每次使用++遞增1

加載數據后(從數據庫或Web請求中,應將下載的項目添加到列表中)。 當前在我的項目中,我的列表是“ mCategoryProducts”,這是我的適配器mProductsResultsListAdapter。

您所需要做的就是添加您下載的所有下一個項目,以列出您附加到適配器上的內容

mCategoryProducts.addAll(downloadedListProducts); // here you are adding items you just loaded to existing list to the end, 

現在下一個代碼:

public void displayGotResults(){
        if(mCategoryProducts != null){
            if(mProductsResultsListAdapter == null && mLastPageRequest==1){
                mProductsResultsListAdapter = new ProductListRecyclerViewAdapter(this, mCategoryProducts, true);
                mProductsResultsList.setAdapter(mProductsResultsListAdapter);
                mProductsResultsListAdapter.setClickListener(this);
            }else{
                mProductsResultsListAdapter.notifyDataSetChanged();
                //notifyItemInserted(mSearchList.size()-1);
            }
            if(mCategoryProducts.size()>0) {
                mCategoryIsEmptyInfo.setVisibility(View.GONE);
            }else{
                mCategoryIsEmptyInfo.setVisibility(View.VISIBLE);
            }
        }else{
            mCategoryIsEmptyInfo.setVisibility(View.VISIBLE);
        }
    }

在這里,如果適配器尚未初始化,則我們將其創建並附加到列表mCategoryProducts上;否則,如果這是第二次加載,則我們簡單地通知適配器“嘿,新數據來了:)”,其中:

mProductsResultsListAdapter.notifyDataSetChanged();

注意:mCategoryIsEmptyInfo-是無內容顯示時顯示的視圖。

在這里,您是我的自定義適配器,帶有可在活動中處理的點擊的界面)

public class ProductListRecyclerViewAdapter extends RecyclerView.Adapter<ProductListRecyclerViewAdapter.ProductListRecyclerViewHolder> {
    private LayoutInflater mInflater;
    private Context mContext;
    private DrawerLayout mNavigationDrawer;
    private ClickListener mClickListener;
    private LongClickListener mLongClickListener;
    List<ProductModel> navigationData = Collections.emptyList();
    private ImageLoader mImageLoader;
    private VolleyServiceSingleton mVollayService;
    private boolean mShowThumbNail;

    //For animations
    private int mLastPositiion = -1;

    public ProductListRecyclerViewAdapter (Context context, List<ProductModel> navData, boolean showThumbNail){
        mInflater = LayoutInflater.from(context);
        this.navigationData = navData;
        mContext = context;
        mVollayService = VolleyServiceSingleton.getInstance();
        mImageLoader = mVollayService.getImageLoader();
        mShowThumbNail = showThumbNail;
    }


    @Override
    public ProductListRecyclerViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        View view = mInflater.inflate(R.layout.list_item_product, parent, false);
        ProductListRecyclerViewHolder holder = new ProductListRecyclerViewHolder(view);
        return holder;
    }

    @Override
    public void onBindViewHolder(final ProductListRecyclerViewHolder viewHolder, int position) {
        ProductModel currentItem = navigationData.get(position);
        viewHolder.productBrand.setText(currentItem.ManufacturerName);
        viewHolder.productName.setText(currentItem.Name);
        viewHolder.productCode.setText(currentItem.Code);
        viewHolder.productPrice.setText(String.format(mContext.getString(R.string.money_sign), Utils.decimalWithCommas(String.valueOf(currentItem.DealerPrice))));

        if(Constants.SHOW_IMAGE_THUMBNAILS_IN_LIST && mShowThumbNail){
            if(currentItem.CatalogImage != null && currentItem.CatalogImage.contains("http")){
                viewHolder.productThumbnail.setVisibility(View.VISIBLE);
                mImageLoader.get(currentItem.CatalogImage, new ImageLoader.ImageListener() {
                    @Override
                    public void onResponse(ImageLoader.ImageContainer response, boolean isImmediate) {
                        viewHolder.productThumbnail.setImageBitmap(response.getBitmap());
                    }

                    @Override
                    public void onErrorResponse(VolleyError error) {

                    }
                });
            }
        }else{
            viewHolder.productThumbnail.setVisibility(View.GONE);
        }

    }

    public void setAnimation(View viewToAnimate, int position)
    {
        // If the bound view wasn't previously displayed on screen, it's animated
        if (position > mLastPositiion)
        {
            Animation animation = AnimationUtils.loadAnimation(mContext, android.R.anim.slide_in_left);
            viewToAnimate.startAnimation(animation);
            mLastPositiion = position;
        }
    }
    @Override
    public int getItemCount() {
        return navigationData.size();
    }

    public void setClickListener(ClickListener clickListener){
        this.mClickListener = clickListener;
    }
    public void setLongClickListener(LongClickListener lognClickListener){
        this.mLongClickListener = lognClickListener;
    }


    public class ProductListRecyclerViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener, View.OnLongClickListener{
        TextView productBrand;
        TextView productName;
        TextView productCode;
        TextView productPrice;
        ImageView productThumbnail;
        public ProductListRecyclerViewHolder(View itemView) {
            super(itemView);
            productBrand = (TextView) itemView.findViewById(R.id.product_brand);
            productName = (TextView) itemView.findViewById(R.id.product_name);
            productCode = (TextView) itemView.findViewById(R.id.product_code);
            productPrice = (TextView) itemView.findViewById(R.id.product_price);
            productThumbnail = (ImageView) itemView.findViewById(R.id.product_thumbnail);
            itemView.setOnClickListener(this);
            itemView.setTag(this);
            itemView.setOnLongClickListener(this);

        }

        @Override
        public void onClick(View v) {
            if(mClickListener!=null){
                mClickListener.itemClicked(v, getAdapterPosition());
            }
        }

        @Override
        public boolean onLongClick(View v) {
            if(mLongClickListener!=null){
                mLongClickListener.itemLongClicked(v, getAdapterPosition());
            }
            return false;
        }
    }
    public interface ClickListener{
        void itemClicked(View view, int position);
    }

    public interface LongClickListener{
        void itemLongClicked(View view, int position);
    }
}

如果您沒有更新您的需求,它可能將無法工作,但是很好的示例必須是)

注意

mProductsResultsListAdapter.setClickListener(this);

然后在活動中,您可以使用捕獲點擊:

public class ProductListActivity extends ActionBarActivity implements ProductListRecyclerViewAdapter.ClickListener {

    //.....

    @Override
    public void itemClicked(View view, int position) {

    }

    //.....
}

還有一件事情,如果您需要捕獲單擊,例如在列表中項目的特定視圖上(例如在視圖持有者中的圖像上),然后將點擊偵聽器設置為“ this”,並將標簽設置為此視圖,然后在活動中,則可以從視圖獲取標簽您將知道您單擊的位置:)

您的加載來自數據庫:

 loading = true;
                    List<Log> newLogs = helper.getLogsRange(loadedEntriesCounter, LOAD_AMOUNT);
                    loadedEntriesCounter += LOAD_AMOUNT;
                    logAdapter.logs.addAll(newLogs);
 loading = false; // somewhere here 

但這不是最終正確的加載數據的方法,如果數據庫太大,您可能會卡住主線程,因為如果選擇的內容過多,您可能會陷入停滯狀態。 您必須在異步任務中完成所有數據加載,然后在完成任務時通知適配器。

在我的項目中,我從webapi而不是從數據庫中加載數據,但是無論如何必須通過異步任務以相同的方式完成,這是正確的方式)

class LoadNextPageTask extends AsyncTask<Integer, Void, List<ProductModel>> {
        int pageToLoad;

        public LoadNextPageTask(int pageToLoad){
            this.pageToLoad = pageToLoad;
        }


        @Override
        protected List<ProductModel> doInBackground(Integer... params) {
            return helper.getLogsRange(loadedEntriesCounter, LOAD_AMOUNT); // here apply page to load??? not sure
        }

        @Override
        protected void onPreExecute() {
            mMainLoadingProgress.setVisibility(View.VISIBLE);
            loading = true;
        }

        @Override
        protected void onPostExecute(List<ProductModel> newLogs) {
            loading = false;
            loadedEntriesCounter += LOAD_AMOUNT;
            logAdapter.logs.addAll(newLogs);

            runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    logAdapter.notifyDataSetChanged();
                }
            });
            mMainLoadingProgress.setVisibility(View.GONE);

        }
    }

上面是一個異步任務,請更新您的需求,然后從簡單的數據加載開始:

new LoadNextPageTask(pagenumber).execute(); // page is int

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM