Firebase Image Uploads for Android Kotlin: How to Add Profile Pictures to Your App

Learn how to add and manage profile pictures and other images in your Android Kotlin app with Firebase. Follow our step-by-step guide .

 


Are you looking to add profile picture upload functionality to your Android app using Kotlin? Firebase Storage is a powerful tool that can help you achieve this goal quickly and easily. In this blog post, we'll walk you through the steps for implementing Firebase image uploads for Android Kotlin, specifically for adding profile pictures to your app.


Click here to Watch Video on Youtube 






Step 1: Set up Firebase in your Android project

Before you can start uploading images to Firebase Storage, you need to create a Firebase project and add the necessary dependencies to your Android project. Here's how you can do that:


Create a Firebase project in the Firebase console and add an Android app to it.

Add the Firebase SDK to your Android project by following the instructions in the Firebase documentation.

Step 2: Add the necessary UI elements to your app

To enable users to upload their profile pictures, you need to add UI elements to your app. Here are some examples of UI elements you can add:


An ImageView to display the user's current profile picture

A Button to trigger the profile picture upload process

A ProgressBar to indicate the progress of the upload process


Add the following UI elements/codes to your project:


border.xml

   

<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">

<solid android:color="@android:color/transparent" />

<stroke
android:width="2dp"
android:color="@color/blue" />

<padding
android:bottom="2dp"
android:left="2dp"
android:right="2dp"
android:top="2dp" />

</shape>


      


Download the following Images. and paste it into a drawable folder of your project:


user png

               
               google png





 

   circle frame






color.xml

   

<color name="blue">#459DE4</color>
<color name="red">#FF0000</color>
<color name="green">#80FF00</color>

      



build.gradle

   

dependencies {

implementation 'androidx.core:core-ktx:1.7.0'
implementation 'androidx.appcompat:appcompat:1.6.1'
implementation 'com.google.android.material:material:1.8.0'
implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
implementation 'com.google.firebase:firebase-auth-ktx:21.3.0'
testImplementation 'junit:junit:4.13.2'
androidTestImplementation 'androidx.test.ext:junit:1.1.5'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1'
implementation platform('com.google.firebase:firebase-bom:31.5.0')
implementation 'com.google.firebase:firebase-auth-ktx'
implementation 'com.google.android.gms:play-services-auth:20.5.0'
implementation 'com.google.firebase:firebase-firestore:23.0.0'
implementation 'com.google.firebase:firebase-auth:20.0.1'
implementation 'com.github.bumptech.glide:glide:4.12.0'
implementation 'com.google.firebase:firebase-storage-ktx:20.0.0'
implementation 'com.google.firebase:firebase-database:20.0.0'
implementation 'com.soundcloud.android:android-crop:1.0.1@aar'


}

      



Manifest activity

   

<activity android:name="com.soundcloud.android.crop.CropImageActivity"
android:theme="@style/Base.Theme.AppCompat"/>

      



Manifest Permissions 

   

<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

      



themes

   Theme.AppCompat.DayNight.NoActionBar      



build.gradle(project)

   

dependencies {

classpath 'com.google.gms:google-services:4.3.14'

}

      

 






Step 3: Implement the image upload process

Once you have set up Firebase in your Android project and added the necessary UI elements, you can start implementing the image upload process. Here are the steps you can follow:


Create a reference to the Firebase Storage location where you want to store the image.

Use an image picker library to allow the user to select an image from their device.

Upload the selected image to the Firebase Storage location using the reference created in the previous step.

Save the download URL of the uploaded image in Firebase Realtime Database or Firestore, depending on your app's requirements.

Step 4: Display the uploaded profile picture

Now that the user's profile picture is uploaded to Firebase Storage, you can display it in your app. Here are the steps you can follow:


Retrieve the download URL of the user's profile picture from Firebase Realtime Database or Firestore.

Use an image loading library to display the profile picture in the ImageView you added earlier.


Create New Empty Activity and name it as SignInActivity

Add the following codes in your activities



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">


<TextView
android:id="@+id/titleTextView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@color/teal_700"
android:text="User Profile"

android:textColor="@color/white"
android:textSize="24sp"
android:textAlignment="center"
/>


