自定义安卓实现数据分页功能
- 1、分页实现原理
- 2、基于tableView实现的数据展示。
- 3、具体实现效果展示:
- 最近基于客户要求做了个手持安卓端的软件,主要是用于数据和相关信息的查看功能。开始由于数据较少,查看的数据都是用的滚屏展示的,后来因为数据量大、经常要加载很久。所以要求实现分页。
1、分页实现原理
-
博主在网上看了比较多的分页模板、大致套路总结有两个思路:
-
(1)一步到位、一次性返回所有数据:将数据在后台封装好、类似于前端数据展示一样、用PageInfo进行封装数据,然后返回到前端。安卓端也相当于是一个前端,此方法相当于一步到位、一次请求返回所有数据,剩下的数据解析翻页啥就交给安卓端搞定了。
-
(2)单独请求每页数据、实时更新:后台编写个获取数据的接口。通过安卓端每次点击下一页发送一个http请求、携带页数参数。对应返回相应页数的一部分数据。相当于每次翻页都会单独发送请求返回数据。个人觉得对于数据实时增删要求较高切服务器压力不大可选用此类方法。
-
由于博主主要只需展示数据、未用到增删,考虑到每次分页都发请求可能会增加服务器压力,那就选用一次性到位的方法吧。而且分页展示用的是自定义的TableView,所以一切都是自己写的。以下是我自己写的一个分页demo、可能不套用、仅供提供思路参考!看看我的效果图吧、非专业UI界面有点丑、哈哈
2、基于tableView实现的数据展示。
- 自定义的TableView:
public class TableView extends HorizontalScrollView {
}
//此处省略一万字,完整版请点最底下链接! 因为都是自定义的!仅提供思路!如想copy博主界面demo的可点最下方链接下载!
- 自定义分页插件: 后台直接返回的是JSONArray,此工具类作用就是解析后台返回的数据,定义一个pageBean封装每页的数据。下面写了三种数据格式、分别是List<String[]> 、 JSONArray、 List 。可根据自己需求增改!
PageUtils
public class PageUtils {
private JSONArray currentJsonArray;
private List<String[]> stringList;
public void setData(JSONArray currentJsonArray, List<String[]> stringList){
this.currentJsonArray = currentJsonArray;
this.stringList = stringList;
}
public static PageBean getPageData(JSONArray currentJsonArray, int pageMax){
if(null == currentJsonArray || 0 == currentJsonArray.size()){
return null;
}
int everyPageLimit = pageMax -1;
PageBean pageData = new PageBean();
int cort = currentJsonArray.size() % everyPageLimit;
int sort = currentJsonArray.size() / everyPageLimit;
int pages = cort == 0 ? sort:sort+1;
pageData.setPages(pages); //总页数
HashMap<Integer, List<Object>> jsonPage = new HashMap<>();
for(int i=0; i<pages; i++){
List<Object> json = new LinkedList<>();
if((i + 1)* everyPageLimit > currentJsonArray.size()){
json = currentJsonArray.subList(i * (everyPageLimit), currentJsonArray.size());
}else{
json = currentJsonArray.subList(i * (everyPageLimit), ((i + 1)* (everyPageLimit)));
}
jsonPage.put(i+1, json);
}
pageData.setJsonPage(jsonPage);
return pageData;
}
public static PageBean getPageArrayData(List<HashMap> currentJsonArray, int pageMax){
if(null == currentJsonArray || 0 == currentJsonArray.size()){
return null;
}
PageBean pageData = new PageBean();
int everyPageLimit = pageMax - 1;
int cort = currentJsonArray.size() % everyPageLimit;
int sort = currentJsonArray.size() / everyPageLimit;
int pages = cort == 0 ? sort:sort+1;
pageData.setPages(pages); //总页数
HashMap<Integer, List<HashMap>> jsonPage = new HashMap<>();
for(int i=0; i<pages; i++){
List<HashMap> json = new LinkedList<>();
if((i + 1)* everyPageLimit >= currentJsonArray.size()){
json = currentJsonArray.subList(i * (everyPageLimit), currentJsonArray.size());
}else{
json = currentJsonArray.subList(i * (everyPageLimit), ((i + 1)* (everyPageLimit)));
}
jsonPage.put(i+1, json);
}
pageData.setMapPage(jsonPage);
return pageData;
}
public static PageBean getPageData(List<String[]> currentJsonArray, int pageMax){
if(null == currentJsonArray || 0 == currentJsonArray.size()){
return null;
}
int everyPageLimit = pageMax -1;
PageBean pageData = new PageBean();
int cort = currentJsonArray.size() % everyPageLimit;
int sort = currentJsonArray.size() / everyPageLimit;
int pages = cort == 0 ? sort:sort+1;
pageData.setPages(pages); //总页数
HashMap<Integer, List<String[]>> jsonPage = new HashMap<>();
for(int i=0; i<pages; i++){
List<String[]> json = new LinkedList<>();
if((i + 1)* everyPageLimit >= currentJsonArray.size()){
json = currentJsonArray.subList(i * (everyPageLimit), currentJsonArray.size());
}else{
json = currentJsonArray.subList(i * (everyPageLimit), ((i + 1)* (everyPageLimit)));
}
jsonPage.put(i+1, json);
}
pageData.setStringPage(jsonPage);
return pageData;
}
}
Pagebean
public class PageBean {
private int pages; //当前页数
//当前页的数据
private HashMap<Integer, List<String[]>> stringPage ;
private HashMap<Integer, List<Object>> jsonPage ;
private HashMap<Integer, List<HashMap>> mapPage ;
public HashMap<Integer, List<HashMap>> getMapPage() {
return mapPage;
}
public void setMapPage(HashMap<Integer, List<HashMap>> mapPage) {
this.mapPage = mapPage;
}
public int getPages() {
return pages;
}
public void setPages(int pages) {
this.pages = pages;
}
public HashMap<Integer, List<String[]>> getStringPage() {
return stringPage;
}
public void setStringPage(HashMap<Integer, List<String[]>> stringPage) {
this.stringPage = stringPage;
}
public HashMap<Integer, List<Object>> getJsonPage() {
return jsonPage;
}
public void setJsonPage(HashMap<Integer, List<Object>> jsonPage) {
this.jsonPage = jsonPage;
}
}
3、具体实现效果展示:
public class AreaCtrlDetailActivity extends Activity {
private JSONArray resultJson ;
private boolean flag = false;
private TextView title;
private String areaType;
private String deptId;
String[] dataP ;
HashMap<String, JSONObject> allAreaRollCallMap = new HashMap<>();
private LinearLayout tableLayout;
PageBean pageData = new PageBean();
private int curPage = 1;
int maxPage = 1;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);
setContentView(R.layout.demo_detail_list);
tableLayout = findViewById(R.id.tableBody);
getActionBar().show();
getActionBar().setBackgroundDrawable(ContextCompat.getDrawable(getApplicationContext(), R.drawable.bg));
getActionBar().setTitle("区域详情");
dataP = getIntent().getStringArrayExtra("rowData");
areaType = getIntent().getStringExtra(Constants.Param.AREA_TYPE);
deptId = getIntent().getStringExtra(Constants.Param.DEPT_ID);
freshPanel();
initTableView();
}
private void freshPanel() {
new Thread(new Runnable() {
@Override
public void run() {
getGlobalData();
}
}).start();
}
private synchronized void initTableView() {
if (!flag){
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
if(null != pageData) {
refreshPanel(pageData.getJsonPage().get(curPage));
maxPage = pageData.getPages();
}else{
CommonCode.showMessage(AreaCtrlDetailActivity.this, "未查询到数据");
finish();
}
}
public void onQueryAddPageButtonClicked(View v){
if(curPage >= maxPage){
CommonCode.showMessage(AreaCtrlDetailActivity.this, "已到最后一页");
}else{
curPage++;
runOnUiThread(()->refreshPanel(pageData.getJsonPage().get(curPage)));
}
}
public void onQueryReducePageButtonClicked(View v){
if(curPage == 1){
CommonCode.showMessage(AreaCtrlDetailActivity.this, "已到首页");
}else{
curPage --;
runOnUiThread(()->refreshPanel(pageData.getJsonPage().get(curPage)));
}
}
void refreshPanel(List<Object> cpData){
TableView2 tv = (TableView2) findViewById(R.id.tableView);
tv.clearData();
tv.setHeaderBackColor(R.color.md_blue_300);
tv.setHeaderNames("姓名", "状态", "部门", "编号", "详情","id");
//设置每格的宽度
tv.setColumnWidth(0, 105);
tv.setColumnWidth(1, 80);
tv.setColumnWidth(2, 170);
tv.setColumnWidth(3, 180);
tv.setColumnWidth(4, 100);
if(null == cpData || 0 == cpData.size()){
runOnUiThread(() -> Toast.makeText(AreaCtrlDetailActivity.this, "当前区域无数据!", Toast.LENGTH_SHORT).show());
finish();
}
for (int i = 0; i < cpData.size(); i++) {
JSONObject rowData = (JSONObject) cpData.get(i);
allAreaRollCallMap.put(rowData.getString(Constants.Param.PERSON_INFO_ID), rowData);
String detail = "详情";
String io = rowData.getString(Constants.Param.IO_TYPE).equals(Constants.Common.IN) ?Constants.Common.E_IN : Constants.Common.E_OUT;
String[] ss = { rowData.getString(Constants.Param.PERSON_INFO_NAME),io, rowData.getString(Constants.Param.DEPT_NAME),
rowData.getString(Constants.Param.PERSONNEL_NUMBER), detail, rowData.getString(Constants.Param.PERSON_INFO_ID)};
Log.d("success", Arrays.toString(ss));
tv.addRowData(i, ss);
}
tv.setOnItemClickListener(new TableView2.OnTableItemClickListener() {
@Override
public void onItemClick(int position, String[] rowData) {
Toast toast=Toast.makeText(AreaCtrlDetailActivity.this,rowData[position]+"的详情信息",Toast.LENGTH_SHORT );
toast.setGravity(Gravity.CENTER, 0, 0);
toast.show();
}
});
tv.setOnItemLongClickListener(new TableView2.OnTableItemLongClickListener() {
@Override
public void onItemLongClick(int position, String[] rowData) {
}
});
tv.setOnUnitClickListener(new TableView2.OnUnitClickListener() {
@Override
public void onUnitClick(int row, int column, String unitText) {
if(!"all".equals(unitText)){
Intent intent = new Intent(AreaCtrlDetailActivity.this, AreaCtrlPersonInfoDetailActivity.class);
String[] data = tv.getRowData(row);
intent.putExtra("rowData", data);
intent.putExtra("areaType", dataP[1]);
intent.putExtra(Constants.Param.PERSON_ID, unitText);
intent.putExtra("dataDetail", allAreaRollCallMap.get(unitText));
startActivity(intent);
}
}
});
tv.setEventMode(TableView2.MODE_EITHER_UNIT_EVENT); //自定义某些列的单元格处理事件
tv.setColumnEventIndex(4);//设置哪些列的单元格处理事件
tv.setUnitSelectable(false);//单元格处理事件的时候是否可以选中
tv.setUnitDownColor(R.color.md_blue_900);//单元格处理事件的时候,按下态的颜色
tableLayout.removeAllViews();
tableLayout.addView(tv);
}
public void onQueryCancelButtonClicked(View v){
finish();
}
//这是后台数据获取、设置个锁、如果数据未获取到、让界面绘制的线程等一下。加载完在唤醒!
private synchronized void getGlobalData(){
JSONObject param = new JSONObject();
//传递的参数
param.put(Constants.Param.AREA_TYPE, areaType);
param.put(Constants.Param.DEPT_ID, deptId);
param.put(Constants.Param.CATEGORY, Constants.Category.PRISON);
String url = CommonCode.getPortalUrl(Constants.Portal.HANDLE_CLIENT_GET_AREA_CTRL_DETAIL);
JSONObject result = CommonCode.postGetJson(param,url);
if (CommonCode.getResultFlag(result)) {
//成功返回数据并用分页封装!
resultJson = (JSONArray) CommonCode.getResultMapProperty(result, Constants.Param.DATA_LIST);
pageData = PageUtils.getPageData(resultJson, 17);
}else{
runOnUiThread(() -> Toast.makeText(AreaCtrlDetailActivity.this, result.getString("message"), Toast.LENGTH_SHORT).show());
}
flag = true;
notify();
}
}
布局文件
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent">
<HorizontalScrollView
android:id="@+id/scroll_data_lay"
android:layout_width="0dp"
android:layout_height="460dp"
android:layout_marginTop="10dp"
android:scrollbarDefaultDelayBeforeFade="400"
android:scrollbarSize="4dp"
android:scrollbars="vertical"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.0"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
<LinearLayout
android:id="@+id/tableBody"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
app:layout_constraintTop_toBottomOf="@id/textView18"
tools:layout_editor_absoluteY="134dp">
<com.neurotec.samples.multibiometric.util.TableView2
android:id="@+id/tableView"
android:layout_width="317dp"
android:layout_height="460dp"
android:layout_marginLeft="1dp"
app:headerTextColor="#000000"
app:headerTextSize="10sp" />
</LinearLayout>
</HorizontalScrollView>
<LinearLayout
android:id="@+id/bottomButtonsLinearLayout"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="10dp"
android:orientation="horizontal"
android:paddingTop="10dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintTop_toBottomOf="@+id/linearLayout">
<Button
android:id="@+id/pageReduce"
android:layout_width="0dp"
android:layout_height="30dp"
android:layout_marginRight="5dp"
android:layout_weight="1"
android:background="@color/md_light_blue_400"
android:gravity="center"
android:onClick="onQueryReducePageButtonClicked"
android:text="上一页"
android:textColor="#FFFFFF" />
<Button
android:id="@+id/pageAdd"
android:layout_width="0dp"
android:layout_height="30dp"
android:layout_marginRight="5dp"
android:layout_weight="1"
android:background="@color/md_light_blue_400"
android:gravity="center"
android:onClick="onQueryAddPageButtonClicked"
android:text="下一页"
android:textColor="#FFFFFF" />
<Button
android:id="@+id/cancel"
android:layout_width="0dp"
android:layout_height="30dp"
android:layout_marginLeft="5dp"
android:layout_weight="1"
android:background="#78909C"
android:gravity="center"
android:onClick="onQueryCancelButtonClicked"
android:text="返 回"
android:textColor="#FFFFFF" />
</LinearLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
-
注:博主的代码未考虑到界面界面适配。因为公司产品用的定制设备不需要多型号界面适配,界面适配暂未有深层次研究,所以布局文件代码仅供参考、未通用!
-
一直不务正业的野鸡Java后端开发!如有错误、还望指正!如果对你有启发,记得点个赞哈!手动滑稽!谢谢!
刚才说到的TableView控件!下载地址 传送门