我们都知道网络取数据是耗时操作,如果我们一次性请求所有数据,假如数据量不多那还可以接受,但是如果数据量特别多,那么带来的后果就是用户的愤怒(用户是很没有耐心的),所以这时候我们就需要动态的加载数据,分批加载我们所需的数据,提升用户体验,先上图。
一般如果一个Activity集成越多的功能,代码量也会随之增多,看起来让人烦,我们可以考虑自定义控件将一些操作集成进去。
自定义ListView
1 package com.example.listviewdynamicloading; 2 3 import android.content.Context; 4 import android.util.AttributeSet; 5 import android.view.LayoutInflater; 6 import android.view.View; 7 import android.widget.AbsListView; 8 import android.widget.AbsListView.OnScrollListener; 9 import android.widget.ListView; 10 11 public class ZdyListView extends ListView implements OnScrollListener { 12 private int totalItemCount;// 总数量; 13 private int lastVisibleItem;// 最后一个可见的item; 14 private boolean isLoading; 15 private View footer; 16 private LayoutInflater inflater; 17 public RefleshDatas refleshDatas; 18 19 public ZdyListView(Context context) { 20 super(context); 21 initView(context); 22 } 23 24 public ZdyListView(Context context, AttributeSet attrs) { 25 super(context, attrs); 26 initView(context); 27 } 28 29 public ZdyListView(Context context, AttributeSet attrs, int defStyle) { 30 super(context, attrs, defStyle); 31 initView(context); 32 } 33 34 private void initView(Context context) { 35 footer=inflater.from(context).inflate(R.layout.layout_util_footer, null); 36 this.setOnScrollListener(this); 37 this.addFooterView(footer); 38 this.removeFooterView(footer); 39 } 40 41 @Override 42 public void onScroll(AbsListView view, int firstVisibleItem, 43 int visibleItemCount, int totalItemCount) { 44 this.lastVisibleItem = firstVisibleItem + visibleItemCount; 45 this.totalItemCount = totalItemCount; 46 } 47 48 @Override 49 public void onScrollStateChanged(AbsListView view, int scrollState) { 50 //listview item总数量等于最后一个可见的item并且ListView停下不动了 51 if (totalItemCount == lastVisibleItem&& scrollState == SCROLL_STATE_IDLE) { 52 if (!isLoading) { 53 isLoading = true; 54 this.addFooterView(footer); 55 if (refleshDatas != null) { 56 //回调执行向服务器端请求数据 57 refleshDatas.onLoading(); 58 } 59 } 60 } 61 }; 62 public void loadComplete() { 63 isLoading = false; 64 this.removeFooterView(footer);//加载完毕,移除footView; 65 } 66 public void setInterface(RefleshDatas refleshDatas) { 67 this.refleshDatas = refleshDatas; 68 } 69 public interface RefleshDatas{ 70 public void onLoading(); 71 } 72 }
MainActivity
1 package com.example.listviewdynamicloading; 2 3 import java.util.ArrayList; 4 5 import com.example.listviewdynamicloading.ZdyListView.RefleshDatas; 6 7 import android.app.Activity; 8 import android.os.Bundle; 9 import android.os.Handler; 10 import android.os.Message; 11 import android.view.Menu; 12 import android.view.MenuItem; 13 import android.widget.ListView; 14 import android.widget.Toast; 15 16 public class MainActivity extends Activity{ 17 //一次从服务器端请求十条数据 18 private int current=1; 19 private int number=9; 20 21 22 private ZdyListView listView; //自定义ListView,将footview,滑动监听等集合在一起,免得Activity代码过多 23 private ArrayList<String> listDatas; 24 private ListViewAdapter adapter; 25 26 27 private Handler handler=new Handler(){ 28 public void handleMessage(android.os.Message msg) { 29 switch (msg.what) { 30 case 0x123: 31 setlistView((ArrayList<String>)msg.obj,"firstLoading");//firstLoading标志位代表数据是初次加载的 32 break; 33 case 0x234: 34 setlistView((ArrayList<String>)msg.obj,"addLoading");//addLoading标志位代表数据是初次加载之后请求服务器所得 35 break; 36 case 0x345: 37 showMsg((String)msg.obj); 38 break; 39 default: 40 break; 41 } 42 }; 43 }; 44 45 @Override 46 protected void onCreate(Bundle savedInstanceState) { 47 super.onCreate(savedInstanceState); 48 setContentView(R.layout.activity_main); 49 listDatas=new ArrayList<String>(); 50 listView=(ZdyListView) this.findViewById(R.id.listview); 51 listView.setInterface(new RefleshDatas() { 52 @Override 53 public void onLoading() { 54 getDataThread(current, current+number, "addLoading"); 55 } 56 }); 57 } 58 59 60 61 @Override 62 protected void onStart() { 63 super.onStart(); 64 getDataThread(current,number,"firstLoading"); 65 } 66 67 //.........................模拟开启线程向服务器请求数据..................................... 68 private void getDataThread(final int current, final int number,final String type) { 69 final Message msg=new Message(); 70 new Thread(){ 71 public void run() { 72 ArrayList<String> datas=ListViewDatas.returnNum(current, current+number); 73 if(datas!=null&&datas.size()>0){ 74 switch (type) { 75 case "firstLoading": 76 msg.what=0x123; 77 break; 78 case "addLoading": 79 msg.what=0x234; 80 break; 81 default: 82 break; 83 } 84 msg.obj=datas; 85 }else { 86 msg.what=0x345; 87 msg.obj=datas; 88 } 89 handler.sendMessage(msg); 90 }; 91 }.start(); 92 } 93 94 95 96 private void setlistView(ArrayList<String> datas,String type) { 97 listDatas.addAll(datas); 98 if(type.equals("firstLoading")){//初次加载 99 adapter=new ListViewAdapter(MainActivity.this, listDatas); 100 current=adapter.getCount()+1; 101 listView.setAdapter(adapter); 102 listView.loadComplete(); 103 }else if(type.equals("addLoading")){//初次加载后请求的数据,执行notifyDataSetChanged(); 104 adapter.notifyDataSetChanged(); 105 current=adapter.getCount()+1; 106 listView.loadComplete(); 107 } 108 } 109 110 111 protected void showMsg(String str) { 112 Toast.makeText(MainActivity.this, "已加载完毕", Toast.LENGTH_SHORT).show(); 113 listView.loadComplete(); 114 } 115 116 117 118 }
模拟服务器端数据
1 package com.example.listviewdynamicloading; 2 3 import java.util.ArrayList; 4 5 public class ListViewDatas { 6 //模拟服务器端数据库中的数据,假设现在只有3条数据 7 public static int NUM=53; 8 public static ArrayList<String> returnNum(int startNum,int endNum){ 9 ArrayList<String> list=new ArrayList<String>(); 10 if(endNum<=NUM){//客户端请求的数据在数据库数据范围之内 11 for(int i=startNum;i<=endNum;i++){ 12 list.add(String.valueOf(i)); 13 } 14 return list; 15 }else if(endNum>=NUM&&startNum<=NUM){//客户端请求的数据不全在数据库数据范围之内 16 for(int i=startNum;i<=NUM;i++){ 17 list.add(String.valueOf(i)); 18 } 19 return list; 20 }else if(startNum>NUM){//客户端请求的数据超出数据库数据范围之内 21 return null; 22 } 23 return null; 24 } 25 }
ListView适配器
1 package com.example.listviewdynamicloading; 2 3 import java.util.ArrayList; 4 5 import android.content.Context; 6 import android.view.LayoutInflater; 7 import android.view.View; 8 import android.view.ViewGroup; 9 import android.widget.BaseAdapter; 10 import android.widget.TextView; 11 12 public class ListViewAdapter extends BaseAdapter{ 13 private Context context; 14 private ArrayList<String> datas; 15 16 public ListViewAdapter(Context context,ArrayList<String> datas){ 17 this.context=context; 18 this.datas=datas; 19 } 20 21 @Override 22 public int getCount() { 23 return datas.size(); 24 } 25 26 @Override 27 public Object getItem(int position) { 28 return null; 29 } 30 31 @Override 32 public long getItemId(int position) { 33 return position; 34 } 35 36 @Override 37 public View getView(int position, View convertView, ViewGroup parent) { 38 ViewHolder vh=null; 39 if(convertView==null){ 40 vh=new ViewHolder(); 41 convertView=LayoutInflater.from(context).inflate(R.layout.listview_item, null); 42 vh.tv=(TextView) convertView.findViewById(R.id.tv); 43 convertView.setTag(vh); 44 }else { 45 vh=(ViewHolder) convertView.getTag(); 46 } 47 vh.tv.setText("这是第"+datas.get(position)+"条数据"); 48 return convertView; 49 } 50 51 52 53 class ViewHolder{ 54 TextView tv; 55 } 56 57 58 }