内容提供器(Content Provider)理论好无聊啊啊啊啊啊啊还是实践有意思啊啊啊不慌不慌整理完之后就去吃饭回来洗衣服啊啊啊
有9个危险权限。。而且是权限组
1.从奇怪的例子开始 (运行时权限)
Intent intent = new Intent(Intent.ACTION_CALL);
intent.setData(Uri.parse("tel:10086"));
startActivity(intent);
构建了一个隐式Intent ,Intent的action指定为Intent.ACTION_CALL ,这是一个系统内置的打电话的动作。之前指定的action是Intent.ACTION_DIAL ,表示打开拨号界面,这个是不需要声明权限的,而Intent.ACTION_CALL 则可以直接拨打电话,因此必须声明权限。另外为了防止程序崩溃,我们将所有操作都放在了异常捕获代码块当中。
<uses-permission android:name="android.permission.CALL_PHONE" />
(低于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 v) { if (ContextCompat.checkSelfPermission(MainActivity.this, Manifest. permission.CALL_PHONE) != PackageManager.PERMISSION_GRANTED) { // 1 先检查有没有赋予好权限。如果没有的话,就去申请一下,有就直接打 // 这个函数接受了context,和权限名 ActivityCompat.requestPermissions(MainActivity.this, new String[]{ Manifest.permission.CALL_PHONE }, 1); // 2 request这个接受3个方法,实例,数组( 权限名字) 请求码 } else { call(); } } }); } // 4 call 这还是一样,只不过6.0版本后面都这么写~ 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 // 3 弹出对话框后返回的 。得到的结果ok,就可以call了 public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) { switch (requestCode) { case 1: if (grantResults.length > 0 && grantResults[0] == PackageManager. PERMISSION_GRANTED) { call(); } else { Toast.makeText(this, "You denied the permission", Toast.LENGTH_ SHORT).show(); } break; default: } } }
总结一下:
1 先判断是否有申请,没申请就动态申请一下 2 申请传入 实例、权限名、请求码~ 3 判断一下申请后的返回结果,如果ok就可以拨打 4 拨打使用intent,打开了对应程序。
2.访问其他程序中的数据
emmmm总体来说思只需要获取到该应用程序的内容URI,然后借助ContentResolver进行CRUD操作就可以了。但是我们还是看自己创建自己的内容提供器……
ContentResolver类,可以通过context的中的getContentResolver() 方法获取到该类的实例。ContentResolver中提供了一系列的方法用于对数据进行CRUD操作。但它接受的是uri,authority和path 前面是包名字 如com.example.app.provider 后面是区分表名 最前面加协议 最标准写法就是
content://com.example.app.provider/table2
解析的话,只要在前面加上Uri uri=Uri.parse("....上面的...") 变成uri对象!对象!对象!就可以进去了
增删改查,,和数据库都差不多。折叠代码看一下
这个代码。一个是,listview是要adapter装的~
ListView contactsView = (ListView) findViewById(R.id.contacts_view);
adapter = new ArrayAdapter<String>(this, android.R.layout. simple_list_
item_1, contactsList);
contactsView.setAdapter(adapter);
后面也是这样新增add 最后的adapter要更新一下qwq
contactsList.add(displayName + "\n" + number);
adapter.notifyDataSetChanged();
其他的都是标准的申请权限的写法吧。。。查询是用的cursor、
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_list_ item_1, contactsList); contactsView.setAdapter(adapter); 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); 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_ SHORT).show(); } break; default: } } } 下面重点看一下readContacts() 方法,可以看到,这里使用了ContentResolver的query() 方法来查询系统的联系人数据。不过传入的Uri 参数怎么有些奇怪啊?为什么没有调用Uri.parse() 方法去解析一个内容URI字符串呢?这是因为ContactsContract.CommonDataKinds.Phone 类已经帮我们做好了封装,提供了一个CONTENT_URI 常量,而这个常量就是使用Uri.parse() 方法解析出来的结果。接着我们对Cursor 对象进行遍历,将联系人姓名和手机号这些数据逐个取出,联系人姓名这一列对应的常量是ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME ,联系人手机号这一列对应的常量是ContactsContract.CommonDataKinds.Phone.NUMBER 。两个数据都取出之后,将它们进行拼接,并且在中间加上换行符,然后将拼接后的数据添加到ListView的数据源里,并通知刷新一下ListView。最后千万不要忘记将Cursor 对象关闭掉。 这样就结束了吗?还差一点点,读取系统联系人的权限千万不能忘记声明。修改AndroidManifest.xml中的代码
最后xml里一定要声明一下
啊~ 下午醒了继续 困困(?)qwq 现在使用资金创建的内容提供器
3. 使用自己的内容提供器
继承ContextProvider、用子类继承它的时候,需要将这6个方法全部重写。新建MyProvider 继承自ContentProvider