当前位置: 首页 > news >正文

37网页游戏平台官网郑州seo优化服务

37网页游戏平台官网,郑州seo优化服务,湘潭学校网站建设 磐石网络专注,雄县做网站的官方页面 参考文章 一、概念 分区存储(Scoped Storage)的推出是针对 APP 访问外部存储的行为(乱建乱获取文件和文件夹)进行规范和限制,以减少混乱使得用户能更好的控制自己的文件。 公有目录被分为两大类:…

官方页面
参考文章

一、概念

        分区存储(Scoped Storage)的推出是针对 APP 访问外部存储的行为(乱建乱获取文件和文件夹)进行规范和限制,以减少混乱使得用户能更好的控制自己的文件。

        公有目录被分为两大类:媒体文件(图片、音频、视频)的访问使用 MediaStore,其它文件通过系统的文件选择器访问 Storage Access Framework(简称SAF)。

二、MediaStore

跳转ContentProvider

class MediaStore.Images所有图片内容的类。
class MediaStore.Video所有视频内容的类。
class MediaStore.Audio所有音频内容的类。
class MediaStore.Files文件储存库中所有文件的索引,包括非媒体文件和媒体文件类。
interface MediaStore.MediaColumns文件储存库中表的公共字段(文件的各种信息)。

2.1 获取 Uri

使用 Context 获取到 ContentResolver 对象,通过 Uri 即可获取各种媒体库的 ContentProvider,从而对媒体文件进行操作。 

文件类型MediaStore 常量Uri 地址
图片MediaStore.Images.Media.EXTERNAL_CONTENT_URIcontent://media/external/images/media
视频MediaStore.Video.Media.EXTERNAL_CONTENT_URIcontent://media/external/video/media
音频MediaStore.Audio.Media.EXTERNAL_CONTENT_URIcontent://media/external/audio/media
非媒体文件MediaStore.Downloads.Media.EXTERNAL_CONTENT_URIcontent://media/external/downloads
val uri1 = Uri.parse("content://media/external/images/media")
val uri2 = MediaStore.Images.Media.getContentUri("external")
val uri3 = MediaStore.Images.Media.EXTERNAL_CONTENT_URI    //推荐

2.2 读取媒体文件

列名(文件信息)可以在 MediaStore.MediaColumns 取公共常量字段,也可以根据文件类型的不同在具体内部类中取值。

文件类型MediaStore 常量(常用列名)说明
图片

MediaStore.Images.Media._ID

磁盘上文件的路径

MediaStore.Images.Media.DATA

磁盘上文件的路径

MediaStore.Images.Media.DATE_ADDED

文件添加到media provider的时间(单位秒)

MediaStore.Images.Media.DATE_MODIFIED

文件最后一次修改单元的时间

MediaStore.Images.Media.DISPLAY_NAME

文件的显示名称

MediaStore.Images.Media.HEIGHT

图像/视频的高度,以像素为单位

MediaStore.Images.Media.MIME_TYPE

文件的 MIME 类型

MediaStore.Images.Media.SIZE

文件的字节大小

MediaStore.Images.Media.TITLE

标题

MediaStore.Images.Media.WIDTH

图像/视频的宽度,以像素为单位
视频

MediaStore.Video.Media.TITLE

名称

MediaStore.Video.Media.DURATION

总时长

MediaStore.Video.Media.DATA

地址

MediaStore.Video.Media.SIZE

大小

MediaStore.Video.Media.WIDTH

视频的宽度,以像素为单位

MediaStore.Video.Media.HEIGHT

视频的高度,以像素为单
音频

MediaStore.Audio.Media.TITLE

歌名

MediaStore.Audio.Media.ARTIST

歌手

MediaStore.Audio.Media.DURATION

总时长

MediaStore.Audio.Media.DATA

地址

MediaStore.Audio.Media.SIZ

大小

