ListView分页加载数据

ListView分页加载数据

ListView分页加载 在Android中是一个经常用到的技术,当我们需要加载大量的数据到列表显示时,假如一次性把所有数据加载完毕,可能会导致整个ListView列表卡顿,给用户的体验也非常不好。因而,我们可以将数据分为多次加载,每次加载其中的一部分,用户有需求的时候再加载其他部分,这样的设计会更加友好。

ListView分页原理

在日常开发中,我们可能会遇到以下两种情况:

  • 服务器支持分页请求,简单地说,比如,我们总共要请求100条数据,服务器支持我们每次请求N条数据,我们可以分100 / N 次请求完成,并且这些数据有一定的顺序,我们想请求第几页的数据就可以请求第几页的数据(这种情况下,我们可以实现真正的分页加载数据)。
  • 服务器不支持分布请求,我们没办法请求指定页的数据,只能一次性请求所有数据(这种情况下,我们只能自己处理,每次加载相应数目数据到ListView中)。

那么ListView分页原理就是,我们不一次性加载所有的数据,每次加载N条,然后我们监听ListView的滚动事件,当ListView滚动到最底部时,判定当前是否已加载完所有数据,如果未加载完毕,请求新一页的数据,直至所有的数据加载完成。

Demo实现

一般情况下,我们需要请求服务器的数据,但是这里我们只是要达到ListView分页加载的效果,我们自己模拟数据加载过程。
首先是我们的主页面MainActivity,其对应的页面文件activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
    <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context="com.hotzhi.listviewtest.MainActivity">

    <ListView
        android:id="@+id/lv_data"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:fastScrollEnabled="false"
        android:smoothScrollbar="true"
        android:cacheColorHint="#00000000"
        android:divider="#ffcccccc"
        android:dividerHeight="0.2dp" />

</RelativeLayout>

这里没啥好介绍的,就只是一个ListView。接下来是,我们将ListView拖动到底部时,如果要加载新的数据,那么我们可以添加一个footerView,以更好的提示用户,下面是其布局文件,foot_view.xml

<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:background="#ffffff" >

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:baselineAligned="true"
        android:gravity="center|center_vertical"
        android:orientation="horizontal"
        android:paddingBottom="15dp"
        android:paddingTop="15dp" >

        <ProgressBar
            android:id="@+id/progressBar_id"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center_vertical"
            android:gravity="center"
            style="?android:attr/progressBarStyleSmall"
            android:paddingBottom="2dp"
            android:paddingTop="2dp" />

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center_vertical"
            android:layout_marginLeft="10dp"
            android:gravity="center"
            android:text="加载更多中……"
            android:textSize="13sp" />
    </LinearLayout>

</FrameLayout>

也非常简单,就一个加载框,然后一个提示文本。
下面就是我们的具体实现了,MainActivity.java

package com.hotzhi.listviewtest;

import android.os.Bundle;
import android.os.Message;
import android.support.v7.app.AppCompatActivity;
import android.view.LayoutInflater;
import android.widget.AbsListView;
import android.widget.ArrayAdapter;
import android.widget.FrameLayout;
import android.widget.ListView;
import android.widget.Toast;

import java.util.ArrayList;
import java.util.List;

public class MainActivity extends AppCompatActivity {

    /** 列表翻页每页加载数目 */
    private static final int ONE_PAGE_ITEM_COUNT = 20;
    // 由于这里是测试数据,我们自己控制所有数据请求的结束位置,也就是页数达到MAX_PAGE无法再次请求数据。
    /** 最大页数(测试) */
    private static final int MAX_PAGE = 8;

    private List<String> lstData = new ArrayList<>();
    private ArrayAdapter<String> mAdapter;
    private ListView lvData;

    /** 当前页码 */
    public int iCurPageIndex = 0;
    /** 列表第一项 */
    private int firstItem;
    /** 列表可见项 */
    private int visibleItem;
    /** 列表可见项 */
    private int totalItem;
    /** 是否可以上拉 */
    private boolean canUpPull = true;
    /** 是否正在加载 */
    private boolean isLoading = false;
    /** 页脚布局 */
    private FrameLayout mFooterView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        findViews();
        setListeners();
        initData();

    }

    private void findViews() {
        lvData = (ListView) findViewById(R.id.lv_data);
        mFooterView = (FrameLayout) LayoutInflater.from(this).inflate(R.layout.foot_view, null);
    }

    private void setListeners() {
        lvData.setOnScrollListener(onScrollListener);
    }

    private void initData() {
        requestData();
    }

    /**
     * ListView滚动监听器
     */
    private AbsListView.OnScrollListener onScrollListener = new AbsListView.OnScrollListener() {
        @Override
        public void onScrollStateChanged(AbsListView view, int scrollState) {

            if (firstItem + visibleItem == totalItem) {

                // 当前处于不可上拉加载状态,不可继续请求数据
                if(!canUpPull) {
                    return ;
                }

                // 数据正在加载,不可继续请求
                if(isLoading) {
                    return ;
                }

                lvData.addFooterView(mFooterView);
                lvData.setSelection(lvData.getBottom());
                isLoading = true;
                iCurPageIndex++;
                requestData();
            }
        }

        @Override
        public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
            firstItem = firstVisibleItem;
            visibleItem = visibleItemCount;
            totalItem = totalItemCount;
        }
    };

    /**
     * 请求加载更多数据
     * 如,请求服务器数据
     */
    private void requestData() {

        // 这里我们休眠3秒钟,相当于3秒钟后数据才加载完毕
        // 当然我们在实际项目中可能不需要休眠处理,直接请求数据等待数据返回即可。
        new Thread() {
            public void run() {
                try {
                    Thread.sleep(3000);
                    // 主线程中加载数据
                    handler.sendEmptyMessage(0);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }.start();

    }

    private android.os.Handler handler = new android.os.Handler() {
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);

            // 加载数据
            // 加载第iCurPageIndex页数据
            for(int i = iCurPageIndex * ONE_PAGE_ITEM_COUNT; i < (iCurPageIndex + 1) * ONE_PAGE_ITEM_COUNT; i++) {
                lstData.add("第" + i + "条数据");
            }

            // 数据加载完毕设置相应标志
            isLoading = false;
            canUpPull = true;
            lvData.removeFooterView(mFooterView);

            // 这里我们通过判断加载页位置与最大可加载页比较判断,是否已加载完所有数据
            if(iCurPageIndex >= MAX_PAGE) {
                canUpPull = false;
                if(iCurPageIndex > 0) {
                    Toast.makeText(MainActivity.this, "已到达最后一页!", Toast.LENGTH_SHORT).show();
                }
            }

            if(mAdapter == null) {
                mAdapter = new ArrayAdapter<String>(MainActivity.this, android.R.layout.simple_list_item_1, android.R.id.text1, lstData);
                lvData.setAdapter(mAdapter);
            } else {
                mAdapter.notifyDataSetChanged();
            }
        }
    };
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值