android显示数据的组件是listView.listView通过adapter适配数据,这里的数据包括字符窜 图片 组件等。
显示数据的机制:列表首先需要得到数据的长度,这时调用的方法是getCount(),然后开始绘制数据,调用getView()方法,列表如何显示就是在这一层体现。listView绘制每一个item,需要adpater返回一个视图,如果你的getCount()返回值是0的话,列表一行都不会显示,如果返回1,就只显示一行。返回几则显示几行。如果加载的数据很多的话,那么就考虑优化的问题。
向上滑动出不可视区域时就会旧的布局去填充新的布局。
ViewHolder Tag 必不可少,这个不多说!
如果自定义Item中有涉及到图片等等的,一定要狠狠的处理图片,图片占的内存是ListView项中最恶心的,处理图片的方法大致有以下几种:2.1:不要直接拿个路径就去循环decodeFile();这是找死….用Option保存图片大小、不要加载图片到内存去;2.2: 拿到的图片一定要经过边界压缩2.3:在ListView中取图片时也不要直接拿个路径去取图片,而是以WeakReference(使用WeakReference代替强引用。比如可以使 用WeakReference<Context> mContextRef)、SoftReference、WeakHashMap等的来存储图片信息,是图片信息不是图片哦!2.4:在getView中做图片转换时,产生的中间变量一定及时释放,用以下形式:
尽量避免在BaseAdapter中使用static 来定义全局静态变量,我以为这个没影响 ,这个影响很大,static是Java中的一个关键字,当用它来修饰成员变量时,那么该变量就属于该类,而不是该类的实例。所以用static修饰的变量,它的生命周期是很长的,如果用它来引用一些资源耗费过多的实例(比如Context的情况最多),这时就要尽量避免使用了..
如果为了满足需求下必须使用Context的话:Context尽量使用Application Context,因为Application的Context的生命周期比较长,引用它不会出现内存泄露的问题
尽量避免在ListView适配器中使用线程,因为线程产生内存泄露的主要原因在于线程生命周期的不可控制
记下小马自己的错误: 之前使用的自定义ListView中适配数据时使用AsyncTask自行开启线程的,这个比用Thread更危险,因为Thread只有在run函数不 结束时才出现这种内存泄露问题,然而AsyncTask内部的实现机制是运用了线程执行池(ThreadPoolExcutor,要想了解这个类的话大家加下我们的Android开发群五号,因为其它群的存储空间快满了,所以只上传到五群里了,看下小马上传的Gallery源码,你会对线程执行池、软、弱、强引用有个更深入的认识),这个类产生的Thread对象的生命周期是不确定的,是应用程序无法控制的,因此如果AsyncTask作为Activity的内部类,就更容易出现内存泄露的问题。这个问题的解决办法小马当时网上查到了记在txt里了,如下: 6.1:将线程的内部类,改为静态内部类。6.2:在线程内部采用弱引用保存Context引用
1 直接定义listView.xml
2 继承listView
生成动态数据:
1
//生成动态数组,加入数据
ArrayList<HashMap<String, Object>> listItem = new ArrayList<HashMap<String, Object>>();
for(int i=0;i<10;i++)
{
HashMap<String, Object> map = new HashMap<String, Object>();
map.put("ItemImage", R.drawable.checked);//图像资源的ID
map.put("ItemTitle", "Level "+i);
map.put("ItemText", "Finished in 1 Min 54 Secs, 70 Moves! ");
listItem.add(map);
}
//下面是数据映射关系,mFrom和mTo按顺序一一对应
String[] mFrom = new String[]{ "img","title1","title2","time"};
int[] mTo = newint[]{R.id.img,R.id.title1,R.id.title2,R.id.time};
//获取数据,这里随便加了10条数据,实际开发中可能需要从数据库或网络读取
List<Map<String,Object>> mList = new ArrayList<Map<String,Object>>();
Map<String,Object> mMap = null;
for(int i = 0;i < 10;i++){
mMap = new HashMap<String,Object>();
mMap.put("img", R.drawable.icon);
mMap.put("title1", "标题");
mMap.put("title2", "副标题");
mMap.put("time", "2011-08-15 09:00");
mList.add(mMap);
}
SimpleAdapter mAdapter = new SimpleAdapter(this,mList,R.layout.item,mFrom,mTo);
mListView.setAdapter(mAdapter);
//生成适配器的Item和动态数组对应的元素
SimpleAdapter listItemAdapter = new SimpleAdapter(this,listItem,//数据源
R.layout.list_items,//ListItem的XML实现
//动态数组与ImageItem对应的子项
new String[] { "ItemImage","ItemTitle", "ItemText"},
//ImageItem的XML文件里面的一个ImageView,两个TextView ID
newint[] {R.id.ItemImage,R.id.ItemTitle,R.id.ItemText}
);
//添加点击
list.setOnItemClickListener(new OnItemClickListener() {
@Override
publicvoid onItemClick(AdapterView<?> arg0, View arg1, int arg2,
long arg3) {
setTitle("点击第"+arg2+"个项目");
}
});
//添加长按点击
list.setOnCreateContextMenuListener(new OnCreateContextMenuListener() {
@Override
publicvoid onCreateContextMenu(ContextMenu menu, View v,ContextMenuInfo menuInfo) {
menu.setHeaderTitle("长按菜单-ContextMenu");
menu.add(0, 0, 0, "弹出长按菜单0");
menu.add(0, 1, 0, "弹出长按菜单1");
}
});
}
//长按菜单响应函数
@Override
publicboolean onContextItemSelected(MenuItem item) {
setTitle("点击了长按菜单里面的第"+item.getItemId()+"个项目");
returnsuper.onContextItemSelected(item);
}
在实际开发中基本上考虑用的是simpleAdpater
布局中常用的控件位置属性 android:layout_alignParentRight="true" android:layout_toRightOf="@id/img" android:paddingLeft="8dp" android:layout_alignParentLeft="true"
改变listView显示的背景:如果你只是换背景的颜色的话,可以直接指定android:cacheColorHint为你所要的颜色,如果你是用图片做背景的话,那也只要将android:cacheColorHint指定为透明(#00000000)就可以了,然后指定属性 android:background="@drawable/bg"
自定义ListView行间的分割线:在ListView中我们使用属性 android:divider="#FF0000" 定义分隔符为红色
点击Item时无背景颜色变化:在xml文件中的ListView控件中加入如下属性:
android:listSelector="@drawable/timer_list_selector"
在drawable中定义timer_list_selector的属性值
timer_list_selector.xml中定义如下:
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_selected="true" android:drawable="@android:color/transparent" />
</selector>
在values文件夹下的colors.xml中定义transparent如下:
<color name="transparent">#50000000</color>
设置Item之间无间隙
在xml文件中ListView控件中加入如下属性:
android:divider="#00000000"
或者在javaCode中如下定义:
listView.setDividerHeight(0);
1.、listview在拖动的时候背景图片消失变成黑色背景。等到拖动完毕我们自己的背景图片才显示出来。
2 、listview的上边和下边有黑色的阴影。
3、lsitview的每一项之间需要设置一个图片做为间隔。
针对以上问题 在listview的xml文件中设置一下语句。
问题1 有如下代码结解决 android:scrollingCache="false"
问题2 用如下代码解决:android:fadingEdge="none"
问题3 用如下代码解决: android:divider="@drawable/list_driver" 其中 @drawable/list_driver 是一个图片资源<ListView
android:id="@+id/myListView01"android:layout_width="fill_parent"android:layout_height="287dip"android:fadingEdge="none"android:scrollingCache="false"
android:divider="@drawable/list_driver"android:background="@drawable/list"></ListView>
Android系统提供了一个SQLiteOpenHelper的一个辅助类,使用此类可以完成对数据库的创建及更新
publicclass DBOpenHelper extends SQLiteOpenHelper{
/**数据库名称*/
privatestaticfinal String DATABASE_NAME="MyAppDB";
/**数据库版本*/
privatestaticfinalint DATABASE_VERSION=1;
/** 创建数据表语句*/
privatestaticfinal String DDL_CREATE_TABLE_APPINFO="CREATE TABLE IF NOT EXISTS AppInfo (appId integer primary key autoincrement,appName text,appDescription text, remark text)";
/**
* 实例化数据库连接.
* @param context
*/
public DBOpenHelper(Context context){
super(context, DATABASE_NAME, null, DATABASE_VERSION);
/**初始化数据表*/
this.getWritableDatabase().execSQL(DDL_CREATE_TABLE_APPINFO);
}
@Override
publicvoid onCreate(SQLiteDatabase db) {
// TODO Auto-generated method stub
}
@Override
publicvoid onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
// TODO Auto-generated method stub
}
}
main.xml,只添加了一个ListView用于显示数据
<?xmlversion="1.0"encoding="utf-8"?>
<LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical">
<ListView
android:id="@+id/listView_appList"
android:layout_width="match_parent"
android:layout_height="wrap_content">
</ListView>
</LinearLayout>
数据列表的项实现:list_item.xml
<?xmlversion="1.0"encoding="utf-8"?>
<LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<TextView
android:id="@+id/textView_appName"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceMedium"/>
<TextView
android:id="@+id/textView_appDescription"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceSmall"/>
</LinearLayout>
SQLiteDemoActivity 代码:
publicclass SQLiteDemoActivity extends Activity {
@Override
publicvoid onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
//initData(); //这个方法只是用来临时加载一下数据以备显示
ListView listView=(ListView)findViewById(R.id.listView_appList);
//获取查询结果
ArrayList<HashMap<String, Object>> listData=fillList();
//获取适配器
SimpleAdapter adapter=fillAdapter(listData);
//添加并且显示
listView.setAdapter(adapter);
}
/**
* 插入数据操作
*/
publicvoid initData(){
DBOpenHelper helper=new DBOpenHelper(this);
ContentValues values=new ContentValues();
values.put("appName", "手机QQ2212");
values.put("appDescription", "手机QQ2012是腾讯公司基于移动终端开发的一款应用软件。");
values.put("remark", "手机QQ2012是腾讯公司基于移动终端开发的一款应用软件。");
helper.getWritableDatabase().insert("AppInfo", null, values);
}
/**
* 查询AppInfo返回Map集合
* @return
*/
public ArrayList<HashMap<String, Object>> fillList(){
//生成动态数组,并且转载数据
ArrayList<HashMap<String, Object>> dataList = new ArrayList<HashMap<String, Object>>();
DBOpenHelper helper=new DBOpenHelper(this);
SQLiteDatabase db=helper.getReadableDatabase();
try{
Cursor cursor=db.rawQuery("SELECT * FROM AppInfo", null);
cursor.moveToFirst();
if(cursor.moveToFirst()) {
Integer appId = cursor.getInt(cursor.getColumnIndex("appId"));
String appName = cursor.getString(cursor.getColumnIndex("appName"));
String appDescription = cursor.getString(cursor.getColumnIndex("appDescription"));
HashMap<String, Object> map = new HashMap<String, Object>();
map.put("appId",appId);
map.put("appName", appName);
map.put("appDescription", appDescription);
dataList.add(map);
}
}catch(Exception ex){
ex.printStackTrace();
}finally{
if(db.isOpen()){
db.close();
}
}
return dataList;
}
/**
* 填充数据,取得数据适配器.
* @param listData
* @return
*/
public SimpleAdapter fillAdapter(ArrayList<HashMap<String, Object>> listData){
//生成适配器,数组===》ListItem
SimpleAdapter adapter = new SimpleAdapter(this,
listData,//数据来源
R.layout.list_item,//ListItem的XML实现
//动态数组与ListItem对应的子项
new String[] { "appName", "appDescription"},
//ListItem的XML文件里面的两个TextView ID
newint[] {R.id.textView_appName,R.id.textView_appDescription});
return adapter;
}
}
<?xmlversion="1.0"encoding="utf-8"?>
<selectorxmlns:android="http://www.norkoo.com">
<itemandroid:state_pressed="true">
<shape>
<gradientandroid:startcolor="#ff8c00"android:endcolor="#ffffff"
android:angle="270"/>
<strokeandroid:width="2dp"android:color="#dcdcdc"/>
<cornersandroid:radius="2dp"/>
<paddingandroid:left="10dp"android:top="10dp"
android:right="10dp"android:bottom="10dp"/>
</shape>
</item>
<itemandroid:state_focused="true">
<shape>
<gradientandroid:startcolor="#ffc2b7"android:endcolor="#ffc2b7"
android:angle="270"/>
<strokeandroid:width="2dp"android:color="#dcdcdc"/>
<cornersandroid:radius="2dp"/>
<paddingandroid:left="10dp"android:top="10dp"
android:right="10dp"android:bottom="10dp"/>
</shape>
</item>
<item>
<shape>
<gradientandroid:startcolor="#ff9d77"android:endcolor="#ff9d77"
android:angle="270"/>
<strokeandroid:width="2dp"android:color="#fad3cf"/>
<cornersandroid:radius="2dp"/>
<paddingandroid:left="10dp"android:top="10dp"
android:right="10dp"android:bottom="10dp"/>
</shape>
</item>
</selector>
listview_item_bg.xml
<?xmlversion="1.0"encoding="utf-8"?>
<selectorxmlns:android="http://schemas.android.com/apk/res/android">
<!-- focused -->
<itemandroid:drawable="@color/white"android:state_focused="true"/>
<!-- focused and pressed -->
<itemandroid:drawable="@color/white"android:state_focused="true"
android:state_pressed="true"/>
<!-- pressed -->
<itemandroid:drawable="@color/tab_blue"android:state_pressed="true"/>
<!-- default -->
<!-- <item android:drawable="@color/white" /> -->
<item>
<shape
android:shape="rectangle">
<gradientandroid:startColor="#ffffff"android:endColor="#EDEDED"
android:angle="-90"/>
</shape>
</item>
</selector>
使用:在listview里面的item的layout中:android:background="@xml/listview_item_bg"