Build A Meme App With Glide And Volley In Kotlin

·

8 min read

->This Blog Aims To Build A Meme App Which Will Use Random Meme Generator API Which Takes Memes From Reddit And Those Memes Will Be Used To Place In An Image View Through Glide. So, If You Are Newbie Like Me And If You Want To Build This App, Let's Get Started. First Things First, Lets Access Internet Access By Adding Following Attribute/Tag In Project Manifest File👇🏻

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

Well, Now We Have Access To The Internet. Let's Start The Project By XML File And By Adding An ImageView And Don't Forget To Add id To The ImageView👇🏻

<ImageView
android:id="@+id/memeView"
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_margin="5dp"
android:src="@drawable/ic_launcher_foreground"
app:layout_constraintBottom_toTopOf="@+id/nextMeme"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="1.0"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.0" />

Note:-As My Layout Is In Constraint Layout I Have Added Required Attributes, Depending On Your Layout You Can Change Those Attributes. ->Well, So, We Have Done Basic Implementation To Display The Image, Now We'll Be Adding ProgressBar Which, Will Be Useful To Inform The User That The Meme Is Loading. For Adding ProgressBar We'll Be Adding ProgressBar Attribute In Layout File || XML File As Following👇🏻 And Don't Forget To Add id Attribute

<ProgressBar
android:id="@+id/progressBar"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintBottom_toBottomOf="@+id/memeView"
app:layout_constraintEnd_toEndOf="@+id/memeView"
app:layout_constraintStart_toStartOf="@+id/memeView"
app:layout_constraintTop_toTopOf="@+id/memeView" />

That's Great, We Have Came So Far In Our XML File, Now Its Time To Add Two Buttons Which Will Be Used For Generating Next Meme And Sharing The Meme Respectively. Note:-Adding Sharing Button Is Optional But Make Sure To Add Next Meme Button As We Have To Reload Another Meme Respectively As Following👇🏻 And Don't Forget To Add id Attribute.

<com.google.android.material.button.MaterialButton
android:id="@+id/nextMeme"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_margin="20dp"
android:background="@color/white"
android:fontFamily="casual"
android:onClick="nextMeme"
android:text="@string/next_meme"
android:textAllCaps="false"
android:textColor="@color/white"
android:textStyle="bold"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="@+id/guideline2" />

<com.google.android.material.button.MaterialButton
android:id="@+id/shareMeme"
style="@style/Widget.MaterialComponents.Button.OutlinedButton"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_margin="20dp"
android:fontFamily="casual"
android:onClick="shareMeme"
android:text="@string/share_meme"
android:textAllCaps="false"
android:textColor="@color/black"
android:textStyle="bold"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="@+id/guideline2"
app:layout_constraintStart_toStartOf="parent" />

Congratulations Buddy, We Have Completed All Necessary Elements In Our XML File || Layout File. Here Is Our Layout File After Adding All The Necessary Elements👇🏻

<ImageView
android:id="@+id/memeView"
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_margin="5dp"
android:src="@drawable/ic_launcher_foreground"
app:layout_constraintBottom_toTopOf="@+id/nextMeme"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="1.0"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.0" />

<ProgressBar
android:id="@+id/progressBar"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintBottom_toBottomOf="@+id/memeView"
app:layout_constraintEnd_toEndOf="@+id/memeView"
app:layout_constraintStart_toStartOf="@+id/memeView"app:layout_constraintTop_toTopOf="@+id/memeView" />

<com.google.android.material.button.MaterialButton
android:id="@+id/nextMeme"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_margin="20dp"
android:background="@color/white"
android:fontFamily="casual"
android:onClick="nextMeme"
android:text="@string/next_meme"
android:textAllCaps="false"
android:textColor="@color/white"
android:textStyle="bold"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="@+id/guideline2" />

<com.google.android.material.button.MaterialButton
android:id="@+id/shareMeme"
style="@style/Widget.MaterialComponents.Button.OutlinedButton"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_margin="20dp"
android:fontFamily="casual"
android:onClick="shareMeme"
android:text="@string/share_meme"
android:textAllCaps="false"
android:textColor="@color/black"
android:textStyle="bold"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="@+id/guideline2"
app:layout_constraintStart_toStartOf="parent" />

As I Said Before That This API Brings Memes From Reddit So, There May InAppropriate Memes As Well, So Inform User[Optional] That Memes May Not Be That Appropriate Alright, It's Time To Create Logic For These Elements. And We Have To Add API And Volley Library For Accessing Those Meme Content From API. Well If You Don't Know What Is An API, Don't Worry☺, You Can Check The Following Video By Hitesh Choudary Which Will Clarify All Doubts About An API👇🏻 %[youtube.com/watch?v=tI8ijLpZaHk]

Well, Now We'll Add Volley Library In Our build.gradle File To Access It In The Project As Follows👇🏻

implementation 'com.android.volley:volley:1.2.0'

Alright, Let's Get Started With The Kotlin Part, Let's Create A Function Named As loadMeme() Which Will Access And Shows The Meme As Follows👇🏻

