Introduction
This code demonstrates the creation of a secondary progress bar in an Android application written in Kotlin. A secondary progress bar provides a visual indication of a sub-task within a larger task. The example showcases how to update both the primary and secondary progress bars while performing a background operation using a separate thread.
Breakdown
The code consists of two main parts: the MainActivity.kt
file containing the Activity code and the activity_main.xml
file defining the layout.
MainActivity.kt:
- Variables: The class defines variables for the progress status (primary), secondary progress status, and a Handler object for updating the UI thread.
- onCreate: This method sets up the layout and retrieves references to the UI elements (button, text views, progress bar).
- Button Click Listener: Clicking the button triggers the following actions:
- Disables the button to prevent multiple clicks.
- Uses
TransitionManager
for a smooth animation when showing the progress bar. - Sets the progress and secondary progress to zero, essentially resetting them.
- Starts a new thread to handle the progress updates.
Thread:
- The thread loop iterates until the primary progress reaches 100.
- Inside the loop, there's a nested loop that increases the secondary progress until it reaches 100.
- The
Handler.post
method is used to update the UI thread safely from within the background thread. - The secondary progress and its corresponding text view are updated within the
post
block. - Once the secondary progress reaches 100, it's reset to zero, and the primary progress is incremented. The progress bar and text view for the primary progress are also updated.
- The button is re-enabled when the primary progress reaches 100, signifying task completion.
activity_main.xml:
This file defines the layout for the activity:
- A
ConstraintLayout
as the root layout. - A
TextView
displaying the primary task progress. - A horizontal
ProgressBar
with styling for the secondary progress. - Another
TextView
displaying the secondary task progress update. - A
Button
to initiate the task.
Summary
This example effectively demonstrates how to create and utilize a secondary progress bar in Android using Kotlin. It showcases background thread usage for progress updates and safe UI manipulation from within the thread. The code includes visual cues (animations) and informative text updates to enhance the user experience.
package com.cfsuman.kotlintutorials
import android.app.Activity
import android.os.Bundle
import android.os.Handler
import android.os.Looper
import android.view.View
import android.widget.Button
import android.widget.ProgressBar
import android.widget.TextView
import androidx.constraintlayout.widget.ConstraintLayout
import androidx.transition.TransitionManager
class MainActivity : Activity() {
var progressStatus = 0
var secondaryProgressStatus = 0
var handler = Handler(Looper.getMainLooper())
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
// Get the widgets reference from XML layout
val rootLayout = findViewById<ConstraintLayout>(R.id.rootLayout)
val button = findViewById<Button>(R.id.button)
val textView = findViewById<TextView>(R.id.textView)
val tvSecondary = findViewById<TextView>(R.id.tvSecondary)
val progressBar = findViewById<ProgressBar>(R.id.progressBar)
// button click listener
button.setOnClickListener {
button.isEnabled = false
TransitionManager.beginDelayedTransition(rootLayout)
progressBar.visibility = View.VISIBLE
// set up progress bar on initial stage
progressBar.progress = 0
progressStatus = 0
Thread {
while (progressStatus < 100) {
while (secondaryProgressStatus < 100) {
secondaryProgressStatus += 1
Thread.sleep(5)
handler.post {
progressBar.secondaryProgress =
secondaryProgressStatus
if (secondaryProgressStatus == 100) {
tvSecondary.text = "Secondary task finished."
secondaryProgressStatus = 0
progressStatus += 1
progressBar.progress = progressStatus
textView.text = "Task finished" +
" $progressStatus of 100"
if (progressStatus == 100) {
button.isEnabled = true
}
} else {
tvSecondary.text = "Secondary task " +
"$secondaryProgressStatus of 100"
}
}
}
}
}.start()
}
}
}
<?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:id="@+id/rootLayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="24dp"
android:background="#DCDCDC">
<TextView
android:id="@+id/textView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="24dp"
android:padding="12dp"
android:fontFamily="sans-serif"
android:textSize="20sp"
android:textStyle="bold"
tools:text="TextView"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<ProgressBar
android:id="@+id/progressBar"
style="?android:attr/progressBarStyleHorizontal"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginTop="12dp"
android:visibility="invisible"
android:secondaryProgressTint="#0018A8"
android:secondaryProgressTintMode="src_in"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/textView" />
<TextView
android:id="@+id/tvSecondary"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:fontFamily="sans-serif"
android:padding="12dp"
android:textSize="18sp"
android:textStyle="italic"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.491"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/progressBar"
tools:text="Secondary Task" />
<Button
android:id="@+id/button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:text="Start Task"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/tvSecondary" />
</androidx.constraintlayout.widget.ConstraintLayout>

