Android Kotlin choose photo from gallery and draws in the application | Android Studio | Kotlin ...
last updated: 11 April 2024
I've written an app that has a
Load photo from Gallery button, and when clicked, I call the standard functionality to select a photo from the Gallery:
I click on the Load photo from Gallery button:
The Android system shows a folder with photos I choose a photo:
My app gets the path to the photo and displays the selected photo:
Step 1. Creating a new project
Step 2. Let's change the code in the file MainActivity.kt
The color indicates that a new code has been added.
File MainActivity.kt
package com.example.androidkotlinapp1
import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import android.content.Intent
import android.content.Intent.ACTION_OPEN_DOCUMENT
import android.net.Uri
import android.widget.Button
import android.widget.ImageView
class MainActivity : AppCompatActivity() {
val MY_REQUEST_CODE1 = 100
override fun onCreate (savedInstanceState: Bundle?) {
super .onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val myButton = findViewById(R.id.button1) as Button
myButton.setOnClickListener {
val intent = Intent(ACTION_OPEN_DOCUMENT)
intent.addCategory(Intent.CATEGORY_OPENABLE)
intent.type = "*/*"
intent.putExtra(Intent.EXTRA_MIME_TYPES, arrayOf("image/*" , "video/*" ))
startActivityForResult(intent, MY_REQUEST_CODE1);
}
}
// I override system function
override fun onActivityResult (requestCode: Int, resultCode: Int, data: Intent?) {
super .onActivityResult(requestCode, resultCode, data)
if (resultCode == RESULT_OK && requestCode == MY_REQUEST_CODE1) {
val uriFilePath_to_gallery = data?.data
show_URI_in_ImageView(uriFilePath_to_gallery)
}
}
// my function for image view
fun show_URI_in_ImageView (uri: Uri?)
{
val myImageView = findViewById(R.id.imageView1) as ImageView
myImageView.setImageURI(uri)
}
}
Step 2. Let's change the code in the file activity_main.xml
In the activity_main.xml file, add the following graphic elements:
LinearLayout
This is a layer where elements are displayed one after the other vertically or horizontally (I have it vertically because the android:orientation ="vertical parameter is set)
ImageView
This is to display the picture
The color indicates that a new code has been added.
Xml
File activity_main.xml
<?xml version="1.0" encoding="utf-8" ?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity" >
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<Button
android:id="@+id/button1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:backgroundTint="#A0A000"
android:textColor="#000000"
android:text="Load photo from Gallery" />
<ImageView
android:id="@+id/imageView1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
tools:srcCompat="@tools:sample/avatars" />
</LinearLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
Explanation
I wonder what path we will see when we select the photo from the gallery
When we select a photo from the gallery, we will see
uri :
content://com.android.providers.media.documents/document/image%3A16
Question: How do I get the path to the file from this
uri ?
Answer: This
uri was generated by the system
Provider . I wouldn't recommend converting
uri to a file path, because there's no guarantee that it will always work. Because only temporary permissions can be allocated to a file by the system.
Problem! Working with
uri from the gallery is not very convenient for me. When I save
uri to the database in a project at work, then this
uri does not always work (after a few days) - the picture for this
uri is not displayed.
Decision:
Step 1. I'm creating an empty file inside my app folder (there's a
getExternalFilesDir function in
Kotlin ).
Step 2. I read the contents (content) from the
uri gallery and save it to my empty file.
Step 3. I get
uri at the location of my file
Download an example:
Changes 1
Created a new file MyFileUtils.kt
package com.example.androidkotlinapp1
import android.content.ContentResolver
import android.content.Context
import android.net.Uri
import android.webkit.MimeTypeMap
import androidx.core.content.FileProvider
import java.io.File
import java.io.InputStream
class MyFileUtils {
fun copyUriContentToFileInsideApp (context: Context, uri: Uri, filenameWithoutExtension: String ): Uri?
{
val fileExtension = getFileExtensionFromUri (context, uri);
val folderApplication = context.getExternalFilesDir(android.os.Environment.DIRECTORY_PICTURES)
val fileDest = File(folderApplication, filenameWithoutExtension + '.' + fileExtension)
val uriDest = FileProvider.getUriForFile(
context, "${BuildConfig.APPLICATION_ID}.fileprovider " , fileDest
)
// get stream by uri
val streamSource = context.contentResolver.openInputStream(uri)
// store source stream to fileDest
if (fileDest!=null && streamSource!=null)
{
streamSource.use { input ->
fileDest.outputStream().use { output ->
input.copyTo(output)
return uriDest
}
}
}
return null
}
private fun getFileExtensionFromUri (context: Context, uri:Uri): String ? {
return if (uri.scheme == ContentResolver.SCHEME_CONTENT) {
val mime = MimeTypeMap.getSingleton()
mime.getExtensionFromMimeType(context.contentResolver.getType(uri))
} else {
MimeTypeMap.getFileExtensionFromUrl(Uri.fromFile(File(uri.path)).toString())
}
}
}
Changes 2
Created a new file inside the folder:
D:\AndroidKotlinApp1
app
src
main
res
xml
File file_paths.xml
<?xml version="1.0" encoding="utf-8" ?>
<paths>
<external-path
name="pictures"
path="Android/data/com.example.androidkotlinapp1 /files/Pictures" />
<external-path
name="music"
path="Android/data/com.example.androidkotlinapp1 /files/Music" />
<external-path
name="docs"
path="Android/data/com.example.androidkotlinapp1 /files/Documents" />
<external-path
name="pdf"
path="." />
</paths>
Changes 3
File AndroidManifest.xml
<?xml version="1.0" encoding="utf-8" ?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools" >
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_MEDIA_IMAGES" />
<uses-permission android:name="android.permission.READ_MEDIA_VIDEO" />
<uses-permission android:name="android.permission.READ_MEDIA_AUDIO" />
<application
android:allowBackup="true"
android:dataExtractionRules="@xml/data_extraction_rules"
android:fullBackupContent="@xml/backup_rules"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:supportsRtl="true"
android:theme="@style/Theme.AndroidKotlinApp1"
tools:targetApi="31" >
<activity
android:name=".MainActivity"
android:exported="true" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<provider
android:name="androidx.core.content.FileProvider"
android:authorities="${applicationId}.fileprovider "
android:exported="false"
android:grantUriPermissions="true" >
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/file_paths" />
</provider>
</application>
</manifest>
Changes 4
File MainActivity.kt
package com.example.androidkotlinapp1
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.content.Intent
import android.content.Intent.ACTION_OPEN_DOCUMENT
import android.net.Uri
import android.widget.Button
import android.widget.ImageView
import androidx.core.content.ContentProviderCompat.requireContext
class MainActivity : AppCompatActivity() {
val MY_REQUEST_CODE1 = 100
override fun onCreate (savedInstanceState: Bundle?) {
super .onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val myButton = findViewById(R.id.button1) as Button
myButton.setOnClickListener {
val intent = Intent(ACTION_OPEN_DOCUMENT)
intent.addCategory(Intent.CATEGORY_OPENABLE)
intent.type = "*/*"
intent.putExtra(Intent.EXTRA_MIME_TYPES, arrayOf("image/*" , "video/*" ))
startActivityForResult(intent, MY_REQUEST_CODE1);
}
}
// I override system function
override fun onActivityResult (requestCode: Int, resultCode: Int, data: Intent?) {
super .onActivityResult(requestCode, resultCode, data)
if (resultCode == RESULT_OK && requestCode == MY_REQUEST_CODE1) {
val uriContent_selected_from_gallery = data?.data
val filenameWithoutExtension = "my_picture1"
val newUri = MyFileUtils().copyUriContentToFileInsideApp(baseContext!!, uriContent_selected_from_gallery!!, filenameWithoutExtension);
show_URI_in_ImageView(newUri)
}
}
// my function for image view
fun show_URI_in_ImageView (uriContent: Uri?)
{
val myImageView = findViewById(R.id.imageView1) as ImageView
myImageView.setImageURI(uriContent)
}
}
Let's run the program
Let's see a new uri for the picture:
content://com.example.androidkotlinapp1.fileprovider /pictures/my_picture1.jpg