Android笔记----Android手势和ContentProvider

本文介绍了Android平台上的手势识别机制及其应用场景,并深入探讨了ContentProvider的实现原理及使用方法,包括如何创建自定义ContentProvider以及如何监听ContentProvider的数据变化。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

手势(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监听器实例。

       为应用程序的ActivityTouchEvent事件绑定监听器,在事件处理中指定把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:这部分是ContentProviderauthority

       words:资源部分,当访问不同资源时,这部分是动态变化的。

 

2ID部分

其他应用程序使用ContentResolver根据Uri去访问指定数据。可以通过getContentResolver()方法来获得该对象。获得ContentResolver对象后,就可以利用如下方法操作数据。

insert(Uri uri,ContentValues values):向Uri对应的ContentProvider中插入values对应的数据。

delete(Uri uri,String where, String[] selectionArgs):删除Uri对应的ContentProviderwhere提交匹配的数据。

update(Uri uri,ContentValues values,String where, String[] selectionArgs):更新Uri对应的ContentProviderwhere提交匹配的数据。

query (Uri uri,String[] projection,String selection, String[] selectionArgs,String sortOrder):查询Uri对应的ContentProviderwhere提交匹配数据。

 

 

操作系统的ContentProvider

使用ContentResolver操作数据的步骤很简单如下所示:

       调用ActivitygetContentResolver()获取ContentResolver()对象。

       根据需要调用ContentResolverinsert()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:管理联系人EmailUri

例:

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描述)进行监听,当监听到数据变化通知时,系统就会调用ContentObserveronChange()方法 。

ContentResolver提供了如下方法来注册监听器:registerContentObserver(Uri uri,boolean notifyForDescendents , ContentObserver observer)

uri:该监听器所监听的ContentProviderUri

notifyForDescendents:如果该参数设为true,假如注册监听的Uricontent://abc,那么Uricontent://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"/>



 

 

 

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值