private fun loadMeme(){
//Further Code
}

->Fine, Now Lets On/Enable The Progress Bar Which Well Disable Later When Meme(s) Display's In Imageview As Follows👇🏻, That Mean ProgressBar Is A Kinda Loading Thing Which Will Intimate User That Meme Is Loading.

val progressBar = findViewById<ProgressBar>(R.id.progressBar)
progressBar.visibility = View.VISIBLE

Here VISIBLE Attribute/Tag Enables The Progress Bar. ->Well Now Let's Add Volley Which Will Be Used To Request Our API As Follows👇🏻

val queue = Volley.newRequestQueue(this)

Here newRequestQueue Is Used To Request The URL Which We Will Add Shortly. ->Now, Let's Add The API URL Which Will Be Used To Access The Meme As Follows👇🏻

val url = "https://meme-api.herokuapp.com/gimme"

For More Information About The API Attributes, You Can Check:- meme-api.herokuapp.com/gimme

->Now Let's Create A Variable Which Will Access The JSON Object Because The API Which We Are Implementing Is In JSON Format As Follows👇🏻

val jsonObjectRequest = JsonObjectRequest()

Now In Invocation/Parenthesis Of The JsonObjectRequest We Will Add 5 Parameters Which Are Important To Access The URL Of The Meme. First Parameter:- Request.Method.GET Which Will Declare What We Want To Do Either Access Or Send And Other Things. In Our Aspect, We Want To Access The Meme/URL So We Have Defined GET Request Method Which Will Be Useful To Access The Information/URL. Now jsonObjectRequest Variable Should Look Like This👇🏻

val jsonObjectRequest = JsonObjectRequest(Request.Method.GET,)

Second Parameter:- url Which Is Our Implemented Variable Which Holds The API URL. Now jsonObjectRequest Variable Should Look Like This👇🏻

val jsonObjectRequest = JsonObjectRequest(Request.Method.GET, url,)

Third Parameter:- null Because We Are Not Sending Any Data🤷🏻‍♂️ Now jsonObjectRequest Variable Should Look Like This👇🏻

val jsonObjectRequest = JsonObjectRequest(Request.Method.GET, url, null,)

Fourth Parameter:- This Is The Most Important Step Because Till Now We Had Only Assigned The URL Through Volley/JSON Object, Now Its Time To Load That Meme In Our ImageView Through Glide. -->Before Going Through Further Make Sure That You Have Added Proper Dependencies For Glide Libray As Follows

implementation 'com.github.bumptech.glide:glide:4.12.0'
annotationProcessor 'com.github.bumptech.glide:compiler:4.12.0'

->First Of All, We'll Add Lamda Function To Move Further, You Can Create Lambda Function And Now jsonObjectRequest Variable Should Look Like This👇🏻

val jsonObjectRequest = JsonObjectRequest(Request.Method.GET, url, null,{response -> })

Here I Have Created Lambda As response You Can Create As You Want. ->Now We'll Get That String URL Which Holds The Meme As Follows👇🏻

memeURL = response.getString("url")

Here url In getString() Method Is The Same Attribute Which Has Listed In The API By The Developer, So Don't Forget Add url And Don't Add Another Stuff In getString() Method(). And memeURL Variable Is Created Before OnCreateView(), You Can Create memeURL Variable As Follows👇🏻

private lateinit var memeURL:String

->Now We'll Load That Incoming Meme In Our Imageview Which We Have Created Earlier, For Loading The Image We'll Use Glide Library; Which Is Used To Load The Images. --> If You Haven't Added Progress Bar jsonObjectRequest Variable Should Look Like This👇🏻

