每个ExpandableListView的child都为gridview怎么实现
一个嵌套GridView的ExpandableListView,就是说,点击ExpandableListView展开显示GridView,基本实现思路就是重写ExpandableListView的getChildView()函数;
参考代码如下:
.ns.gridlist;
import android.app.Activity;
import android.content.Context;
import android.content.res.Resources.Theme;
import android.database.Cursor;
import .Uri;
import android.os.Bundle;
import android.provider.ContactsContract;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Adapter;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.ExpandableListView;
import android.widget.GridView;
import android.widget.ImageView;
import android.widget.SimpleCursorAdapter;
import android.widget.SimpleCursorTreeAdapter;
import android.widget.TextView;
/**
* @author xiaolifan 2011-12-22
* 嵌套显示GridView的ExpandableListView*/
public class GridListViewActivity extends Activity {
private ExpandableListView mExpandableListView;
/**
* 获取联系人ID的列位置,一般都是第一个,也就是0
*/
private int mGroupIdColumnIndex;
/**
* 要查询联系人的电话号码的字段(也就是子视图的信息)
*/
private String mPhoneNumberProjection[] = new String[] {
ContactsContract.CommonDataKinds.Phone._ID,
ContactsContract.CommonDataKinds.Phone.NUMBER, };
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
mExpandableListView = (ExpandableListView) findViewById(R.id.expandableListView1);
// 查询联系人并获取其Cursor对象
Cursor groupCursor = managedQuery(
ContactsContract.Contacts.CONTENT_URI, new String[] {
ContactsContract.Contacts._ID,
ContactsContract.Contacts.DISPLAY_NAME }, null, null,
null);
// 保存取联系人ID的列位置
mGroupIdColumnIndex = groupCursor.getColumnIndexOrThrow(ContactsContract.Contacts._ID);
// 设置 adapter
MyExpandableListAdapter mAdapter = new MyExpandableListAdapter(
groupCursor, this,
R.layout.list_header_layout,// 组视图(联系人)
R.layout.list_grid_layout,// 子视图(电话号码)
new String[] { ContactsContract.Contacts.DISPLAY_NAME }, // 显示联系人名字
new int[] { R.id.textView1 },
new String[] { ContactsContract.CommonDataKinds.Phone.NUMBER }, // 显示电话号码
new int[] { R.id.textView2 });
mExpandableListView.setAdapter(mAdapter);
mExpandableListView.setOnItemClickListener(new OnItemClickListener() {
public void onItemClick(AdapterView<?> parent, View view,int position, long id) {
// TODO Auto-generated method stub
}
});
}
/**
*
* 为ExpandableListView填充数据的Adapter类,在这里面实现了在ExpandableListView中嵌套显示Gridview的功能;
*
*/
private class MyExpandableListAdapter extends SimpleCursorTreeAdapter implements OnItemClickListener{
private int gridLayoutResId;
private LayoutInflater mLayoutInflater;
private Cursor mGroupCursor;//用于填充数据的Cursor对象
public MyExpandableListAdapter(Cursor cursor, Context context,
int groupLayout, int childLayout, String[] groupFrom,
int[] groupTo, String[] childrenFrom, int[] childrenTo) {
// 别忘了调用父类的同等参数的构造函数
// 这里用了八个参数,lastChildLayout没有设置;还有就是groupLayout整合了collapsedGroupLayout和expandedGroupLayout
super(context, cursor, groupLayout, groupFrom, groupTo,
childLayout, childrenFrom, childrenTo);
this.gridLayoutResId = childLayout;
mLayoutInflater = LayoutInflater.from(GridListViewActivity.this);
this.mGroupCursor = cursor;
}
@Override
public int getChildrenCount(int groupPosition) {
//这里返回1是为了让ExpandableListView只显示一个ChildView,否则在展开
//ExpandableListView时会显示和ChildCount数量相同的GridView
return 1;
}
/**
*
* 回调函数,主要实现当选中某个组视图时,要查询指定的子视图所需的信息。
<br>
* 注意:<br>
* 别忘了在AdroidManifest.xml中配置读取联系人的权限。
<br>
*
*/
@Override
protected Cursor getChildrenCursor(Cursor groupCursor) {
// 获取联系人ID
Long contactId = groupCursor.getLong(mGroupIdColumnIndex);
Log.i("debug_out", "the contact id is " + contactId);
// 构造电话号码URI
Uri.Builder builder = ContactsContract.CommonDataKinds.Phone.CONTENT_URI.buildUpon();
Uri phoneNumbersUri = builder.build();
// 开始查询,Android推荐是其自身的managedQuery()方法进行查询,也就是自动管理Cursor。
return managedQuery(
phoneNumbersUri,
mPhoneNumberProjection,
ContactsContract.CommonDataKinds.Phone.CONTACT_ID + " = ? ",
new String[] { String.valueOf(contactId) }, null);
}
/**
* 实现嵌套GridView的关键所在,这里返回一个包含GridView控件的View并未这个GridView绑定数据*/
@Override
public View getChildView(int groupPosition, int childPosition,boolean isLastChild, View convertView, ViewGroup parent) {
ViewHolder mViewHolder;
if (convertView == null) {//利用视图缓存优化数据加载过程
convertView = mLayoutInflater.inflate(this.gridLayoutResId,null);
mViewHolder = new ViewHolder();
mViewHolder.gridView = (GridView) convertView.findViewById(R.id.gridView1);
convertView.setTag(mViewHolder);
} else {
mViewHolder = (ViewHolder) convertView.getTag();
}
this.mGroupCursor.moveToPosition(groupPosition);
Cursor childCursor = getChildrenCursor(this.mGroupCursor);
//给GridView填充数据
GridAdapter gridAdapter = new GridAdapter(
GridListViewActivity.this,
R.layout.grid_item_layout,
childCursor,
new String[] { ContactsContract.CommonDataKinds.Phone.NUMBER },
new int[] { R.id.textView2 });
mViewHolder.gridView.setAdapter(gridAdapter);
mViewHolder.gridView.setOnItemClickListener(this);
return convertView;
}
class ViewHolder {
GridView gridView;
}
public void onItemClick(AdapterView<?> parent, View view, int position,long id) {
Adapter adapter = parent.getAdapter();
Cursor cursor = (Cursor) adapter.getItem(position);
String number = cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER));
Log.i("debug_out", "------------>onItemClick the number is " + number);
}
}
private class GridAdapter extends SimpleCursorAdapter {
private LayoutInflater mLayoutInflater;
private Cursor mCursor;
public GridAdapter(Context context, int layout, Cursor c,String[] from, int[] to) {
super(context, layout, c, from, to);
mLayoutInflater = LayoutInflater.from(GridListViewActivity.this);
this.mCursor = c;
}
class ViewHolder2 {
ImageView ig;
TextView tx;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder2 mViewHolder2;
if (convertView == null) {
convertView = mLayoutInflater.inflate(R.layout.grid_item_layout, null);
mViewHolder2 = new ViewHolder2();
mViewHolder2.ig = (ImageView) convertView.findViewById(R.id.imageView2);
mViewHolder2.tx = (TextView) convertView.findViewById(R.id.textView2);
convertView.setTag(mViewHolder2);
} else {
mViewHolder2 = (ViewHolder2) convertView.getTag();
}
this.mCursor.moveToPosition(position);
String number = this.mCursor.getString(mCursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER));
Log.i("debug_out", "the number is " + number);
mViewHolder2.tx.setText(number);
return convertView;
}
}
如何使用ContentResolver
两种办法:
1.创建自己的ContentProvider,需要继承ContentProvider类
2.如果你的数据和已存在的ContentProvider数据结构一致,可以将数据写到已存在的ContentProvider中
当然前提是获取写该ContentProvider的权限.比如把OA中的成员通讯信息加入到系统的联系人ContentProvider中
ContentProvider基础
所有ContentProvider都需要实现相同的接口,用于查询ContentProvider并返回数据.也包括增加、修改和删除数据.
步骤:
1.获得一个ContentResolver的实例,可通过Activity的成员方法getContentResovler()方法:
ContentResolver cr = this.getContentResolver();
ContentResolver实例带的方法可实现找到指定的ContentProvider并获取到ContentProvider的数据
ContentResolver的查询过程开始,Android系统将确定查询所需的具体ContentProvider,确认它是否启动并运行它.
android系统负责初始化所有的ContentProvider,不需要用户自己去创建.实际上,ContentProvider的用户都不可能直接访问到ContentProvider实例,只能通过ContentResolver在中间代理.
2.数据模型
ContentProvider展示数据类似一个单个数据库表.
其中:
每行有个带唯一值的数字字段,名为_ID,可用于对表中指定记录的定位.
ContentProvider返回的数据结构,是类似JDBC的ResultSet,在android中,是Cursor对象.
URI,每个ContentProvider定义一个唯一的公开的URI,用于指定到它的数据集.
一个ContentProvider可以包含多个数据集(可以看作多张表),这样,就需要有多个URI与每个数据集对应.
这些URI要以这样的格式开头:
content://
表示这个URI指定一个ContentProvider.
如果你想创建自己的ContentProvider,最好把自定义的URI设置为类的常量,这样简化别人的调用,并且以后如果更新URI也很容易.
android定义了CONTENT_URI常量用于URI,如:android.provider.Contacts.Phones.CONTENT_URI
2.查询ContentProvider
要想使用一个ContentProvider,需要以下信息:
定义这个ContentProvider的URI,返回结果的字段名称,这些字段的数据类型
如果需要查询ContentProvider数据集的特定记录(行),还需要知道该记录的ID的值.
构建查询
查询就是输入URI等参数,其中URI是必须的,其他是可选的,如果系统能找到URI对应的ContentProvider将返回一个Cursor对象.
可以通过ContentResolver.query()或者Activity.managedQuery()方法.
两者的方法参数完全一样,查询过程和返回值也是相同的.
区别是,通过Activity.managedQuery()方法,不但获取到Cursor对象,而且能够管理Cursor对象的生命周期.
比如当Activity暂停(pause)的时候,卸载该Cursor对象,当Activity Restart的时候重新查询.另外,也可以对一个没有处于Activity管理的Cursor对象做成被Activity管理的,通过调用Activity.startManaginCursor()方法.
类似这样:
Cursor cur = managedQuery(myPerson,null,null,null,null);
其中第一个参数myPerson是Uri类型实例.
如果需要查询的是指定行的记录,需要用_ID值,比如ID值为23,URI将是类似:
content://....../23
android提供了方便的方法,让开发者不需要自己拼接上面这样的URI,比如类似:
Uri myPerson = ContentUris.withAppendedId(People.CONTENT_URI,23);
或者:
Uri myPerson = Uri.withAppendedPath(People.CONTENT_URI,"23");
二者的区别是一个接收整数类型的ID值,一个接收字符串类型.
其他几个参数:
names,可以为null,表示取数据集的全部列,或者声明一个String数组,数组中存放列名称,比如:People._ID.一般列名都在该ContentProvider中有常量对应;
针对返回结果的过滤器,格式类似于SQL中的WHERE子句,区别是不带WHERE关键字,如果返回null表示不过滤,比如name=?;
前面过滤器的参数,是String数组,是针对前面条件中?占位符的值;
排序参数,类似SQL的ORDER BY字句,不过不需要写ORDER BY部分,比如name desc,如果不排序,可输入null.
返回值是Cursor对象,游标位置在第一条记录之前.
下面实例适用于android 2.0及以上版本,从android通讯录中得到姓名字段:
java代码:
Cursor cursor = getContentResolver().query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI,null,null,null,null);
读取返回的数据
如果在查询的时候使用到ID,那么返回的数据只有一条记录.在其他情况下,一般会有多条记录.和JDBC的ResultSet类似,需要操作游标遍历结果集,在每行,再通过列名获取到列的值,可以通过getString()、getInt()、getFloat()等方法获取值.
比如类似下面:
java代码:
while(cursor.moveToNext()) {
builder.append(cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME))).append("-");
}
和JDBC中不同,没有直接通过列名获取列值的方法,只能先列名获取到列的整型索引值,然后再通过该索引值定位获取列的值.
编辑数据
可以通过ContentProvider实现以下编辑功能:
增加新的记录:
在已经存在的记录中增加新的值、批量更新已经存在的多个记录、删除记录.
所有的编辑功能都是通过ContentResolver的方法实现.一些ContentProvider对权限要求更严格一些,需要写的权限,如果没有会报错.
增加记录
要想增加记录到ContentProvider,首先,要在ContentValues对象中设置类似map的键值对,在这里,键的值对应ContentProvider中的列的名字,键值对的值,是对应列希望的类型.
然后,调用ContentResolver.insert()方法,传入这个ContentValues对象,和对应ContentProvider的URI即可.返回值是这个新记录的URI对象.这样你可以通过这个URI获得包含这条记录的Cursor对象.
比如:
java代码:
ContentValues values = new ContentValues();
values.put(People.NAME,"Abraham Lincoln");
Uri uri = getContentResolver().insert(People.CONTENT_URI, values);
在原有记录上增加值
如果记录已经存在,可在记录上增加新的值,或者编辑已经存在的值.
首先要找到原来的值对象,然后要清除原有的值,然后像上面增加记录一样即可:
java代码:
Uri uri = Uri.withAppendedPath(People.CONTENT_URI, "23");
Uri phoneUri = Uri.withAppendedPath(uri, People.Phones.CONTENT_DIRECTORY);
values.clear();
values.put(People.Phones.TYPE, People.Phones.TYPE_MOBILE);
values.put(People.Phones.NUMBER, "1233214567");
getContentResolver().insert(phoneUri, values);
批量更新值
批量更新一组记录的值,比如NY改名为Eew York.可调用ContentResolver.update()方法.
删除记录
如果是删除单个记录,调用ContentResolver.delete()方法,URI参数,指定到具体行即可.
如果是删除多个记录,调用ContentResolver.delete()方法,URI参数指定Contentprovider即可,并带一个类似SQL的WHERE子句条件.这里和上面类似,不带WHERE关键字.
创建自己的ContentProvider
创建contentprovider,需要设置存储系统.大多数ContentProvider使用文件或者SQLite数据库,不过你可以用任何方式存储数据.android提供SQLiteOpenHelper帮助开发者创建和管理SQLiteDatabase.
继承ContentProvider,提供对数据的访问.在manifest文件中声明ContentProvider.继承ContentProvider类
必须定义ContentProvider类的子类,需要实现如下方法:
java代码:
query()
insert()
update()
delete()
getType()
onCreate()
在实现子类的时候,还有一些步骤可以简化ContentProvider客户端的使用:
定义public static final Uri常量,名称为CONTENT_URI:
java代码:
public static final Uri CONTENT_URI = Uri.parse("content:/.example.codelab.transportationprovider");
如果有多个表,它们也是使用相同的CONTENT_URI,只是它们的路径部分不同.
声明ContentProvider
创建ContentProvider后,需要在manifest文件中声明,android系统才能知道它,当其他应用需要调用该ContentProvider时才能创建或者调用它.
语法类似:
android:name要写ContentProvider继承类的全名.
android:authorities要写和CONTENT_URI常量的B部分
如何将uri地址转换成url地址
string myImageUrl = "content://media/external/images/media/***";
Uri uri = Uri.parse(myImageUrl);
String[] proj = { MediaStore.Images.Media.DATA };
Cursor actualimagecursor = this.ctx.managedQuery(uri,proj,null,null,null);
int actual_image_column_index = actualimagecursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
actualimagecursor.moveToFirst();
String img_path = actualimagecursor.getString(actual_image_column_index);
URIs, URLs区别:
一、URI,是uniform resource identifier,统一资源标识符,用来唯一的标识一个资源。
二、URL是uniform resource locator,统一资源定位器,它是一种具体的URI,即URL可以用来标识一个资源,而且还指明了如何locate这个资源。
如何将uri地址转换成url地址
string myImageUrl = "content://media/external/images/media/***";
Uri uri = Uri.parse(myImageUrl);
String[] proj = { MediaStore.Images.Media.DATA };
Cursor actualimagecursor = this.ctx.managedQuery(uri,proj,null,null,null);
int actual_image_column_index = actualimagecursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
actualimagecursor.moveToFirst();
String img_path = actualimagecursor.getString(actual_image_column_index);
URIs, URLs区别:
一、URI,是uniform resource identifier,统一资源标识符,用来唯一的标识一个资源。
二、URL是uniform resource locator,统一资源定位器,它是一种具体的URI,即URL可以用来标识一个资源,而且还指明了如何locate这个资源。
android中怎么将SQLite中的数据显示在Listview中(用Cursor)
try{ Cursor myCursor = managedQuery(Uri.parse("content://sms/inbox"), projection, null, null , "date desc"); str.append(processResults(myCursor, true)); } catch (SQLiteException ex) { Log.d(LOG_TAG, ex.getMessage()); }