Android_ListView_Adapter使用和数据动态加载
2013-10-16 09:36
585 查看
本博文为子墨原创,转载请注明出处!
/article/1349476.html
引用:ListView是比较常用的控件,其存在的最根本的原因在于它的高效,ListView通过对象的复用从而减少内存的消耗,也减少了对象的创建从而也减少的cpu的消耗(在Androidk中创建View对象经常伴随着解析xml)。ListView的本质是一张bitmap(当然所有的控件文字等在屏幕上看到的最终都会变成bitmap),ListView会按照需求,根据Adapter提供的信息把需要的Item画出来显示在屏幕上,当屏幕滚动的时候会重新计算Item的位置并绘制出新的bitmap显示在屏幕上。这样听起来感觉可能不是很高效,但这样带的好处就是,每用为一第个Item 创建一个View对象,样式一样的对象可以共用一个View对象,减少了内存的消耗。而且ListView是事件驱动的,只有当需要的时候才会重新绘制,并且只会 绘制当前屏幕上所显示的Items.
[java] view
plaincopy
//ArrayAdapter Constructor
{
new ArrayAdapter(Context context, //The current context.
int resource, /*
The resource ID for a layout file containing a layout to use when instantiating views
例如:android.R.layout.simple_list_item_single_choice
*/
List<T> objects) //数据对象
}
[java] view
plaincopy
//SimpleAdapter Constructor
{
SimpleAdapter (Context context, // 上下文
List<? extends Map<String, ?>> data,
/*
* A List of Maps.每个list元素就是一列
* Map集合中的key集合,应该包含后面参数(from)中每个元素
*/
int resource, //为view layout定义的一列,其中应该包含后面参数(to)中每个元素
String[] from, //从data引出的某些列名
int[] to) //从resource对应的layout文件中,找到相应的id而组成的数组,从而决定使用哪些view组件组合一个列表项
}
plaincopy
/**
* 自定义适配器,常见将Cursor或者其他的数据存储在一个集合中,效率提高!
*
*/
private class MyAdapter extends BaseAdapter {
private List<String> list;
//为该适配器设置展现的数据,当我们为该适配器指定了新的数据后,应该调用notifyDataSetChanged()方法后才能完成数据的动态加载
public void setList( List<String> list){
this.list = list;
}
@Override
public int getCount() {
return list.size();
}
@Override
public Object getItem(int position) {
return list.get(position);
}
@Override
public long getItemId(int position) {
return position;
}
//重要方法,用于展现该listview的item条目
@Override
public View getView(int position, View convertView, ViewGroup parent) {
/*
* convertView为一个item条目对象,每个item滑过之后,创建的item对象有被重新销毁,为此安卓提供一种机制,
* 创建的条目不被销毁而是供后来展现的item重复使用,大大提高了效率
*/
TextView textView = null;
if (convertView == null) { //如果没有可供重复使用的item View对象
textView = new TextView(getActivity());
/*
* 里面包含一种高效的处理机制,当每个item比较复杂,如果重复的执行类型转换、查找控件等操作,将会很大浪费,
* 可以定义一个类,专门用来存放控件对象的引用。后面的例子键会介绍到
*/
} else {
textView = (TextView) convertView; //如果已经加载将重复使用
}
textView.setText(list.get(position));
textView.setPadding(20, 20, 20, 20);
textView.setBackgroundColor(Color.GREEN);
return textView;
}
}
plaincopy
listView.setOnScrollListener(new AbsListView.OnScrollListener() {
@Override
public void onScrollStateChanged(AbsListView view, int scrollState) {
//监听listView的状态是否改变
}
@Override
public void onScroll(AbsListView view, int firstVisibleItem,
int visibleItemCount, int totalItemCount) {
//在滚动的过程中会触发该事件
}
});
plaincopy
listView.setOnScrollListener(new OnScrollListener() {
private boolean isBottom = false; //用于标记是否到达顶端
//listview的状态发送改变时执行
@Override
public void onScrollStateChanged(AbsListView view, int scrollState) {
System.out.println("scrollState:"+scrollState);
if(isBottom && scrollState==OnScrollListener.SCROLL_STATE_IDLE){
System.out.println("数据加载");
//简单模拟数据加载过程
for(int j=0; j<10; j++){
Map<String, String> map = new HashMap<String, String>();
map.put("id", String.valueOf((i++)));
map.put("name", "newName="+i);
map.put("age", String.valueOf(i));
adapter.getList().add(map);
}
adapter.notifyDataSetChanged();
isBottom = false;
}
}
//在滚动的过程中不断执行
@Override
public void onScroll(AbsListView view, int firstVisibleItem,
int visibleItemCount, int totalItemCount) {
System.out.println(firstVisibleItem+":"+visibleItemCount+":"+totalItemCount);
if(firstVisibleItem+visibleItemCount == totalItemCount){
isBottom = true;
}else{
isBottom = false;
}
}
});
下面一个应用,在主Activity中EditText中添加一条数据,在其内部的ListFragment动态更新数据。
[java] view
plaincopy
public class MainActivity extends Activity {
private FragmentManager manager;
private Button button;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
manager = getFragmentManager();
button = (Button) findViewById(R.id.confirm);
//将ListFragment添加进主Activity中,如果没有使用布局加载一个ListView对象
if (manager.findFragmentByTag("right") == null) {
manager.beginTransaction()
.replace(R.id.right, new RightFrag(), "right")
.addToBackStack("right")
.commit(); //事务提交
}
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//使用内容提供者,添加数据
Uri uri = Uri.parse("content://com.baidu.provider/music");
ContentValues values = new ContentValues();
values.put("name", ((EditText) findViewById(R.id.name)).getText().toString());
Uri u = getContentResolver().insert(uri, values);
//判断数据是否添加成功
if (u != null) {
Toast.makeText(MainActivity.this, "添加成功!", 1).show();
/*
* 重启loader对象,完成数据的动态加载,
* 读者可能遇到一个问题,数据时重新加载了,但是listView的item重新回到了第一个item位置,
* 这是因为我们在重启的过程中,又为该listView设置了适配器,只要不重新设置,item的位置不会改变
*/
getLoaderManager().restartLoader(
1, //该loaderManger管理下的Id为1的loader
null, //传递参数bundle,常为null
(RightFrag) (getFragmentManager().findFragmentByTag("right")));
//LoaderManager.LoaderCallbacks的回掉函数,由于该ListFragment实现了该接口
} else {
Toast.makeText(MainActivity.this, "添加失败", 1).show();
}
}
});
}
}
[java] view
plaincopy
public class RightFrag extends ListFragment implements LoaderCallbacks<Cursor> {
private LoaderManager manager;
private MyAdapter adapter;
private List<String> list; //用于存放数据库数据,这里每个item只简单展现一条文本数据
//完成一些初始化操作
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
manager = getLoaderManager();
list = new ArrayList<String>();
adapter = new MyAdapter(); //创建自定义适配器
/*
* 为该listView设置adapter,如果普通的listView使用setAdapter()方法
* 如果该方法在Cursor数据查询完成后设置,listView的将会查询回到第一个。
*/
setListAdapter(adapter);
manager.initLoader(1, null, this); //初始化一个loader对象
}
/*完成layout布局文件的加载并返回,
* 该方法不用重写,由于ListFragment已经默认返回一个listView对象
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.list, null);
return view;
}*/
//使用内容提供者,返回loader对象
@Override
public Loader<Cursor> onCreateLoader(int id, Bundle args) {
Uri uri = Uri.parse("content://com.baidu.provider/music");
//CursorLoader是AsyncTaskLoader的子类,异步查询
return new CursorLoader(getActivity(), uri, new String[] { "name" },
null, null, null);
}
@Override
public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
/*
* 将list数据清空
* 如果数据量很大,这种操作就有问题,如果只有增加,我们就不要清空,
* 只需要记录上次查询的id,这次查询满足_id > id即可,提高效率
*/
list.clear();
while (data.moveToNext()) {
list.add(data.getString(data.getColumnIndex("name")));
}
/*
* 使用该方法应该注意,如果数据库的数据发送改变,listView不能动态更新,
* 只有适配器的对应的list数据发生了改变,调用该方法才能达到更新的效果
*/
adapter.notifyDataSetChanged();
}
@Override
public void onLoaderReset(Loader<Cursor> loader) {
}
/**
* 自定义适配器,常见将Cursor或者其他的数据存储在一个集合中,效率提高!
*
*/
private class MyAdapter extends BaseAdapter {
@Override
public int getCount() {
return list.size();
}
@Override
public Object getItem(int position) {
return list.get(position);
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
/*
* convertView为一个item条目对象,每个item滑过之后,创建的item对象有被重新销毁,为此安卓提供一种机制,
* 创建的条目不被销毁而是供后来展现的item重复使用,大大提高了效率
*/
View view = null;
if (convertView == null) { //如果没有可供重复使用的item View对象
view = getActivity().getLayoutInflater().inflate(R.layout.item, null);
//如果view的布局很复杂,可以将内部的控件保存下来
TextView textView = (TextView) view.findViewById(R.id.text);
ViewSet set = new ViewSet();
set.textView = textView;
view.setTag(set);
} else {
view = convertView; //如果已经加载将重复使用
}
//不用重复的查找控件
ViewSet views = (ViewSet) view.getTag();
views.textView.setText(list.get(position));
return view;
}
}
//保存item控件
static class ViewSet{
TextView textView;
}
}
[java] view
plaincopy
public void setNotificationUri(ContentResolver cr, Uri notifyUri) {
mContentResolver = cr;
mNotifyUri = notifyUri;
mSelfObserver = new SelfContentObserver(this);
//内部实际上也是注册了一个观察者
mContentResolver.registerContentObserver(mNotifyUri, true, mSelfObserver);
}
上面方法时cursor.setNotificationUri() 内部实现,即注册了一个观察者,当数据发生改版时,再通知。
[java] view
plaincopy
public class DBProvider extends ContentProvider{
private ContentResolver contentResolver;
@Override
public Cursor query(Uri uri, String[] projection, String selection,
String[] selectionArgs, String sortOrder) {
switch (MATCHER.match(uri)) {
case 2:
SQLiteDatabase db = myDB.getWritableDatabase();
Cursor cursor = db.query("music", projection, selection, null, null, null, null);
/*
* cursor设置uri监听数据变化,使用了监听者模式
* 内部实际上为contentResolver注册了一个观察者
*/
cursor.setNotificationUri(contentResolver, uri);
return cursor;
}
return null;
}
@Override
public Uri insert(Uri uri, ContentValues values) {
switch (MATCHER.match(uri)) {
case 2:
SQLiteDatabase db = myDB.getWritableDatabase();
long id = db.insert("music", null, values);
if(id > 0){
//数据发生改变,发出通知
contentResolver.notifyChange(uri, null);
}
return ContentUris.withAppendedId(uri, id);
}
return null;
}
//...
}
[java] view
plaincopy
/**
* ListViewTest.java
* @author Administrator
*
*/
public class MainActivity extends ListActivity {
private ListView listView;
private List<Map<String, String>> resource;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
get();
listView = this.getListView();//由于继承了ListActivity,可以直接得到listView控件,但是前提xml文件中需指定默认id
////////method1()
listView.setAdapter(new SimpleAdapter(MainActivity.this, resource,
R.layout.item, new String[] { "name", "info" }, new int[] {
R.id.name, R.id.info }));
listView.setChoiceMode(ListView.CHOICE_MODE_SINGLE); //设定后才可选中
////////method2()
listView.setAdapter(new ArrayAdapter<String>(this,
android.R.layout.simple_list_item_single_choice, new String[] {
"河南", "湖北", "北京", "上海", "河南", "湖北", "北京", "上海", "河南",
"湖北", "北京", "上海", "河南", "湖北", "北京", "上海" }));
listView.setChoiceMode(ListView.CHOICE_MODE_SINGLE);
}
public void get() {
resource = new ArrayList<Map<String, String>>();
Map<String, String> map1 = new HashMap<String, String>();
map1.put("name", "小李飞刀");
map1.put("info", "good!");
resource.add(map1);
Map<String, String> map2 = new HashMap<String, String>();
map2.put("name", "北京爱情故事");
map2.put("info", "ok!");
resource.add(map2);
Map<String, String> map3 = new HashMap<String, String>();
map3.put("name", "亮剑");
map3.put("info", "22~~~~~~~~");
resource.add(map3);
}
}
[html] view
plaincopy
<!-- activity_main.xml -->
<LinearLayout 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:orientation="vertical" >
<LinearLayout android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView android:layout_height="wrap_content"
android:layout_width="match_parent"
android:layout_weight="1"
android:text="@string/name"
android:layout_marginLeft="3sp"/>
<TextView android:layout_height="wrap_content"
android:layout_width="match_parent"
android:layout_weight="1"
android:text="@string/age"
android:layout_marginLeft="3sp"/>
</LinearLayout>
<!-- 一定要注意ListView空间的id,详细说明要看本页说明 -->
<ListView
android:id="@android:id/list"
android:layout_width="fill_parent"
android:layout_height="match_parent"
/>
</LinearLayout>
[html] view
plaincopy
<!-- item.xml -->
<LinearLayout 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:orientation="vertical" >
<TextView
android:id="@+id/name"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textSize="20sp"
android:layout_marginLeft="3sp" />
<TextView
android:id="@+id/info"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textSize="15sp"
android:layout_marginLeft="10sp" />
</LinearLayout>
/article/1349476.html
1.ListView概述
引用:ListView是比较常用的控件,其存在的最根本的原因在于它的高效,ListView通过对象的复用从而减少内存的消耗,也减少了对象的创建从而也减少的cpu的消耗(在Androidk中创建View对象经常伴随着解析xml)。ListView的本质是一张bitmap(当然所有的控件文字等在屏幕上看到的最终都会变成bitmap),ListView会按照需求,根据Adapter提供的信息把需要的Item画出来显示在屏幕上,当屏幕滚动的时候会重新计算Item的位置并绘制出新的bitmap显示在屏幕上。这样听起来感觉可能不是很高效,但这样带的好处就是,每用为一第个Item 创建一个View对象,样式一样的对象可以共用一个View对象,减少了内存的消耗。而且ListView是事件驱动的,只有当需要的时候才会重新绘制,并且只会 绘制当前屏幕上所显示的Items.
2.ListView有关的三要素
(1).ListVeiw
用来展示列表的View,如果继承了ListActivity则使用getListView()得到listView对象(2).Adapter
用来把数据映射到ListView上的中介,常用的有ArrayAdapter,SimpleAdapter,CursorAdapter和SimpleCursorAdapter.BaseAdapter1).ArrayAdapter
构造函数objects接收一个集合或者数组,将会按照集合的元素(或者数组的子集)逐条在ListView列出,一个一行;[java] view
plaincopy
//ArrayAdapter Constructor
{
new ArrayAdapter(Context context, //The current context.
int resource, /*
The resource ID for a layout file containing a layout to use when instantiating views
例如:android.R.layout.simple_list_item_single_choice
*/
List<T> objects) //数据对象
}
2).CursorAdapter
Adapter that exposes data from a Cursor to a ListView widget. The Cursor must include a column named "_id" or this class will not work;3).SimpleAdapter
有最好的扩充性,通过自定义xml样式文件,达到自定义的列表文件[java] view
plaincopy
//SimpleAdapter Constructor
{
SimpleAdapter (Context context, // 上下文
List<? extends Map<String, ?>> data,
/*
* A List of Maps.每个list元素就是一列
* Map集合中的key集合,应该包含后面参数(from)中每个元素
*/
int resource, //为view layout定义的一列,其中应该包含后面参数(to)中每个元素
String[] from, //从data引出的某些列名
int[] to) //从resource对应的layout文件中,找到相应的id而组成的数组,从而决定使用哪些view组件组合一个列表项
}
4).SimpleCursorAdapter
可以理解为SimpleAdapter对数据库的简单结合,可以方面的把数据库的内容以列表的形式展示出来。5).BaseAdapter
[java] viewplaincopy
/**
* 自定义适配器,常见将Cursor或者其他的数据存储在一个集合中,效率提高!
*
*/
private class MyAdapter extends BaseAdapter {
private List<String> list;
//为该适配器设置展现的数据,当我们为该适配器指定了新的数据后,应该调用notifyDataSetChanged()方法后才能完成数据的动态加载
public void setList( List<String> list){
this.list = list;
}
@Override
public int getCount() {
return list.size();
}
@Override
public Object getItem(int position) {
return list.get(position);
}
@Override
public long getItemId(int position) {
return position;
}
//重要方法,用于展现该listview的item条目
@Override
public View getView(int position, View convertView, ViewGroup parent) {
/*
* convertView为一个item条目对象,每个item滑过之后,创建的item对象有被重新销毁,为此安卓提供一种机制,
* 创建的条目不被销毁而是供后来展现的item重复使用,大大提高了效率
*/
TextView textView = null;
if (convertView == null) { //如果没有可供重复使用的item View对象
textView = new TextView(getActivity());
/*
* 里面包含一种高效的处理机制,当每个item比较复杂,如果重复的执行类型转换、查找控件等操作,将会很大浪费,
* 可以定义一个类,专门用来存放控件对象的引用。后面的例子键会介绍到
*/
} else {
textView = (TextView) convertView; //如果已经加载将重复使用
}
textView.setText(list.get(position));
textView.setPadding(20, 20, 20, 20);
textView.setBackgroundColor(Color.GREEN);
return textView;
}
}
(3).Data数据
List集合或者一个Cursor实例对象。但是如果查询数据库,将会很耗时,因此将使用loaderManager进行统一的管理,异步完成Cursor到数据集合的转化,可参考使用LoaderManager管理Loader实现异步动态加载数据一文。
3.ListView的id说明
(1).ListActivity子类
如果java类继承了ListActivity,那么表明该类只能存在一个ListView控件,可以通过getListView()方法取得默认的控件,但是在相应的xml文件中,定义的ListView必须指明固定的id,android:id="@android:id/list"
(2).Activity子类
如果java类继承了Activity,那么id就没有特定的要求,xml支持自定义id
4.ListView的滚动事件
(1).AbsListView.OnScrollListener事件类型
事件常量 | 常量值 | 描述 |
SCROLL_STATE_IDLE | 0 | 当前item处于空闲状态,没有发生滚动 |
SCROLL_STATE_TOUCH_SCROLL | 1 | item正在滚动,但是手指还停留在屏幕上 |
SCROLL_STATE_FLING | 2 | 类似惯性,当前item正在滚动 |
(2).OnScrollListener方法
[java] viewplaincopy
listView.setOnScrollListener(new AbsListView.OnScrollListener() {
@Override
public void onScrollStateChanged(AbsListView view, int scrollState) {
//监听listView的状态是否改变
}
@Override
public void onScroll(AbsListView view, int firstVisibleItem,
int visibleItemCount, int totalItemCount) {
//在滚动的过程中会触发该事件
}
});
(3).下拉刷新底部
[java] viewplaincopy
listView.setOnScrollListener(new OnScrollListener() {
private boolean isBottom = false; //用于标记是否到达顶端
//listview的状态发送改变时执行
@Override
public void onScrollStateChanged(AbsListView view, int scrollState) {
System.out.println("scrollState:"+scrollState);
if(isBottom && scrollState==OnScrollListener.SCROLL_STATE_IDLE){
System.out.println("数据加载");
//简单模拟数据加载过程
for(int j=0; j<10; j++){
Map<String, String> map = new HashMap<String, String>();
map.put("id", String.valueOf((i++)));
map.put("name", "newName="+i);
map.put("age", String.valueOf(i));
adapter.getList().add(map);
}
adapter.notifyDataSetChanged();
isBottom = false;
}
}
//在滚动的过程中不断执行
@Override
public void onScroll(AbsListView view, int firstVisibleItem,
int visibleItemCount, int totalItemCount) {
System.out.println(firstVisibleItem+":"+visibleItemCount+":"+totalItemCount);
if(firstVisibleItem+visibleItemCount == totalItemCount){
isBottom = true;
}else{
isBottom = false;
}
}
});
5.ListView数据的动态刷新
(1).通过重启loader
ListView动态更新应用很广,比如执行添加或者删除后,数据的动态更新展现。为了达到这种目的,不得不提到适配器的notifyDataSetChanged()方法,有时可能读者在使用的过程中,会发现即便调用了该方法数据并没有实时的更新,先别急,后面将分析原因。下面一个应用,在主Activity中EditText中添加一条数据,在其内部的ListFragment动态更新数据。
[java] view
plaincopy
public class MainActivity extends Activity {
private FragmentManager manager;
private Button button;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
manager = getFragmentManager();
button = (Button) findViewById(R.id.confirm);
//将ListFragment添加进主Activity中,如果没有使用布局加载一个ListView对象
if (manager.findFragmentByTag("right") == null) {
manager.beginTransaction()
.replace(R.id.right, new RightFrag(), "right")
.addToBackStack("right")
.commit(); //事务提交
}
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//使用内容提供者,添加数据
Uri uri = Uri.parse("content://com.baidu.provider/music");
ContentValues values = new ContentValues();
values.put("name", ((EditText) findViewById(R.id.name)).getText().toString());
Uri u = getContentResolver().insert(uri, values);
//判断数据是否添加成功
if (u != null) {
Toast.makeText(MainActivity.this, "添加成功!", 1).show();
/*
* 重启loader对象,完成数据的动态加载,
* 读者可能遇到一个问题,数据时重新加载了,但是listView的item重新回到了第一个item位置,
* 这是因为我们在重启的过程中,又为该listView设置了适配器,只要不重新设置,item的位置不会改变
*/
getLoaderManager().restartLoader(
1, //该loaderManger管理下的Id为1的loader
null, //传递参数bundle,常为null
(RightFrag) (getFragmentManager().findFragmentByTag("right")));
//LoaderManager.LoaderCallbacks的回掉函数,由于该ListFragment实现了该接口
} else {
Toast.makeText(MainActivity.this, "添加失败", 1).show();
}
}
});
}
}
[java] view
plaincopy
public class RightFrag extends ListFragment implements LoaderCallbacks<Cursor> {
private LoaderManager manager;
private MyAdapter adapter;
private List<String> list; //用于存放数据库数据,这里每个item只简单展现一条文本数据
//完成一些初始化操作
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
manager = getLoaderManager();
list = new ArrayList<String>();
adapter = new MyAdapter(); //创建自定义适配器
/*
* 为该listView设置adapter,如果普通的listView使用setAdapter()方法
* 如果该方法在Cursor数据查询完成后设置,listView的将会查询回到第一个。
*/
setListAdapter(adapter);
manager.initLoader(1, null, this); //初始化一个loader对象
}
/*完成layout布局文件的加载并返回,
* 该方法不用重写,由于ListFragment已经默认返回一个listView对象
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.list, null);
return view;
}*/
//使用内容提供者,返回loader对象
@Override
public Loader<Cursor> onCreateLoader(int id, Bundle args) {
Uri uri = Uri.parse("content://com.baidu.provider/music");
//CursorLoader是AsyncTaskLoader的子类,异步查询
return new CursorLoader(getActivity(), uri, new String[] { "name" },
null, null, null);
}
@Override
public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
/*
* 将list数据清空
* 如果数据量很大,这种操作就有问题,如果只有增加,我们就不要清空,
* 只需要记录上次查询的id,这次查询满足_id > id即可,提高效率
*/
list.clear();
while (data.moveToNext()) {
list.add(data.getString(data.getColumnIndex("name")));
}
/*
* 使用该方法应该注意,如果数据库的数据发送改变,listView不能动态更新,
* 只有适配器的对应的list数据发生了改变,调用该方法才能达到更新的效果
*/
adapter.notifyDataSetChanged();
}
@Override
public void onLoaderReset(Loader<Cursor> loader) {
}
/**
* 自定义适配器,常见将Cursor或者其他的数据存储在一个集合中,效率提高!
*
*/
private class MyAdapter extends BaseAdapter {
@Override
public int getCount() {
return list.size();
}
@Override
public Object getItem(int position) {
return list.get(position);
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
/*
* convertView为一个item条目对象,每个item滑过之后,创建的item对象有被重新销毁,为此安卓提供一种机制,
* 创建的条目不被销毁而是供后来展现的item重复使用,大大提高了效率
*/
View view = null;
if (convertView == null) { //如果没有可供重复使用的item View对象
view = getActivity().getLayoutInflater().inflate(R.layout.item, null);
//如果view的布局很复杂,可以将内部的控件保存下来
TextView textView = (TextView) view.findViewById(R.id.text);
ViewSet set = new ViewSet();
set.textView = textView;
view.setTag(set);
} else {
view = convertView; //如果已经加载将重复使用
}
//不用重复的查找控件
ViewSet views = (ViewSet) view.getTag();
views.textView.setText(list.get(position));
return view;
}
}
//保存item控件
static class ViewSet{
TextView textView;
}
}
(2).使用观察者模式
利用观察者模式,用于观察数据的变化。在设计内容提供者时,查询数据应该注册一个观察者,观察数据的变化。当在增删改时,再通知这种改变。该方法比上面重启loader要高效,应为使用的是同一个cursor对象。[java] view
plaincopy
public void setNotificationUri(ContentResolver cr, Uri notifyUri) {
mContentResolver = cr;
mNotifyUri = notifyUri;
mSelfObserver = new SelfContentObserver(this);
//内部实际上也是注册了一个观察者
mContentResolver.registerContentObserver(mNotifyUri, true, mSelfObserver);
}
上面方法时cursor.setNotificationUri() 内部实现,即注册了一个观察者,当数据发生改版时,再通知。
[java] view
plaincopy
public class DBProvider extends ContentProvider{
private ContentResolver contentResolver;
@Override
public Cursor query(Uri uri, String[] projection, String selection,
String[] selectionArgs, String sortOrder) {
switch (MATCHER.match(uri)) {
case 2:
SQLiteDatabase db = myDB.getWritableDatabase();
Cursor cursor = db.query("music", projection, selection, null, null, null, null);
/*
* cursor设置uri监听数据变化,使用了监听者模式
* 内部实际上为contentResolver注册了一个观察者
*/
cursor.setNotificationUri(contentResolver, uri);
return cursor;
}
return null;
}
@Override
public Uri insert(Uri uri, ContentValues values) {
switch (MATCHER.match(uri)) {
case 2:
SQLiteDatabase db = myDB.getWritableDatabase();
long id = db.insert("music", null, values);
if(id > 0){
//数据发生改变,发出通知
contentResolver.notifyChange(uri, null);
}
return ContentUris.withAppendedId(uri, id);
}
return null;
}
//...
}
6.简单适配器的使用
[java] viewplaincopy
/**
* ListViewTest.java
* @author Administrator
*
*/
public class MainActivity extends ListActivity {
private ListView listView;
private List<Map<String, String>> resource;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
get();
listView = this.getListView();//由于继承了ListActivity,可以直接得到listView控件,但是前提xml文件中需指定默认id
////////method1()
listView.setAdapter(new SimpleAdapter(MainActivity.this, resource,
R.layout.item, new String[] { "name", "info" }, new int[] {
R.id.name, R.id.info }));
listView.setChoiceMode(ListView.CHOICE_MODE_SINGLE); //设定后才可选中
////////method2()
listView.setAdapter(new ArrayAdapter<String>(this,
android.R.layout.simple_list_item_single_choice, new String[] {
"河南", "湖北", "北京", "上海", "河南", "湖北", "北京", "上海", "河南",
"湖北", "北京", "上海", "河南", "湖北", "北京", "上海" }));
listView.setChoiceMode(ListView.CHOICE_MODE_SINGLE);
}
public void get() {
resource = new ArrayList<Map<String, String>>();
Map<String, String> map1 = new HashMap<String, String>();
map1.put("name", "小李飞刀");
map1.put("info", "good!");
resource.add(map1);
Map<String, String> map2 = new HashMap<String, String>();
map2.put("name", "北京爱情故事");
map2.put("info", "ok!");
resource.add(map2);
Map<String, String> map3 = new HashMap<String, String>();
map3.put("name", "亮剑");
map3.put("info", "22~~~~~~~~");
resource.add(map3);
}
}
[html] view
plaincopy
<!-- activity_main.xml -->
<LinearLayout 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:orientation="vertical" >
<LinearLayout android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView android:layout_height="wrap_content"
android:layout_width="match_parent"
android:layout_weight="1"
android:text="@string/name"
android:layout_marginLeft="3sp"/>
<TextView android:layout_height="wrap_content"
android:layout_width="match_parent"
android:layout_weight="1"
android:text="@string/age"
android:layout_marginLeft="3sp"/>
</LinearLayout>
<!-- 一定要注意ListView空间的id,详细说明要看本页说明 -->
<ListView
android:id="@android:id/list"
android:layout_width="fill_parent"
android:layout_height="match_parent"
/>
</LinearLayout>
[html] view
plaincopy
<!-- item.xml -->
<LinearLayout 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:orientation="vertical" >
<TextView
android:id="@+id/name"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textSize="20sp"
android:layout_marginLeft="3sp" />
<TextView
android:id="@+id/info"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textSize="15sp"
android:layout_marginLeft="10sp" />
</LinearLayout>
相关文章推荐
- Android_ListView_Adapter使用和数据动态加载
- Android_ListView_Adapter使用和数据动态加载
- [置顶] Android_ListView_Adapter使用和数据动态加载
- [置顶] Android_ListView_Adapter使用和数据动态加载
- 【android动态布局】之【ListView动态加载数据模板(使用xml布局)】
- Android中使用Listview动态加载数据
- Android ListView 中Adapter的使用及listView的动态加载
- 【android动态布局】之【ListView动态加载数据模板(使用xml布局)】
- 【android动态布局】之【ListView动态加载数据模板(使用xml布局)】
- Android列表组件ListView使用详解之动态加载或修改列表数据
- android使用notifyDataSetChanged()方法,adapter的数据更新了,但是ListView的内容没有更新;
- 【Android】使用自定义Adapter优化ListView、修改数据及控件内部布局
- android结合异步任务,动态加载图片,Json解析数据展示在ListView,并且实现按日期分类展示,借口回调
- ListView动态加载数据分页(使用Handler+线程和AsyncTask两种方法)
- android开发--详解ListView,动态添加,删除Adapter中的数据项
- Android 实现json网络数据通过BaseAdapter加载到ListView中
- Android中ListView同过自定义布局并使用SimpleAdapter的方式实现数据的绑定
- ListView动态加载数据分页(使用Handler+线程和AsyncTask两种方法)
- android使用notifyDataSetChanged()方法,adapter的数据更新了,但是ListView的内容没有更新;
- android开发--详解ListView,动态添加,删除Adapter中的数据项