知芯

《第一行代码android》第7-9章

2020-09-27

7. 跨程序共享数据

7.1 运行时权限

Android 6及其之前就是通过在AndroidManifest.xml中声明需要使用的权限,用户认可就安装程序。存在的问题是可能少数权限用户不同意,直接就不能安装应用。这种方式我理解为是静态的权限声明。
运行时权限使得用户不用在安装时一次性授权所有权限,而是在使用过程中授权某一项。Android将权限分为普通权限和危险权限,普通权限自动授权,危险权限才需要用户同意。用户同意授权是以权限组为单位的。

1
2
3
4
5
if (ContextCompat.checkSelfPermission()){
ActivityCompat.requestPermissions()
}else{
dangerOperation();
}

实现逻辑就是,危险操作之前检测是否有权限,没有则发起申请,申请回调函数中判断用户是否同意,没同意就提醒。

1
2
3
4
5
6
7
public void onRequestPermissionsResult(){
if(grantResults[0]==PERMISSION_GRANTED){
dangerOperation();
}else{
toast();
}
}

7.2 Content Resolver

访问其他应用提供的数据,比如联系人信息,通过Uri访问,Uri具有特定格式:协议+authority+path,比如下面的com.example.app.providerauthroity部分。
然后通过Context的方法getContentResolver进行访问。后续操作就和直接在内容提供方封装方式类似了。

1
2
Uri uri = Uri.parse("content://com.example.app.provider/table1");
Cursor cursor = getContentResolver().query(uri, projection, selection, selectionArgs, sortOrder);

7.3 Content Provider

与前面的文件存储和sharedPreferences不同的是,Content Provider可以选择对哪一部分数据进行共享。通过继承ContentProvider并实现定义的CRUD,在对应的函数中通过正则识别出path部分,即操作对象,然后按照参数进行数据操作。

1
2
3
4
5
class MyProvider extends ContentProvider{
onCreate();
CRUD();
getType();
}

getType()返回Uri对应的MIME类型,格式为:vnd.<authority>.<path>,以路径结尾则表示为dir,以id结尾则表示为item.

1
2
3
4
content://com.example.app.provider/table1
# MIME: vnd.android.cursor.dir/vnd.com.example.app.provider/table1
content://com.example.app.provider/table1/1
# MIME: vnd.android.cursor.item/vnd.com.example.app.provider/table1

Contet Resolver 类似浏览器提供统一的访问工具,content provider类似各个服务器接口提供数据访问的入口。测试发现提供者App关闭时也能访问数据,content provider不依赖于App进程。

8. 使用多媒体

8.1 Notification

1
2
3
4
5
6
String id = "my_channel_01";
NotificationManager manager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
NotificationChannel mChannel = new NotificationChannel(id, name, NotificationManager.IMPORTANCE_LOW);
manager.createNotificationChannel(mChannel);
Notification notification = new NotificationCompat.Builder(this, id).setSomeProperity().build();
manager.notify(1, notification);

setSomeProperity表示一系列设置属性的方法,用于设置通知的图标、文字、样式等。需要注意,builder携带channelId,在android 8开始通知划分渠道了,并且每个渠道可以设置重要程度,重要程度越高提醒越强,需要谨慎使用。

8.2 摄像头和相册

拍照

首先在应用特有缓存目录下创建文件,并获取文件路径(android7开始需要通过FileProvider访问,并且在AndroidManifest.xml中声明),然后使用相机拍摄并指定保存路径。

1
2
3
4
5
6
7
8
9
File outputImage = new File(getExternalCacheDir(), "output_image.jpg");
if (Build.VERSION.SDK_INT >=24){
imageUri = FileProvider.getUriForFile(MainActivity.this, "cn.codeyourlife.cameraalbum.fileprovider", outputImage);
}else{ // android 7 开始不能直接使用本地真实路径
imageUri = Uri.fromFile(outputImage);
}
Intent intent = new Intent("android.media.action.IMAGE_CAPTURE");
intent.putExtra(MediaStore.EXTRA_OUTPUT, imageUri);
startActivityForResult(intent, TAKE_PHOTO);

从相册选择

从相册选择就跨应用访问了数据,遵循前面运行时权限的请求过程,因此重点在于选中图片之后的回调函数,android 4.4(19) 开始返回图片不再是真实的Uri,因此需要解析。
另外,从android 10(29)开始,采用scope storage,在这之前只要有权限就可以直接读写,现在访问其他应用的媒体文件,需要通过ContentResolver()的方法进行加载操作:

1
2
bitmap = BitmapFactory.decodeStream(getContentResolver().openInputStream(uri));
imageView.setImageBitmap(bitmap);

或者在android 10中使用requestLegacyExternalStorage来暂时禁用分区存储。

8.3 播放音频视频

使用MediaPlayer类播放音频,需要熟悉常用的控制方法,依然是申请运行时权限获取文件路径,然后设置给mediaplayer,从android 10(29)开始,依然需要遵循scope storage
使用VideoView类播放视频,注意项和播放音频类似。

9. 网络技术

WebView的使用较为简单,不过从Android 9开始默认不支持cleartext,也就是http协议,改用https或者在AndroidManifest中指定usecleartextTraffix
通过HttpURLConnection发送请求时,通过创建线程发送,但是响应结果时如果需要更新UI,不允许直接在子线程更新,可使用runOnUIThread()进行。使用OkHttp网络库来进行请求更加容易。发送网络请求依然从Android 9开始默认不支持cleartext
另外解析xmljsonSAXPull两种解析xml方式,前者类似面向流程;后者面向对象,抽象出一个Handler符合template-method

Tags: android
使用支付宝打赏
使用微信打赏

若你觉得我的文章对你有帮助,欢迎点击上方按钮对我打赏

扫描二维码,分享此文章