[英]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.