手势(Gesture)
ContentProvider简介
操作系统的ContentProvider
实现ContentProvider
监听ContentProvider的数据改变
手势(Gesture)
所谓手势,指用户手指或触摸笔在触摸屏上的连续触碰行为。手势这种连续的触碰会形成某个方向上的移动趋势,也会形成一个不规则的几何图形。
Android对两种手势行为都提供了支持:
第一种手势行为而言,Android提供了手势检测,并为手势提供相应的监听器。
对于第二种手势行为,Android允许开发者添加手势,并提供相应的API。
1.1 手势检测
GestureDetector是一个手势检测器,创建GestureDetector时需要传入一个GestureDetector.OnGestureListener实例, 负责对用户的手势行为提供响应。GestureDetector包含的事件处理方法如下:
boolean onDown(MotionEvent e):当触碰事件按下时触发该方法。
boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) :在触摸屏上拖过时触发该方法。
void onLongPress(MotionEvent e):当用户在屏幕上长按时触发该方法。
boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY):当用户在屏幕上”滚动”时触发该方法。
void onShowPress(MotionEvent e) :当用户在触摸屏上按下、而且还未移动和松开时触发该方法。
boolean onSingleTapConfirmed(MotionEvent e)
boolean onSingleTapUp(MotionEvent e):用户在屏幕上的轻击事件将会触发该方法。
使用Android手势检测只需要两个步骤:
创建一个GestureDetector对象,创建该对象时必须实现GestureDetector.OnGestureListener监听器实例。
为应用程序的Activity的TouchEvent事件绑定监听器,在事件处理中指定把Activity上的TouchEvent事件交给GestureDetector处理。
例:手势动作测试:
手势动作测试
GestureTest.java
public class GestureTest extends Activity
implements OnGestureListener
{
// 定义手势检测器实例
GestureDetector detector;
@Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
//创建手势检测器
detector = new GestureDetector(this);
}
//将该Activity上的触碰事件交给GestureDetector处理
@Override
public boolean onTouchEvent(MotionEvent me)
{
return detector.onTouchEvent(me);
}
@Override
public boolean onDown(MotionEvent arg0)
{
Toast.makeText(this,"onDown" , 8000)
.show();
return false;
}
@Override
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX,
float velocityY)
{
Toast.makeText(this , "onFling" , 8000)
.show();
return false;
}
@Override
public void onLongPress(MotionEvent e)
{
Toast.makeText(this ,"onLongPress" , 8000)
.show();
}
@Override
public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX,
float distanceY)
{
Toast.makeText(this ,"onScroll" , 8000)
.show();
return false;
}
@Override
public void onShowPress(MotionEvent e)
{
Toast.makeText(this ,"onShowPress" , 8000)
.show();
}
@Override
public boolean onSingleTapUp(MotionEvent e)
{
Toast.makeText(this ,"onSingleTapUp" , 8000)
.show();
return false;
}
}
例:手势实现翻页效果:
GestureFlip.java
public class GestureFlip extends Activity
implements OnGestureListener
{
// ViewFlipper实例
ViewFlipper flipper;
// 定义手势检测器实例
GestureDetector detector;
//定义一个动画数组,用于为ViewFlipper指定切换动画效果
Animation[] animations = new Animation[4];
//定义手势动作两点之间的最小距离
final int FLIP_DISTANCE = 50;
@Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
//创建手势检测器
detector = new GestureDetector(this);
// 获得ViewFlipper实例
flipper = (ViewFlipper) this.findViewById(R.id.flipper);
// 为ViewFlipper添加5个ImageView组件
flipper.addView(addImageView(R.drawable.java));
flipper.addView(addImageView(R.drawable.ee));
flipper.addView(addImageView(R.drawable.ajax));
flipper.addView(addImageView(R.drawable.xml));
flipper.addView(addImageView(R.drawable.classic));
//初始化Animation数组
animations[0] = AnimationUtils.loadAnimation(this
, R.anim.left_in);
animations[1] = AnimationUtils.loadAnimation(this
, R.anim.left_out);
animations[2] = AnimationUtils.loadAnimation(this
, R.anim.right_in);
animations[3] = AnimationUtils.loadAnimation(this
, R.anim.right_out);
}
// 定义添加ImageView的工具方法
private View addImageView(int resId)
{
ImageView imageView = new ImageView(this);
imageView.setImageResource(resId);
imageView.setScaleType(ImageView.ScaleType.CENTER);
return imageView;
}
@Override
public boolean onFling(MotionEvent event1, MotionEvent event2,
float velocityX, float velocityY)
{
/*
* 如果第一个触点事件的X座标大于第二个触点事件的X座标超过FLIP_DISTANCE
* 也就是手势从右向左滑。
*/
if (event1.getX() - event2.getX() > FLIP_DISTANCE)
{
// 为flipper设置切换的的动画效果
flipper.setInAnimation(animations[0]);
flipper.setOutAnimation(animations[1]);
flipper.showPrevious();
return true;
}
/*
* 如果第二个触点事件的X座标大于第一个触点事件的X座标超过FLIP_DISTANCE
* 也就是手势从右向左滑。
*/
else if (event2.getX() - event1.getX() > FLIP_DISTANCE)
{
// 为flipper设置切换的的动画效果
flipper.setInAnimation(animations[2]);
flipper.setOutAnimation(animations[3]);
flipper.showNext();
return true;
}
return false;
}
@Override
public boolean onTouchEvent(MotionEvent event)
{
//将该Activity上的触碰事件交给GestureDetector处理
return detector.onTouchEvent(event);
}
@Override
public boolean onDown(MotionEvent arg0)
{
return false;
}
@Override
public void onLongPress(MotionEvent event)
{
}
@Override
public boolean onScroll(MotionEvent event1, MotionEvent event2,
float arg2, float arg3)
{
return false;
}
@Override
public void onShowPress(MotionEvent event)
{
}
@Override
public boolean onSingleTapUp(MotionEvent event)
{
return false;
}
}
Main.xm
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical" >
<!-- 定义ViewFlipper组件 -->
<ViewFlipper
android:id="@+id/flipper"
android:layout_width="fill_parent"
android:layout_height="fill_parent" />
</LinearLayout>
1.2 增加手势
Android除了手势检测外,还允许应用程序把用户手势添加到指定文件,以备以后使用,如果程序需要,当用户下次再次画出该手势,系统将可识别该手势。
Android使用GestureLibrary来代表手势库,并提供GestureLibraries工具类来创建手势库,添加手势库的方法如下:
static GestureLibraryfromFile(File path):从path代表的文件中加载手势库。
static GestureLibraryfromFile(String path):从path代表的文件中加载手势库。
static GestureLibraryfromPrivateFile(Context context, String name):从指定的应用程序的数据文件中name文件中加载手势库。
static GestureLibraryfromRawResource(Context context, int resourceId):从resourceId所代表的资源中加载手势库。
一旦程序中获得了GestureLibrary对象后,该对象提供了如下方法来添加手势、识别手势。
例:增加手势:
AddGesture.java
public class AddGesture extends Activity
{
EditText editText;
GestureOverlayView gestureView;
@Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
// 获取文本编辑框
editText = (EditText) findViewById(R.id.gesture_name);
// 获取手势编辑视图
gestureView = (GestureOverlayView) findViewById(R.id.gesture);
// 设置手势的绘制颜色
gestureView.setGestureColor(Color.RED);
// 设置手势的绘制宽度
gestureView.setGestureStrokeWidth(4);
// 为gesture的手势完成事件绑定事件监听器
gestureView.addOnGesturePerformedListener(
new OnGesturePerformedListener()
{
@Override
public void onGesturePerformed(GestureOverlayView overlay,
final Gesture gesture)
{
//加载save.xml界面布局代表的视图
View saveDialog = getLayoutInflater().inflate(
R.layout.save, null);
// 获取saveDialog里的show组件
ImageView imageView = (ImageView) saveDialog
.findViewById(R.id.show);
// 获取saveDialog里的gesture_name组件
final EditText gestureName = (EditText) saveDialog
.findViewById(R.id.gesture_name);
// 根据Gesture包含的手势创建一个位图
Bitmap bitmap = gesture.toBitmap(128, 128, 10, 0xFFFF0000);
imageView.setImageBitmap(bitmap);
//使用对话框显示saveDialog组件
new AlertDialog.Builder(AddGesture.this)
.setView(saveDialog)
.setPositiveButton("保存", new OnClickListener()
{
@Override
public void onClick(DialogInterface dialog,
int which)
{
// 获取指定文件对应的手势库
GestureLibrary gestureLib = GestureLibraries
.fromFile("/sdcard/mygestures");
// 添加手势
gestureLib.addGesture(gestureName.getText().toString(),
gesture);
// 保存手势库
gestureLib.save();
}
})
.setNegativeButton("取消", null)
.show();
}
});
}
}
Main.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"
android:gravity="center_horizontal"
>
<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="请在下面屏幕上绘制手势"/>
<!-- 使用手势绘制组件 -->
<android.gesture.GestureOverlayView
android:id="@+id/gesture"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:gestureStrokeType="multiple" />
</LinearLayout>
save.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">
<LinearLayout
android:orientation="horizontal"
android:layout_width="fill_parent"
android:layout_height="wrap_content">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginRight="8dip"
android:text="@string/gesture_name"
/>
<!-- 定义一个文本框来让用户输入手势名 -->
<EditText
android:id="@+id/gesture_name"
android:layout_width="fill_parent"
android:layout_height="wrap_content"/>
</LinearLayout>
<!-- 定义一个图片框来显示手势 -->
<ImageView
android:id="@+id/show"
android:layout_width="128dp"
android:layout_height="128dp"
android:layout_marginTop="10dp" />
</LinearLayout>
ContentProvider简介
为了在应用程序之间交换数据,Android提供了ContentProvider,它提供了不同应用程序之间交换数据的标准API,当一个应用程序需要把自己的数据暴露给其他应用程序使用时,该应用程序通过提供ContentProvider来实现其他应用程序可通过ContentResolver来操作ContentProvider暴露的数据。
ContentProvider是四大组件之一,也需要在AndroidManifest.xml文件中进行配置。
2.1共享数据标准: ContentProvider简介
ContentProvider提供了数据访问的接口,以某种Uri的形式对外提供数据,允许其他应用访问或修改数据;其他应用程序使用ContentResolver根据Uri去访问操作指定的数据。
开发一个ContentProvider的步骤如下:
定义ContentProvider类,该类需要继承ContentProvider基类。
在AndroidManifest.xml文件中配置该ContentProvider。
一个ContentProvider类除了继承ContentProvider基类外,还需要提供的方法如下:
onCreate():ContentProvider在其它应用第一次访问时才会被创建。
insert ():用于供外部应用往ContentProvider添加数据。
delete ():用于供外部应用从ContentProvider删除数据。
update():用于供外部应用更新ContentProvider中的数据
query():用于供外部应用从ContentProvider中获取数据。
对于ContentProvider而言,都是以Uri形式对外提供数据,Uri形如:
content://www.abc/words/2
content:这部分是Android所规定的。
com.boby.providers.dictprovider:这部分是ContentProvider的authority。
words:资源部分,当访问不同资源时,这部分是动态变化的。
2:ID部分
其他应用程序使用ContentResolver根据Uri去访问指定数据。可以通过getContentResolver()方法来获得该对象。获得ContentResolver对象后,就可以利用如下方法操作数据。
insert(Uri uri,ContentValues values):向Uri对应的ContentProvider中插入values对应的数据。
delete(Uri uri,String where, String[] selectionArgs):删除Uri对应的ContentProvider中where提交匹配的数据。
update(Uri uri,ContentValues values,String where, String[] selectionArgs):更新Uri对应的ContentProvider中where提交匹配的数据。
query (Uri uri,String[] projection,String selection, String[] selectionArgs,String sortOrder):查询Uri对应的ContentProvider中where提交匹配数据。
操作系统的ContentProvider
使用ContentResolver操作数据的步骤很简单如下所示:
调用Activity的getContentResolver()获取ContentResolver()对象。
根据需要调用ContentResolver的insert()、delete()、update()和query方法。
Android系统中提供了Contacts应用程序来管理联系人,而且Android系统中还为联系人管理提供了ContentProvider,这就允许其他应用程序ContentResolver来管理联系人数据。
Android系统对联系人管理ContentProvider的几个Uri如下:
ContactsContract.Contacts.CONTENT_URI:管理联系人的Uri。
ContactsContract.CommonDataKinds.Phone.CONTENT_URI:管理联系人电话的Uri。
ContactsContract.CommonDataKinds.Email.CONTENT_URI:管理联系人Email的Uri。
例:
ContactProviderTest.java
public class ContactProviderTest extends Activity
{
Button search;
Button add;
@Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
// 获取系统界面中查找、添加两个按钮
search = (Button) findViewById(R.id.search);
add = (Button) findViewById(R.id.add);
search.setOnClickListener(new OnClickListener()
{
@Override
public void onClick(View source)
{
// 定义两个List来封装系统的联系人信息、指定联系人的电话号码、Email等详情
final ArrayList<String> names = new ArrayList<String>();
final ArrayList<ArrayList<String>> details
= new ArrayList<ArrayList<String>>();
// 使用ContentResolver查找联系人数据
Cursor cursor = getContentResolver().query(
ContactsContract.Contacts.CONTENT_URI
, null, null, null, null);
// 遍历查询结果,获取系统中所有联系人
while (cursor.moveToNext())
{
// 获取联系人ID
String contactId = cursor.getString(cursor
.getColumnIndex(ContactsContract.Contacts._ID));
// 获取联系人的名字
String name = cursor.getString(cursor
.getColumnIndex(ContactsContract.Contacts.DISPLAY_NAME));
names.add(name);
// 使用ContentResolver查找联系人的电话号码
Cursor phones = getContentResolver().query(
ContactsContract.CommonDataKinds.Phone.CONTENT_URI,
null,
ContactsContract.CommonDataKinds.Phone.CONTACT_ID
+ " = " + contactId, null, null);
ArrayList<String> detail = new ArrayList<String>();
// 遍历查询结果,获取该联系人的多个电话号码
while (phones.moveToNext())
{
// 获取查询结果中电话号码列中数据。
String phoneNumber = phones
.getString(phones
.getColumnIndex(ContactsContract
.CommonDataKinds.Phone.NUMBER));
detail.add("电话号码:" + phoneNumber);
}
phones.close();
// 使用ContentResolver查找联系人的Email地址
Cursor emails = getContentResolver().query(
ContactsContract.CommonDataKinds.Email.CONTENT_URI,
null,
ContactsContract.CommonDataKinds.Email.CONTACT_ID
+ " = " + contactId, null, null);
// 遍历查询结果,获取该联系人的多个Email地址
while (emails.moveToNext())
{
// 获取查询结果中Email地址列中数据。
String emailAddress = emails
.getString(emails
.getColumnIndex(ContactsContract
.CommonDataKinds.Email.DATA));
detail.add("邮件地址:" + emailAddress);
}
emails.close();
details.add(detail);
}
cursor.close();
//加载result.xml界面布局代表的视图
View resultDialog = getLayoutInflater().inflate(
R.layout.result, null);
// 获取resultDialog中ID为list的ExpandableListView
ExpandableListView list = (ExpandableListView)resultDialog
.findViewById(R.id.list);
//创建一个ExpandableListAdapter对象
ExpandableListAdapter adapter = new BaseExpandableListAdapter()
{
//获取指定组位置、指定子列表项处的子列表项数据
@Override
public Object getChild(int groupPosition, int childPosition)
{
return details.get(groupPosition).get(childPosition);
}
@Override
public long getChildId(int groupPosition, int childPosition)
{
return childPosition;
}
@Override
public int getChildrenCount(int groupPosition)
{
return details.get(groupPosition).size();
}
private TextView getTextView()
{
AbsListView.LayoutParams lp = new AbsListView.LayoutParams(
ViewGroup.LayoutParams.FILL_PARENT, 64);
TextView textView = new TextView(ContactProviderTest.this);
textView.setLayoutParams(lp);
textView.setGravity(Gravity.CENTER_VERTICAL | Gravity.LEFT);
textView.setPadding(36, 0, 0, 0);
textView.setTextSize(20);
return textView;
}
// 该方法决定每个子选项的外观
@Override
public View getChildView(int groupPosition, int childPosition,
boolean isLastChild, View convertView, ViewGroup parent)
{
TextView textView = getTextView();
textView.setText(getChild(groupPosition, childPosition).toString());
return textView;
}
//获取指定组位置处的组数据
@Override
public Object getGroup(int groupPosition)
{
return names.get(groupPosition);
}
@Override
public int getGroupCount()
{
return names.size();
}
@Override
public long getGroupId(int groupPosition)
{
return groupPosition;
}
//该方法决定每个组选项的外观
@Override
public View getGroupView(int groupPosition, boolean isExpanded,
View convertView, ViewGroup parent)
{
TextView textView = getTextView();
textView.setText(getGroup(groupPosition).toString());
return textView;
}
@Override
public boolean isChildSelectable(int groupPosition, int childPosition)
{
return true;
}
@Override
public boolean hasStableIds()
{
return true;
}
};
// 为ExpandableListView设置Adapter对象
list.setAdapter(adapter);
// 使用对话框来显示查询结果。
new AlertDialog.Builder(ContactProviderTest.this)
.setView(resultDialog)
.setPositiveButton("确定" , null)
.show();
}
});
// 为add按钮的单击事件绑定监听器
add.setOnClickListener(new OnClickListener()
{
@Override
public void onClick(View v)
{
// 获取程序界面中的3个文本框
String name = ((EditText)findViewById(R.id.name))
.getText().toString();
String phone = ((EditText)findViewById(R.id.phone))
.getText().toString();
String email = ((EditText)findViewById(R.id.email))
.getText().toString();
// 创建一个空的ContentValues
ContentValues values = new ContentValues();
// 向RawContacts.CONTENT_URI执行一个空值插入,
// 目的是获取系统返回的rawContactId
Uri rawContactUri = getContentResolver()
.insert(RawContacts.CONTENT_URI, values);
long rawContactId = ContentUris.parseId(rawContactUri);
values.clear();
values.put(Data.RAW_CONTACT_ID, rawContactId);
// 设置内容类型
values.put(Data.MIMETYPE, StructuredName.CONTENT_ITEM_TYPE);
// 设置联系人名字
values.put(StructuredName.GIVEN_NAME, name);
// 向联系人URI添加联系人名字
getContentResolver().insert(
android.provider.ContactsContract.Data.CONTENT_URI, values);
values.clear();
values.put(Data.RAW_CONTACT_ID, rawContactId);
values.put(Data.MIMETYPE, Phone.CONTENT_ITEM_TYPE);
// 设置联系人的电话号码
values.put(Phone.NUMBER, phone);
// 设置电话类型
values.put(Phone.TYPE, Phone.TYPE_MOBILE);
// 向联系人电话号码URI添加电话号码
getContentResolver().insert(
android.provider.ContactsContract.Data.CONTENT_URI, values);
values.clear();
values.put(Data.RAW_CONTACT_ID, rawContactId);
values.put(Data.MIMETYPE, Email.CONTENT_ITEM_TYPE);
// 设置联系人的Email地址
values.put(Email.DATA, email);
// 设置该电子邮件的类型
values.put(Email.TYPE, Email.TYPE_WORK);
// 向联系人Email URI添加Email数据
getContentResolver().insert(
android.provider.ContactsContract.Data.CONTENT_URI, values);
Toast.makeText(ContactProviderTest.this
, "联系人数据添加成功" , 8000)
.show();
}
});
}
}
main.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"
>
<LinearLayout
android:orientation="horizontal"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:gravity="center_horizontal"
>
<Button
android:id="@+id/search"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/search"
/>
<Button
android:id="@+id/add"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/add"
/>
</LinearLayout>
<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="@string/name"
/>
<EditText
android:id="@+id/name"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:hint="@string/input"
/>
<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="@string/phone"
/>
<EditText
android:id="@+id/phone"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:phoneNumber="true"
android:hint="@string/input"
/>
<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="@string/email"
/>
<EditText
android:id="@+id/email"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:hint="@string/input"
/>
</LinearLayout>
result.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"
>
<ExpandableListView
android:id="@+id/list"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:childIndicator="@drawable/icon"
/>
</LinearLayout>
前面是如何使用ContentResolver来操作系统的ContentProvider提供的数据。下面介绍如何开发自己的ContentProvider。
4.1 创建ContentProvider的步骤:
开发一个ContentProvider子类,该子类需要实现增、删、改、查等方法。
在AndroidManifest.xml文件中注册该ContentProvider。
为了确定该ContentProvider实际能匹配的Uri,以及确定每个方法中Uri参数所操作的数据,Android系统中提供了UriMatcher工具类,提供了以下两个方法:
void addURI(String quthority,String path,int code):该方法用于向UriMatcher对象注册Uri。
int match(Uri uri):根据前面注册的Uri来判断指定Uri对应的标识码。
实现ContentProvider
Android还提供了ContentUris工具类,它是一个Uri字符串的工具类,它提供了如下两个工具方法。
withAppendedId(uri, id):用于为路径加上ID部分。
parseId(uri):用于从指定Uri中解析出所包含的ID值。
监听ContentProvider的数据改变
当ContentProvider将数据共享出来以后,ContentResolver会根据业务需要主动查询ContentProvider所共享数据;在有些时候,应用程序需要实时监听ContentProvider所共享数据的改变。并随着ContentProvider的数据改变而提供响应,这就需要利用ContentObserver了。
5.1 ContentObserver简介
ContentProvider 发生数据变化时,调用getContentResolver().notifyChange(uri, null)来通知注册在此URI上的访问者
访问者使用ContentObserver对数据(数据采用uri描述)进行监听,当监听到数据变化通知时,系统就会调用ContentObserver的onChange()方法 。
ContentResolver提供了如下方法来注册监听器:registerContentObserver(Uri uri,boolean notifyForDescendents , ContentObserver observer)
uri:该监听器所监听的ContentProvider的Uri。
notifyForDescendents:如果该参数设为true,假如注册监听的Uri为content://abc,那么Uri为content://abc/xyz的数据改变时也会触发该监听器。如果该参数设为false,只有content://abc的数据发生改变时会触发该监听器。
observer:监听器实例。
例:监听发出的短信:
MonitorSms.java
public class MonitorSms extends Activity
{
@Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
//为content://sms的数据改变注册监听器
getContentResolver().registerContentObserver(
Uri.parse("content://sms")
, true, new SmsObserver(new Handler()));
}
// 提供自定义的ContentObserver监听器类
private final class SmsObserver extends ContentObserver
{
public SmsObserver(Handler handler)
{
super(handler);
}
public void onChange(boolean selfChange)
{
// 查询发送箱中的短信(处于正在发送状态的短信放在发送箱)
Cursor cursor = getContentResolver().query(
Uri.parse("content://sms/outbox")
, null, null, null, null);
// 遍历查询得到的结果集,即可获取用户正在发送的短信
while (cursor.moveToNext())
{
StringBuilder sb = new StringBuilder();
// 获取短信的发送地址
sb.append("address=").append(
cursor.getString(cursor.getColumnIndex("address")));
// 获取短信的标题
sb.append(";subject=").append(
cursor.getString(cursor.getColumnIndex("subject")));
// 获取短信的内容
sb.append(";body=").append(
cursor.getString(cursor.getColumnIndex("body")));
// 获取短信的发送时间
sb.append(";time=").append(
cursor.getLong(cursor.getColumnIndex("date")));
System.out.println("Has Sent SMS:::" + sb.toString());
}
}
}
}
注意添加权限:
<!-- 授予读联系人ContentProvider的权限 -->
<uses-permission android:name="android.permission.READ_SMS"/>