Firebase Storage
Firebase storage provides facility to upload any file like image, video, audio, etc without using server side code.
In this blog, I’ll explain how to create in android application a feature that allows users to upload local image to firebase storage and download the list from the images with the help of firebase database with an example.
Our example app lets user enter file name in a text field and upload image.
Step 1. Create a new project on android studio or open an existing project in which you want to add firebase storage.
Step 2. Add the firebase to the project, follow this link to setup firebase to project. Link: https://firebase.google.com/docs/android/setup
Step 3. Add these dependency to the build.gradle(app)
1 2 3 |
implementation 'com.google.firebase:firebase-database:16.0.4' implementation 'com.google.firebase:firebase-storage:16.0.4' implementation 'com.google.firebase:firebase-auth:16.0.5' |
Step 4. Add the permission to the Androidmanifest.xml
1 |
<uses-permission android:name="android.permission.INTERNET" /> |
Now Let’s Start the coding part
1. Firstly image is selected from gallery using file chooser and displayed in ImageView.
2. Before using firebase we have to get its instance and then using the instance create reference to firebase storage app. It can be done by following code.
1 2 |
mStorageRef = FirebaseStorage.getInstance().getReference("uploads") mDatabaseRef = FirebaseDatabase.getInstance().getReference("uploads") |
3. Now a child reference is created and using it we call putFile() method to upload image to firebase storage.
4. If image is uploaded successfully then success message is shown otherwise error is shown in toast.
5. To upload the image url to firebase database.
How to Upload the image
After Getting the image from the application we are now calling then uploadFile() method defined in the main activity to upload image to firebase storage.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
fun uploadFile() { if (imageUri != null) { val fileReference = mStorageRef?.child("${System.currentTimeMillis()}.${getFileExtention(imageUri!!)}") fileReference?.putFile(imageUri!!)?.addOnSuccessListener { task -> Handler().postDelayed({ mBinding.progressBar.progress = 0 }, 200) Toast.makeText(this, getString(R.string.upload_successful), Toast.LENGTH_LONG) .show() fileReference.downloadUrl.addOnSuccessListener{ Log.d("tag",it.toString()) val upload = Upload() upload.name = mBinding.nameEt.text.toString() upload.mImageUrl =it.toString() uploadFileToDatabase(upload) } } ?.addOnFailureListener { Toast.makeText(this, it.message, Toast.LENGTH_LONG).show() } ?.addOnProgressListener { takeSnapshot -> val progress = (100.0 * takeSnapshot.bytesTransferred / takeSnapshot.totalByteCount) mBinding.progressBar.progress = progress.roundToInt() } } else { Toast.makeText(this, getString(R.string.no_file_selected), Toast.LENGTH_LONG).show() } } |
In this firstly we are creating a child on the storage and using the that child reference to upload the image to firebase storage using putFile(imageUri!!). To get Success, failure and progress we using
-
- addOnSuccessListener
- addOnFailureListener
- addOnProgressListener
after successfully uploading the file to firebase storage we will be uploading the image url to the firebase database to do that we getting the name from the editText and image from the fileReference downloadurl and saving it to the firebase database by calling uploadFileToDatabase.
Full Source Code
1. Let’s start with MainActivity.kt
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 |
class MainActivity : AppCompatActivity() { lateinit var mBinding: ActivityMainBinding private val PICK_IMAGE_REQUEST = 1 private var imageUri: Uri? = null private var mStorageRef: StorageReference? = null private var mDatabaseRef: DatabaseReference? = null override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) mBinding = DataBindingUtil.setContentView(this, R.layout.activity_main) mBinding.handler = MainActivityHandler(this) mStorageRef = FirebaseStorage.getInstance().getReference("uploads") mDatabaseRef = FirebaseDatabase.getInstance().getReference("uploads") } fun getFileExtention(uri: Uri): String { val contentResolver = contentResolver val mimeType = MimeTypeMap.getSingleton() return mimeType.getExtensionFromMimeType(contentResolver.getType(uri)).toString() } fun uploadFile() { if (imageUri != null) { val fileReference = mStorageRef?.child("${System.currentTimeMillis()}.${getFileExtention(imageUri!!)}") fileReference?.putFile(imageUri!!)?.addOnSuccessListener { task -> Handler().postDelayed({ mBinding.progressBar.progress = 0 }, 200) Toast.makeText(this, getString(R.string.upload_successful), Toast.LENGTH_LONG) .show() fileReference.downloadUrl.addOnSuccessListener{ Log.d("tag",it.toString()) val upload = Upload() upload.name = mBinding.nameEt.text.toString() upload.mImageUrl =it.toString() uploadFileToDatabase(upload) } } ?.addOnFailureListener { Toast.makeText(this, it.message, Toast.LENGTH_LONG).show() } ?.addOnProgressListener { takeSnapshot -> val progress = (100.0 * takeSnapshot.bytesTransferred / takeSnapshot.totalByteCount) mBinding.progressBar.progress = progress.roundToInt() } } else { Toast.makeText(this, getString(R.string.no_file_selected), Toast.LENGTH_LONG).show() } } private fun uploadFileToDatabase(upload: Upload) { val uploadId = mDatabaseRef?.push()?.key.toString() mDatabaseRef?.child(uploadId)?.setValue(upload) } fun openFileChooser() { val intent = Intent() intent.type = "image/*" intent.action = Intent.ACTION_GET_CONTENT startActivityForResult(intent, PICK_IMAGE_REQUEST) } override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { super.onActivityResult(requestCode, resultCode, data) if (requestCode == PICK_IMAGE_REQUEST && resultCode == Activity.RESULT_OK && data != null && data.data != null) { imageUri = data.data Picasso.with(this).load(imageUri).into(mBinding.imageIv) } } } |
2. activity_main.xml :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 |
<?xml version="1.0" encoding="utf-8"?> <layout xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" xmlns:android="http://schemas.android.com/apk/res/android"> <data> <variable name="handler" type="com.example.myapplication.handlers.MainActivityHandler" /> </data> <RelativeLayout android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".activities.MainActivity"> <androidx.appcompat.widget.AppCompatButton android:id="@+id/choose_file" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/choose_file" android:onClick="@{()->handler.onClickChooseFile()}" /> <EditText android:id="@+id/name_et" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_alignParentEnd="true" android:layout_alignParentRight="true" android:layout_toEndOf="@id/choose_file" android:layout_marginStart="@dimen/space_normal" android:layout_toRightOf="@id/choose_file" android:hint="Hello World!" android:layout_marginLeft="@dimen/space_normal" /> <androidx.appcompat.widget.AppCompatButton android:id="@+id/upload_file" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentBottom="true" android:layout_marginBottom="@dimen/spacing_large" android:layout_centerHorizontal="true" android:onClick="@{()->handler.onClickUploadImage()}" android:text="@string/upload" /> <ImageView android:id="@+id/image_iv" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_below="@id/name_et" android:layout_above="@id/progress_bar" android:layout_margin="@dimen/spacing_large" /> <ProgressBar android:id="@+id/progress_bar" android:layout_width="match_parent" android:layout_height="wrap_content" style="@style/Widget.AppCompat.ProgressBar.Horizontal" android:layout_above="@id/upload_file" android:layout_marginBottom="@dimen/spacing_generic" /> <TextView android:id="@+id/show_upload_tv" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentEnd="true" android:layout_alignParentRight="true" android:layout_alignParentBottom="true" android:layout_alignBaseline="@id/upload_file" android:gravity="center" android:textSize="@dimen/text_size_medium" android:padding="@dimen/spacing_large" android:layout_toEndOf="@+id/upload_file" android:layout_toRightOf="@+id/upload_file" android:onClick="@{()->handler.onClickShowImages()}" android:text="@string/show_uploads" /> </RelativeLayout> </layout> |
3. MainActivityHandler.kt : The handler will be used to handle the click on the button.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
class MainActivityHandler(val mContext: MainActivity) { fun onClickChooseFile() { mContext.openFileChooser() } fun onClickUploadImage() { mContext.uploadFile() } fun onClickShowImages() { mContext.startActivity(Intent(mContext,ImagesActivity::class.java)) } } |
4. To Save the link of the image to database we can use Upload.kt which will save the name of the image and it’s url
1 2 3 4 5 6 7 8 |
class Upload { @SerializedName("name") @Expose var name:String="no name" @SerializedName("mimageUrl") @Expose var mImageUrl:String="" } |
5. After Uploading the image to firebase storage and firebase database Now to download all the images saved in the storage.
Create a class having name as ImagesActivity.kt : In this activity we are getting all the list of images saved in the firebase database.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
class ImagesActivity : AppCompatActivity() { lateinit var mBinding: ActivityImagesBinding private var mDatabaseReference: DatabaseReference?=null override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) mBinding = DataBindingUtil.setContentView(this, R.layout.activity_images) mDatabaseReference=FirebaseDatabase.getInstance().getReference("uploads") mDatabaseReference?.addValueEventListener(object: ValueEventListener { override fun onCancelled(error: DatabaseError) { Toast.makeText(this@ImagesActivity,error.message.toString(),Toast.LENGTH_LONG).show() } override fun onDataChange(dataSnapshot: DataSnapshot) { val upload=ArrayList<Upload>() dataSnapshot.children.forEach { val uploaded = Upload() val name = it.child("name").getValue() as String val imageUrl = it.child("mimageUrl").getValue() as String uploaded.name = name uploaded.mImageUrl = imageUrl upload.add(uploaded) } val adapter=ImageListAdapter(this@ImagesActivity,upload) mBinding.recyclerView.adapter=adapter } }) } } |
6. Layout of the activity_images.xml:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
<?xml version="1.0" encoding="utf-8"?> <layout 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"> <data> </data> <RelativeLayout android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".activities.ImagesActivity"> <androidx.recyclerview.widget.RecyclerView android:id="@+id/recycler_view" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"/> </RelativeLayout> </layout> |
7. In this we activity we are using the RecyclerView to show list of images. So we have to create the adapter to show the list of images downloaded from the firebase.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
class ImageListAdapter(val mContext: ImagesActivity, val imageList: List<Upload> ): RecyclerView.Adapter<ImageListAdapter.ViewHolder>() { class ViewHolder(val binding: ImageItemBinding) : RecyclerView.ViewHolder(binding.root) { } override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder { return ViewHolder(DataBindingUtil.inflate(LayoutInflater.from(parent.context), R.layout.image_item,parent, false)) } override fun getItemCount(): Int { return imageList.size } override fun onBindViewHolder(holder: ViewHolder, position: Int) { holder.binding.nameTv.text=imageList[position].name Picasso.with(mContext).load(imageList[position].mImageUrl).into(holder.binding.imageIv) } } |
8. Layout for the list item having name “image_item.xml”
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 |
<?xml version="1.0" encoding="utf-8"?> <layout> <data> <variable name="data" type="com.example.myapplication.models.Upload" /> </data> <androidx.cardview.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical" android:layout_margin="@dimen/spacing_generic"> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical"> <TextView android:id="@+id/name_tv" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_margin="@dimen/spacing_generic" /> <ImageView android:id="@+id/image_iv" android:layout_width="@dimen/spacing_huge" android:layout_height="@dimen/spacing_huge" android:layout_margin="@dimen/spacing_generic" /> </LinearLayout> </androidx.cardview.widget.CardView> </layout> |
. . . . . . .
That’s all for now, I hope this blog have helped you, Comment below if you have any queries related to above android upload image to firebase storage example.