I am practicing the working of the AsyncTask and with that purpose I wanted to use the onProgressUpdate function. Currently in my program I have UI that lets the user choose an input (which would be show in a TextView after the AsyncTask is finished) and a timer (determines Thread.sleep() time in the AsyncTask)
What I want to do is ... if the user selects a time of 5. Then in every passing second I would like to send a notification to the UI (where a progress dialog is called) ... indicating progress of 1 of 5 ... 2 of 5 ... 3 of 5.
Here's the progress that I have made so far:
public class ViewFiller extends AsyncTask<String, Integer, String> {
#Override
protected String doInBackground(String... input) {
// TODO Auto-generated method stub
try {
int time;
if (input[1].equalsIgnoreCase("")) {
time = 0;
} else {
time = Integer.parseInt(input[1]) * 1000;
for (int i = 1; i <= time / 1000; i++) {
publishProgress(i, time);
}
Thread.sleep(time);
}
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return input[0];
}
#Override
protected void onPostExecute(String result) {
// TODO Auto-generated method stub
super.onPostExecute(result);
execute.setText("Execute");
progress.dismiss();
tvInput.setText(result);
}
#Override
protected void onPreExecute() {
// TODO Auto-generated method stub
super.onPreExecute();
execute.setText("Running...");
displayProgress("Updating field ... ");
// Start the progress dialog
progress.show();
}
#Override
protected void onProgressUpdate(Integer... values) {
// TODO Auto-generated method stub
super.onProgressUpdate(values);
progress.setMessage("Updating field ... " + values[0] + " of "
+ values[1] / 1000);
}
}
The current implementation only gives me 5 of 5 directly. Can anyone suggest me a solution ?
Because it is going through your loop faster than you see it
for (int i = 1; i <= time / 1000; i++) {
publishProgress(i, time);
You don't need the loop there. Just sleep for whatever amount of time then show your progress and have the sleep() and the publishProgress() in the loop. Something like
try {
int time = 0;
for (int i = 1; i <= time / 1000; i++) {
if (input[1].equalsIgnoreCase("")) {
time = 0;
} else {
time = Integer.parseInt(input[1]) * 1000;
publishProgress(time);
}
Thread.sleep(time);
}
Although, I'm not sure what input actually contains but you might want input[i]. It looks like its always going to be the same otherwise.
Also, CountDownTimer would be good for this I would think.
Related
I have an asynctask in which I pass an array of progressbars as a parameter. In the doinbackground method, I compute the progress of each progressbar and make a call to PublishProgress with progress as parameter. This is how I have done:
static volatile int currentProgressBarIndex;
#Override
protected Integer doInBackground(String... arg0) {
// TODO Auto-generated method stub
// display the images in now playing
while (ScheduleManager.isScheduleRunning) {
Iterator iterator = nowPlayingMediaSet.entrySet().iterator();
// set images on now playing
for (int i = 0; i < btnImgNowPlaying.length && iterator.hasNext(); ++i) {
Map.Entry mEntry = (Map.Entry) iterator.next();
Show mShowNowPlaying = (Show) mEntry.getKey();
// get show status
currentProgressBarIndex = i;
mProgressStatus[i] = ScheduleManager
.getCurrentPlayingShowStatus(mShowNowPlaying);
// Update the progress bar
publishProgress(mProgressStatus[i]);
}
// sleep 20 second to show the progress
try {
Thread.sleep(20000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
return null;
}
#Override
protected void onPostExecute(Integer result) {
// TODO Auto-generated method stub
super.onPostExecute(result);
}
#Override
protected void onProgressUpdate(Integer... progress) {
// TODO Auto-generated method stub
this.progBar[currentProgressBarIndex].setProgress(progress[0]);
}
What happens is that, only my last progressbar in the array is updated. Rest are updated, but later on.. I am sure I am doing something wrong here..
I am performing some operations(uploading image to webservice) in IntentService.
Please see my code below.
Inside the activity i am calling service like this.
I am calling the below method after capturing the image i.e. inside onActivityResult. The app is getting hanged when i call this method in onActivityResult. I am able to perform the task in IntentService. But the acitivity is getting hanged.
private void callService(){
Intent intent = new Intent(this, TestIntentService.class);
intent.putExtra("imageData", imageData);
startService(intent);
}
This is my IntentService Class.
Can i perform webservice call inside callImageUploadAPI().
Am i doing anything wrong here?
public class TestIntentService extends IntentService {
public TestIntentService() {
super("com.screens.testapp");
// TODO Auto-generated constructor stub
}
//imageData passed from the activity
#Override
protected void onHandleIntent(Intent intent) {
// TODO Auto-generated method stub
if(intent != null){
Bundle extras = intent.getExtras();
imageData= extras.getString("imageData");
}
callImageUploadAPI(imageData);
}
private void callImageUploadAPI(final String imageData) {
// TODO Auto-generated method stub
try {
if (Log.checkNetworkStatus(TestIntentService.this)) {
} else {
}
} catch (Exception e) {
// TODO: handle exception
}
}
}
Thanks
If you need to do a task in background, Android provides a class called AsyncTask which you can extend and use it for doing a network operation or any other heavy operation. This is an example from Android Developer Website (AsyncTask Page):
private class DownloadFilesTask extends AsyncTask<URL, Integer, Long> {
protected Long doInBackground(URL... urls) {
int count = urls.length;
long totalSize = 0;
for (int i = 0; i < count; i++) {
totalSize += Downloader.downloadFile(urls[i]);
publishProgress((int) ((i / (float) count) * 100));
// Escape early if cancel() is called
if (isCancelled()) break;
}
return totalSize;
}
protected void onProgressUpdate(Integer... progress) {
setProgressPercent(progress[0]);
}
protected void onPostExecute(Long result) {
showDialog("Downloaded " + result + " bytes");
}
}
This may be used in your code this way:
if (Log.checkNetworkStatus(TestIntentService.this)) {
new DownloadFilesTask().execute(url1, url2, url3);
} else {
}
For you to perform actions in the background use Services.
You can launch the services from your activity and you can assign a thread for the service and a handler for communication from that thread to the UIThread.
Check this: http://developer.android.com/guide/components/services.html
A little sneak peek
A Service is an application component that can perform long-running operations in the background and does not provide a user interface.
I want to add a simple process bar to my code with asy task. I tryed some exampels but cant see that process bar working.
I post here my code hope you can help me.
I want to stop process bar when some of my code is done like with some flag to stop the proses bar.
plese post some code.
thanks a lot!
here my code:
private class loading extends AsyncTask<Void, Void, Integer> {
Context context;
ProgressBar progressBar;
static final long waitTime = 1 * 4000L;
long preTime;
int progress;
public loading(Context context) {
this.context = context;
progressBar = (ProgressBar) findViewById(R.id.progress_bar);
progressBar.setProgress(0);
}
protected void onPostExecute(Integer result) {
Intent intent = new Intent(this.context, first.class);
intent.setFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
context.startActivity(intent);
finish();
return;
}
protected void onPreExecute() {
// TODO Auto-generated method stub
super.onPreExecute();
preTime = System.currentTimeMillis();
}
protected void onProgressUpdate(Integer... values) {
progressBar.setProgress(values[0]);
}
#Override
synchronized protected Integer doInBackground(Void... arg0) {
int waited = 0;
while (waited < 3000) {
try {
// SystemClock.sleep(100);
this.wait(100);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
waited += 100;
}
return null;
}
}
Your doInBackground method needs to call publishProgress() in order for you to update the UI.
After the line waited += 100; add:
int progress = Math.round((float)waited / 3000 * 100);
publishProgress(progress);
Also, the signature of AsyncTask is wrong if you intend on using an integer to reflect your progress. The generic parameters are AsyncTask<Params, Progress, Result>, so in your case, you're not accepting any arguments, or returning any meaningful value from doInBackground, but, you do want to return an Integer to indicate progress. So, change your class declaration to match:
private class loading extends AsyncTask<Void, Integer, Integer>
{
//your implementation
}
You are not calling AsyncTask.publishProgress and that is why your onProgressUpdate method is never called.
And by the way, your class name loading brokes naming conventions, that's not a good practice.
I am facing a very silly problem in my project and not able to resolve it. I am using AsyncTask for fetching current location of user. In that i used one counter to work as timer. Inside doInBackground I am incrementing that counter and if its greater than x value then i cancel the async task.
Here is the code snippet : -
class CurrentPositionTask extends AsyncTask<String, Void, Void> {
long counter = 0;
boolean flag = true;
#Override
public void onPreExecute() {
// TODO Auto-generated method stub
}
#Override
public Void doInBackground(String... params) {
// TODO Auto-generated method stub
do {
counter++;
if (latitude != 0 && longitude != 0) {
flag = false;
}
} while (counter <= 100000);
return null;
}
#Override
public void onPostExecute(Void result) {
// TODO Auto-generated method stub
super.onPostExecute(result);
}
}
But here the while condition is not working. I also tried the for loop instead of while but that is not also working for me. Also face very strange problem, when i print the counter using sysout its working fine but without it its not working..
All suggestions are welcome.
This loop
while (counter <= 100000 || flag);
will go on as long as any of the conditions hold, so it will continue while counter <= 10000 or flag is true. If flag is false but counter is less than 100000 it will continue. If you intend to terminate the loop when flag is false, then you need to do instead:
while (counter <= 100000 && flag);
Update: It seems from your comments that you expect the hundred thousand incrementation of the counter variable to take roughly 20-30 seconds. Current day processors are way faster than that. I won't even mention the speed variation between processors, because its negligible anyway. You can wait for real 30 seconds with this loop, though is a busy-waiting loop (just like your original intent) and not something nice to do:
final long startTime = System.currentTimeMillis();
do {
...
} while( System.currentTimeMillis() - startTime <= 30 * 1000 );
Time bound task can be done using the TimerTask. Check the following:
boolean timeExpired = false;
#Override
protected Void doInBackground(Void... params) {
Timer t =new Timer();
TimerTask tk = new TimerTask() {
#Override
public void run() {
timeExpired = true;
}
};
t.schedule(tk, 500);
while(!timeExpired){
if (latitude != 0 && longitude != 0) {
t.cancel();
tk.cancel();
break;
}
}
return null;
}
Hope this helps.
Just use
Looper.prepare();
before while loop in doInBackground method
In my android application I am trying to show a "Loading..." text which will change every 100 ms. After every 100 milliseconds it will increase one dot. So first it will be like "Loading." and the after another 100 ms it will be "Loading.." When it will be "Loading..." , this process will terminate and again start from the first on words. It will continue till 3500 ms. It will be pretty like progress bar.
I hope I am able to explain the problem.
How to resolve this problem? Please help.
Not the best answer, but it works.
Handler handler = new Handler();
for (int i = 100; i <= 3500; i=i+100) {
handler.postDelayed(new Runnable() {
#Override
public void run() {
if(i%300 == 0){
textView.setText("Loading.");
}else if(i%200 == 0){
textView.setText("Loading..");
}else if(i%100 == 0){
textView.setText("Loading...");
}
}
}, i);
}
Kotlin Snippet for Animating (Loading...):
ValueAnimator.ofInt(0, 4).apply {
repeatCount = 10
duration = 1000
addUpdateListener { valueAnimator ->
val dotsCount = valueAnimator.getAnimatedValue() as Int
if (dotsCount < 4) {
spannable.setSpan(transparentColorSpan, 7 + dotsCount, 10,
Spanned.SPAN_EXCLUSIVE_EXCLUSIVE)
textView.invalidate()
}
}
}.start()
A CountdownTimer seems to fit, change the text in onTick.
You should use an AsyncTask. This class is meant to do long-running background tasks that will publish updates and run on the UI thread automatically.
In doInBackground, have your loop that will then call publishProgress which will call onProgressUpdate every 100ms with the new values.
This will be done in the background and onProgressUpdate will run on the UI thread for you automatically.
Something on the lines of:
private class ShowLoading extends AsyncTask<Void, Integer, Void> {
#Override
protected Void doInBackground(Void... params) {
for (int i = 0; i < 3500; i++){
publishProgress(i);
try {
Thread.sleep(100);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
return null;
}
#Override
protected void onProgressUpdate(Integer... values) {
// TODO Auto-generated method stub
super.onProgressUpdate(values);
if (values[0]%3 == 0){
textview.setText ("Loading.");
} else if (values[0]%3 == 1){
textview.setText ("Loading..");
} else if (values[0]%3 == 2){
textview.setText ("Loading..");
}
}
}