这一篇博客和上一篇讲的都是listView的动态加载,但有所不同的是,本篇的listView是嵌套在ScrollView下的,有时候在一个Activity中可能分为好几个模块,由于展示的需要(手机屏幕大小有限),我们需要在这些模块的外层嵌套ScrollView,这时候我们就不能根据listView的状态来监听是否需要加载数据啦,但是转念一想,我们可以监听scrollview,但scrollview滑动到最底部时,那listview肯定也滑动到底部啦。思路确定啦,但是在开发的过程中发现了一个bug,listView有时候会加载重复的数据,搞的莫名其妙,后来经过查资料得知在ScrollView滑动中,onScrollChanged总是在不停被调用,导致多次向服务器端请求同样的数据,这时候就需要我们自己做并发控制

ZdyListView

 package com.example.listview;

 import android.content.Context;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.ListView;
import android.widget.ProgressBar;
import android.widget.TextView; /**
* Created by keranbin on 2015/10/25.
*/
public class ZdyListView extends ListView {
private Context context;
private View footer;
private ProgressBar progressBar;
private TextView tv; public ZdyListView(Context context) {
super(context);
init(context);
}
public ZdyListView(Context context, AttributeSet attrs) {
super(context, attrs);
init(context);
}
public ZdyListView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init(context);
}
private void init(Context context) {
this.context=context;
footer=LayoutInflater.from(context).inflate(R.layout.activity_footer, null);
this.addFooterView(footer);
progressBar=(ProgressBar) footer.findViewById(R.id.progressBar);
tv=(TextView) footer.findViewById(R.id.tv);
tv.setText("上拉加载更多");
} //正在加载数据,将listview底部提示文字置为"正在加载中。。。。"
public void onLoading(){
progressBar.setVisibility(VISIBLE);
tv.setText("正在加载中。。。。");
} //加载完毕,将listView底部提示文字改为"上拉加载更多"
public void LoadingComplete(){
progressBar.setVisibility(GONE);
tv.setText("上拉加载更多");
} //重写onMeasure,解决scrollview与listview冲突
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int expandSpec = MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE >> 2,
MeasureSpec.AT_MOST);
super.onMeasure(widthMeasureSpec, expandSpec);
} }

ZdyScrollView

 package com.example.listview;

 import android.content.Context;
import android.util.AttributeSet;
import android.view.View;
import android.widget.ScrollView; public class ZdyScrollView extends ScrollView{
private int flag=0; //并发控制标志位 private OnZdyScrollViewListener onZdyScrollViewListener; public ZdyScrollView(Context context) {
super(context);
} public ZdyScrollView(Context context, AttributeSet attrs) {
super(context, attrs);
} public ZdyScrollView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
} //listview加载完毕,将并发控制符置为0
public void loadingComponent(){
flag=0;
} @Override
protected void onScrollChanged(int l, int t, int oldl, int oldt) {
super.onScrollChanged(l, t, oldl, oldt);
View view=this.getChildAt(0);
//如果scrollview滑动到底部并且并发控制符为0,回调接口向服务器端请求数据
if (this.getHeight() + this.getScrollY() == view.getHeight() && flag == 0) {
flag = 1;//一进来就将并发控制符置为1,虽然onScrollChanged执行多次,但是由于并发控制符的值为1,不满足条件就不会执行到这
onZdyScrollViewListener.ZdyScrollViewListener();
}
} public void setOnZdyScrollViewListener(OnZdyScrollViewListener onZdyScrollViewListener){
this.onZdyScrollViewListener=onZdyScrollViewListener;
} public interface OnZdyScrollViewListener{
public void ZdyScrollViewListener();
} }