public final Cursor query (

    Uri uri,        //要查询的 ContentProvider 的 Uri

    String[] projection,        //要查询的字段(列Column),用 null 表示返回所有字段内容。

    String selection,        //查询条件,相当于SQL语句中的where,用 null 表示不进行筛选。

    String[] selectionArgs,        //如果 selection 里有?符号这里可以以实际值代替。没有的话可以为null。

    String sortOrder        //对结果进行排序,相当于SQL语句中的Order by,升序 asc /降序 desc,null为默认排序。

)

返回的是一个封装了结果集的游标对象 Cursor ,资源用完需要调用 close() 关闭。

//获取图片类型的Uri
val uri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI
//要获取的信息(列名)
val projection = arrayOf(MediaStore.Images.Media._ID,    //获取IDMediaStore.Images.Media.MIME_TYPE,  //获取MIME_TYPEMediaStore.Images.Media.DISPLAY_NAME    //获取DISPLAY_NAME
)
//筛选条件(png格式的图片)
val selection = "${MediaStore.Images.Media.DISPLAY_NAME}='.png'"  // ='xx.png' 改成 =?
//筛选条件的参数
val selectionArgs = arrayOf(".png")   //替换筛选条件语句中?部分
//对结果的排序方式
val sortOrder = "${ContactsContract.Contacts._ID} DESC" //注意:desc前有空格
//开始查询(返回的是一个封装了结果集的游标对象,资源用完需要关闭使用use函数)
contentResolver.query(uri, projection, selection, selectionArgs, sortOrder)?.use { cursor ->//表都是通过行和列定位到具体的位置然后数据将其取出cursor.run {//获取字段在第几列(查询什么才能取出什么,否则空指针异常)val idIndex  = getColumnIndexOrThrow(MediaStore.Images.Media._ID)val mimeTypeIndex = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.MIME_TYPE)val displayNameIndex = cursor.getColumnIndex(MediaStore.Images.Media.DISPLAY_NAME)//循环取出每一行对应字段的数据while (moveToNext()) {val id = getLong(idIndex)val mineType = getString(mimeTypeIndex)val displayName = getString(displayNameIndex)//合成图片的UriContentUris.withAppendedId(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, id)//TODO...}}
}
//获取到的 Uri 可以通过 Glide 显示
Glide.with(context).load(uri).into(imageView)
//手动解析成图片的话
contentResolver.openFileDescriptor(uri, "")?.use {val bitmap = BitmapFactory.decodeFileDescriptor(it.fileDescriptor)imageView.setImageBitmap(bitmap)
}

2.3 写入媒体文件

通过 MediaStore 创建文件会保存到对应类型的默认目录中,也可以指定存放到其它同类型的公有目录或子文件夹中。如果存放到不同类型的公有目录中会报错 IllegalArgumentException(但是三种都可以存到Download中)。

