preface
Adaptation is one of the essential tasks of the foreground programmer and can take a lot of time and effort.
What is a front-end programmer is the user-facing end, including front-end, mobile, PC, and so on.
What is adaptation, adaptation is when our development environment, operating environment changes, the program can still run stably.
And the adaptation of the most difficult for programmers is Android, in addition to the development environment, operating environment and other factors, because of the Android open source, but also to adapt to the major manufacturers.
The number of conditions is often a headache for Android programmers.
Take a look at the camera, photo album related adaptation process:
- Android 6 Permission adaptation
- Android 7 file adaptation
- Android 10/11 storage adapter
Ok, let’s take a quick example of changing your avatar.
The sample
Click on your avatar, then pop up, give you different options, do different things.
mBinding.llImg.setOnClickListener {
TakeImageDialog {
when (it) {
TakeImageDialog.ALBUM -> {
openAlbum()
}
TakeImageDialog.CAMERA -> {
checkPermission()
}
}
}.show(supportFragmentManager, "TakeImageDialog")}Copy the code
Define some parameter variables that will be used later:
// The location where the camera saves the photo
private lateinit var photoUri: Uri
companion object {
private const val REQUEST_CODE_PERMISSIONS = 1000 / / permission
private const val REQUEST_CODE_ALBUM = 1001 / / photo album
private const val REQUEST_CODE_CAMERA = 1002 / / camera
}
Copy the code
Open the photo album
Choose picture
private fun openAlbum(a) {
val intent = Intent()
intent.type = "image/*"
intent.action = "android.intent.action.GET_CONTENT"
intent.addCategory("android.intent.category.OPENABLE")
startActivityForResult(intent, REQUEST_CODE_ALBUM)
}
Copy the code
Fixed way of writing it.
Since it’s startActivityForResult, take a look at the onActivityResult callback
The callback
override fun onActivityResult(requestCode: Int, resultCode: Int.data: Intent?). {
super.onActivityResult(requestCode, resultCode, data)
if (resultCode == RESULT_OK) {
when (requestCode) {
REQUEST_CODE_ALBUM -> {
doCrop(data? .data!!) }... }}}Copy the code
In the case of requestCode being REQUEST_CODE_ALBUM:
doCrop(data? .data!!)
Copy the code
data? .data!! That is, select the Uri returned by the image, which can be used directly. Here is the next step, clipping
clipping
private fun doCrop(sourceUri: Uri) {
Intrinsics.checkParameterIsNotNull(sourceUri, "Resources are empty")
UCrop.of(sourceUri, getDestinationUri())// The current resource saves the target location
.withAspectRatio(1f.1f)/ / aspect ratio
.withMaxResultSize(500.500)/ wide/high
.start(this)}Copy the code
For convenience, a three-party library UCrop is used here, which is easy to use.
GetDestinationUri () is the target location where the current resource is clipped to save
private fun getDestinationUri(a): Uri {
val fileName = String.format("fr_crop_%s.jpg", System.currentTimeMillis())
val cropFile = File(getExternalFilesDir(Environment.DIRECTORY_PICTURES), fileName)
return Uri.fromFile(cropFile)
}
Copy the code
The UCrop callback is also in onActivityResult
override fun onActivityResult(requestCode: Int, resultCode: Int.data: Intent?). {
super.onActivityResult(requestCode, resultCode, data)
if (resultCode == RESULT_OK) {
when (requestCode) {
REQUEST_CODE_ALBUM -> {
doCrop(data? .data!!)
}
UCrop.REQUEST_CROP -> {
val resultUri: Uri = UCrop.getOutput(data!!) !!!!!val bitmap = BitmapFactory.decodeStream(contentResolver.openInputStream(resultUri))
// todo
}
UCrop.RESULT_ERROR -> {
val error: Throwable = UCrop.getError(data!!) !!!!! ToastUtil.show("Picture cropping failed" + error.message)
}
}
}
}
Copy the code
UCrop.getOutput(data!!) !!!!! Is the returned Uri, which can be manipulated directly or converted into a bitmap.
Ok, here to open the album to introduce the end.
Let’s get to the point. Turn on the camera.
Author: yechaoa
Open the camera
Opening the camera is a little more complicated.
permissions
The first step is not to turn it on, but to check whether you have camera permissions, which is mandatory on some phones like Huawei.
- Config file add:
<uses-permission android:name="android.permission.CAMERA" />
Copy the code
- Code:
private fun checkPermission(a) {
if (ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA) == PackageManager.PERMISSION_GRANTED) {
openCamera()
} else {
ActivityCompat.requestPermissions(this, arrayOf(Manifest.permission.CAMERA), REQUEST_CODE_PERMISSIONS)
}
}
Copy the code
- The callback:
override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<out String>, grantResults: IntArray) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults)
if (requestCode == REQUEST_CODE_PERMISSIONS) {
if (grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
openCamera()
} else {
ToastUtil.show("Refusal will result in the inability to use the camera.")}}}Copy the code
The openCamera method is just open the camera.
Before opening fit
private fun openCamera(a) {
val intent = Intent(MediaStore.ACTION_IMAGE_CAPTURE)
photoUri = getDestinationUri()
photoUri = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
// Apply Android 7.0 file permissions to create a Uri of the content type through the FileProvider
FileProvider.getUriForFile(this."$packageName.fileProvider", File(photoUri.path!!))
} else {
getDestinationUri()
}
// After Android11 force partition storage, external resources can not access, so add an output save location, and then value operation
intent.putExtra(MediaStore.EXTRA_OUTPUT, photoUri)
startActivityForResult(intent, REQUEST_CODE_CAMERA)
}
Copy the code
- Adaptation:
FileProvider.getUriForFile(this."$packageName.fileProvider", File(photoUri.path!!) )Copy the code
7.0 or above, use fileProvider to share files.
- Adapter 2:
intent.putExtra(MediaStore.EXTRA_OUTPUT, photoUri)
Copy the code
Since Android 11 forces partition storage, external resources cannot be accessed, so add an output save location, photoUri, and then select the value
The callback
override fun onActivityResult(requestCode: Int, resultCode: Int.data: Intent?). {
super.onActivityResult(requestCode, resultCode, data)
if (resultCode == RESULT_OK) {
when (requestCode) {
REQUEST_CODE_ALBUM -> {
doCrop(data? .data!!)
}
REQUEST_CODE_CAMERA -> {
// Take the value from the saved location
doCrop(photoUri)
}
UCrop.REQUEST_CROP -> {
val resultUri: Uri = UCrop.getOutput(data!!) !!!!!val bitmap = BitmapFactory.decodeStream(contentResolver.openInputStream(resultUri))
// todo
}
UCrop.RESULT_ERROR -> {
val error: Throwable = UCrop.getError(data!!) !!!!! ToastUtil.show("Picture cropping failed" + error.message)
}
}
}
Copy the code
And notice, instead of evaluating it from data like an album, we’re evaluating it from where we saved it.
The rear clipping is the same process as the album.
conclusion
The biggest change to this feature point is partition storage, which Android 10 May be able to do, but Android 11 will enforce partition storage.
The application can access its own partition and perform read/write operations without requiring read/write permissions. After uninstallation, the partition files are deleted accordingly, so there is no need to put cached files in the folder of competing products.
Below Android 10, you still need read and write permissions, and you can still run amok.
Get your own partition address:
getExternalFilesDir(Environment.DIRECTORY_PICTURES)
Copy the code
Corresponding Address:
file:/ / / storage/emulated / 0 / Android/data/files/Pictures/package name
Copy the code
File starts with sandbox files and Content starts with shared files.
What if I have access to other files, such as albums, music, that still need to read and write permission, and have to access through the MediaStore API, can specifically view the document.
The last
Writing is hard. If it works for you, give it a thumbs up
Android 11 Development Manual
Android 11 Developer Manual
reference
- Official Camera documentation
- Official Permissions Document
- Official Storage documents