<Button
android:id="@+id/logout_button"
android:layout_width="match_parent"
android:layout_height="50dp"
android:background="@color/red"
android:text="logout"
android:textColor="@color/white"
android:textStyle="bold"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.0"
app:layout_constraintStart_toStartOf="parent" />

<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="50dp"
android:gravity="center"
android:orientation="vertical"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.497"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
>





<FrameLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="20dp">

<ImageView
android:id="@+id/profile_picture_image_view"
android:layout_width="150dp"
android:layout_height="150dp"
android:layout_gravity="center"
android:scaleType="centerCrop"
android:src="@drawable/man_pro" />

<ImageView
android:id="@+id/crop"
android:layout_width="150dp"
android:layout_height="150dp"
android:layout_gravity="center"
android:scaleType="centerCrop"
android:src="@drawable/circleframe" />
</FrameLayout>


<TextView
android:id="@+id/name"
android:layout_width="wrap_content"
android:layout_height="39dp"
android:padding="5dp"
android:text="Loading.."
android:textStyle="bold"
android:textSize="20dp"
android:textColor="@color/black"

app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.031"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.0" />


<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal">

<Button
android:id="@+id/upload"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:background="@color/green"
android:text="Upload" />

<Button
android:id="@+id/remove"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="10dp"
android:layout_marginTop="16dp"
android:background="@color/teal_200"
android:text="Remove" />


</LinearLayout>


</LinearLayout>


</androidx.constraintlayout.widget.ConstraintLayout>



      




activity_sign_in.xml

   

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout 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"
android:padding="16dp"
tools:context=".SignInActivity">


<LinearLayout
android:layout_centerInParent="true"
android:layout_marginTop="50dp"
android:background="@drawable/border"
android:layout_width="wrap_content"
android:layout_height="wrap_content">

<ImageView
android:layout_width="28dp"
android:layout_height="28dp"
android:layout_alignParentLeft="true"
android:layout_centerVertical="true"
android:layout_gravity="center"
android:layout_marginLeft="11dp"
android:layout_marginRight="11dp"
android:background="@color/white"
android:src="@drawable/google" />

<Button
android:id="@+id/signInButton"
android:textAllCaps="false"
android:layout_width="200dp"
android:layout_height="50dp"
android:background="@color/blue"
android:text="Sign up with Google"
android:textColor="@color/white"
android:textSize="20sp" />

</LinearLayout>

<TextView
android:id="@+id/textView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:layout_centerHorizontal="true"
android:layout_marginTop="181dp"
android:text="Click below button to Sign in"
android:textAlignment="center"
android:textSize="40dp" />


</RelativeLayout>

      



mainActivity.kt

   

import android.app.Activity
import android.Manifest
import android.content.Intent
import android.content.pm.PackageManager
import android.net.Uri
import android.os.Build
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.os.Handler
import android.provider.MediaStore
import android.util.Log
import android.widget.Button
import android.widget.ImageView
import android.widget.TextView
import android.widget.Toast
import androidx.core.app.ActivityCompat
import androidx.core.content.ContextCompat
import com.bumptech.glide.Glide
import com.google.android.gms.auth.api.signin.GoogleSignIn
import com.google.android.gms.auth.api.signin.GoogleSignInClient
import com.google.android.gms.auth.api.signin.GoogleSignInOptions
import com.google.android.gms.tasks.Continuation
import com.google.android.gms.tasks.Task
import com.google.firebase.auth.FirebaseAuth
import com.google.firebase.auth.ktx.auth
import com.google.firebase.database.FirebaseDatabase
import com.google.firebase.firestore.FirebaseFirestore
import com.google.firebase.ktx.Firebase
import com.google.firebase.storage.FirebaseStorage
import com.google.firebase.storage.StorageReference
import com.google.firebase.storage.UploadTask
import com.google.firebase.storage.ktx.storage
import com.soundcloud.android.crop.Crop
import java.io.File


class MainActivity : Activity() {


private lateinit var mGoogleSignInClient: GoogleSignInClient
private lateinit var mAuth: FirebaseAuth


private val PICK_IMAGE_REQUEST = 1
private lateinit var imageView: ImageView
private lateinit var storageRef: StorageReference
private lateinit var profilePicRef: StorageReference


override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)


