内容提供器(Content Provider)主要用于在不同的应用程序之间实现数据共享的功能,它提供了一套完整的机制,允许一个程序访问另一个程序中的数据,同时还能保证被访数据的安全性。目前,使用内容提供器是 Android 实现快程序共享数据的标准方式。
运行时权限:当一些软件已经让我们产生依赖的时候就会容易“店大欺客”,反正这个权限我就是要了,你自己看着办吧!Android 开发团队当然也意识到了这个问题,于是在6.0系统中加入了运行时权限功能。也就是说,用户不需要在安装软件的时候一次性授权所有申请的权限,而是可以在软件的使用过程中在对某一项权限申请进行授权。比如说一款相机应用在运行时申请了地理位置定位权限,就算我拒绝了这个权限,但是我应该仍然可以使用这个应用的其他功能,而不是像之前那样直接无法安装它。
Android现在将所有的权限归成了两类:
一类是普通权限,指的是那些不会直接威胁到用户的安全和隐私的权限,对于这部分权限申请,系统会自动帮我们进行授权,无需用户操作;
一类是危险权限,表示那些可能会触及用户隐私或者对设备安全性造成影响的权限,如获取设备联系人信息、定位设备的地理位置等,一共有九组24个权限;
权限组名 权限名
CALENDAR READ_CALENDAR、WRITE_CALENDAR
CAMERA CAMERA
CONTACTS READ_CONTACTS、WRITE_CONTACTS、GET_CAAOUNTS
LOCATION ACCESS FINE_LOCATION、ACCESS_COARSE_LOCATION
MICROPHONE RECORD_AUDIO
PHONE READ_PHONE_STATE、CALL_PHONE、RAED_CALL_LOG、WRITE_CALL_LOG、ADD_VOICEMAIL、USE_SIP、PROCESS_OUTGOING_CALLS
SENSORS BODY_SENSORS
SMS SEND_SMS、RECEIVE_SMS、READ_SMS、RECEIVE_WAP_PUSH、RECEIVE_MMS
STORAGE READ_EXTERNAL_STORAGE、WRITE_EXTERNAL_STORAGE
其实还有特殊权限。
每当要使用一个权限时,先到这张表中查一下,如果是属于这表中的权限,那么就需要进行运行时权限处理,如果不在这张表中,那么只需要在AndroidManifest.xml文件中添加一下权限声明就可以了。此外需要注意的是,上列每个危险权限都属于一个权限组,我们在进行运行时权限处理时使用的是权限名,但是用户一旦同意授权了,那么该权限所对应的权限组中所有的其他权限也会同时被授权。
运行时权限的核心就是在程序运行过程中由用户授权我们去执行某些危险操作,程序是不可以擅自做主去执行这些危险操作的。
终于自建内容提供器了,路径如下:
内容提供器的用法一般有两种,一种是使用现有的内容提供器来读取和操作相应程序中的数据,另一种是创建自己的内容提供器给我们程序的数据提供外部访问接口。
如果一个应用程序通过内容提供器对其数据提供了外部访问接口,那么其他任何程序就都可以对这部分数据进行访问。Android系统中自带的电话簿、短信、媒体库等程序都提供了类似的访问接口,这就使得第三方应用程序可以充分地利用这部分数据来实现更好的功能。
ContentResolver类
Context.getContentResolver()方法获取该类的实例
支持CRUD操作,接收参数为内容Uri参数,类似
content://com.example.app.provider/table1
一、查询操作:
1 Cursor cursor=getContentResolver().query(uri,projection:null,selection:null,selectionArgs:null,sortOrder:null);
获取结果:
1 if(cursor!=null){ 2 while(cursor.moveToNext){ 3 String column1=cursor.getString(cursor.getColumnIndex("column1")); 4 int column2=cursor.getInt(cursor.getColumnIndex("column2")); 5 } 6 corsor.close(); 7 }
二、插入操作:
1 ContentValues values=new ContentValues(); 2 values.put("column1","text"); 3 values.put("column2",1); 4 getContentResolver().insert(uri,values);
三、更新操作:
更新上一操作新增数据,把column1的值清空
1 ContentValues values=new ContentValues(); 2 values.put("column1",""); 3 getContentResolver().update(uri,values,"column1=? and column2=?",new String[]{"text","1"})
四、删除操作:
1 getContentResolver().delete(uri,"column2=?",new String[]{"1"});
创建自己的内容提供器,实现方法,定义一个继承ContentProvider的类,重写类中6个抽象方法即可
1 package com.example.databasetest; 2 3 import android.content.ContentProvider; 4 import android.content.ContentValues; 5 import android.content.UriMatcher; 6 import android.database.Cursor; 7 import android.database.sqlite.SQLiteDatabase; 8 import android.net.Uri; 9 10 public class DatabaseProvider extends ContentProvider { 11 12 public static final int BOOK_DIR=0; 13 14 public static final int BOOK_ITEM=1; 15 16 public static final int CATEGORY_DIR=2; 17 18 public static final int CATEGORY_ITEM=3; 19 20 public static final String AUTHORITY="com.example.databasetest.provider"; 21 22 private static UriMatcher uriMatcher; 23 24 private static MyDatabaseHelper dbHelper; 25 26 static{ 27 uriMatcher=new UriMatcher(UriMatcher.NO_MATCH); 28 uriMatcher.addURI(AUTHORITY,"book",BOOK_DIR); 29 uriMatcher.addURI(AUTHORITY,"book/#",BOOK_ITEM); 30 uriMatcher.addURI(AUTHORITY,"category",CATEGORY_DIR); 31 uriMatcher.addURI(AUTHORITY,"category/#",CATEGORY_ITEM); 32 } 33 34 public DatabaseProvider() { 35 36 } 37 38 @Override 39 public boolean onCreate() { 40 // TODO: Implement this to initialize your content provider on startup. 41 dbHelper=new MyDatabaseHelper(getContext(),"BookStore.db",null,2); 42 return true; 43 } 44 45 @Override 46 public int delete(Uri uri, String selection, String[] selectionArgs) { 47 // Implement this to handle requests to delete one or more rows. 48 //删除数据 49 SQLiteDatabase db=dbHelper.getWritableDatabase(); 50 int deletedRows=0; 51 switch(uriMatcher.match(uri)){ 52 case BOOK_DIR: 53 deletedRows=db.delete("Book",selection,selectionArgs); 54 break; 55 case BOOK_ITEM: 56 String bookId=uri.getPathSegments().get(1); 57 deletedRows=db.delete("Book","id=?",new String[]{bookId}); 58 break; 59 case CATEGORY_DIR: 60 deletedRows=db.delete("Category",selection,selectionArgs); 61 break; 62 case CATEGORY_ITEM: 63 String categoryId=uri.getPathSegments().get(1); 64 deletedRows=db.delete("Category","id=?",new String[]{categoryId}); 65 break; 66 default: 67 break; 68 } 69 return deletedRows; 70 } 71 72 @Override 73 public String getType(Uri uri) { 74 // TODO: Implement this to handle requests for the MIME type of the data 75 // at the given URI. 76 switch (uriMatcher.match(uri)){ 77 case BOOK_DIR: 78 return "vnd.android.cursor.dir/vnd.com.example.databasetest.provider.book"; 79 case BOOK_ITEM: 80 return "vnd.android.cursor.item/vnd.com.example.databasetest.provider.book"; 81 case CATEGORY_DIR: 82 return "vnd.android.cursor.dir/vnd.com.example.databasetest.provider.category"; 83 case CATEGORY_ITEM: 84 return "vnd.android.cursor.item/vnd.com.example.databasetest.provider.category"; 85 } 86 return null; 87 } 88 89 @Override 90 public Uri insert(Uri uri, ContentValues values) { 91 // TODO: Implement this to handle requests to insert a new row. 92 SQLiteDatabase db=dbHelper.getWritableDatabase(); 93 Uri uriReturn=null; 94 switch(uriMatcher.match(uri)){ 95 case BOOK_DIR: 96 case BOOK_ITEM: 97 long newBookId=db.insert("Book",null,values); 98 uriReturn=Uri.parse("content://"+AUTHORITY+"/book/"+newBookId); 99 break; 100 case CATEGORY_DIR: 101 case CATEGORY_ITEM: 102 long newCategoryId=db.insert("Category",null,values); 103 uriReturn=uri.parse("content://"+AUTHORITY+"/category/"+newCategoryId); 104 break; 105 default: 106 break; 107 } 108 return uriReturn; 109 } 110 111 @Override 112 public Cursor query(Uri uri, String[] projection, String selection, 113 String[] selectionArgs, String sortOrder) { 114 // TODO: Implement this to handle query requests from clients. 115 //查询数据 116 SQLiteDatabase db=dbHelper.getReadableDatabase(); 117 Cursor cursor=null; 118 switch (uriMatcher.match(uri)){ 119 case BOOK_DIR: 120 cursor=db.query("Book",projection,selection,selectionArgs,null,null,sortOrder); 121 break; 122 case BOOK_ITEM: 123 String bookId=uri.getPathSegments().get(1); 124 cursor=db.query("Book",projection,"id=?",new String[]{bookId},null,null,sortOrder); 125 break; 126 case CATEGORY_DIR: 127 cursor=db.query("Category",projection,selection,selectionArgs,null,null,sortOrder); 128 break; 129 case CATEGORY_ITEM: 130 String categoryId=uri.getPathSegments().get(1); 131 cursor=db.query("Category",projection,"id=?",new String[]{categoryId},null,null,sortOrder); 132 break; 133 default: 134 break; 135 } 136 return cursor; 137 } 138 139 @Override 140 public int update(Uri uri, ContentValues values, String selection, 141 String[] selectionArgs) { 142 // TODO: Implement this to handle requests to update one or more rows. 143 //更新数据 144 SQLiteDatabase db=dbHelper.getWritableDatabase(); 145 int updateRows=0; 146 switch (uriMatcher.match(uri)){ 147 case BOOK_DIR: 148 updateRows=db.update("Book",values,selection,selectionArgs); 149 break; 150 case BOOK_ITEM: 151 String bookId=uri.getPathSegments().get(1); 152 updateRows=db.update("Book",values,"id=?",new String[]{bookId}); 153 break; 154 case CATEGORY_DIR: 155 updateRows=db.update("Category",values,selection,selectionArgs); 156 break; 157 case CATEGORY_ITEM: 158 String categoryId=uri.getPathSegments().get(1); 159 updateRows=db.update("Category",values,"id=?",new String[]{categoryId}); 160 break; 161 default: 162 break; 163 } 164 return updateRows; 165 } 166 }