val jsonObjectRequest = JsonObjectRequest(Request.Method.GET, url, null, { response ->memeURL = response.getString("url")
Glide.with(this).load(memeURL).into(imageViewFromXML)}

-->Now If You Have Implemented ProgressBar We'll Go Through Few More Steps To Disable That Loading Thing When Meme Is Loaded.

Now jsonObjectRequest Variable Should Look Like This👇🏻

val jsonObjectRequest = JsonObjectRequest(
Request.Method.GET, url, null, { response ->
memeURL = response.getString("url")
Glide.with(this).load(memeURL).listener(object : RequestListener<Drawable> {
override fun onLoadFailed /**Implement This Function Or By Implementing Members By Clicking Alt+Enter On Object*/(
e: GlideException?,
model: Any?,
target: Target<Drawable>?,
isFirstResource: Boolean
): Boolean {
progressBar.visibility = View.GONE /**We Should Add `GONE` To Disable That Loading Thing*/
return false
}
override fun onResourceReady /**Implement This Function Or By Implementing Members By Clicking Alt+Enter On Object*/(
resource: Drawable?,
model: Any?,
target: Target<Drawable>?,
dataSource: DataSource?,
isFirstResource: Boolean
): Boolean {
progressBar.visibility = View.GONE /**We Should Add `GONE` To Disable That Loading Thing*/
return false
}
}).into(memeView)
},

Fifth Parameter:- This Is The Last Parameter Where We Define The Logic If Request Was Failed Now jsonObjectRequest Variable Should Look Like This👇🏻

val jsonObjectRequest = JsonObjectRequest(
Request.Method.GET, url, null, { response ->
memeURL = response.getString("url")
Glide.with(this).load(memeURL).listener(object : RequestListener<Drawable> {
override fun onLoadFailed(
e: GlideException?,
model: Any?,
target: Target<Drawable>?,
isFirstResource: Boolean
): Boolean {
progressBar.visibility = View.GONE
return false
}

override fun onResourceReady(
resource: Drawable?,
model: Any?,
target: Target<Drawable>?,
dataSource: DataSource?,
isFirstResource: Boolean
): Boolean {
progressBar.visibility = View.GONE
return false
}

}).into(memeView)
}, {
Toast.makeText(this, "Something Went Wrong", Toast.LENGTH_SHORT).show()
}
)

Now let's Merge Our JSON Request To The Volley By Adding 👇🏻

queue.add(jsonObjectRequest)

Finally, We Have Requested The Meme Successfully But There Are Few Finishing Touches Like Enabling Next Button And Share(Optional) Button, Let's Add Them Quickly. Let's Recall The loadMeme Function Here Because The Whole Processing Stuff Already Implemented There! In My Case, I Have Implemented OnClick In XML So My Code For Button Will Be Like This👇🏻

fun nextMeme(view: View) {
loadMeme()
}

If You Didn't Implement OnClick In Your XML File You Can Use .setOnClickListener Method To Call The Button. Then Your Code Can Be Like This👇🏻

nextMeme.setOnClickListener{
loadMeme()
}

We'll, We Are Almost To The End If You Want To Add Share(Optional) Button You Can Use Intent. In My Case, I Have Implemented OnClick In XML So My Code For Share Button Will Be Like This👇🏻

fun shareMeme(view: View) {
val intent = Intent(Intent.ACTION_SEND)
intent.type = "text/plain"
intent.putExtra(
Intent.EXTRA_TEXT,
"Hey Buddy,Check This Meme Which I Have Got From A Meme App Via Reddit :- $memeURL"
)
val intentChooser = Intent.createChooser(intent, "Share This Meme Via:")
startActivity(intentChooser)
}

If You Didn't Implement OnClick In Your XML File You Can Use .setOnClickListener Method To Call The Button. Then Your Code Can Be Like This👇🏻

shareMeme.setOnClickListener{
val intent = Intent(Intent.ACTION_SEND)
intent.type = "text/plain"
intent.putExtra(
Intent.EXTRA_TEXT,
"Hey Buddy,Check This Meme Which I Have Got From A Meme App Via Reddit :- $memeURL"
)
val intentChooser = Intent.createChooser(intent, "Share This Meme Via:")
startActivity(intentChooser)
}

->Now The Most Important Don't Forget To Add loadMeme Function To The OnCreateView() Method Or Any Other Parent Method Respectively To Complete The Process. Now Your Kotlin File Should Look Like This👇🏻

class MainActivity : AppCompatActivity() {
private lateinit var memeURL: String
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
loadMeme()
}

private fun loadMeme() {
val progressBar = findViewById<ProgressBar>(R.id.progressBar)
progressBar.visibility = View.VISIBLE
val queue = Volley.newRequestQueue(this)
val memeView = findViewById<ImageView>(R.id.memeView)
val url = "https://meme-api.herokuapp.com/gimme"
val jsonObjectRequest = JsonObjectRequest(
Request.Method.GET, url, null, { response ->
memeURL = response.getString("url")
Glide.with(this).load(memeURL).listener(object : RequestListener<Drawable> {
override fun onLoadFailed(
e: GlideException?,
model: Any?,
target: Target<Drawable>?,
isFirstResource: Boolean
): Boolean {
progressBar.visibility = View.GONE
return false
}

override fun onResourceReady(
resource: Drawable?,
model: Any?,
target: Target<Drawable>?,
dataSource: DataSource?,
isFirstResource: Boolean
): Boolean {
progressBar.visibility = View.GONE
return false
}

}).into(memeView)
}, {
Toast.makeText(this, "Something Went Wrong", Toast.LENGTH_SHORT).show()
}
)
queue.add(jsonObjectRequest)
}

fun nextMeme(view: View) {
loadMeme()
}

fun shareMeme(view: View) {
val intent = Intent(Intent.ACTION_SEND)
intent.type = "text/plain"
intent.putExtra(
Intent.EXTRA_TEXT,
"Hey Buddy,Check This Meme Which I Have Got From A Meme App Via Reddit :- $memeURL"
)
val intentChooser = Intent.createChooser(intent, "Share This Meme Via:")
startActivity(intentChooser)
}
}

Congratulations Buddy, We Have Completed Our Meme App Successfully👊🏻. As I Said Before That This API Brings Memes From Reddit So, There May InAppropriate Memes As Well, So Inform User[Optional] That Memes May Not Be That Appropriate