if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
window.statusBarColor = ContextCompat.getColor(this, R.color.teal_700)
}


mAuth = FirebaseAuth.getInstance()


val gso = GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN)
.requestIdToken(getString(R.string.default_web_client_id))
.requestEmail()
.build()

mGoogleSignInClient = GoogleSignIn.getClient(this, gso)


val textView = findViewById<TextView>(R.id.name)

val auth = Firebase.auth
val user = FirebaseAuth.getInstance().currentUser!!

if (user != null) {
val userName = user.displayName
textView.text = userName
} else {
// Handle the case where the user is not signed in
}


// Inside onCreate() method
val sign_out_button = findViewById<Button>(R.id.logout_button)
sign_out_button.setOnClickListener {
signOutAndStartSignInActivity()
}








imageView = findViewById(R.id.profile_picture_image_view)
val uploadButton = findViewById<Button>(R.id.upload)

// Get a reference to the Firebase Storage location where the profile picture will be stored
storageRef = FirebaseStorage.getInstance().reference

// Get a reference to the current user's profile picture in Firebase Storage
val currentUser = FirebaseAuth.getInstance().currentUser
val userId = currentUser?.uid
profilePicRef = storageRef.child("images/$userId.jpg")

// Check if the user has a profile picture in Firebase Storage
profilePicRef.downloadUrl.addOnSuccessListener { uri ->
// If the user has a profile picture, load it into the ImageView using Glide
Glide.with(this).load(uri).into(imageView)
}.addOnFailureListener { exception ->
// If the user doesn't have a profile picture, do nothing
Log.d("ProfilePic", "Profile picture not available", exception)
}

// Set up the button to open the image picker
uploadButton.setOnClickListener {
val intent = Intent(Intent.ACTION_GET_CONTENT)
intent.type = "image/*"
startActivityForResult(intent, PICK_IMAGE_REQUEST)
}













val deleteButton = findViewById<Button>(R.id.remove)
deleteButton.setOnClickListener {
if (userId != null) {

storageRef = FirebaseStorage.getInstance().getReference("images/$userId.jpg")
storageRef.delete().addOnSuccessListener {
val databaseRef = FirebaseDatabase.getInstance().getReference("users/$userId")
val updates = HashMap<String, Any?>()
updates["profile_pic_url"] = null
imageView.setImageResource(R.drawable.man_pro)
Toast.makeText(this, "User profile removed successfully", Toast.LENGTH_SHORT).show()

databaseRef.updateChildren(updates).addOnSuccessListener {
// User profile updated successfully


}.addOnFailureListener {
// Failed to update user profile
}
}.addOnFailureListener {
// Failed to delete image file

Toast.makeText(this, "Failed to delete image file", Toast.LENGTH_SHORT).show()
}
}
}


}















private fun signOutAndStartSignInActivity() {
mAuth.signOut()

mGoogleSignInClient.signOut().addOnCompleteListener(this) {
// Optional: Update UI or show a message to the user
val intent = Intent(this@MainActivity, SignInActivity::class.java)
startActivity(intent)
finish()
}
}










override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)

if (requestCode == PICK_IMAGE_REQUEST && resultCode == RESULT_OK && data != null && data.data != null) {
// Get the URI of the selected image
val imageUri = data.data



// Start the crop activity
Crop.of(imageUri, Uri.fromFile(File(this.getExternalCacheDir(), "cropped_image.jpg")))
.asSquare().start(this)



Handler().postDelayed({
// Upload the cropped image to Firebase Storage
val file = File(this.getExternalCacheDir(), "cropped_image.jpg")

val uploadTask = profilePicRef.putFile(Uri.fromFile(file))

uploadTask.continueWithTask(Continuation<UploadTask.TaskSnapshot, Task<Uri>> { task ->
if (!task.isSuccessful) {
task.exception?.let {
throw it
}
}
return@Continuation profilePicRef.downloadUrl
}).addOnCompleteListener { task ->
if (task.isSuccessful) {
val downloadUri = task.result
Glide.with(this).load(downloadUri).into(imageView)
} else {
// Handle errors here
Log.d("UploadError", task.exception.toString())
}
}


}, 5000) // 5000 milliseconds = 5 seconds




}
}





















