Android LoadMore-ListView

时间:2016-05-25 00:05:21

标签: android sql database listview load

我有一个包含许多条目的内部数据库(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();

                }
            }

加载只发生一次!我在哪里设置加载假?

1 个答案:

答案 0 :(得分:1)

首先,最好使用带有viewholder的RecyclerView,其次你最好在滚动侦听器上加载数据和一些技巧,例如你已经加载了20个项目然后滚动列表时滚动列表并滚动到列表时加载数据会很好例如,在底部的18项,这里你开始你的异步任务,当你滚动到20你的加载将完成,你将更新列表20多,所以用户甚至不会看到你加载。

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

这是我的回滚视图滚动监听器(可以调整到你的列表视图):

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 - int我用来知道我加载了哪个页面,然后我必须加载哪个页面,每次用++递增1

加载数据后(从数据库或Web请求中,您应该将下载的项目添加到列表中)。 目前在我的项目中,我的列表是&#34; mCategoryProducts&#34;这是我的适配器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,否则如果这是第二次加载,那么我们简单地通知适配器&#34;嘿man new data is comeing :)&#34;用:

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) {

    }

    //.....
}

如果您需要在列表中的项目中的特定视图上捕获点击,例如在视图持有者中的图像上,然后将点击监听器设置为&#34;此&#34;并将标记设置为此视图,然后在活动中,您可以从视图中获取标记,并且您将知道单击的位置:)

您的加载来自数据库:

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

但是这并不是最终正确的加载数据的方法,如果数据库太大或者你会使'#34; heavy&#34;选择你可以卡住几个milisec。你必须在异步任务中加载所有数据,然后在任务完成通知适配器上。

在我的项目中我从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