I have a simple function that counts from 0 to 5000 and does funky math with those numbers, and I would like to display progress bar showing where it is currently counting at (each iteration roughly takes 1 second).
My ProgressBar is the following
<TableRow
android:visibility="gone"
android:id="#+id/progress_bar_row" >
<ProgressBar
android:id="#+id/progress_bar"
style="?android:attr/progressBarStyleHorizontal"
android:layout_width="wrap_content"
android:layout_span="2"
android:layout_height="wrap_content" />
</TableRow>
When user presses button my function starts, it makes the row visible, and I would like to refresh the ProgressBar with each iteration. My function is the following
private void find_number(View v)
{
String response = "";
TextView answer = (TextView)findViewById(R.id.answer);
TableRow progress_bar_row = (TableRow)findViewById(R.id.progress_bar_row);
ProgressBar progress_bar = (ProgressBar)findViewById(R.id.progress_bar);
progress_bar.setProgress(0);
progress_bar.setMax(5000);
progress_bar_row.setVisibility(View.VISIBLE);
answer.setText("");
for(int i = 0; i <= 5000; i++)
{
progress_bar.setProgress(i);
// a lot of heavy math is being performed here and answer is stored inside response string
}
//progress_bar.dismiss();
progress_bar_row.setVisibility(View.GONE);
answer.append(response);
}
I can't seem to figure out a way of going about refreshing the screen. I poked around and got a suggestion to use threads and handlers, I never used threads before, nor would I know how to change my function to adapt to thread use. Or if there is a simpler way without using any threads and simply calling some kind of refresh function I would appreciate it too. Any help or guidance would be very welcome. Thanks in advance
you should use AsyncTask for this problem.
private class YourTask extends AsyncTask<String, Integer, Long> {
protected Long doInBackground(String... strings) {
for(int i = 0; i <= 5000; i++)
{
// your code here
publishProgress((int) ((i / (float) 5000) * 100));
}
return i;
}
protected void onProgressUpdate(Integer... progress) {
progress_bar.setProgress(progress);
}
protected void onPostExecute(Long result) {
//Do something after this task finish
}
}
Related
My doubt is will there be a low performance if we perform calculations before setting data in the recycler view in Android?
For example, Im receiving list of data as a server response such as:
Sales target:50 and Sales target achieved:10 for Person A
Sales Target:60 and Sales Target Achieved:15 for Person B,etc..
and I have to show this in a recycler view along with Percentage,
So I do a calculation at Android side to convert these sales target into percentage before setting in the adapter. So before setting the first data, I calculate percentage by doing this: (10/50) *100, which gives me 20%,and so on, for all the list data. So does this calculation lower the performance of loading in Android or will it be better if I calculate the percentage in the server side and get the percentage in the response itself so that I can simply set it without any calculation, but will it affect response time?
So I'm in a confusion between Server Response Time and Android Processing time.
The percentage seems to be not security-sensitive, you could calculate it on client side. If you want to save time on processing the data, try fill some data to the recycler view's adapter to make it visible to user, then perform some asynchronous
background task to calculate the data and update the view.
You should use AsyncTask. It will do task in background thread and will update the UI accordingly.
Below is a simple example:
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");
}
}
To run AsyncTask
new DownloadFilesTask(). execute(param1, param2, param3);
To cancel task call
cancel();
i want to implement a login activity. it checks user existance with a webservice.
EditText un=(EditText) findViewById(R.id.txtName);
EditText pass=(EditText) findViewById(R.id.txtPass);
WS ss=new WS();
String str=ss.execute("checkLogin",un.getText().toString(),pass.getText().toString()).get();
Intent in=new Intent(arg0.getContext(), Overview.class);
in.putExtra("username", str);
if(str=="No User")
Toast.makeText(getApplicationContext(), "ss", 300).show();
else
{
startActivity(in);
finish();
}
the problem is in "IF" section. "str" value sets after finishing code lines.
but i want to get "str" value then check for IF to run proper actions.
You need override onPostExecute method see below example
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));
}
return totalSize;
}
protected void onProgressUpdate(Integer... progress) {
setProgressPercent(progress[0]);
}
protected void onPostExecute(Long result) {
showDialog("Downloaded " + result + " bytes");
}
}
The whole point of an asynchronous task is to not block synchronously. You have several options if you do want synchronous behavior:
Don't use AsyncTask in the first place (probably not a good idea if it is a long-running network call)
Put the code you want to run after the AsyncTask completes it's background work in the onPostExecute method, which will have access to the result of the data returned from the background method
Provide a callback to the AsyncTask that onPostExecute can call when it is finished (similar in concept to the previous option but more formal and robust to changes)
I prefer the last option, but it also takes more dev time to write than the other options.
Don't forget that an AsyncTask may do it's background work and/or finish after the activity has been finished and shut down, so make sure to check for that state appropriately before you start interacting with the UI.
If you are trying to do a network call you shouldn't use asynctask rather use loopj or google's volley library .
Asynctask is not meant for long network calls , having said that here's an example of asynctask class , code:
class AsyncTaskExample extends AsyncTask<Void, Integer, String> {
private final String TAG = AsyncTaskExample.class.getName();
protected void onPreExecute(){
Log.d(TAG, "On preExceute...");
}
protected String doInBackground(Void...arg0) {
Log.d(TAG, "On doInBackground...");
for(int i = 0; i<5; i++){
Integer in = new Integer(i);
publishProgress(i);
}
return "You are at PostExecute";}
protected void onProgressUpdate(Integer...a){
Log.d(TAG,"You are in progress update ... " + a[0]);
}
protected void onPostExecute(String result) {
Log.d(TAG,result);
}
}
Edit it as you wish and instanciate a new one in your code when you want to do the check up ,
Hope it helps
I can easily get data from the database.. But because Asynctask runs in the background, it has not downloaded the data before i call my update() method.
Example.
MyGetDataFromDatebaseCall();
UpdateSomething();
So here's my question. How can you make the UpdateSomething() method wait until the MyGetDatebaseCall() has downloaded alle the data?
I have made a Dialog window that pops up, so the user have to press okay to proceed and that works. I could also create 2 buttons so they call one method each. But they are such ugly solutions. I have also tried to send an instance of the Activity i was in, and making the AsyncTask class try and update the Activity class in the doInBackground, but apperently it cant be done?
You should call MyGetDataFromDatebaseCall() method in doInBackground() and after downloading all the data, you can call updateSomething() method in onPostExecute().
It will work fine.
Did you ever look at the documentation?
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");
}
}
So I have this class that downloads stuff... and I am implementing NotificationHelper based on this person's example
private class DatabaseStorageTask extends AsyncTask<String, Integer, String> {
protected String doInBackground(String... params) {
for(int i=0; i<10; i++){
//codes here
downloadFileCount++;
publishProgress( (int) ((downloadFileCount/totalDownloadFileCount) * 100 ) );
}
}
protected void onProgressUpdate(Integer... progress){
Log.e("progressupdate", "in progressupdate");
mNotificationHelper.progressUpdate(progress[0]);
}
}
This is the gist of what goes on in the code. I am unable to see whats causing my problem, as the Notification is constantly displaying 0%, even though I did a Log.e() printing of downloadFileCount and totalDownloadFileCount, which I have checked to be accurate.
Is there something I have missed out to cause the percentage progress not to be updated?
EDIT: Ok so I've placed Log.e() everywhere and I kinda figured out the problem but am not sure of the solution. The percentages and calculates all work fine and are giving the right numbers. However when publishProgress is invoked, the onProgressUpdate is not being called. I do not see the Log.e("progressupdate", "in progressupdate") displayed at all.
maybe it works when
protected String doInBackground(String... params) {
while(downloadFileCount<100){ //try while instead of for-loop
downloadFileCount++;
publishProgress(downloadFileCount); //only count downloadFileCount
}
}
don´t know if it´s the solution, it´s just an idea....
The answer lies in using float rather than int values to get the percentage.
E.g. 5 of 20 = 25%
5/20 = 0.25
when using int = 0
int * 100 = 0
when using float = 0.25
float * 100 = 25
I have a table called student which I want to populate from the server. In my activity I show a progress bar and call ContentProvder.requestSync(Content URI of student..). Now if I understand correctly as per Virgil's talk I should add an observer on the ContentURI of the student to be notified later by the ContentProvider when the sync finishes. But what happens if say there was a network error. The student table will never be populated and my progress dialog will never be removed.
I understand the
"broadcast receiver approach"
mentioned in another thread but that deviates from Virgil's approach which I consider ideal.
Also on those lines why doesn't the requestSync allow to pass a ResultReceiver as part of the extras. Isn't that generally a Service talks back to an Activity?
A SyncAdapter is not meant to be used for this kind of scenario. SyncAdapter is meant for background sync of data, invisible to the user.
Your case sounds like perfect for a AsyncTask. With that you can use publishProgress() to update your progress bar while your network task happens in another thread. You can find a lot of information and examples on AsyncTask online.
Example from the link above:
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");
}
}
run it by executing it like so:
new DownloadFilesTask().execute(url1, url2, url3);
Here is another example, with tutorial (simply found by google):
http://androidresearch.wordpress.com/2012/03/17/understanding-asynctask-once-and-forever/