private fun loadProfilePicture() {
// Get a reference to the current user's profile picture in Firebase Storage
val currentUser = FirebaseAuth.getInstance().currentUser
val userId = currentUser?.uid
profilePicRef = storageRef.child("images/$userId.jpg")

// Check if the user has a profile picture in Firebase Storage
profilePicRef.downloadUrl.addOnSuccessListener { uri ->
// If the user has a profile picture, load it into the ImageView using Glide
Glide.with(this).load(uri).into(imageView)
}.addOnFailureListener { exception ->
// If the user doesn't have a profile picture, set a default image
imageView.setImageResource(R.drawable.man_pro)
Log.d("ProfilePic", "Profile picture not available", exception)
}
}








}

      



SignInActivity.kt

   



import android.content.Intent
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.widget.Button
import android.widget.LinearLayout
import android.widget.Toast
import com.google.android.gms.auth.api.signin.GoogleSignIn
import com.google.android.gms.auth.api.signin.GoogleSignInOptions
import com.google.android.gms.common.api.ApiException
import com.google.firebase.auth.FirebaseAuth
import com.google.firebase.auth.GoogleAuthProvider

class SignInActivity : AppCompatActivity() {


companion object {
private const val RC_SIGN_IN = 9001
}

private lateinit var auth: FirebaseAuth



override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_sign_in)

auth = FirebaseAuth.getInstance()



val currentUser = auth.currentUser

if (currentUser != null) {
// The user is already signed in, navigate to MainActivity
val intent = Intent(this, MainActivity::class.java)
startActivity(intent)
finish() // finish the current activity to prevent the user from coming back to the SignInActivity using the back button
}




val signInButton = findViewById<Button>(R.id.signInButton)
signInButton.setOnClickListener {
signIn()
}
}

private fun signIn() {
val gso = GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN)
.requestIdToken(getString(R.string.default_web_client_id))
.requestEmail()
.build()

val googleSignInClient = GoogleSignIn.getClient(this, gso)
val signInIntent = googleSignInClient.signInIntent
startActivityForResult(signInIntent, RC_SIGN_IN)
}

override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)

if (requestCode == RC_SIGN_IN) {
val task = GoogleSignIn.getSignedInAccountFromIntent(data)
try {
val account = task.getResult(ApiException::class.java)
firebaseAuthWithGoogle(account.idToken!!)
} catch (e: ApiException) {
Toast.makeText(this, "Google sign in failed: ${e.message}", Toast.LENGTH_SHORT).show()
}
}
}

private fun firebaseAuthWithGoogle(idToken: String) {
val credential = GoogleAuthProvider.getCredential(idToken, null)
auth.signInWithCredential(credential)
.addOnCompleteListener(this) { task ->
if (task.isSuccessful) {
val user = auth.currentUser
Toast.makeText(this, "Signed in as ${user?.displayName}", Toast.LENGTH_SHORT).show()
startActivity(Intent(this, MainActivity::class.java))
finish()
} else {
Toast.makeText(this, "Authentication failed", Toast.LENGTH_SHORT).show()
}
}
}
}

      



Manifest file

   <activity
    android:name=".MainActivity"
android:exported="false" />
<activity
android:name="com.soundcloud.android.crop.CropImageActivity"
android:theme="@style/Base.Theme.AppCompat" />
<activity
android:name=".SignInActivity"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />

<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>      





Final Result



Conclusion

In this blog post, we showed you how to implement Firebase image uploads for Android Kotlin specifically for adding profile pictures to your app. By following these steps, you can add profile picture upload functionality to your app quickly and easily. If you have any questions or feedback, feel free to leave a comment below.



Cookie Consent
We serve cookies on this site to analyze traffic, remember your preferences, and optimize your experience.
Oops!
It seems there is something wrong with your internet connection. Please connect to the internet and start browsing again.
AdBlock Detected!
We have detected that you are using adblocking plugin in your browser.
The revenue we earn by the advertisements is used to manage this website, we request you to whitelist our website in your adblocking plugin.
Site is Blocked
Sorry! This site is not available in your country.