Creating a Photo Post and Storing it in Room Database in Android

Abhishek Pathak
4 min readAug 15, 2023

--

In this tutorial, we’ll guide you through the process of building an Android app that enables users to create photo posts by selecting images from their gallery. We’ll then store these posts in a Room database using Kotlin. This step-by-step guide will help you understand how to integrate image selection, database operations, and Room database

Prerequisites

  • Android Studio installed, I am using Android studio Giraffe.
  • Basic understanding of Android app development and Kotlin programming.

Step 1: Set Up Your Project

  1. Launch Android Studio and create a new project.
  2. Choose an appropriate project name, package name, and other settings.

Step 2: Add Dependencies

Add the necessary dependencies to your app’s build.gradle file:

  // plugin of KSP
id("com.google.devtools.ksp") version "1.8.10-1.0.9"

//Room Dependency
implementation("androidx.room:room-runtime:2.5.2")
ksp("androidx.room:room-compiler:2.5.2")

// support of android 1.8 with KSP and Room with Kotlin
kotlin {
jvmToolchain(8)
}

Sync your project to ensure the dependencies are added.

Step 3: Create Room Entity

Define your Room database entity for the PhotoPost:

@Entity(tableName = "photo_posts")
data class PhotoPost(
@PrimaryKey(autoGenerate = true) val id: Long = 0,
val imagePath: String,
val caption: String
)

Step 4: Create Room Database

Create your Room database class:

@Database(entities = [PhotoPost::class], version = 1)
abstract class AppDatabase : RoomDatabase() {
abstract fun photoPostDao(): PhotoPostDao

companion object {
@Volatile
private var INSTANCE: AppDatabase? = null

fun getInstance(context: Context): AppDatabase {
return INSTANCE ?: synchronized(this) {
val instance = Room.databaseBuilder(
context.applicationContext,
AppDatabase::class.java,
"app_database"
).build()
INSTANCE = instance
instance
}
}
}
}

Step 5: Create DAO Interface

Create a DAO (Data Access Object) interface for performing database operations on PhotoPost:

@Dao
interface PhotoPostDao {
@Insert
suspend fun insert(photoPost: PhotoPost)

@Query("SELECT * FROM photo_posts")
fun getAllPhotoPosts(): List<PhotoPost>
}

Step 6: Layouts

Create the layout XML file for the activity (activity_create_photo_post.xml).

<!-- activity_photo_list.xml -->
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/photoRecyclerView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="8dp"
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintBottom_toBottomOf="parent" />

Step 7: Create RecyclerView Item Layout

  1. Create a new layout XML file named item_photo.xml for the RecyclerView item layout.
  2. Design the item layout to display an image and caption:
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:padding="8dp">

<ImageView
android:id="@+id/itemImageView"
android:layout_width="match_parent"
android:layout_height="200dp"
android:scaleType="centerCrop" />

<TextView
android:id="@+id/itemCaptionTextView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:textSize="16sp" />
</LinearLayout>

Step 8: Create PhotoAdapter

Create a RecyclerView adapter to display the list of photos. Create a new Kotlin file named PhotoAdapter.kt:

class PhotoAdapter(private val photoList: List<PhotoPost>) :
RecyclerView.Adapter<PhotoAdapter.PhotoViewHolder>() {

class PhotoViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
val imageView: ImageView = itemView.findViewById(R.id.itemImageView)
val captionTextView: TextView = itemView.findViewById(R.id.itemCaptionTextView)
}

override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): PhotoViewHolder {
val itemView = LayoutInflater.from(parent.context)
.inflate(R.layout.item_photo, parent, false)
return PhotoViewHolder(itemView)
}

override fun onBindViewHolder(holder: PhotoViewHolder, position: Int) {
val currentPhoto = photoList[position]
val context = holder.itemView.context

// Set image and caption
Glide.with(context)
.load(Uri.parse(currentPhoto.imagePath))
.into(holder.imageView)

holder.captionTextView.text = currentPhoto.caption
}

override fun getItemCount() = photoList.size
}

Step 9: Display Photo Posts

To display the stored photo posts, you can create another activity or fragment, retrieve the posts from the database, and populate a RecyclerView.

In your activity where you want to display the list of photos, add the following code:

import android.app.Activity
import android.content.Intent
import android.net.Uri
import android.os.Bundle
import android.provider.MediaStore
import android.widget.Button
import android.widget.EditText
import android.widget.ImageView
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.bumptech.glide.Glide

class CreatePhotoPostActivity : AppCompatActivity() {

private val SELECT_IMAGE_REQUEST = 1
private lateinit var photoPostDao: PhotoPostDao
private var selectedImagePath: String = ""
private lateinit var recyclerView: RecyclerView
private lateinit var adapter: PhotoAdapter

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

photoPostDao = AppDatabase.getInstance(this).photoPostDao()

recyclerView = findViewById(R.id.photoRecyclerView)
adapter = PhotoAdapter(emptyList()) // Initial empty list

recyclerView.layoutManager = LinearLayoutManager(this)
recyclerView.adapter = adapter

val selectImageButton: Button = findViewById(R.id.selectImageButton)
selectImageButton.setOnClickListener {
val intent = Intent(Intent.ACTION_PICK, MediaStore.Images.Media.EXTERNAL_CONTENT_URI)
startActivityForResult(intent, SELECT_IMAGE_REQUEST)
}

val postButton: Button = findViewById(R.id.postButton)
postButton.setOnClickListener {
val caption = findViewById<EditText>(R.id.captionEditText).text.toString()

if (selectedImagePath.isNotBlank() && caption.isNotBlank()) {
val photoPost = PhotoPost(imagePath = selectedImagePath, caption = caption)
insertPhotoPost(photoPost)
} else {
Toast.makeText(this, "Please select an image and enter a caption", Toast.LENGTH_SHORT).show()
}
}
}

override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
if (requestCode == SELECT_IMAGE_REQUEST && resultCode == Activity.RESULT_OK && data != null) {
val selectedImageUri: Uri = data.data!!
selectedImagePath = selectedImageUri.toString()

val imageView: ImageView = findViewById(R.id.imageView)
Glide.with(this)
.load(selectedImageUri)
.into(imageView)
}
}

private fun insertPhotoPost(photoPost: PhotoPost) {
photoPostDao.insert(photoPost)
Toast.makeText(this, "Photo post saved successfully", Toast.LENGTH_SHORT).show()
clearFields()
loadPhotoPosts()
}

private fun clearFields() {
findViewById<ImageView>(R.id.imageView).setImageResource(0)
findViewById<EditText>(R.id.captionEditText).text.clear()
selectedImagePath = ""
}

private fun loadPhotoPosts() {
val photoList = photoPostDao.getAllPhotoPosts()
adapter.setPhotoList(photoList)
}
}

Step 10: Run the app on Emulator or Physical device

Conclusion

You’ve successfully developed an Android app that allows users to create photo posts by selecting images from their gallery and storing them in a Room database. By following this tutorial, you’ve learned how to integrate image selection, database operations, and Room database without using the MVVM architecture. You can now extend this app by implementing additional features such as editing and deleting posts, enhancing the user interface, and optimizing the image storage strategy.

If you found this article valuable, please show your appreciation by applauding it 👏. Your feedback is important to me, so please share any suggestions for improvement in the comments section.

Let’s stay connected on Linkedin , GitHub to continue learning and collaborating together.

--

--