工程:
Phone、Sms (短信、单元测试)、File(存储文件、sdcard文件存储)、Other(访问file项目中的文件、AccessOtherAppPreferenceTest访问Preferences)、XML、SoftPreferences
权限:
1、添加权限方式
AndroidManifest.xml中添加电话服务权限:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="cn.nbchina.action"
android:versionCode="1"
android:versionName="1.0">
略....
<uses-sdk android:minSdkVersion=“6" />
<uses-permission android:name="android.permission.CALL_PHONE"/>
</manifest>
2、权限种类
<!-- 在SDCard中创建与删除文件权限 -->
<uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"/>
<!-- 往SDCard写入数据权限 -->
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<!-- 电话服务权限 -->
<uses-permission android:name="android.permission.CALL_PHONE"/>
<!--短信服务权限-->
<uses-permission android:name="android.permission.SEND_SMS"/>
<!--单元测试权限-->
<application ....>
<uses-library android:name="android.test.runner" />
....
</application>
<instrumentation android:name="android.test.InstrumentationTestRunner"
android:targetPackage="cn.nbchina.action" android:label="Tests for My App" />
三种通知方式:
1、状态栏通知 ppt93页
2、对话框通知 ppt94页
3、土司通知(Toast)
Toast.makeText(SmsActivity.this, R.string.success, Toast.LENGTH_LONG).show();
信息输出:
show view-->
Devices 管理设备
LogCat 查看输出信息 android输出日志信息。
输出级别(i:info;d:debug;e:error;w:warn)
Log.i(tag,输出内容); tag标签,一般使用测试代码所在类的类名作为标签。
一般定一个常量 private static final String TAG = "PersonServiceTest";
Log.i(TAG,输出内容);
System.out.println 也可向控制台输出信息 级别info
界面布局:
LinearLayout (线性布局)、AbsoluteLayout(绝对布局)、RelativeLayout(相对布局)、TableLayout(表格布局)、FrameLayout(帧布局)
- <?xmlversion="1.0"encoding="utf-8"?>
- <LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android"
- android:orientation="vertical"
- android:layout_width="fill_parent"
- android:layout_height="fill_parent">
- <TextView
- android:layout_width="fill_parent"android:layout_height="wrap_content"
- android:text="@string/inputmobile"/>
- <EditTextandroid:layout_width="fill_parent"android:layout_height="wrap_content"
- android:id="@+id/mobile"/>
- <Buttonandroid:layout_width="wrap_content"android:layout_height="wrap_content"
- android:text="@string/button"
- android:id="@+id/button"/>
- </LinearLayout>
布局几种方式
1、LinearLayout (线性布局)
2、AbsoluteLayout(绝对布局) 不建议使用
3、RelativeLayout(相对布局)
4、TableLayout(表格布局)
5、FrameLayout(帧布局) 以屏幕左上角坐标为叠加,一个个画面叠加,主要使用在动画场合。比如一个视频,鼠标移动到上面,就会出现一个画面。这就是利用了帧布局
布局实例参考file:///D:/android-sdk-windows/docs/guide/topics/ui/layout-objects.html
Dev Guide项 下的Framework Topics -->User interface -->Common Layout Objects
可查看到这几种布局的实例代码
列 相对布局
- <?xmlversion="1.0"encoding="utf-8"?>
- <RelativeLayoutxmlns:android="http://schemas.android.com/apk/res/android
- android:layout_width="fill_parent"
- android:layout_height="wrap_content"
- android:background="@drawable/blue"
- android:padding="10px">
- <TextViewandroid:id="@+id/label"
- android:layout_width="fill_parent"
- android:layout_height="wrap_content"
- android:text="Typehere:"/>
- <EditTextandroid:id="@+id/entry"
- android:layout_width="fill_parent"
- android:layout_height="wrap_content"
- android:background="@android:drawable/editbox_background"
- android:layout_below="@id/label"/>
- <Buttonandroid:id="@+id/ok"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_below="@id/entry"
- android:layout_alignParentRight="true"
- android:layout_marginLeft="10px"
- android:text="OK"/>
- <Buttonandroid:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_toLeftOf="@id/ok"
- android:layout_alignTop="@id/ok"
- android:text="Cancel"/>
- </RelativeLayout>
单元测试:
AndroidManifest.xml文件中添加权限
- packagecom.nbchina.service;
- publicclassPersonService{
- publicintsave(){
- Stringin="78";
- intb=newInteger(in);
- returnb;
- }
- }
上面targetPackage指定的包要和应用的package相同。
第二步:编写单元测试代码(选择要测试的方法,右键点击“Run As”--“Android Junit Test” ):
- packagecom.nbchina.test;
- importjunit.framework.Assert;
- importcom.nbchina.service.PersonService;
- importandroid.test.AndroidTestCase;
- importandroid.util.Log;
- publicclassPersonServiceTestextendsAndroidTestCase{
- privatestaticfinalStringTAG="PersonServiceTest";
- publicvoidtestSave()throwsThrowable{
- PersonServiceservice=newPersonService();
- intb=service.save();//检验save()方法运行是否正常
- Log.i(TAG,"result="+b);
- //System.out.println();
- //System.err.println("result="+b);
- //Assert.assertEquals(738,b);
- }
- }
- MV
- Service
- C—Activity
- V—main.xml
Android中的显示单位
px (pixels)像素
一般HVGA代表320x480像素,这个用的比较多。
dip或dp (device independent pixels)设备独立像素
这个和设备硬件有关,一般为了支持WVGA、HVGA和QVGA 推荐使用这个,不依赖像素。
sp (scaled pixels — best for text size)比例像素
主要处理字体的大小,可以根据系统的字体自适应。
为了适应不同分辨率,不同的像素密度,推荐使用dip ,文字使用sp。
数据存储与访问:
以下五种:
1、文件
2、SharedPreferences(参数)
3、SQLite数据库
4、内容提供者(Content provider)
5、网络
文件的权限:
Context.MODE_PRIVATE:为默认操作模式,代表该文件是私有数据,只能被应用本身访问,在该模式下,写入的内容会覆盖原文件的内容,如果想把新写入的内容追加到原文件中。可以使用Context.MODE_APPEND
Context.MODE_APPEND:模式会检查文件是否存在,存在就往文件追加内容,否则就创建新文件。
Context.MODE_WORLD_READABLE和Context.MODE_WORLD_WRITEABLE用来控制其他应用是否有权限读写该文件。
MODE_WORLD_READABLE:表示当前文件可以被其他应用读取;MODE_WORLD_WRITEABLE:表示当前文件可以被其他应用写入。
如果希望文件被其他应用读和写,可以传入:
openFileOutput("nbchina.txt", Context.MODE_WORLD_READABLE + Context.MODE_WORLD_WRITEABLE);
Activity还提供了getCacheDir()和getFilesDir()方法:
getCacheDir()方法用于获取/data/data/<package name>/cache目录
getFilesDir()方法用于获取/data/data/<package name>/files目录
SDCard存放文件:
要往SDCard存放文件,程序必须先判断手机是否装有SDCard,并且可以进行读写。
注意:访问SDCard必须在AndroidManifest.xml中加入访问SDCard的权限
- if(Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)){
- FilesdCardDir=Environment.getExternalStorageDirectory();//获取SDCard目录
- FilesaveFile=newFile(sdCardDir,“nbchina.txt”);
- FileOutputStreamoutStream=newFileOutputStream(saveFile);
- outStream.write("笔记本中国".getBytes());
- outStream.close();
- }
Environment.getExternalStorageState()方法用于获取SDCard的状态,如果手机装有SDCard,并且可以进行读写,那么方法返回的状态等于Environment.MEDIA_MOUNTED。
在Android平台上可以使用Simple API for XML(SAX) 事件驱动、 Document Object Model(DOM)和Android附带的事件驱动 pull解析器解析XML文件。
推荐使用pull
具体使用方式见代码。
SharedPreferences
主要用于保存软件参数,其背后是用xml文件存放数据,文件存放在/data/data/<package name>/shared_prefs目录下
访问SharedPreferences中的数据代码如下:
SharedPreferences sharedPreferences = getSharedPreferences("nbchina", Context.MODE_PRIVATE);
//getString()第二个参数为缺省值,如果preference中不存在该key,将返回缺省值
String name = sharedPreferences.getString("name", "");
int age = sharedPreferences.getInt("age", 1);
如果访问其他应用中的Preference,前提条件是:该preference创建时指定了Context.MODE_WORLD_READABLE或者Context.MODE_WORLD_WRITEABLE权限。如:有个<package name>为cn.nbchina.action的应用使用下面语句创建了preference。
getSharedPreferences("nbchina", Context.MODE_WORLD_READABLE);
其他应用要访问上面应用的preference,首先需要创建上面应用的Context,然后通过Context 访问preference ,访问preference时会在应用所在包下的shared_prefs目录找到preference :
Context otherAppsContext = createPackageContext("cn.nbchina.action", Context.CONTEXT_IGNORE_SECURITY);
SharedPreferences sharedPreferences = otherAppsContext.getSharedPreferences("nbchina", Context.MODE_WORLD_READABLE);
String name = sharedPreferences.getString("name", "");
int age = sharedPreferences.getInt("age", 0);
参考Other工程的AccessOtherAppPreferenceTest代码
嵌入式关系型SQLite数据库存储数据
为了实现对数据库版本进行管理,SQLiteOpenHelper类提供了两个重要的方法,分别是onCreate(SQLiteDatabase db)和onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion),前者用于初次使用软件时生成数据库表,后者用于升级软件时更新数据库表结构。当调用SQLiteOpenHelper的getWritableDatabase()或者getReadableDatabase()方法获取用于操作数据库的SQLiteDatabase实例的时候,如果数据库不存在,Android系统会自动生成一个数据库,接着调用onCreate()方法,onCreate()方法在初次生成数据库时才会被调用,在onCreate()方法里可以生成数据库表结构及添加一些应用使用到的初始化数据。onUpgrade()方法在数据库的版本发生变化时会被调用,一般在软件升级时才需改变版本号,而数据库的版本是由程序员控制的,假设数据库现在的版本是1,由于业务的变更,修改了数据库表结构,这时候就需要升级软件,升级软件时希望更新用户手机里的数据库表结构,为了实现这一目的,可以把原来的数据库版本设置为2(有同学问设置为3行不行?当然可以,如果你愿意,设置为100也行),并且在onUpgrade()方法里面实现表结构的更新。当软件的版本升级次数比较多,这时在onUpgrade()方法里面可以根据原版号和目标版本号进行判断,然后作出相应的表结构及数据更新。
SQLiteOpenHelper对数据库进行版本管理
- publicclassDatabaseHelperextendsSQLiteOpenHelper{
- //类没有实例化,是不能用作父类构造器的参数,必须声明为静态
- privatestaticfinalStringname="itcast";//数据库名称
- privatestaticfinalintversion=1;//数据库版本
- publicDatabaseHelper(Contextcontext){
- //第三个参数CursorFactory指定在执行查询时获得一个游标实例的工厂类,设置为null,代表使用系统默认的工厂类
- super(context,name,null,version);
- }
- @OverridepublicvoidonCreate(SQLiteDatabasedb){
- db.execSQL("CREATETABLEIFNOTEXISTSperson(personidintegerprimarykeyautoincrement,namevarchar(20),ageINTEGER)");
- }
- @OverridepublicvoidonUpgrade(SQLiteDatabasedb,intoldVersion,intnewVersion){
- db.execSQL("DROPTABLEIFEXISTSperson");
- onCreate(db);
- }
- }
上面onUpgrade()方法在数据库版本每次发生变化时都会把用户手机上的数据库表删除,然后再重新创建。一般在实际项目中是不能这样做的,正确的做法是在更新数据库表结构时,还要考虑用户存放于数据库中的数据不会丢失。
创建数据库与添删改查操作、事务操作参考实例代码
数据显示
使用ListView组件
Item.xml
- <?xmlversion="1.0"encoding="utf-8"?>
- <LinearLayout
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:orientation="horizontal"
- android:layout_width="fill_parent"
- android:layout_height="wrap_content">
- <!--android:orientation="horizontal"水平-->
- <!--android:layout_width="fill_parent"宽度填充-->
- <!--android:layout_height="wrap_content"高度包裹-->
- <TextView
- android:layout_width="80dip"
- android:layout_height="wrap_content"
- android:text="435"
- android:id="@+id/id"
- />
- <TextView
- android:layout_width="100dip"
- android:layout_height="wrap_content"
- android:text="liming"
- android:id="@+id/name"
- />
- <TextView
- android:layout_width="fill_parent"
- android:layout_height="wrap_content"
- android:text="45"
- android:id="@+id/amount"
- />
- </LinearLayout>
Main.xml
- <?xmlversion="1.0"encoding="utf-8"?>
- <LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android"
- android:orientation="vertical"
- android:layout_width="fill_parent"
- android:layout_height="fill_parent"
- >
- <Button
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="添加记录"
- android:id="@+id/insertbutton"
- />
- <LinearLayout
- android:orientation="horizontal"
- android:layout_width="fill_parent"
- android:layout_height="wrap_content">
- <TextView
- android:layout_width="80dip"
- android:layout_height="wrap_content"
- android:text="编号"
- />
- <TextView
- android:layout_width="100dip"
- android:layout_height="wrap_content"
- android:text="姓名"
- />
- <TextView
- android:layout_width="fill_parent"
- android:layout_height="wrap_content"
- android:text="存款"
- />
- </LinearLayout>
- <ListView
- android:layout_width="fill_parent"
- android:layout_height="fill_parent"
- android:id="@+id/listView"
- />
- </LinearLayout>
MainActivity.java(使用SimpleCursorAdapter方式获取数据,建议这个。)
- packagecom.nbchina.db;
- publicclassMainActivityextendsActivity{
- privatePersonServicepersonService;
- @Override
- publicvoidonCreate(BundlesavedInstanceState){
- super.onCreate(savedInstanceState);
- setContentView(R.layout.main);
- this.personService=newPersonService(this);
- ListViewlistView=(ListView)this.findViewById(R.id.listView);
- Cursorcursor=(Cursor)personService.getCursorScrollData(0,5);
- SimpleCursorAdapteradapter=newSimpleCursorAdapter(this,R.layout.item,cursor,
- newString[]{"_id","name","amount"},newint[]{R.id.id,R.id.name,R.id.amount});
- //记录集游标必须包括_id这个字段,否则会出错
- listView.setAdapter(adapter);
- listView.setOnItemClickListener(newOnItemClickListener(){
- @Override
- publicvoidonItemClick(AdapterView<?>parent,Viewview,intposition,longid){
- ListViewlView=(ListView)parent;
- Cursordata=(Cursor)lView.getItemAtPosition(position);
- intpersonid=data.getInt(data.getColumnIndex("_id"));
- Toast.makeText(MainActivity.this,personid+"",1).show();
- }
- });
- }
- }
- PersonService.java
- packagecom.nbchina.service;
- publicclassPersonService{
- privateDBOpenHelperdbOpenHelper;
- publicPersonService(Contextcontext){
- this.dbOpenHelper=newDBOpenHelper(context);
- }
- publicCursorgetCursorScrollData(Integeroffset,IntegermaxResult){
- //SimpleCursorAdaptercursor字段中必须有个_id。所以必须这么做
- SQLiteDatabasedb=dbOpenHelper.getReadableDatabase();
- returndb.rawQuery("selectpersonidas_id,name,amountfrompersonlimit?,?",
- newString[]{offset.toString(),maxResult.toString()});
- }
- }
MainActivity.java(使用SimpleAdapter方式获取数据,不建议)
- packagecom.nbchina.db;
- publicclassMainActivityextendsActivity{
- privatePersonServicepersonService;
- @Override
- publicvoidonCreate(BundlesavedInstanceState){
- super.onCreate(savedInstanceState);
- setContentView(R.layout.main);
- this.personService=newPersonService(this);
- ListViewlistView=(ListView)this.findViewById(R.id.listView);
- List<Person>persons=personService.getScrollData(0,5);
- List<HashMap<String,Object>>data=newArrayList<HashMap<String,Object>>();
- for(Personperson:persons){
- HashMap<String,Object>item=newHashMap<String,Object>();
- item.put("id",person.getId());
- item.put("name",person.getName());
- item.put("amount",person.getAmount());
- data.add(item);
- }
- SimpleAdapteradapter=newSimpleAdapter(this,data,R.layout.item,
- newString[]{"id","name","amount"},newint[]{R.id.id,R.id.name,R.id.amount});
- listView.setAdapter(adapter);
- listView.setOnItemClickListener(newOnItemClickListener(){
- @Override
- publicvoidonItemClick(AdapterView<?>parent,Viewview,intposition,longid){
- ListViewlView=(ListView)parent;
- HashMap<String,Object>item=(HashMap<String,Object>)lView.getItemAtPosition(position);
- Toast.makeText(MainActivity.this,item.get("id").toString(),1).show();
- }
- });
- }
- }
- PersonService.java
- packagecom.nbchina.service;
- publicclassPersonService{
- privateDBOpenHelperdbOpenHelper;
- publicPersonService(Contextcontext){
- this.dbOpenHelper=newDBOpenHelper(context);
- }
- publicList<Person>getScrollData(Integeroffset,IntegermaxResult){
- List<Person>persons=newArrayList<Person>();
- SQLiteDatabasedb=dbOpenHelper.getReadableDatabase();
- Cursorcursor=db.rawQuery("select*frompersonlimit?,?",
- newString[]{offset.toString(),maxResult.toString()});
- while(cursor.moveToNext()){
- intpersonid=cursor.getInt(cursor.getColumnIndex("personid"));
- Stringname=cursor.getString(cursor.getColumnIndex("name"));
- intamount=cursor.getInt(cursor.getColumnIndex("amount"));
- Personperson=newPerson(personid,name);
- person.setAmount(amount);
- persons.add(person);
- }
- cursor.close();
- returnpersons;
- }
- }
ContentProvider对外共享数据
一、配置AndroidManifest.xml
- <?xmlversion="1.0"encoding="utf-8"?>
- <manifestxmlns:android="http://schemas.android.com/apk/res/android"
- package="com.nbchina.db"
- android:versionCode="1"
- android:versionName="1.0">
- <applicationandroid:icon="@drawable/icon"android:label="@string/app_name">
- <uses-libraryandroid:name="android.test.runner"/>
- <activityandroid:name=".MainActivity"
- android:label="@string/app_name">
- ……
- </activity>
- <!--".PersonProvider"其中点代表应用的包路径。配置内容提供者-->
- <providerandroid:name=".PersonProvider"android:authorities="com.nbchina.providers.personprovider"/>
- </application>
- <uses-sdkandroid:minSdkVersion="8"/>
- </manifest>
二、建立PersonProvider.java 继承ContentProvider
- packagecom.nbchina.db;
- publicclassPersonProviderextendsContentProvider{
- //主件必须放入应用的包或者子包下。本项目person对外共享数据
- privateDBOpenHelperdbOpenHelper;
- //UriMatcher.NO_MATCH代表用户传进来的uri和里面所有的都不匹配的话,则返回NO_MATCH-1.
- privatestaticfinalUriMatcherMATCHER=newUriMatcher(UriMatcher.NO_MATCH);
- privatestaticfinalintPERSONS=1;
- privatestaticfinalintPERSON=2;
- static{
- MATCHER.addURI("com.nbchina.providers.personprovider","person",PERSONS);
- MATCHER.addURI("com.nbchina.providers.personprovider","person/#",PERSON);
- }
- @Override
- publicbooleanonCreate(){
- //当内容提供者被实例化之后调用。生命周期只调用一次。
- this.dbOpenHelper=newDBOpenHelper(this.getContext());
- returnfalse;
- }
- @Override
- publicStringgetType(Uriuri){//返回当前所操作数据的类型
- switch(MATCHER.match(uri)){
- casePERSONS:
- return"vnd.android.cursor.dir/person";
- casePERSON:
- return"vnd.android.cursor.item/person";
- default:
- thrownewIllegalArgumentException("UnkwonUri:"+uri.toString());
- }
- /*该方法用于返回当前Url所代表数据的MIME类型。
- 如果操作的数据属于集合类型,那么MIME类型字符串应该以vnd.android.cursor.dir/开头,
- 要得到所有person记录的Uri为content://com.nbchina.provider.personprovider/person,
- 那么返回的MIME类型字符串应该为:“vnd.android.cursor.dir/person”。
- 如果要操作的数据属于非集合类型数据,那么MIME类型字符串应该以vnd.android.cursor.item/开头,
- 得到id为10的person记录,Uri为content://com.nbchina.provider.personprovider/person/10,
- 那么返回的MIME类型字符串应该为:“vnd.android.cursor.item/person”。*/
- }
- @Override
- publicUriinsert(Uriuri,ContentValuesvalues){
- SQLiteDatabasedb=dbOpenHelper.getWritableDatabase();
- switch(MATCHER.match(uri)){
- casePERSONS:
- //如用字符串作为主键,则返回的是记录行号。若用数字作为主键,则返回的是主键值
- longrowid=db.insert("person","personid",values);
- <spanstyle="background-color:rgb(102,51,51);"><spanstyle="color:#ffffff;">//返回Uri,构造新的uri,把新id附加进去
- //ContentUris类使用介绍
- //ContentUris类用于获取Uri路径后面的ID部分,它有两个比较实用的方法:
- //withAppendedId(uri,id)用于为路径加上ID部分:
- //Uriuri=Uri.parse("content://cn.itcast.provider.personprovider/person")
- //UriresultUri=ContentUris.withAppendedId(uri,10);
- //生成后的Uri为:content://cn.itcast.provider.personprovider/person/10
- //parseId(uri)方法用于从路径中获取ID部分:
- //Uriuri=Uri.parse("content://cn.itcast.provider.personprovider/person/10")
- //longpersonid=ContentUris.parseId(uri);//获取的结果为:10</span></span>
- UriinsertUri=ContentUris.withAppendedId(uri,rowid);
- <spanstyle="background-color:rgb(0,0,102);"><spanstyle="color:#ffffff;">this.getContext().getContentResolver().notifyChange(uri,null);//通知Other项目中监听</span></span>
- returninsertUri;
- default:
- thrownewIllegalArgumentException("UnkwonUri:"+uri.toString());
- }
- }
- ……其他操作代码见实例
- }
Other项目中
- packagecom.nbchina.other;
- publicclassAccessContentProviderTestextendsAndroidTestCase{
- privatestaticfinalStringTAG="AccessContentProviderTest";
- /**
- *往内容提供者添加数据
- *@throwsThrowable
- */
- publicvoidtestInsert()throwsThrowable{
- 当外部应用需要对ContentProvider中的数据进行添加、删除、修改和查询操作时,可以使用ContentResolver类来完成,要获取ContentResolver对象,可以使用Activity提供的getContentResolver()方法。
- ContentResolvercontentResolver=this.getContext().getContentResolver();
- UriinsertUri=Uri.parse("content://com.nbchina.providers.personprovider/person");
- ContentValuesvalues=newContentValues();
- values.put("name","zhangxiaoxiao");
- values.put("amount",90);
- Uriuri=contentResolver.insert(insertUri,values);
- Log.i(TAG,uri.toString());
- }
- …其他操作见实例代码
- }
监听ContentProvider数据的变化
一、注册监听ContentProvider,在other项目中建立如下文件
- packagecom.nbchina.other;
- publicclassOtherActivityextendsActivity{
- //注册监听ContentProvider
- privatestaticfinalStringTAG="OtherActivity";
- @Override
- publicvoidonCreate(BundlesavedInstanceState){
- super.onCreate(savedInstanceState);
- setContentView(R.layout.main);
- UriinsertUri=Uri.parse("content://com.nbchina.providers.personprovider/person");
- ContentResolvercontentResolver=this.getContentResolver();
- //对指定uri进行监听,如果该uri代表的数据发生变化,就会调用PersonObserver中的onChange()
- <spanstyle="color:#ffffff;background-color:rgb(51,0,153);">contentResolver.registerContentObserver(insertUri,true,newPersonObserver(newHandler()));</span>
- }
- privatefinalclassPersonObserverextendsContentObserver{
- publicPersonObserver(Handlerhandler){
- super(handler);
- }
- @Override
- publicvoidonChange(booleanselfChange){//一旦数据发生改变,则查询所有内容
- ContentResolvercontentResolver=getContentResolver();
- UriselectUri=Uri.parse("content://com.nbchina.providers.personprovider/person");
- Cursorcursor=contentResolver.query(selectUri,null,null,null,"personiddesc");
- while(cursor.moveToNext()){
- intid=cursor.getInt(cursor.getColumnIndex("personid"));
- Stringname=cursor.getString(cursor.getColumnIndex("name"));
- intamount=cursor.getInt(cursor.getColumnIndex("amount"));
- Log.i(TAG,"id="+id+",name="+name+",amount="+amount);
- }
- }
- }
- }
PersonProvider 的insert方法内加入如下代码
this.getContext().getContentResolver().notifyChange(uri, null);//通知
通信录中的联系人操作
手机内项目都通过内容提供者进行操作。
联系人内容提供者
D:\android-sdk-windows\platforms\android-8\sources\ContactsProvider\src\com\android\providers\contacts\ContactsProvider2.java
呼叫记录内容提供者
D:\android-sdk-windows\platforms\android-8\sources\ContactsProvider\src\com\android\providers\contacts\CallLogProvider.java
短信内容提供者
D:\android-sdk-windows\platforms\android-8\sources\TelephonyProvider\src\com\android\providers\telephony\SmsProvider.java
彩信内容提供者
D:\android-sdk-windows\platforms\android-8\sources\TelephonyProvider\src\com\android\providers\telephony\MmsProvider.java
电话内容提供者
D:\android-sdk-windows\platforms\android-8\sources\TelephonyProvider\src\com\android\providers\telephony\ TelephonyProvider.java
建立 Content项目
AndroidManifest.xml内加入权限
- <?xmlversion="1.0"encoding="utf-8"?>
- <manifestxmlns:android="http://schemas.android.com/apk/res/android"
- package="com.nbchina.contact"
- android:versionCode="1"
- android:versionName="1.0">
- <applicationandroid:icon="@drawable/icon"android:label="@string/app_name">
- <uses-libraryandroid:name="android.test.runner"/>
- </application>
- <uses-permissionandroid:name="android.permission.READ_CONTACTS"/>
- <uses-permissionandroid:name="android.permission.WRITE_CONTACTS"/>
- <instrumentationandroid:name="android.test.InstrumentationTestRunner"
- android:targetPackage="com.nbchina.contact"android:label="TestsforMyApp"/>
- </manifest>
手机内容提供者操作代码如下
- ContactTest.java
- packagecom.nbchina.contact;
- publicclassContactTestextendsAndroidTestCase{
- privatestaticfinalStringTAG="ContactTest";
- publicvoidtestGetAllContact()throwsThrowable{
- //content://com.android.contacts/contacts
- Uriuri=ContactsContract.Contacts.CONTENT_URI;
- //访问内容提供者
- ContentResolvercontentResolver=this.getContext().getContentResolver();
- //查询所有数据
- //contentResolver.query(uri,projection,selection,selectionArgs,sortOrder)
- Cursorcursor=contentResolver.query(uri,null,null,null,null);
- while(cursor.moveToNext()){
- StringBuildersb=newStringBuilder();
- StringcontactId=cursor.getString(cursor.getColumnIndex(ContactsContract.Contacts._ID));
- Stringname=cursor.getString(cursor.getColumnIndex(ContactsContract.Contacts.DISPLAY_NAME));
- sb.append("contactId=").append(contactId).append(",name=").append(name);
- Cursorphones=contentResolver.query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI,
- null,
- ContactsContract.CommonDataKinds.Phone.CONTACT_ID+"="+contactId,
- null,null);
- while(phones.moveToNext()){
- StringphoneNumber=phones.getString(phones.getColumnIndex(
- ContactsContract.CommonDataKinds.Phone.NUMBER));
- sb.append(",phone=").append(phoneNumber);
- }
- phones.close();
- Cursoremails=contentResolver.query(ContactsContract.CommonDataKinds.Email.CONTENT_URI,
- null,
- ContactsContract.CommonDataKinds.Email.CONTACT_ID+"="+contactId,
- null,null);
- while(emails.moveToNext()){
- StringemailAddress=emails.getString(emails.getColumnIndex(
- ContactsContract.CommonDataKinds.Email.DATA));
- sb.append(",emailAddress=").append(emailAddress);
- }
- emails.close();
- Log.i(TAG,sb.toString());
- }
- cursor.close();
- }
- /**
- *首先向RawContacts.CONTENT_URI执行一个空值插入,目的是获取系统返回的rawContactId
- *这时后面插入data表的依据,只有执行空值插入,才能使插入的联系人在通讯录里面可见
- */
- publicvoidtestInsert(){
- ContentValuesvalues=newContentValues();
- //首先向RawContacts.CONTENT_URI执行一个空值插入,目的是获取系统返回的rawContactId
- UrirawContactUri=this.getContext().getContentResolver().insert(RawContacts.CONTENT_URI,values);
- longrawContactId=ContentUris.parseId(rawContactUri);
- //往data表入姓名数据
- values.clear();
- values.put(Data.RAW_CONTACT_ID,rawContactId);
- values.put(Data.MIMETYPE,StructuredName.CONTENT_ITEM_TYPE);//内容类型
- values.put(StructuredName.GIVEN_NAME,"李天山");
- this.getContext().getContentResolver().insert(android.provider.ContactsContract.Data.CONTENT_URI,values);
- //往data表入电话数据
- values.clear();
- values.put(Data.RAW_CONTACT_ID,rawContactId);
- values.put(Data.MIMETYPE,Phone.CONTENT_ITEM_TYPE);
- values.put(Phone.NUMBER,"13921009789");
- values.put(Phone.TYPE,Phone.TYPE_MOBILE);
- this.getContext().getContentResolver().insert(android.provider.ContactsContract.Data.CONTENT_URI,values);
- //往data表入Email数据
- values.clear();
- values.put(Data.RAW_CONTACT_ID,rawContactId);
- values.put(Data.MIMETYPE,Email.CONTENT_ITEM_TYPE);
- values.put(Email.DATA,"[email protected]");
- values.put(Email.TYPE,Email.TYPE_WORK);
- this.getContext().getContentResolver().insert(android.provider.ContactsContract.Data.CONTENT_URI,values);
- }
- //批量添加,处于同一个事务中.一般添加最好使用此方式。删除修改等自己研究。
- publicvoidtestSave()throwsThrowable{
- //文档位置:reference\android\provider\ContactsContract.RawContacts.html
- ArrayList<ContentProviderOperation>ops=newArrayList<ContentProviderOperation>();
- intrawContactInsertIndex=ops.size();
- ops.add(ContentProviderOperation.newInsert(RawContacts.CONTENT_URI)
- .withValue(RawContacts.ACCOUNT_TYPE,null)
- .withValue(RawContacts.ACCOUNT_NAME,null)
- .build());
- //文档位置:reference\android\provider\ContactsContract.Data.html
- ops.add(ContentProviderOperation.newInsert(android.provider.ContactsContract.Data.CONTENT_URI)
- .withValueBackReference(Data.RAW_CONTACT_ID,rawContactInsertIndex)
- .withValue(Data.MIMETYPE,StructuredName.CONTENT_ITEM_TYPE)
- .withValue(StructuredName.GIVEN_NAME,"赵薇")
- .build());
- ops.add(ContentProviderOperation.newInsert(android.provider.ContactsContract.Data.CONTENT_URI)
- .withValueBackReference(Data.RAW_CONTACT_ID,rawContactInsertIndex)
- .withValue(Data.MIMETYPE,Phone.CONTENT_ITEM_TYPE)
- .withValue(Phone.NUMBER,"13671323809")
- .withValue(Phone.TYPE,Phone.TYPE_MOBILE)
- .withValue(Phone.LABEL,"手机号")
- .build());
- ops.add(ContentProviderOperation.newInsert(android.provider.ContactsContract.Data.CONTENT_URI)
- .withValueBackReference(Data.RAW_CONTACT_ID,rawContactInsertIndex)
- .withValue(Data.MIMETYPE,Email.CONTENT_ITEM_TYPE)
- .withValue(Email.DATA,"[email protected]")
- .withValue(Email.TYPE,Email.TYPE_WORK)
- .build());
- ContentProviderResult[]results=this.getContext().getContentResolver()
- .applyBatch(ContactsContract.AUTHORITY,ops);
- for(ContentProviderResultresult:results){
- Log.i(TAG,result.uri.toString());
- }
- }
- }