Android学习随笔(13)------内容提供器
来源:互联网 发布:网络教学英语作文优点 编辑:程序博客网 时间:2024/06/07 12:47
学习流程来自《第一行代码》(第二版)
Content Provider主要用于在不同应用之间实现跨程序数据共享。
Android运行时权限
Android在6.0系统中加入了运行时权限功能,将所有权限归为了两类 :
1. 普通权限 :系统自动帮我们授权
2. 危险权限 :需要用户手动授权 一共9组,24个权限。一旦用户同意授权,那么该权限组中所有的其他权限也会同时被授权。
在程序运行时申请权限
activity_main.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent"> <Button android:id="@+id/make_call" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="Make Call" /></LinearLayout>
点击按钮触发打电话的逻辑。
public class MainActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); Button makeCall = (Button) findViewById(R.id.make_call); // 6.0以下版本运行 权限 代码 makeCall.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { try { Intent intent = new Intent(Intent.ACTION_CALL); // 系统内置的打电话的动作 intent.setData(Uri.parse("tel:10086")); startActivity(intent); // 需要在AndroidManifest.xml中声明 } catch (SecurityException e) { e.printStackTrace(); } } }); }}
会要求我们申请权限
AndroidManifest.xml
<uses-permission android:name="android.permission.CALL_PHONE" />
运行,在6.0版本以上的手机是会报错的
6.0及以上系统在使用危险权限时都必须进行运行时权限处理。
修改代码 :
public class MainActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); Button makeCall = (Button) findViewById(R.id.make_call); // 使用危险权限 必须 进行运行时权限处理 makeCall.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { if (ContextCompat.checkSelfPermission(MainActivity.this, Manifest.permission.CALL_PHONE) != PackageManager.PERMISSION_GRANTED) { // 判断用户是不是已经授权checkSelfPermission(context, 具体权限) 相等就已经授权 // ContextCompat.checkSelfPermission,主要用于检测某个权限是否已经被授予,方法返回值为PackageManager.PERMISSION_DENIED或者PackageManager.PERMISSION_GRANTED。当返回DENIED就需要进行申请授权了。 ActivityCompat.requestPermissions(MainActivity.this, new String[]{ Manifest.permission.CALL_PHONE}, 1); // 申请权限 这是一个异步方法用于向用户申请授权 //Activity activity,String[] permissions,int requestCode // Activity实例, String数组 申请权限名(是支持一次性申请多个权限的,系统会通过对话框逐一询问用户是否授权), 请求码(唯一值,主要用于回调时候的检测) } else { call(); } } }); } private void call() { try { Intent intent = new Intent(Intent.ACTION_CALL); intent.setData(Uri.parse("tel:10086")); startActivity(intent); } catch (SecurityException e) { e.printStackTrace(); } } @Override public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) { // 授权结果封装在grantResults参数中 处理申请回掉 int requestCode switch (requestCode) { // 对于权限的申请结果,首先验证requestCode定位到你的申请,然后验证grantResults对应于申请的结果,这里的数组对应于申请时的第二个权限字符串数组。 // 如果你同时申请两个权限,那么grantResults的length就为2,分别记录你两个权限的申请结果 case 1: // ActivityCompat.requestPermissions()方法中的第三个参数 if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) { // 申请结果是通过 call(); } else { Toast.makeText(this, "You denied the permission", Toast.LENGTH_LONG).show(); } break; default: break; } }}
点击允许,再次点击Make Call
可以在设置中对授予的权限进行关闭。
访问其他程序的数据
内容提供器有两种使用方法 :
1. 使用现有的内容提供器来读取和操作相应程序中的数据
2. 创建自己的内容提供器给程序的数据提供外部访问的接口
利用ContentResolver类(getContentResolver()方法获得)
内容提供器的唯一标识符是内容URI参数(由两部分组成authority和path,Content://com.example.app.provider/table1)
读取系统联系人
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="match_parent" android:layout_height="match_parent"> <ListView android:id="@+id/contacts_view" android:layout_width="match_parent" android:layout_height="match_parent" /></LinearLayout>
利用ListView 来显示从手机中读取的联系人信息
public class MainActivity extends AppCompatActivity { ArrayAdapter<String> adapter; List<String> contactsList = new ArrayList<>(); @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); ListView contactsView =(ListView) findViewById(R.id.contacts_view); adapter = new ArrayAdapter<String>(this, android.R.layout.simple_expandable_list_item_1, contactsList); contactsView.setAdapter(adapter); // 配置ListView if (ContextCompat.checkSelfPermission(this, Manifest.permission.READ_CONTACTS) != PackageManager.PERMISSION_GRANTED) { // 判断用户是否已经授权 ActivityCompat.requestPermissions(this, new String[]{ Manifest.permission.READ_CONTACTS}, 1); // 没有授权,请求用户授权 } else { readContacts(); } } private void readContacts() { Cursor cursor = null; try { cursor = getContentResolver().query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI, null, null, null, null); // 查询联系人数据(联系人的URI,指定查询的列名,指定where的约束条件,为where中的占位符提供具体的值,指定查询结果的排序方式) if (cursor != null) { // 利用游标来读取返回的数据 while (cursor.moveToNext()) { String displayName = cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME)); // 获取联系人姓名 String number = cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER)); // 获取联系人手机号 contactsList.add(displayName + "\n" + number); // 显示 } adapter.notifyDataSetChanged(); } } catch (Exception e) { e.printStackTrace(); } finally { if (cursor != null) cursor.close(); } } @Override public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) { switch (requestCode) { case 1: if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) { readContacts(); // 用户同意读取 } else { Toast.makeText(this, "You denied the permission", Toast.LENGTH_LONG).show(); } break; default: break; } }}
添加读取联系人的权限
<uses-permission android:name="android.permission.READ_CONTACTS" />
创建自己的内容提供器
通过新建类继承ContentProvider来创建一个内容提供器。
public class DatabaseProvider extends ContentProvider { public static final int BOOK_DIR = 0; public static final int BOOK_ITEM = 1; public static final int CATEGORY_DIR = 2; public static final int CATEGORY_ITEM = 3; public static final String AUTHORITY = "com.yezhou.example.com.databasetest.provider"; private static UriMatcher uriMatcher; private MyDatabaseHelper dbHelper; static { // 初始化操作,将期望匹配的几种uri格式添加 uriMatcher = new UriMatcher(UriMatcher.NO_MATCH); uriMatcher.addURI(AUTHORITY, "book", BOOK_DIR); uriMatcher.addURI(AUTHORITY, "book/#", BOOK_ITEM); uriMatcher.addURI(AUTHORITY, "category", CATEGORY_DIR); } public DatabaseProvider() { } @Override public boolean onCreate() { dbHelper = new MyDatabaseHelper(getContext(), "BookStore.db", null, 2); return true; } @Override public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) { // 查询数据 // TODO: Implement this to handle query requests from clients. SQLiteDatabase db = dbHelper.getReadableDatabase(); Cursor cursor = null; switch (uriMatcher.match(uri)) { case BOOK_DIR: cursor = db.query("Book", projection, selection, selectionArgs, null, null, sortOrder); break; case BOOK_ITEM: String bookId = uri.getPathSegments().get(1); // 将内容URI权限之后的部分以"/"分割 0位置路径 1位置就是id cursor = db.query("Book", projection, "id = ?", new String[] { bookId}, null, null, sortOrder); break; case CATEGORY_DIR: cursor = db.query("Category", projection, selection, selectionArgs, null, null ,sortOrder); break; case CATEGORY_ITEM: String categoryId = uri.getPathSegments().get(1); cursor = db.query("Category", projection, "id = ?", new String[] { categoryId}, null, null,sortOrder); break; default: break; } return cursor; } @Override public Uri insert(Uri uri, ContentValues values) { // 添加数据 SQLiteDatabase db = dbHelper.getWritableDatabase(); Uri uriReturn = null; switch (uriMatcher.match(uri)) { case BOOK_DIR: case BOOK_ITEM: long newBookId = db.insert("Book", null, values); uriReturn = Uri.parse("content://" + AUTHORITY + "/book/" + newBookId); break; case CATEGORY_DIR: case CATEGORY_ITEM: long newCategoryId = db.insert("Category", null, values); uriReturn = Uri.parse("content://" + AUTHORITY + "/category/" + newCategoryId); break; default: break; } return uriReturn; } @Override public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) { // 更新数据 SQLiteDatabase db = dbHelper.getWritableDatabase(); int updateRows = 0; switch (uriMatcher.match(uri)) { case BOOK_DIR: updateRows = db.update("Book", values, selection, selectionArgs); break; case BOOK_ITEM: String bookId = uri.getPathSegments().get(1); updateRows = db.update("Book", values, "id = ?", new String[] { bookId}); break; case CATEGORY_DIR: updateRows = db.update("Category", values, selection, selectionArgs); break; case CATEGORY_ITEM: String categoryId = uri.getPathSegments().get(1); updateRows = db.update("Category", values, "id = ?", new String[] { categoryId}); break; default: break; } return updateRows; } @Override public int delete(Uri uri, String selection, String[] selectionArgs) { // 删除数据 SQLiteDatabase db = dbHelper.getWritableDatabase(); int deleteRows = 0; switch (uriMatcher.match(uri)) { case BOOK_DIR: deleteRows = db.delete("Book", selection,selectionArgs); break; case BOOK_ITEM: String bookId = uri.getPathSegments().get(1); deleteRows = db.delete("Book", "id = ?", new String[] { bookId}); break; case CATEGORY_DIR: deleteRows = db.delete("Category", selection,selectionArgs); break; case CATEGORY_ITEM: String categoryId = uri.getPathSegments().get(1); deleteRows = db.delete("Category", "id = ?", new String[] {categoryId}); break; default: break; } return deleteRows; } @Override public String getType(Uri uri) { // 用于获取Uri对象所对应的MIME类型 // 必须以vnd开头 如果内容URI以路径结尾,则后接android.cursor.dir/,如果内容URI以id结尾,则后接android.cursor.item/ // 最后接上vnd.authority.path switch (uriMatcher.match(uri)) { case BOOK_DIR: return "vnd.android.cursor.dir/vnd.com.yezhou.example.com.databasetest.provider.book"; case BOOK_ITEM: return "vnd.android.cursor.item/vnd.com.yezhou.example.com.databasetest.provider.book"; case CATEGORY_DIR: return "vnd.android.cursor.dir/vnd.com.yezhou.example.com.databasetest.provider.category"; case CATEGORY_ITEM: return "vnd.android.cursor.item/vnd.com.yezhou.example.com.databasetest.provider.category"; default: break; } return null; }}
<provider android:name=".DatabaseProvider" android:authorities="com.yezhou.example.com.databasetest.provider" android:enabled="true"</provider> <!--用于对DatabaseProvider进行注册,name 类名,-->
我们自己的内容提供器创建好了。
新建一个Android Project
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="match_parent" android:layout_height="match_parent"> <Button android:id="@+id/add_data" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="Add To Book" /> <Button android:id="@+id/query_data" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="Query From Book" /> <Button android:id="@+id/update_data" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="Update Book" /> <Button android:id="@+id/delete_data" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="Delete From Book" /></LinearLayout>
public class MainActivity extends AppCompatActivity { // 用于读取DatabaseTest应用数据库中的数据 private String newId; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); Button addData = (Button) findViewById(R.id.add_data); addData.setOnClickListener(new View.OnClickListener() { // 添加数据 @Override public void onClick(View view) { Uri uri = Uri.parse("content://com.yezhou.example.com.databasetest.provider/book"); ContentValues values = new ContentValues(); values.put("name", "A Clash of Kings"); values.put("author", "George Martin"); values.put("pages", 1040); values.put("price", 22.85); Uri newUri = getContentResolver().insert(uri, values); newId = newUri.getPathSegments().get(1); // 将id取出 } }); Button queryData = (Button) findViewById(R.id.query_data); queryData.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { // 查询数据 Uri uri = Uri.parse("content://com.yezhou.example.com.databasetest.provider/book"); Cursor cursor = getContentResolver().query(uri, null, null, null, null); if (cursor != null) { while (cursor.moveToNext()) { String name = cursor.getString(cursor.getColumnIndex("name")); String author = cursor.getString(cursor.getColumnIndex("author")); int pages = cursor.getInt(cursor.getColumnIndex("pages")); double price = cursor.getDouble(cursor.getColumnIndex("price")); Log.d("admin", "book name is " + name); Log.d("admin", "book name is " + author); Log.d("admin", "book name is " + pages); Log.d("admin", "book name is " + price); } cursor.close(); } } }); Button updateData = (Button) findViewById(R.id.update_data); updateData.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { Uri uri = Uri.parse("content://com.yezhou.example.com.databasetest.provider/book/" + newId); // 只希望更新刚刚添加的那条数据 ContentValues values = new ContentValues(); values.put("name", "A Storm of Swords"); values.put("pages", 1216); values.put("price", 24.05); getContentResolver().update(uri, values, null, null); } }); Button deleteData = (Button) findViewById(R.id.delete_data); deleteData.setOnClickListener(new View.OnClickListener() { //删除数据 @Override public void onClick(View view) { Uri uri = Uri.parse("content://com.yezhou.example.com.databasetest.provider/book/" + newId); getContentResolver().delete(uri, null, null); // newId必须有值 } }); }}
新项目就可以访问到之前项目中的数据了。
第三方ContentURI,匹配手机上所有app的Provider Authority,找到App,通过UriMatcher再次过滤,不匹配丢弃,匹配相应请求。
此博文为个人学习笔记,仅供个人学习使用,希望对大家有帮助。
- Android学习随笔(13)------内容提供器
- android 学习笔记 内容提供器ContentResolver
- Android学习-内容提供器 数据共享
- android内容提供器
- Android内容提供器
- android 学习笔记 创建自己的内容提供器
- Android基础学习之Provider(内容提供器)
- android学习笔记——内容提供器
- Android第一行代码学习笔记五----内容提供器
- Android学习笔记——内容提供器
- Android 内容提供器---简介
- Android 内容提供器---简介 .
- android 内容提供器api
- Android之内容提供器
- Android 内容提供器 ContentProvider
- Android 内容提供器小结
- Android创建内容提供器
- Android 内容提供器---内容提供器基础(概述)
- adonis命令模块学习笔记
- 查看混淆后的日志
- Java中的代理机制
- 算法入门
- Java实现——将数据存入剪切板
- Android学习随笔(13)------内容提供器
- 最长上升子序列问题(LIS)
- kubernet 在centos 搭建的集群上的实践 -- 《一》
- Gradle GradleWapper AndroidBuildTools版本兼容问题
- 第二天课程总结
- OverFeat论文理解
- 解决Activiti Modeler 部署中文流程 报错问题
- python+selenium初级(4)—selenium中对于鼠标的操作
- linux环境搭建nginx+tomcat7(安装篇)