文件类型mimeType 文件类型默认存储目录(其它允许存储目录)
图片image/*Pictures(DICM)
视频video/*Movies(DICM)
音频audio/*Music(Alarms、Notifications、Podcasts、Ringtones)
文件file/*Download

public final Uri insert( Uri url, ContentValues values) 

构造一个 ContentValues 对象通过 ContentResolver.insert 插入到对应的目录中,对返回的 Uri  对象进行文件流写入即可。

val values = ContentValues().apply {//指定 MimeTypeput(MediaStore.Images.Media.MIME_TYPE,"image/png")//指定文件名put(MediaStore.Images.Media.DISPLAY_NAME,"${System.currentTimeMillis()}.png")//指定保存的文件目录(如果不设置这个值,则会被默认保存到对应的媒体类型的文件夹下)if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {//Android 10中新增了一个RELATIVE_PATH常量,表示文件存储的相对路径,可选值有DIRECTORY_DCIM、DIRECTORY_PICTURES、DIRECTORY_MOVIES、DIRECTORY_MUSICput(MediaStore.Images.Media.RELATIVE_PATH, "${Environment.DIRECTORY_PICTURES}/DemoPicture")} else {//之前的系统版本中并没有RELATIVE_PATH,所以要使用 DATA 并拼装出一个文件存储的绝对路径才行put(MediaStore.MediaColumns.DATA, "${Environment.getExternalStorageDirectory().path}${File.separator}${Environment.DIRECTORY_DCIM}${File.separator}${System.currentTimeMillis()}.png")}
}
//插入文件数据库并获取到文件的Uri
val uri= contentResolver.insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values)
//对Uri进行文件流写入
uri?.let {//通过outputStream将本地图片bitmap或网络图片输入流写入UrlcontentResolver.openOutputStream(it)?.use { outputStream ->//TODO...//bitmap.compress(Bitmap.CompressFormat.PNG,100, outputStream)}
}

2.4 下载文件到Download目录

 方式和上面的写入一样,将网络获取的输入流写入。

  • 注意:MediaStore.Downloads是Android 10中新增的API,Android 9及以下的系统版本仍然使用之前的代码来进行文件下载。 
val inputStream = XXX.inputStream
val bis = BufferedInputStream(inputStream)
val buffer  = ByteArray(1024)//对Uri进行文件流写入
insertUri?.let {//通过outputStream将本地bitmap或网络输入流写入UrlcontentResolver.openOutputStream(it)?.use { outputStream ->BufferedOutputStream(outputStream).use { bos ->var bytes = bis.read(buffer)while (bytes >= 0) {bos.write(buffer, 0, bytes)bos.flush()bytes = bis.read(buffer)}}}
}

三、使用文件选择器 SAF

对于非媒体文件,无法像之前那样手写一个文件浏览器,而是必须使用系统提供的内置文件选择器。通过 Intent 启动系统的文件选择器,然后在 onActivityResult() 中获取到用户选中文件的 Uri 通过ContentResolver打开文件输入流来进行读取就可以了。

const val PICK_FILE = 1private fun pickFile() {val intent = Intent(Intent.ACTION_OPEN_DOCUMENT)intent.addCategory(Intent.CATEGORY_OPENABLE)intent.type = "*/*"startActivityForResult(intent, PICK_FILE)
}override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {super.onActivityResult(requestCode, resultCode, data)when (requestCode) {PICK_FILE -> {if (resultCode == Activity.RESULT_OK && data != null) {val uri = data.dataif (uri != null) {val inputStream = contentResolver.openInputStream(uri)// 执行文件读取操作}}}}
}

四、第三方库不支持的解决办法

编写一个文件复制功能,将Uri对象所对应的文件复制到应用程序的关联目录下,然后再将关联目录下这个文件的绝对路径传递给第三方SDK,这样就可以完美进行适配了。

fun copyUriToExternalFilesDir(uri: Uri, fileName: String) {val inputStream = contentResolver.openInputStream(uri)val tempDir = getExternalFilesDir("temp")if (inputStream != null && tempDir != null) {val file = File("$tempDir/$fileName")val fos = FileOutputStream(file)val bis = BufferedInputStream(inputStream)val bos = BufferedOutputStream(fos)val byteArray = ByteArray(1024)var bytes = bis.read(byteArray)while (bytes > 0) {bos.write(byteArray, 0, bytes)bos.flush()bytes = bis.read(byteArray)}bos.close()fos.close()}
}

五、管理设备上所有的文件(公有目录 + 自定义目录)

绝大部分的应用程序都不应该申请这个权限,仅适用于文件浏览器、病毒查杀类APP,需要跳转到系统页面让用户手动授权,Play商店上架也会更严格。即便得到授权也只能访问 公有目录 + 自定义目录,依然无法访问私有目录。

5.1 权限声明 

//不加 ignore 属性 AndroidStudio 会用警告提醒。
<uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE"tools:ignore="ScopedStorage" />

5.2 跳转系统页面授权 

//系统低于11或者方法返回true说明已经拥有整个SD卡管理权限
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.R || Environment.isExternalStorageManager()) {Toast.makeText(this, "已获得访问所有文件权限", Toast.LENGTH_SHORT).show()
} else {//否则弹窗告知申请原因并跳转到系统授权界面让用户手动授权val builder = AlertDialog.Builder(this).setMessage("本程序需要您同意允许访问所有文件权限").setPositiveButton("确定") { _, _ ->val intent = Intent(Settings.ACTION_MANAGE_ALL_FILES_ACCESS_PERMISSION)startActivity(intent)}builder.show()
}

六、修改其它APP贡献的文件

修改其它APP贡献的文件是不安全的行为,默认情况下会抛异常,需要跳转到系统页面让用户手动授权,仅适用于美图秀秀类APP。在 Android 10 中每次跳转授权只能操作一张图片,如果一个程序需要修改很多张图片会很麻烦,在 Android 11 中提供了 Batch Operations 从而一次性对多个文件的操作权限进行申请。

  • 由于10 之前没有分区存储,10 和 11以后是两套处理方案,专门针对 10 一个版本去写处理方案会很麻烦,由于 10 不是强制启用分区存储,可以在 AndroidManifest 中配置 requestLegacyExternalStorage 来禁用。 

createWriteRequest()

请求对多个文件的写入权限。

createFavoriteRequest()

请求将多个文件加入到Favorite(收藏)的权限。

createTrashRequest()

请求将多个文件移至回收站的权限。

createDeleteRequest()

请求将多个文件删除的权限。

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {/创建了一个集合用于存放所有要批量申请权限的文件Urival urisToModify = listOf(uri1, uri2, uri3, uri4)//创建一个PendingIntentval editPendingIntent = MediaStore.createWriteRequest(contentResolver, urisToModify)//进行权限申请startIntentSenderForResult(editPendingIntent.intentSender, EDIT_REQUEST_CODE, null, 0, 0, 0)
}override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {super.onActivityResult(requestCode, resultCode, data)when (requestCode) {EDIT_REQUEST_CODE -> {if (resultCode == Activity.RESULT_OK) {Toast.makeText(this, "用户已授权", Toast.LENGTH_SHORT).show()} else {Toast.makeText(this, "用户没有授权", Toast.LENGTH_SHORT).show()}}}
}
http://www.tj-hxxt.cn/news/13645.html

相关文章:

  • 南宁网站建设排名做一个公司网站要多少钱
  • 品牌网站建设哪个好近一周热点新闻
  • 北京怀柔做网站管理运营的公司爱链工具
  • 17一起做网店网站谷歌seo什么意思
  • 阿里巴巴java开发手册seo百度刷排名
  • 园林网站建设设计方案seo是什么意思知乎
  • 学校网站建设策划方案百度搜索排名
  • 网站开发与设计英文文献百度极速版推广
  • wordpress的博客主题seo技术教学视频
  • 做网店好还是自己建网站好云搜索引擎
  • 潍坊建网站友情链接有用吗
  • 重庆网站设计哪家公司好品牌策划方案怎么写
  • 培训机构的网站建设seo整站优化
  • ps做网站首页怎么运用起来百度搜索关键词排名优化
  • 哪个网站做外贸比较好seo搜索引擎营销工具
  • txt做网站 插入图片广告投放
  • 个人做金融网站能赚钱吗seo运营招聘
  • 广告业网站开发企业网络推广的方式有哪些
  • 做网站模板用什么软件个人网页怎么制作
  • do_action wordpress 模板seo产品优化免费软件
  • 网页建站工具如何推广网址链接
  • 网站手机验证码怎么做网站点击快速排名
  • 西宁网站建设网络广告策划流程有哪些?
  • 跨越网站建设科技有限公司百度招聘网最新招聘信息
  • 日本亲子游哪个网站做的好seo网络营销
  • 有没有做丝网的网站呀淘宝友情链接怎么设置
  • 怎样做私人网站成人速成班有哪些专业
  • 微信 app 微网站 整合香港百度广告
  • 专业外贸网站建设_诚信_青岛百度网盘下载
  • 贵州省建设厅住房和城乡建设官网网站优化seo培