MainActivity

 package com.example.listview;

 import java.util.ArrayList;

 import com.example.listview.ZdyScrollView.OnZdyScrollViewListener;

 import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message; public class MainActivity extends Activity { private ZdyScrollView scrollView;
private ZdyListView listView;
private ListViewAdapter adapter; //一次从服务器端请求十条数据
private int current=1;
private int number=9; ArrayList<String> listDatas; private Handler handler=new Handler(){
public void handleMessage(Message msg) {
setListView((ArrayList<String>)msg.obj);
}
}; @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initView();
initListener();
} @Override
protected void onStart() {
super.onStart();
//第一次请求数据
getDataThread(current,number);
} private void initView() {
listView=(ZdyListView) this.findViewById(R.id.listView);
scrollView=(ZdyScrollView) this.findViewById(R.id.scrollView); } private void initListener() {
scrollView.setOnZdyScrollViewListener(new OnZdyScrollViewListener() {
@Override
public void ZdyScrollViewListener() {
//上拉加载更多数据
getDataThread(current,number);
}
}); } private void setListView(ArrayList<String> datas) {
if(listDatas==null){//第一次加载数据,为listview设置适配器
listDatas=new ArrayList<String>();
listDatas.addAll(datas);
adapter=new ListViewAdapter(MainActivity.this,listDatas);
listView.setAdapter(adapter);
current=adapter.getCount()+1; //记录当前listview中的最后一个数据的下标
listView.LoadingComplete(); //告诉listview已经加载完毕,重置提示文字
scrollView.loadingComponent();//告示scrollview已经加载完毕,重置并发控制符的值
}else{//下拉加载更多数据,只需要告诉adapter刷新就行
listDatas.addAll(datas);
adapter.notifyDataSetChanged();
current=adapter.getCount()+1;
listView.LoadingComplete();
scrollView.loadingComponent();
} }; private void getDataThread(final int current, final int number){
final Message msg=new Message();
listView.onLoading();
new Thread(){
public void run() {
try {//模拟向服务器请求数据耗时
sleep(10000);
} catch (InterruptedException e) {
e.printStackTrace();
}
ArrayList<String> datas=ListViewDatas.returnNum(current, current+number);
if(datas!=null&&datas.size()>0){
msg.obj=datas;
handler.sendMessage(msg);
}
};
}.start();
} }

模拟服务器端发回数据ListViewDatas

 package com.example.listview;

 import java.util.ArrayList;

 public class ListViewDatas {
//模拟服务器端数据库中的数据,假设现在只有3条数据
public static int NUM=53;
public static ArrayList<String> returnNum(int startNum,int endNum){
ArrayList<String> list=new ArrayList<String>();
if(endNum<=NUM){//客户端请求的数据在数据库数据范围之内
for(int i=startNum;i<=endNum;i++){
list.add(String.valueOf(i));
}
return list;
}else if(endNum>=NUM&&startNum<=NUM){//客户端请求的数据不全在数据库数据范围之内
for(int i=startNum;i<=NUM;i++){
list.add(String.valueOf(i));
}
return list;
}else if(startNum>NUM){//客户端请求的数据超出数据库数据范围之内
return null;
}
return null;
}
}

页面布局activity_main.xml

 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical" > <com.example.listview.ZdyScrollView
android:id="@+id/scrollView"
android:layout_width="match_parent"
android:layout_height="match_parent" > <com.example.listview.ZdyListView
android:id="@+id/listView"
android:layout_width="match_parent"
android:layout_height="match_parent" >
</com.example.listview.ZdyListView>
</com.example.listview.ZdyScrollView> </LinearLayout>

listView的footView  activity_footer.xml

 <?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" > <LinearLayout
android:id="@+id/load_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:orientation="horizontal"
android:paddingBottom="10dip"
android:paddingTop="10dip" > <ProgressBar
style="?android:attr/progressBarStyleSmall"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/progressBar"
android:visibility="gone"/> <TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="正在加载..."
android:id="@+id/tv"/> </LinearLayout> </LinearLayout>

