In my application i'm downloading a video file. I want to show the progress bar for the download.
How is it possible through AsyncTask Concept?
Thanks,
Niki
Use the onProgressUpdate method of AsyncTask.
If you know the size of the file you can set the max value in onPreExecute:
protected void onPreExecute() {
ProgressDialog myDialog = new ProgressDialog(context);
myDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
myDialog.setMax(maxValue);
myDialog.show();
}
EDIT: added myDialog.show();
There are several methods to update the progress, either by incrementing by an amount or by setting the progress to a specific value:
#Override
protected void onProgressUpdate(Integer... progress) {
myDialog.incrementProgressBy(progress[0]);
// or
// myDialog.setProgress(progress[0]);
}
Then in the onDoInBackground():
#Override
protected void doInBackGround() {
// your code
publishProgress(1);
}
EDIT example with progressbar in layout:
In your layout file, add a progressbar like this
<ProgressBar
android:id="#+id/progressbar"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
style="?android:attr/progressBarStyleHorizontal"
android:visibility="gone"
/>
And in your asynctask:
protected void onPreExecute() {
ProgressBar myProgress = findViewById(R.id.progressbar);
myProgress.setMax(maxValue);
myProgress.setVisibility(View.VISIBLE);
}
protected void onProgressUpdate(Integer... progress) {
myProgress.setProgress(progress[0]);
}
First you have to calculate downloading timi, and then implement progress bar as per time limit. here i enclosed the sample program of progress bar
new Thread(new Runnable() {
public void run() {
while (mProgressStatus < 100) {
mProgressStatus = doWork();
// Update the progress bar
mHandler.post(new Runnable() {
public void run() {
mProgress.setProgress(mProgressStatus);
}
});
And this is the code for calculating the Time length for downloading file
//once the connection has been opened
List values = urlConnection.getHeaderFields().get("content-Length")
if (values != null && !values.isEmpty()) {
// getHeaderFields() returns a Map with key=(String) header
// name, value = List of String values for that header field.
// just use the first value here.
String sLength = (String) values.get(0);
if (sLength != null) {
//parse the length into an integer...
}
Related
I'm following this tutorial
to learn how to make progress bars. I'm trying to show the progress bar on top of my activity and have it update the activity's table view in the background.
So I created an async task for the dialog that takes a callback:
package com.lib.bookworm;
import android.app.ProgressDialog;
import android.content.Context;
import android.os.AsyncTask;
public class UIThreadProgress extends AsyncTask<Void, Void, Void> {
private UIThreadCallback callback = null;
private ProgressDialog dialog = null;
private int maxValue = 100, incAmount = 1;
private Context context = null;
public UIThreadProgress(Context context, UIThreadCallback callback) {
this.context = context;
this.callback = callback;
}
#Override
protected Void doInBackground(Void... args) {
while(this.callback.condition()) {
this.callback.run();
this.publishProgress();
}
return null;
}
#Override protected void onProgressUpdate(Void... values) {
super.onProgressUpdate(values);
dialog.incrementProgressBy(incAmount);
};
#Override
protected void onPreExecute() {
super.onPreExecute();
dialog = new ProgressDialog(context);
dialog.setCancelable(true);
dialog.setMessage("Loading...");
dialog.setProgress(0);
dialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
dialog.setMax(maxValue);
dialog.show();
}
#Override
protected void onPostExecute(Void result) {
super.onPostExecute(result);
if (this.dialog.isShowing()) {
this.dialog.dismiss();
}
this.callback.onThreadFinish();
}
}
In My Activity:
final String page = htmlPage.substring(start, end).trim();
//Create new instance of the AsyncTask..
new UIThreadProgress(this, new UIThreadCallback() {
#Override
public void run() {
row_id = makeTableRow(row_id, layout, params, matcher); //ADD a row to the table layout.
}
#Override
public void onThreadFinish() {
System.out.println("FINISHED!!");
}
#Override
public boolean condition() {
return matcher.find();
}
}).execute();
So the above creates an async task to run to update a table layout activity while showing the progress bar that displays how much work has been done..
However, I get an error saying that only the thread that started the activity can update its views. I tried changing my Async Task's run to the following:
MainActivity.this.runOnUiThread(new Runnable() {
#Override public void run() {
row_id = makeTableRow(row_id, layout, params, matcher); //ADD a row to the table layout.
}
}
But this gives me synchronization errors.. Any ideas how I can display progress and at the same time update my table in the background?
Currently my UI looks like:
Whatever update that you are doing in the UI do it in progress update, use Global Variables to pass values or use Getter Setter.
Here is a simple example, from one of my current project.
It changes the width of the LinearLayout, which acts as progress bar and also updates the textview with X%. Am updating by calling onProgressUpdate
public class Updater extends AsyncTask<Void, Void, Void> {
#Override
protected void onPreExecute() {
super.onPreExecute();
width = getWindowManager().getDefaultDisplay().getWidth();
Log.wtf(tag, "width" + width);
}
#Override
protected Void doInBackground(Void... params) {
while (updated < sleep) {
try {
Thread.sleep(updateEveryXmillSec);
updated = updated + updateEveryXmillSec;
publishProgress();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
return null;
}
#Override
protected void onProgressUpdate(Void... values) {
super.onProgressUpdate(values);
mTextView.setText((int) (100 * updated / sleep) + " %");
xwidth = (width * ((int) (100 * updated / sleep)) / 100);
mLayout.setLayoutParams(new RelativeLayout.LayoutParams(xwidth,
height));
}
#Override
protected void onPostExecute(Void result) {
super.onPostExecute(result);
startActivity(new Intent(getApplicationContext(), Main.class));
finish();
}
}
Call new Updater().execute(); to trigger the action.
You should split your UI data from the Row Data. Make a RowObject which contains the data to display in the table:
class RowData {
String program;
String course;
String bookName;
// get/set etc
}
You can fill this object in the UIThreadProgress class run method and push it to a synced list.
In onProcessUpdate() you can than build the View Object based on the synced list and add it to the View Hierachie. You are on the UI thread now, and adding should be possible.
You have to care about a synced list during this. Because the Background Thread and the UI Thread will adding and removing objects at the same time. a synchronized will help here. Depending on the speed of your algorithm to calculate the needed data, a faster approach than the synced list is better. But the Idea is always the same. You have to split your data and the View Operations.
I am running an async task.
In the doinbackground method i have a method that returns int or some other value may be boolean value some times.
I also want to increase my progress bar as it goes to finishing.
problem is how to keep the track of counter ?
Some times db query may take some time and some times it goes faster . :)
public void getAllSchoolsSearchResult(InputBean nb , SearchLogic mLogic){
mSRLogic=mLogic;
new AsyncTask<Void, Integer, List<SResultModel>>() {
#Override
protected void onPreExecute() {
super.onPreExecute();
mProgressDialog.setProgressStyle(ProgressDialog.STYLE_SPINNER);
mProgressDialog.setProgress(0);
mProgressDialog.setMax(100);
mProgressDialog.show();
}
#Override
protected List<SResultModel> doInBackground(
Void... paramArrayOfParams) {
progressbar_Status=0;
while(progressbar_Status<100){
progressbar_Status += 1;
publishProgress(progressbar_Status);
}
if(ConnectionProvider.checkConnection()==false){
return null;
}
return SearchResultHandler.searchStudent(searchAllSchools);
}
#Override
protected void onPostExecute(List<SResultModel> result) {
super.onPostExecute(result);
if(mProgressDialog!=null&&mProgressDialog.isShowing()){
mProgressDialog.dismiss();
}
}
#Override
protected void onProgressUpdate(Integer... values) {
super.onProgressUpdate(values);
mProgressDialog.setProgress(values[0]);
}
}.execute();
}
In the case of an unknown duration you should probably be using an indeterminate progress bar which you can set via the android:indeterminate layout property or setIndeterminate method.
If you know how many operations you're doing you can hold a member variable inside the asynctask or a local variable in the doInBackground method.
publishProgress can't be used like this.
From your code, you are showing the progress bar (while doing nothing) and then when it reaches 100% then you request the students.
The publishProgress should be inside the
SearchResultHandler.searchStudent()
depending on how it's implemented. If it doesn't have a loop inside, you won't be able to publish any progress.
In this cases, use an INDETERMINATE progress dialog, and do nothing in your doInBackground
protected void onPreExecute() {
super.onPreExecute();
mProgressDialog.setIndeterminate(true);
mProgressDialog.show();
}
protected List<SResultModel> doInBackground(Void... paramArrayOfParams) {
if(!ConnectionProvider.checkConnection()) return null;
return SearchResultHandler.searchStudent(searchAllSchools);
}
I have an activity that loads an xml file, but when the app is invoked without reply in 1 or 2 seconds, I wonder if I can put some kind of loading not to appear that the app crashed, thanks.
The rule of thumb is, if you do anything, use AsyncTask, otherwise your application will eventually crash on long network delays or large files.
private class doSomethingTask extends AsyncTask<SomeData,Integer,SomeData[]> {
private ProgressDialog dialog;
protected SomeData[] doInBackground(SomeData... values) {
int count = values.length;
for( int i=0; i<count; i++) {
publishProgress(count,i+1);
// do something here
....
//
if( isCancelled() ) return null;
}
return values;
}
protected void onPreExecute()
{
// show progress bar or something
dialog = new ProgressDialog(context);
dialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
dialog.setMessage(context.getString(R.string.downloading));
dialog.show();
}
protected void onProgressUpdate(Integer... values) {
super.onProgressUpdate(values);
dialog.setMax(values[0]);
dialog.setProgress(values[1]);
}
protected void onPostExecute(SomeData[] result) {
// kill progress bar here
if( this.dialog.isShowing()) {
this.dialog.dismiss();
}
}
}
I am having a problem with ProgressDialog UI being frozen when I start the action in the AsyncTask.
My problem is somewhat different than the bunch of other similar question because the my background task consists of two parts:
- first part (loadDB()) is related to the database access
- second part (buildTree()) is related to building the ListView contents and is started with runOnUiThread call
The progress dialog is correctly updated during the 1st part of the task, but not during the 2dn part.
I tried moving the buildTree part in the AsyncTask's onPostExecute but it doesn't help, this part of the code still causes the progress to freeze temporarily until this (sometimes quite lengthy) part of the work is done. I can not recode the buildTree part from scratch because it is based on external code I use.
Any tips on how to resolve this? Is there a method to force updating some dialog on screen?
The code goes here:
public class TreePane extends Activity {
private ProgressDialog progDialog = null;
public void onCreate(Bundle savedInstanceState) {
// first setup UI here
...
//now do the lengthy operation
new LoaderTask().execute();
}
protected class LoaderTask extends AsyncTask<Void, Integer, Void>
{
protected void onPreExecute() {
progDialog = new ProgressDialog(TreePane.this);
progDialog.setMessage("Loading data...");
progDialog.show();
}
protected void onPostExecute(final Void unused) {
if (progDialog.isShowing()) {
progDialog.dismiss();
}
}
protected void onProgressUpdate(Integer... progress) {
//progDialog.setProgress(progress[0]);
}
protected Void doInBackground(final Void... unused)
{
//this part does not block progress, that's OK
loadDB();
publishProgress(0);
//long UI thread operation here, blocks progress!!!!
runOnUiThread(new Runnable() {
public void run() {
buildTree();
}
});
return null;
}
}
public void buildTree()
{
//build list view within for loop
int nCnt = getCountHere();
for(int =0; i<nCnt; i++)
{
progDialog.setProgress(0);
//add tree item here
}
}
}
Don't run your whole buildTree() method inside the UI thread.
Instead, run only the changes you want to make to the UI in the UI thread:
protected Void doInBackground(final Void... unused)
{
//this part does not block progress, that's OK
loadDB();
publishProgress(0);
buildTree();
return null;
}
And then:
public void buildTree()
{
//build list view within for loop
int nCnt = getCountHere();
for(int =0; i<nCnt; i++)
{
progDialog.setProgress(0);
runOnUiThread(new Runnable() {
public void run() {
// update your UI here and return
}
});
// now you can update progress
publishProgress(i);
}
}
You should call AsyncTask's publishProgress method and not the progDialog.setProgress(0); as you call.
Also the buildTree shouln't run on the UI thread since it will block it.
run the logic from the doInBackground method.
note that you don't actually build the ListView, rather you should build it's data model.
look here
something like this:
protected Void doInBackground(final Void... unused)
{
//this part does not block progress, that's OK
loadDB();
publishProgress(0);
buildTree();
}
public void buildTree()
{
//build list view within for loop
int nCnt = getCountHere();
for(int =0; i<nCnt; i++)
{
publishProgress(i); //for exmple...
//add tree item here
}
}
Firs of all thanks for reading this.
I'm having trouble updating the progress from my custom ProgressBar through an AsyncTask inner class. I'm using 9patch for the background and progress drawables. It just don't update. It stays there all filled like it was in the maxed value, I'm using the onProgressUpdate() to call the invalidate() and update the UI thread.
Here's what it looks like now, it goes visible and just stays there all filled up: http://imageshack.us/photo/my-images/651/mobicashprogressbar.png/
The progressbar should only be
visible after the user concludes the
form.
There's another inner AsyncTask handling the send SMS button that connects with an Web Service.
HERES THE CODE:
public void setTimerProgress(int progress){
progressBar.setProgress(progress);
}
public void updateProgress(){
progressBar.invalidate();
}
public void showProgress(){
progressBar.setVisibility(View.VISIBLE);
}
//Classe auxiliar para controle da progress bar
private class TimerProgress extends AsyncTask<Void, Void, Void>{
private int start;
private final int OTP_TIMEOUT = 900000;
#Override
protected void onPreExecute() {
super.onPreExecute();
showProgress();
start = (int) System.currentTimeMillis();
}
#Override
protected Void doInBackground(Void... param) {
int timer = (int) System.currentTimeMillis() - start;
while (timer <= OTP_TIMEOUT){
setTimerProgress(timer);
timer = (int) System.currentTimeMillis() - start;
publishProgress();
}
return null;
}
#Override
protected void onProgressUpdate(Void... values) {
super.onProgressUpdate(values);
updateProgress();
}
}
HERE'S XML:
<ProgressBar
style="#android:style/Widget.ProgressBar.Horizontal"
android:layout_gravity="center_horizontal"
android:visibility="invisible"
android:id="#+id/progress_bar_timer"
android:max="900000"
android:progress="3000"
android:progressDrawable="#drawable/progress_bar"
android:background="#drawable/progress_background"
android:layout_width="fill_parent"
android:layout_height="25dip"
android:layout_marginRight="73sp"
android:layout_marginLeft="70sp">
</ProgressBar>
HERE'S ONE PLACE WHERE I CALL IT
#Override
public void onClick(View v) {
if (v.getId() == R.id.refresh_otp) {
saveParametersForOTP();
if (edtIniPin.getText().length() == pinLengthInt) {
try {
disableEditText(edtIniPin);
disableEditText(edtValue);
edtOTP.setText(Facade.getInstance().nextOTP(Facade.getInstance().getPin(), Facade.getInstance().getValue()));
//Inicia o timer da progressbar
new TimerProgress().execute();
Help? :D
UPDATE:
For test purpuses I've set the OTP_TIMEOUT to 50000, made the following changes to the code and removed the 9patch drawables properties so it would use the native drawables for the bar. It works, however, when I use the images to customize the bar it appears the same old problem is happening. It is static, all filled up like before.
private final int OTP_TIMEOUT = 50000;
#Override
protected void onPreExecute() {
super.onPreExecute();
Log.i("PROGRESS", "Chegou no PreExecute!");
showProgress();
ENABLE_REFRESH = false;
start = (int) System.currentTimeMillis();
}
#Override
protected Void doInBackground(Void... param) {
int timer = (int) System.currentTimeMillis() - start;
while (timer <= OTP_TIMEOUT){
Log.i("PROGRESS", "Chegou no while!");
setTimerProgress((int)timer);
timer = (int) System.currentTimeMillis() - start;
publishProgress();
if (timer >= OTP_TIMEOUT) {
ENABLE_REFRESH = true;
}
}
return null;
}
#Override
protected void onProgressUpdate(Void... values) {
super.onProgressUpdate(values);
Log.i("PROGRESS", "Chegou no Progress Update!");
updateProgress();
}
You need to add a layer-list resource and configure your ProgressBar to use it.
Here an example that I use. Note that in progress_bar.xml progress_bar_progress and progress_bar_background are nine-patch images.
progress_bar.xml:
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item android:id="#android:id/background" android:drawable="#drawable/progress_bar_background" />
<item android:id="#android:id/progress" >
<clip android:drawable="#drawable/progress_bar_progress" />
</item>
</layer-list>list>
layout snippet:
<ProgressBar
android:layout_width="fill_parent"
android:layout_height="30dp"
android:max="100"
android:progress="50"
android:progressDrawable="#drawable/progress_bar"
android:indeterminateOnly="false" />