Apuna12
Apuna12

Reputation: 239

Update ProgressBar during a for loop using AsyncTask in Android app

I am trying to do an app where I want to update a ProgressBar in a for loop using AsyncTask. The best is to show you a pseudo code of what I am trying to do

button.setOnClickListener{
    for(int i=0; i<5000; i++)
    {
        doSomeHeavyStuff();
        UpdateProgressBarAsyncTask(i).execute()
    }
}

This is what I have so far

MainActivity:

    class MainActivity : AppCompatActivity() {

    var progress:ProgressBar? = null


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

        progress = findViewById(R.id.progress)
        val buttonStart = findViewById<TextView>(R.id.button)
        var maxNumber = 5000
        buttonStart.setOnClickListener{
            for(i in 0 until maxNumber)
            {
                HeavyStuff()
                ProgressTask(i,progress!!,maxNumber,this).execute()
            }
        }


    }

internal class ProgressTask (var actual:Int, var progress: ProgressBar, var max: Int, var context: Activity): AsyncTask <Void, Int, Int>()
    {
        override fun onPreExecute() {
            super.onPreExecute()
            progress.visibility = View.VISIBLE
            progress.max = max
        }

        override fun onProgressUpdate(vararg values: Int?) {
            super.onProgressUpdate(*values)
            progress.setProgress(values[0]!!)
        }

        override fun doInBackground(vararg params: Void?): Int? {
            publishProgress(actual)
            return null
        }

        override fun onPostExecute(result: Int?) {
            super.onPostExecute(result)
            progress.visibility = View.INVISIBLE
            Toast.makeText(context, "Finished!", Toast.LENGTH_SHORT).show()
        }
    }

XML:

<ProgressBar
        android:id="@+id/progress"
        style="@android:style/Widget.ProgressBar.Horizontal"
        android:layout_width="300dp"
        android:layout_height="wrap_content"
        android:layout_marginStart="24dp"
        android:layout_marginLeft="24dp"
        android:layout_marginTop="24dp"
        android:layout_marginEnd="24dp"
        android:layout_marginRight="24dp"
        android:layout_marginBottom="24dp"
        android:visibility="invisible"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

Do I miss something here? Right now it shows ProgressBar after the HeavyStuff() is finished and thus it is not shown during the for loop. What am I missing here?

Can you guys please help me with this?

Thanks

Upvotes: 0

Views: 643

Answers (2)

Carlos Jim&#233;nez
Carlos Jim&#233;nez

Reputation: 158

I would go with this approach to avoid memory leaks:

private lateinit var mTextView: WeakReference<TextView>
private lateinit var mProgressBar: WeakReference<ProgressBar>

private const val MAX = 50000

class ProgressTask(
    pb: ProgressBar,

var max: Int
) : AsyncTask<Void, Int, Int>() {

init {
    mProgressBar = WeakReference(pb)
}

override fun onPreExecute() {
    super.onPreExecute()
    mProgressBar.get()?.visibility = View.VISIBLE
    mProgressBar.get()?.max = MAX
}

override fun onProgressUpdate(vararg values: Int?) {
    super.onProgressUpdate(*values)
    mProgressBar.get()?.progress = values[0]!!
}

override fun doInBackground(vararg p0: Void?): Int {
    for (i in 0 until MAX) {
        doHeavyStuff()
        publishProgress(i)
    }
    return 1
}

override fun onPostExecute(result: Int?) {
    super.onPostExecute(result)
    mProgressBar.get()?.visibility = View.GONE
}

}

Upvotes: 0

Zakaria
Zakaria

Reputation: 599

Actually, I think that both the heavy stuff and the For Loop need to be present inside of the doBackground function (The call of heavy stuff in the main thread will freeze the UI and cause an ANR), see the code below :

const val max = 50000

class MainActivity : AppCompatActivity() {

    var progress: ProgressBar? = null

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

        progress = findViewById(R.id.progress)
        buttonStart.setOnClickListener {
            ProgressTask(progress!!, max, this).execute()
        }
    }

    internal class ProgressTask(
        var progress: ProgressBar,
        var max: Int,
        var context: Activity
    ) : AsyncTask<Void, Int, Int>() {
        override fun onPreExecute() {
            super.onPreExecute()
            progress.visibility = View.VISIBLE
            progress.max = max
        }

        override fun onProgressUpdate(vararg values: Int?) {
            super.onProgressUpdate(*values)
            progress.setProgress(values[0]!!)
        }

        override fun doInBackground(vararg params: Void?): Int? {
            for (i in 0 until max) {
                doHeavyStuff()
                publishProgress(i)
            }
            return null
        }

        override fun onPostExecute(result: Int?) {
            super.onPostExecute(result)
            progress.visibility = View.INVISIBLE
            Toast.makeText(context, "Finished!", Toast.LENGTH_SHORT).show()
        }
    }
}

Upvotes: 1

Related Questions