在Android中如果要做到大数据分页加载则需要我们的Activity实现OnScrollListener滚动条监听接口。当如果要做的更加高大上。比如需要在用户滑动至列表的底部,触碰摸个区域,则需要实现OnTouchListener接口,等等。
这里先讲加载大数据
首先需要在main.xml申明一个ListView,存放数据
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:paddingLeft="3dp"
android:paddingRight="3dp">
<!-- 当ListActivity时,ListView中就需要@id/android:list,否则logCat会报错
Android内置的名为list的id,因为我们后面要使用到ListActivity,我们的MainActivity继承于它 -->
<TextView android:id="@+id/txtView"
android:text="编号"
android:textSize="24dp"
android:textColor="#ff00FF"
android:background="#80D640"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:gravity="center_horizontal"/>
<ListView android:id="@id/android:list"
android:layout_width="fill_parent"
android:layout_height="wrap_content"/>
</LinearLayout>
由于ListView试图组件中,需要封装每一个item,所以需要layout中申明:
list_item.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<!-- 它是ListView中单个列表项的布局文件,从效果图中可以看到,这里只使用到了一个TextView组件 -->
<!-- 在getView或者bindview里面首先用一文本TextView显示在本地,同时启动线程去网上获取图片资源,一旦某TextView的数据得到就立马刷新将那张本地的TextView换掉 -->
<TextView android:id="@+id/list_item_text"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:gravity="center"
android:textSize="20sp"
android:paddingTop="10dp"
android:paddingBottom="10dp"/>
</LinearLayout>
在加上我们的效果时,当滑动至列表的底部也就是应用程序窗体底部时,想要加载下一行,所以需要一个按钮来触发 load_more.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="wrap_content">
<Button android:id="@+id/loadMoreButton"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="load more"
android:onClick="loadMore"/>
</LinearLayout>
在使用BaseAdapter适配器加载大量数据
package com.lol.huixin.adapter;
import java.util.List;
import java.util.Map;
import com.lol.huixin.loaddatamore.R;
import com.lol.huixin.views.ViewHolder;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.TextView;
public class ListViewAdapter extends BaseAdapter {
private List<Map<String,Object>> items;
private LayoutInflater inflater;
public ListViewAdapter(Context context, List<Map<String,Object>> items) {
this.items = items;
inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
}
@Override
public int getCount() {
return items.size();
}
@Override
public Object getItem(int position) {
return items.get(position);
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder holder=null;
if (convertView == null) {
holder=new ViewHolder();
convertView = inflater.inflate(R.layout.list_item, null);
holder.list_item_text=(TextView) convertView.findViewById(R.id.list_item_text);
convertView.setTag(holder);
} else{
holder=(ViewHolder)convertView.getTag();
}
holder.list_item_text.setText((String)items.get(position).get("bianhao"));
return convertView;
}
/**
* 添加列表项
* @param item
*/
public void addItem(Map<String,Object> listmap) {
items.add(listmap);
}
}
MainActivity.java中调用
package com.lol.huixin.loaddatamore;
import android.os.Bundle;
import android.os.Handler;
import android.util.Log;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import com.lol.huixin.adapter.ListViewAdapter;
import android.app.ListActivity;
import android.view.Menu;
import android.view.View;
import android.widget.AbsListView;
import android.widget.AbsListView.OnScrollListener;
import android.widget.Button;
import android.widget.ListView;
//由于我们这里模拟加载大量数据的样本,所以就需要有个滚动条,所以需要实现滚动条的接口
public class MainActivity extends ListActivity implements OnScrollListener{
private ListView listView;
private int visibleLastIndex = 0; //最后的可视项索引
private int visibleItemCount; // 当前窗口可见项总数
private ListViewAdapter adapter; //数据适配器
private View loadMoreView;
private Button loadMoreButton;
private Handler handler = new Handler();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//相当于实例化一个Layout,并在这个实例化的Layout中加一个按钮
loadMoreView = getLayoutInflater().inflate(R.layout.load_more, null);
loadMoreButton = (Button) loadMoreView.findViewById(R.id.loadMoreButton);
listView = getListView(); //获取id是list的ListView
listView.addFooterView(loadMoreView); //设置列表底部视图
//初始化数据
initAdapter();
setListAdapter(adapter); //自动为id是list的ListView设置适配器
listView.setOnScrollListener(this); //添加滑动监听
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
/**
* 初始化适配器
*/
private void initAdapter() {
List<Map<String,Object>> listMap=new ArrayList<Map<String,Object>>();
for (int i = 0; i < 10; i++) {
Map<String,Object> map=new HashMap<String,Object>();
map.put("bianhao",String.valueOf(i+1));
listMap.add(map);
}
adapter = new ListViewAdapter(this, listMap);
}
/**
* 滑动状态改变时被调用
*/
@Override
public void onScrollStateChanged(AbsListView view, int scrollState) {
int itemsLastIndex = adapter.getCount() - 1; //数据集最后一项的索引
int lastIndex = itemsLastIndex + 1; //加上底部的loadMoreView项
if (scrollState == OnScrollListener.SCROLL_STATE_IDLE && visibleLastIndex == lastIndex) {
//如果是自动加载,可以在这里放置异步加载数据的代码
Log.i("LOADMORE", "loading...");
}
}
/**
* 滑动时被调用
*/
@Override
public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
this.visibleItemCount = visibleItemCount;
visibleLastIndex = firstVisibleItem + visibleItemCount - 1;
}
/**
* 点击按钮事件
* @param view
*/
public void loadMore(View view) {
loadMoreButton.setText("loading..."); //设置按钮文字loading
handler.postDelayed(new Runnable() {
@Override
public void run() {
loadData();
adapter.notifyDataSetChanged(); //数据集变化后,通知adapter
listView.setSelection(visibleLastIndex - visibleItemCount + 1); //设置选中项
loadMoreButton.setText("load more"); //恢复按钮文字
}
}, 2000);
}
/**
* 模拟加载数据
*/
private void loadData() {
int count = adapter.getCount();
for (int i = count; i < count + 10; i++) {
Map<String,Object> map=new HashMap<String,Object>();
map.put("bianhao",String.valueOf(i+1));
adapter.addItem(map);
}
}
}
这个时候我们注意到了一个奇怪的现象:ViewHolder类
package com.lol.huixin.views;
import java.io.Serializable;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.TextView;
@SuppressWarnings("serial")
public class ViewHolder implements Serializable{
public ImageView img;
//public TextView title;
public TextView list_item_text;
public TextView info;
public Button viewBtn;
}
项目结构:
运行效果:也是ok的。
然后我就在想为什么这样写了?
1.首先ListViewAdapter中有一个有参构造方法,我们在MainActivity调用时传入了两个参数,参数一是需要装载值ListView中的数据,参数二是当前上下文对象Context,
inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE)
从当前layout的上下文作用域中得到SystemService中的LAYOUT_INFLATER_SERVICE东东,那么LAYOUT_INFLATER_SERVICE是什么东东,Android官网给与了解释:
Use with getSystemService
to retrieve a android.view.LayoutInflater
for inflating layout resources in this context.
-
See Also:
- getSystemService
- android.view.LayoutInflater
- Google说:使用带有getSystemService检索android.view.LayoutInflater进行充气布局资源于该上下文。
- 也就是说我们通过LayoutInflater这个类实例化一个layout,将我们 load_more.xml中的按钮给动态加至ListView中
- 2.我们知道Android中提高滑动效率,就意味着需要修改GetView方法,那么我们那样写的目的何在
- 原因有两点:
- 一>adapter每次加载时,都需要去创建一个item中的内容,也就是Layout和其中的组件,很影响效率,如果我们把组件进行封装是不是会优化效率呢?在这,如果在内存中已经分配了使用LayoutInflater创建了一个Layout呢?我们是不是不需要在此创建
- 二>我们都知道在看书的时候,要想定位到上次看过的地方,最简单的方法就是在书中做个标记,同样的android也支持这样一种写法
- convertView.setTag(holder); //做数据标记
-
-