First: 首先具体方法如下:
通过intent跳转到Android系统联系人的方法之一:
Intent intent=new Intent(Intent.ACTION_EDIT)
Uri data=ContactsContract.Contacts.getLookupUri(contact.get_id(), contact.getLookupKey())
intent.setDataAndType(data, ContactsContract.Contacts.CONTENT_ITEM_TYPE)
intent.putExtra("finishActivityOnSaveCompleted", true)
context.startActivity(intent)
======================================================================================================
Second: 以下部分是本人的一个学习的案例:
点击左上角编辑小图标,跳转到手机中的联系人编辑页面:具体截图在代码下方
public static void showDetail(final Context context, final Contact contact) {
AlertDialog.Builder builder=new AlertDialog.Builder(context)
//标准的AlertDialog的写法
/*builder.setIcon/setTittle/setMessage/setPositiveButton/setNativeButton
builder.create().show()*/
final AlertDialog dialog=builder.create()
dialog.show()
Window window=dialog.getWindow()//创建窗口,然后添加布局文件,用来显示联系人详细信息
/**在实际开发中LayoutInflater这个类还是非常有用的,它的作用类似于findViewById()。
* 不同点是LayoutInflater是用来找res/layout/下的xml布局文件,并且实例化;
* 而findViewById()是找xml布局文件下的具体widget控件(如Button、TextView等)。
* 具体作用:
1、对于一个没有被载入或者想要动态载入的界面,都需要使用LayoutInflater.inflate()来载入;
2、对于一个已经载入的界面,就可以使用Activity.findViewById()方法来获得其中的界面元素。
LayoutInflater 是一个抽象类,在文档中如下声明:
public abstract class LayoutInflater extends Object
获得 LayoutInflater 实例的三种方式:
1.LayoutInflater inflater = getLayoutInflater() //调用Activity的getLayoutInflater()
2.LayoutInflater localinflater =(LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE)
3. LayoutInflater inflater = LayoutInflater.from(context) */
LayoutInflater inflater=(LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE)
View view=inflater.inflate(R.layout.contact_detail_dialog1, null)
//window.setContentView(layoutId/view)两种方式,指定布局文件,或者view都可以,在layout中创建
window.setContentView(view)
//关联详情页面的头像,姓名,电话信息
ImageView ivImage=(ImageView) view.findViewById(R.id.iv_detail_image)
TextView tvName=(TextView) view.findViewById(R.id.tv_detail_name)
TextView tvNumber=(TextView) view.findViewById(R.id.tv_detail_number)
ivImage.setImageBitmap(getAmage(context, contact.getPhoto_id()))
tvName.setText(contact.getName())
tvNumber.setText(contact.getNumber())
-
//关联编辑图标和关闭图标,设置监听
ImageView ivEdit=(ImageView) view.findViewById(R.id.iv_detail_edit)
ImageView ivClose=(ImageView) view.findViewById(R.id.iv_detail_close)
//设置点击关闭按钮的监听
ivClose.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
dialog.dismiss()
}
})
ivEdit.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
//发送一个隐式意图,打开手机系统联系人界面编辑contact的信息,
Intent intent=new Intent(Intent.ACTION_EDIT)
//需要获取到数据库contacts表中lookup列中的key值,在上面遍历contacts集合时获取到
Uri data=ContactsContract.Contacts.getLookupUri(contact.get_id(), contact.getLookupKey())
intent.setDataAndType(data, ContactsContract.Contacts.CONTENT_ITEM_TYPE)
intent.putExtra("finishActivityOnSaveCompleted", true)
context.startActivity(intent)
dialog.dismiss()
}
})
}
1.适用场景1) ContentProvider为存储和读取数据提供了统一的接口
2) 使用ContentProvider,应用程序可以实现数据共享
3) android内置的许多数据都是使用ContentProvider形式,供开发者调用的(如视频,音频,图片,通讯录等)
2.相关概念介绍
1)ContentProvider简介
当应用继承ContentProvider类,并重写该类用于提供数据和存储数据的方法,就可以向其他应用共享其数据。虽然使用其他方法也可以对外共享数据,但数据访问方式会因数据存储的方式而不同,如:采用文件方式对外共享数据,需要进行文件 *** 作读写数据;采用sharedpreferences共享数据,需要使用sharedpreferences API读写数据。而使用ContentProvider共享数据的好处是统一了数据访问方式。
2)Uri类简介
Uri uri = Uri.parse("content://com.changcheng.provider.contactprovider/contact")
在Content Provider中使用的查询字符串有别于标准的SQL查询。很多诸如select, add, delete, modify等 *** 作我们都使用一种特殊的URI来进行,这种URI由3个部分组成, “content://”, 代表数据的路径,和一个可选的标识数据的ID。以下是一些示例URI:
content://media/internal/images 这个URI将返回设备上存储的所有图片
content://contacts/people/ 这个URI将返回设备上的所有联系人信息
content://contacts/people/45 这个URI返回单个结果(联系人信息中ID为45的联系人记录)
尽管这种查询字符串格式很常见,但是它看起来还是有点令人迷惑。为此,Android提供一系列的帮助类(在android.provider包下),里面包含了很多以类变量形式给出的查询字符串,这种方式更容易让我们理解一点,因此,如上面content://contacts/people/45这个URI就可以写成如下形式:
Uri person = ContentUris.withAppendedId(People.CONTENT_URI, 45)
然后执行数据查询:
Cursor cur = managedQuery(person, null, null, null)
这个查询返回一个包含所有数据字段的游标,我们可以通过迭代这个游标来获取所有的数据:
package com.wissen.testApp
public class ContentProviderDemo extends Activity {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState)
setContentView(R.layout.main)
displayRecords()
}
private void displayRecords() {
//该数组中包含了所有要返回的字段
String columns[] = new String[] { People.NAME, People.NUMBER }
Uri mContacts = People.CONTENT_URI
Cursor cur = managedQuery(
mContacts,
columns, // 要返回的数据字段
null, // WHERE子句
null, // WHERE 子句的参数
null // Order-by子句
)
if (cur.moveToFirst()) {
String name = null
String phoneNo = null
do {
// 获取字段的值
name = cur.getString(cur.getColumnIndex(People.NAME))
phoneNo = cur.getString(cur.getColumnIndex(People.NUMBER))
Toast.makeText(this, name + ” ” + phoneNo, Toast.LENGTH_LONG).show()
} while (cur.moveToNext())
}
}
}
上例示范了一个如何依次读取联系人信息表中的指定数据列name和number。
修改记录:
我们可以使用ContentResolver.update()方法来修改数据,我们来写一个修改数据的方法:
private void updateRecord(int recNo, String name) {
Uri uri = ContentUris.withAppendedId(People.CONTENT_URI, recNo)
ContentValues values = new ContentValues()
values.put(People.NAME, name)
getContentResolver().update(uri, values, null, null)
}
现在你可以调用上面的方法来更新指定记录:
updateRecord(10, ”XYZ”) //更改第10条记录的name字段值为“XYZ”
添加记录:
要增加记录,我们可以调用ContentResolver.insert()方法,该方法接受一个要增加的记录的目标URI,以及一个包含了新记录值的Map对象,调用后的返回值是新记录的URI,包含记录号。
上面的例子中我们都是基于联系人信息簿这个标准的Content Provider,现在我们继续来创建一个insertRecord() 方法以对联系人信息簿中进行数据的添加:
private void insertRecords(String name, String phoneNo) {
ContentValues values = new ContentValues()
values.put(People.NAME, name)
Uri uri = getContentResolver().insert(People.CONTENT_URI, values)
Log.d(”ANDROID”, uri.toString())
Uri numberUri = Uri.withAppendedPath(uri, People.Phones.CONTENT_DIRECTORY)
values.clear()
values.put(Contacts.Phones.TYPE, People.Phones.TYPE_MOBILE)
values.put(People.NUMBER, phoneNo)
getContentResolver().insert(numberUri, values)
}
这样我们就可以调用insertRecords(name, phoneNo)的方式来向联系人信息簿中添加联系人姓名和电话号码。
删除记录:
Content Provider中的getContextResolver.delete()方法可以用来删除记录,下面的记录用来删除设备上所有的联系人信息:
private void deleteRecords() {
Uri uri = People.CONTENT_URI
getContentResolver().delete(uri, null, null)
}
你也可以指定WHERE条件语句来删除特定的记录:
getContentResolver().delete(uri, “NAME=” + “‘XYZ XYZ’”, null)
这将会删除name为‘XYZ XYZ’的记录。
3. 创建ContentProvider
要创建我们自己的Content Provider的话,我们需要遵循以下几步:
a. 创建一个继承了ContentProvider父类的类
b. 定义一个名为CONTENT_URI,并且是public static final的Uri类型的类变量,你必须为其指定一个唯一的字符串值,最好的方案是以类的全名称, 如:
public static final Uri CONTENT_URI = Uri.parse( “content://com.google.android.MyContentProvider”)
c. 定义你要返回给客户端的数据列名。如果你正在使用Android数据库,必须为其定义一个叫_id的列,它用来表示每条记录的唯一性。
d. 创建你的数据存储系统。大多数Content Provider使用Android文件系统或SQLite数据库来保持数据,但是你也可以以任何你想要的方式来存储。
e. 如果你要存储字节型数据,比如位图文件等,数据列其实是一个表示实际保存文件的URI字符串,通过它来读取对应的文件数据。处理这种数据类型的Content Provider需要实现一个名为_data的字段,_data字段列出了该文件在Android文件系统上的精确路径。这个字段不仅是供客户端使用,而且也可以供ContentResolver使用。客户端可以调用ContentResolver.openOutputStream()方法来处理该URI指向的文件资源;如果是ContentResolver本身的话,由于其持有的权限比客户端要高,所以它能直接访问该数据文件。
f. 声明public static String型的变量,用于指定要从游标处返回的数据列。
g. 查询返回一个Cursor类型的对象。所有执行写 *** 作的方法如insert(), update() 以及delete()都将被监听。我们可以通过使用ContentResover().notifyChange()方法来通知监听器关于数据更新的信息。
h. 在AndroidMenifest.xml中使用<provider>标签来设置Content Provider。
i. 如果你要处理的数据类型是一种比较新的类型,你就必须先定义一个新的MIME类型,以供ContentProvider.geType(url)来返回。MIME类型有两种形式:一种是为指定的单个记录的,还有一种是为多条记录的。这里给出一种常用的格式:
vnd.android.cursor.item/vnd.yourcompanyname.contenttype (单个记录的MIME类型)
比如, 一个请求列车信息的URI如content://com.example.transportationprovider/trains/122 可能就会返回typevnd.android.cursor.item/vnd.example.rail这样一个MIME类型。
vnd.android.cursor.dir/vnd.yourcompanyname.contenttype (多个记录的MIME类型)
比如, 一个请求所有列车信息的URI如content://com.example.transportationprovider/trains 可能就会返回vnd.android.cursor.dir/vnd.example.rail这样一个MIME 类型。
下列代码将创建一个Content Provider,它仅仅是存储用户名称并显示所有的用户名称(使用 SQLLite数据库存储这些数据):
public class MyUsers {
public static final String AUTHORITY = “com.wissen.MyContentProvider”
// BaseColumn类中已经包含了 _id字段
public static final class User implements BaseColumns {
public static final Uri CONTENT_URI = Uri.parse(”content://com.wissen.MyContentProvider”)
// 表数据列
public static final String USER_NAME = “USER_NAME”
}
}
上面的类中定义了Content Provider的CONTENT_URI,以及数据列。下面我们将定义基于上面的类来定义实际的Content Provider类:
public class MyContentProvider extends ContentProvider {
private SQLiteDatabase sqlDB
private DatabaseHelperdbHelper
private static final String DATABASE_NAME = “Users.db”
private static final int DATABASE_VERSION= 1
private static final String TABLE_NAME= “User”
private static final String TAG = “MyContentProvider”
private static class DatabaseHelper extends SQLiteOpenHelper {
DatabaseHelper(Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION)
}
@Override
public void onCreate(SQLiteDatabase db) {
//创建用于存储数据的表
db.execSQL(”Create table ” + TABLE_NAME + “( _id INTEGER PRIMARY KEY AUTOINCREMENT, USER_NAME TEXT)”)
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
db.execSQL(”DROP TABLE IF EXISTS ” + TABLE_NAME)
onCreate(db)
}
}
@Override
public int delete(Uri uri, String s, String[] as) {
return 0
}
@Override
public String getType(Uri uri) {
return null
}
@Override
public Uri insert(Uri uri, ContentValues contentvalues) {
sqlDB = dbHelper.getWritableDatabase()
long rowId = sqlDB.insert(TABLE_NAME, “”, contentvalues)
if (rowId >0) {
Uri rowUri = ContentUris.appendId(MyUsers.User.CONTENT_URI.buildUpon(), rowId).build()
getContext().getContentResolver().notifyChange(rowUri, null)
return rowUri
}
throw new SQLException(”Failed to insert row into ” + uri)
}
@Override
public boolean onCreate() {
dbHelper = new DatabaseHelper(getContext())
return (dbHelper == null) ? false : true
}
@Override
public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {
SQLiteQueryBuilder qb = new SQLiteQueryBuilder()
SQLiteDatabase db = dbHelper.getReadableDatabase()
qb.setTables(TABLE_NAME)
Cursor c = qb.query(db, projection, selection, null, null, null, sortOrder)
c.setNotificationUri(getContext().getContentResolver(), uri)
return c
}
@Override
public int update(Uri uri, ContentValues contentvalues, String s, String[] as) {
return 0
}
}
一个名为MyContentProvider的Content Provider创建完成了,它用于从Sqlite数据库中添加和读取记录。
Content Provider的入口需要在AndroidManifest.xml中配置:
<provider android:name=”MyContentProvider” android:authorities=”com.wissen.MyContentProvider” />
之后,让我们来使用这个定义好的Content Provider:
1)为应用程序添加ContentProvider的访问权限。
2)通过getContentResolver()方法得到ContentResolver对象。
3)调用ContentResolver类的query()方法查询数据,该方法会返回一个Cursor对象。
4)对得到的Cursor对象进行分析,得到需要的数据。
5)调用Cursor类的close()方法将Cursor对象关闭。
public class MyContentDemo extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState)
insertRecord(”MyUser”)
displayRecords()
}
private void insertRecord(String userName) {
ContentValues values = new ContentValues()
values.put(MyUsers.User.USER_NAME, userName)
getContentResolver().insert(MyUsers.User.CONTENT_URI, values)
}
private void displayRecords() {
String columns[] = new String[] { MyUsers.User._ID, MyUsers.User.USER_NAME }
Uri myUri = MyUsers.User.CONTENT_URI
Cursor cur = managedQuery(myUri, columns,null, null, null )
if (cur.moveToFirst()) {
String id = null
String userName = null
do {
id = cur.getString(cur.getColumnIndex(MyUsers.User._ID))
userName = cur.getString(cur.getColumnIndex(MyUsers.User.USER_NAME))
Toast.makeText(this, id + ” ” + userName, Toast.LENGTH_LONG).show()
} while (cur.moveToNext())
}
}
}
Android 系统给我们提供了访问通讯录的接口,通过接口获取通讯录信息。Adapter 与 View 的连接主要依靠 getView 这个方法返回我们需要的自定义 view。 ListView 是 Android App 中一个最最最常用的控件了,所以如何让 ListView 流畅运行,获取良好的用户体验是非常重要的。 对 ListView 优化就是对 Adapter 中的 getView 方法进行优化。
核心内容:
1.获取手机通讯录
2.数据封装
3.创建 Adapter
4.优化适配器
开发环境:Eclipse
效果图:
步骤:
1.新建项目,新建 GetNumber.class 类,用来获取通讯录中的信息
package com.yanis.getmyphonenumberimport java.util.ArrayListimport java.util.Listimport android.content.Contextimport android.database.Cursorimport android.provider.ContactsContract.CommonDataKinds.Phonepublic class GetNumber { public static List<PhoneInfo>lists = new ArrayList<PhoneInfo>() public static String getNumber(Context context) {
Cursor cursor = context.getContentResolver().query(Phone.CONTENT_URI, null, null, null, null)
String phoneNumber
String phoneName while (cursor.moveToNext()) {
phoneNumber = cursor.getString(cursor.getColumnIndex(Phone.NUMBER))//电话号码
phoneName = cursor.getString(cursor.getColumnIndex(Phone.DISPLAY_NAME))//姓名
PhoneInfo info = new PhoneInfo(phoneName, phoneNumber)
lists.add(info)
System.out.println(phoneName+phoneNumber)
} return null
}
}
2.添加权限
<!-- 读取联系人权限 --> <uses-permission android:name="android.permission.READ_CONTACTS"/>
3.新建 PhoneInfo.class 类作为通讯录信息封装类
package com.yanis.getmyphonenumber/**
*
* @author yechao
* @说明 通讯录信息封装类 */public class PhoneInfo { private String phoneName private String phoneNumber public PhoneInfo(String phoneName, String phoneNumber) {
setPhoneName(phoneName)
setPhoneNumber(phoneNumber)
} public String getPhoneName() { return phoneName
} public void setPhoneName(String phoneName) { this.phoneName = phoneName
} public String getPhoneNumber() { return phoneNumber
} public void setPhoneNumber(String phoneNumber) { this.phoneNumber = phoneNumber
}
}
4.自定义 ListView 的适配器类 MyAdapter.class
package com.yanis.getmyphonenumberimport java.util.Listimport android.content.Contextimport android.view.LayoutInflaterimport android.view.Viewimport android.view.ViewGroupimport android.widget.BaseAdapterimport android.widget.LinearLayoutimport android.widget.TextViewpublic class MyAdapter extends BaseAdapter { private List<PhoneInfo>lists private Context context//承接上下文
public MyAdapter(List<PhoneInfo>lists,Context context)
{ this.lists = lists this.context = context
}
//返回集合的数量 @Override public int getCount() { return lists.size()
} //返回当前数据 @Override public Object getItem(int position) { return lists.get(position)
} //获取当前ID @Override public long getItemId(int position) { return position
} //返回当前视图 @Override public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder holder if(convertView==null)
{
convertView = LayoutInflater.from(context).inflate(R.layout.call,null)
holder = new ViewHolder()
holder.tvName = (TextView)convertView.findViewById(R.id.tv_Name)
holder.tvNumber = (TextView)convertView.findViewById(R.id.tv_Number)
convertView.setTag(holder)
}else {
holder = (ViewHolder)convertView.getTag()
}
holder.tvName.setText(lists.get(position).getPhoneName())
holder.tvNumber.setText(lists.get(position).getPhoneNumber()) return convertView
}
private static class ViewHolder{
TextView tvName
TextView tvNumber
}
}
5.最后就是主界面代码,至于布局太简单就不列出来了,有兴趣的童鞋可以查看源代码package com.yanis.getmyphonenumberimport android.app.Activityimport android.os.Bundleimport android.widget.ListViewpublic class MainActivity extends Activity { private ListView listView private MyAdapter adapter
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
GetNumber.getNumber(this)
initView()
} private void initView() {
listView =(ListView) findViewById(R.id.listView)
adapter = new MyAdapter(GetNumber.lists, this)
listView.setAdapter(adapter)
}
}
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)