Android Scrollview嵌套下listView动态加载数据,解决onScrollChanged执行多次数据重复问题的更多相关文章

  1. 携程Android App插件化和动态加载实践

    携程Android App的插件化和动态加载框架已上线半年,经历了初期的探索和持续的打磨优化,新框架和工程配置经受住了生产实践的考验.本文将详细介绍Android平台插件式开发和动态加载技术的原理和实 ...

  2. AppCan学习笔记----关闭页面listview动态加载数据

    AppCan页面关闭 AppCan 的页面是由两个HTML组成,如果要完全关闭的话需要在主HTML eg.index.html中关闭,关闭方法:appcan.window.close(-1); 管道 ...

  3. ie6,7下js动态加载图片不显示错误

    ie6,7下js动态加载图片不显示错误 先描述一下出现这种匪夷所思bug的背景: 我在页面加载的时候加载一堆小缩略图,<a href="javascript:void(0);" ...

  4. 分享个刚写好的 android 的 ListView 动态加载类,功能全而代码少。

    (转载声明出处:http://www.cnblogs.com/linguanh/) 简介:      该ListView 实现动态加载数据,为了方便用户充分地自定义自己的数据源.点击事件,等核心操作, ...

  5. Android中ListView动态加载数据

    1. 引言: 为了提高ListView的效率和应用程序的性能,在Android应用程序中不应该一次性加载ListView所要显示的全部信息,而是采取分批加载策略,随着用户的滑动,动态的从后台加载所需的 ...

  6. Android中插件开发篇之----动态加载Activity(免安装运行程序)

    一.前言 又到周末了,时间过的很快,今天我们来看一下Android中插件开发篇的最后一篇文章的内容:动态加载Activity(免安装运行程序),在上一篇文章中说道了,如何动态加载资源(应用换肤原理解析 ...

  7. android sax解析xml 文件 动态加载标题

    要解决一个问题 : 问题描述为 把标题动态的加载到 listView子布局中 我们首先通过 java程序写一个把标题写到xml文件的程序.这个程序会在以后讲解. 现在截图 已经写好的xm文件格式如下 ...

  8. Android 插件化方案(动态加载)总结

    1.作用 大多数Android开发人员开始接触这个问题是因为 App 爆棚了,方法数超过了一个 Dex 最大方法数 65535 的上限,因而便有了插件化的概念,将一个 App 划分为多个插件(Apk ...

  9. Android应用安全之外部动态加载DEX文件风险

    1. 外部动态加载DEX文件风险描述 Android 系统提供了一种类加载器DexClassLoader,其可以在运行时动态加载并解释执行包含在JAR或APK文件内的DEX文件.外部动态加载DEX文件 ...

随机推荐

  1. 2018710101110-李华《面向对象程序设计(java)》第十二周学习总结

    项目 内容 这个作业属于哪个课程 https://www.cnblogs.com/nwnu-daizh/ 这个作业的要求在哪里 https://www.cnblogs.com/nwnu-daizh/p ...

  2. 代码审计-数组返回NULL绕过

    <?php $flag = "flag"; if (isset ($_GET['password'])) { if (ereg ("^[a-zA-Z0-9]+$&q ...

  3. python批量修改文件名(以修改图片名为例)

    #coding=utf-8import sys, string, os, shutil #输入目录名和前缀名,重命名后的名称结构类似prefix_0001 def RenameFiles(srcdir ...

  4. nullptr与NULL

    NULL NULL can be defined as any null pointer constant. Thus existing code can retain definitions of  ...

  5. Centos7 安装mysql-8.0.18(rpm)

    1.前言 当前MySQL最新版本:8.0.18 (听说比5.7快2倍)官方之前表示:MySQL 8.0 正式版 8.0.18 已发布,MySQL 8 要比 MySQL 5.7 快 2 倍,还带来了大量 ...

  6. linux下安装编译为安装的php扩展

    1.进入php源码包中,找到需要安装的扩展模块目录.cd /root/php-5.6.26/ext/mbstring 2.在扩展模块目录,运行phpize程序,(作用是检测 php 的内核版本,并为扩 ...

  7. Eclipse安装svn插件(五)

    一.在线安装 1. 点击 Help --> Install New Software... 2. 在弹出的窗口中点击add按钮,输入Name(任意)和Location(插件的URL),点击OK ...

  8. javaweb监听器实现与原理

    参考:https://www.cnblogs.com/lxp503238/p/6678688.html https://blog.csdn.net/CPOHUI/article/details/888 ...

  9. 数据结构——顺序栈(sequence stack)

    /* sequenceStack.c */ /* 栈 先进后出(First In Last Out,FILO)*/ #include <stdio.h> #include <stdl ...

  10. HTTP协议COOKIE和SESSION有什么区别

    1.为什么会有COOKIE这种机制 首先一种场景, 在一个网站上面, 我发起一次请求,那服务器怎么知道我是谁?是谁发起的这次请求呢,  HTTP协议是无状态的协议, 浏览器的每一次请求,服务器都当做一 ...