asyncTask onProgressUpdate does not work at 2nd invoking - android

im using asyncTask to showing a download progress , my download will be done by a library named "file-downloader" in my main activity.
it's github page is "https://github.com/wlfcolin/file-downloader"
my custom dialog shows when i click to my specified button , and download task and progressBar starts when i press download button in this custom dialog
all thing is ok and progressBar works fine.
but when i dismiss this dialog and another time i invoke this dialog the progressBar does not work !
i save download status in database using the fileDownloader library listeners and anothe time i invoke custom dialog it read from database
and detect downloadProgress is currently running but we see no changing in custom dialog's progressBar , what is the problem ?
activity code
public class MainActivity extends AppCompatActivity {
/*
/
/ some variables
/
*/
public static int downloadedFile2SizePercent = 0 ; // downloaded file percent
public static int downloadingFileStatus = 0; // downloading status
Button myBtn ;
DownloadDialog dd;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main2);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
myBtn = (Button)findViewById(R.id.button22);
myBtn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
dd = new DownloadDialog(mContext,1);
dd.getWindow().setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));
dd.show();
}
});
/*
/ downloadingFileStatus value manages here by file downloader listeners correctly and saves as static variable and also in database
/ downloadedFile2SizePercent value manages here by file downloader listeners correctly and saves as static variable
/
*/
}
}
DownloadDialog Class
public class DownloadDialog extends Dialog implements View.OnClickListener{
public Context c;
public Button download, delete;
private ProgressBar pb;
ProgressTask progressTask;
private int downloadStatus;
private String downloadLink;
private int downloadID
public DownloadDialog(Context a, int downloadId) {
super(a);
this.c = a;
this.downloadId = downloadId
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.download_dialog);
download = (Button) findViewById(R.id.downloaddialot_downloadbtn);
delete = (Button) findViewById(R.id.downloaddialot_deletebtn);
download.setOnClickListener(this);
delete.setOnClickListener(this);
pb = (ProgressBar)findViewById(R.id.progressBar);
pb.setMax(100);
pb.setProgress(0);
//database is opend at mainActivity it's static
downloadStatus=Integer.parseInt(MainActivity.prDb.intSearch(downloadId));// detects download status --> 0 is "notDownloadedYet" and
// 1 is "downloading" and 2 is "downloaded"
downloadLink= MainActivity.puDb.intSearch(downloadId);//detects download link
progressTask = new ProgressTask();
if(downloadStatus==1){
pb.setProgress(MainActivity.downloadedFile2SizePercent);//this code line works every 2nd and after dialog invoking
progressTask.execute(true);
Toast.makeText(c,"test task progress for 2nd started", Toast.LENGTH_SHORT).show();//this code line works every 2nd and afterdialog invoking
}
}
#Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.downloaddialot_downloadbtn:
FileDownloader.start(downloadLink); // download task starts here
progressTask.execute(true);
Toast.makeText(c,"download task progress for 1nd started", Toast.LENGTH_SHORT).show();
break;
case R.id.downloaddialot_deletebtn:
if(downloadStatus==2){
// delete codes
}
break;
}
}
public class ProgressTask extends AsyncTask<Boolean, Integer, Boolean> {
#Override
protected void onPreExecute() {
super.onPreExecute();
}
#Override
protected Boolean doInBackground(Boolean... params) {
while (MainActivity.downloadedFile2SizePercent!=100){
publishProgress(MainActivity.downloadedFile2SizePercent);
}
if(MainActivity.downloadedFile2SizePercent==100){
publishProgress(MainActivity.downloadedFile2SizePercent);
}
return true;
}
#Override
protected void onProgressUpdate(Integer... values) {
pb.setProgress(values[0]);
}
#Override
protected void onPostExecute(Boolean aBoolean) {
super.onPostExecute(aBoolean);
downloadStatus=2; //also saves in database by download listeners in mainActivity
}
}
}

The progress bar just like any other UI element can only be managed or updated from the main UI thread.
It is the time consuming task the part that should be run in a AsyncTask, then this task can save the progress status in a volatile variable and then the UI thread can periodically update the progress bar reading the volatile variable, for example using a timer.

You can read all about AsyncTask here: https://developer.android.com/reference/android/os/AsyncTask.html
But here's my quick example/tutorial:
private class MyAsyncTask extends AsyncTask<Void, Integer, Void> {
#Override
protected void onPreExecute() {
super.onPreExecute();
// prepare your UI for the background task beginning
}
#Override
protected Void doInBackground(Void... params) {
// do some long-running task...
// you can do partial updates like:
publishProgress(25);
/* more hard work */
publishProgress(50);
/* even more hard work */
publishProgress(75);
// and when you're done...
return null;
}
#Override
protected void onProgressUpdate(Integer... values) {
super.onProgressUpdate(values);
// update your UI with the current progress (values[0])
}
#Override
protected void onPostExecute(Void aVoid) {
super.onPostExecute(aVoid);
// update your UI now that it's done
}
}
The key concept to understand regarding AsyncTask is that every method except doInBackground() is executed on the UI thread (the main thread). That means you are free to update your UI from these calls.
doInBackground(), however, is executed on a different thread. That means you can do expensive work here without slowing down your app's user interface.
Of course, all the hard work you're doing on that background thread needs to make its way to the UI thread somehow (so that you can use it). That's what publishProgress() and the return statement of doInBackground() are for. When you call publishProgress(someValue), the system will invoke onProgressUpdate(someValue) for you. When you return someValue, the system will invoke onPostExecute(someValue) for you.

Related

Fix ProgressDialog showing up after download is complete

I have a ListView that is populated with articles. When the user long clicks on an article, I want to download its summary and display it to the user. I have a function in AsyncTask (NOT doInBackground...) that takes care of the download. During the downloading process, I want to display a ProgressDialog. Since the download is on the main thread, there is a delay when I long click an article and the ProgressDialog shows AFTER the download is complete. How can I get it to show DURING the download?
I have tried these methods but I don't really understand it since I am a beginner in Android Development. The app freezes while its downloading and shows the Dialog after it's done.
ProgressDialog shows up after thread is done
display progressdialog while listview is loading
HomeActivity
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_home);
StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().permitAll().build();
StrictMode.setThreadPolicy(policy);
trendingList.setOnItemLongClickListener(new AdapterView.OnItemLongClickListener() {
#Override
public boolean onItemLongClick(AdapterView<?> parent, View view, int position, long id) {
try {
...
} catch (Exception e) {
String link = homeLinks.get(position);
//TASK TO DOWNLOAD SUMMARIES FROM ASYNCTASK
task.downloadSummary(link);
adapter.notifyDataSetChanged();
}
return true;
}
});
Background Class
public class BackgroundTask extends AsyncTask<String, Void, String> {
ProgressDialog progress = new ProgressDialog(HomeActivity.this);
//SHOW DIALOG AND THEN DOWNLOAD SUMMARIES
public void downloadSummary(String address){
progress.setMessage("Downloaded summary ");
progress.show();
...
When initializing an AsyncTask you must allocate the 3 dependent methods of this thread, onPreExecute that will allocate your ProgressDialog, the InBackground that put the job you want to perform and the onPostExecute that reotrna the result of your work and you close your progressDialog
It had stayed like this
public class BackgroundTask extends AsyncTask<String, Void, String> {
ProgressDialog progress = new ProgressDialog(HomeActivity.this);
#Override
protected void onPreExecute() {
super.onPreExecute();
progress.setMessage("Downloaded summary ");
progress.show();
}
#Override
protected void doInBackground(String... strings) {
//Ação do Trabalho
}
#Override
protected void onPostExecute(String result) {
progress.dismiss();
Log.e("Work", "Result "+result);
}
}
it is mandatory the google background method does not like when ignoring this use being an AsysnTask will have to use it. If on the contrary if it is a fast job use a thread invoked with run

AsyncTask survived screenOrientation without headless fragment

I am trying to know how to make the AsyncTask survives the screenOrientation change. So, I created an example for a MainActivity with AsyncTask. As shown in the code below, in
the doInBackground() method I print the incremented value of the variable "i" each second upto 7 seconds, and I publish the value of the variable "i" using publishProgress()
and display it in the TextView. while the value of varibale "i" is being published I changed the orientation of the device and I expected the App will crash, but what happened is,
that the the screenOrientation has changed and the value of the variable "i" was being published and normally displayed in the TextView without crash.
Is the AsyncTask I created not a suitable example to learn how to survive the screenOrientation?
MainActivity
public class MainActivity extends AppCompatActivity {
private final static String TAG = MainActivity.class.getSimpleName();
private TextView mtv11Up = null;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
this.mtv11Up = (TextView) findViewById(R.id.tv11_up);
new ATRetain().execute();
}
private class ATRetain extends AsyncTask<Void, Integer, Void> {
private long mStartTime;
private int i = 0;
#Override
protected void onPreExecute() {
super.onPreExecute();
this.mStartTime = TimeUtils.getTSSec();
}
#Override
protected Void doInBackground(Void... params) {
Log.i(TAG, "started");
while((TimeUtils.getTSSec() - this.mStartTime) <= 7) {
Log.i(TAG, "i: " + (++i));
publishProgress(i);
SystemClock.sleep(1000);
}
Log.i(TAG, "finished");
return null;
}
#Override
protected void onProgressUpdate(Integer... values) {
super.onProgressUpdate(values);
mtv11Up.setText(String.valueOf(values[0]));
}
}
}
AsyncTask create separate thread from UI Thread when orientation changes it recreated it self but AsyncTask is still running because it separate Background thread.
While doing some important work you can lock the screen orientation for some time until AsyncTask will complete then unlock.
Lock:
protected void onPreExecute() {
// ....
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_NOSENSOR);
}
Unlock:
protected void onPostExecute(String result) {
// ...
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED);
}

Delaying a Task and showing progress bar

I seem to be going round in circles.
I have some code that even on a Galaxy S3 takes a few seconds to run. Drags data from database.
I want to add a progress bar popup (spinning circle) around this to give the user that the app is doing something.
I have tried Asyntasks elsewhere in app and work fine but for this type the main UI is not waiting for the Asyntask to finish before moving on and so the new activity that is called does not have all the data it needs and crashes.
Is AsyncTask the best way round this or is there an easier way to Puase the main Activity, show a progress bar and then move on once the long deley has been completed.
Thanks for time
UPDATE
public class UpdateDetailsAsyncTask extends AsyncTask<Void, Void, Boolean> {
private Context context;
private TaskCallback callback;
private ArrayList<Object> object;
private ProgressDialog progress;
public UpdateDetailsAsyncTask (
Context pContext,
ArrayList<Object> pObject,
TaskCallback pCallback) {
context = pContext;
callback = pCallback;
object = pObject;
}
#Override
protected void onPreExecute() {
Log.i("AsyncTask", "onPreExecuted");
progress = new ProgressDialog(context);
progress.setMessage(context.getResources().getString(R.string.loading));
progress.show();
}
#Override
protected Boolean doInBackground(Void... params) {
Log.i("Archery", "AsyncTask Excuted");
Log.i("Archery Scorepad", "Building Continue Round Details");
// Save Data to Database
return true;
}
protected void onPostExecute(Boolean result) {
Log.i("AsyncTask", "onPostExuted");
progress.dismiss();
callback.startNewActivity();
}
}
Task is called from main Activity
new UpdateDetailsAsyncTask(this, ArrayListOfObjects, this).exute();
UPDATE 2
..
UPDATE 3
The Code that does some work calls an a method within a Util Class which in calls a database class. I have log messages showing for all the rows of data I am saving to the database. It starts correctly and runs through it but the onPostExecute() appears to be called before the database method has completed.
Is my issue that I have nested classes within the activity and the task appears to have completed when the class below it has not?
Thanks
You must change to the next activity in onPostExecute from Asyntask
Yes!
Here is a simple code of AsuncTask
private class LoadImageAction extends AsyncTask<String, String, String>{
private Course course;
private ProgressBar pb;
public LoadImageAction(Course course, ProgressBar pb){
this.course = course;
this.pb = pb;
}
#Override
protected void onPreExecute(){
}
#Override
protected String doInBackground(String... arg0) {
// TODO Auto-generated method stub
return null;
}
#Override
protected void onProgressUpdate(String... string){
}
#Override
protected void onPostExecute(String result){
}
}
You can run the action by
new LoadImageAction().execute();

How to make asynctask work properly

I have a button on my app, if the user click it, it will refresh the current page by calling onResume(), and there are lots of database operations in onResume(). Instead of keeping the button stay pressed for a while, I would like to use asynctask to make a progressdialog while loading the data. But the problem is that the button will still be in pressed state and the progressdialog only show at the end of the operation for a very short duration.
RefreshButton.setOnClickListener(new OnClickListener()
{
public void onClick(View v)
{
onResume();
}
});
protected void onResume()
{
doneloading = false;
monResumeloading = new onResumeloading();
monResumeloading.execute();
....loading...
doneloading = true;
}
private class onResumeloading extends AsyncTask<Integer, Integer, String>
{
private ProgressDialog progressDialog;
#Override
protected void onPostExecute(String result)
{
progressDialog.dismiss();
}
#Override
protected void onPreExecute()
{
progressDialog = new ProgressDialog(StatisticsActivity.this);
progressDialog.setMessage("Loading...");
progressDialog.setCancelable(true);
progressDialog.show();
Log.i(TAG, " doneloading=false");
}
#Override
protected void onProgressUpdate(Integer... values)
{
}
#Override
protected String doInBackground(Integer... params)
{
while(!doneloading)
{
publishProgress(0); //dummy
log.i(TAG, "loading");
}
return null;
}
}
I observed that the "loading" log is showing right after the asynctask execution and stop right after the boolean doneloading becomes false. But the progressdialog is not working properly. Please help me :(
First thing, I don't think you should be calling your AsyncTask in the onResume() function. You can simply call it from your ClickListener.
Right now, you are doing your '....loading...' code before you even execute your AsyncTask. That's why the button stays pressed while it's executing '....loading...' and then when it's done, it executes your AsyncTask which really isn't doing anything - that's why it just shows up for a short duration.
Move your '....loading...' code into your doInBackground() of your AsyncTask and it should work ok.
Summary:
Click: Execute AsyncTask
AsyncTask: opens ProgressDialog
AsyncTask: Executes your '...loading...' code
AsyncTask: Wait for '...loading...' code to complete while still displaying dialog.
AsyncTask: Dismiss ProgressDialog

Android: Problems with ProgressDialog

Dear Android hackers,
I am trying to do the following in my Android App: When the User clicks on a list item in a ListActivity, a ProgressDialog should show up, some preloading should happen and after it's done, another Activity should be called using an intent.
I tried different approaches. What didn't work at all was using an Async Task. Apparently I cannot show, dismiss or edit my ProgressDialog out of the Async Task, if that Class is not a Member of my original Activity.
I switched to a simple Thread then, this is how I'm trying to do it:
dialog = ProgressDialog.show(BookmarkActivity.this, "", "Loading...",true);
new Thread() {
public void run() {
// do something
dialog.setMessage("Change Message...");
// do more
dialog.dismiss();
// ...
Intent intent = new Intent(BookmarkActivity.this, ThreadActivity.class);
BookmarkActivity.this.startActivity(intent);
}
}.start();
This works almost, but the changing of the dialog message does not. I'm getting errors saying something about "leaked windows". (I can post the complete log if it is needed).
My questions:
How can I use an Async Task for this, where the Class has it's own file?
How can I change the ProgressDialog out of my Thread or AsyncTask without causing an error for changing the UI in another thread?
Thanks in advance, Jan Oliver
Ok, with the help of Jason, I put together this Async Task. That works!
public class ThreadPreLoader extends AsyncTask<Object, String, Void> {
private Activity mActivity;
private ProgressDialog mDialog;
public ThreadPreLoader(Activity activity) {
mActivity = activity;
}
protected void onPreExecute() {
mDialog = new ProgressDialog(mActivity);
mDialog.setMessage("Loading...");
mDialog.show();
}
protected Void doInBackground(Object... args) {
publishProgress("Loading something else..");
return null;
}
protected void onProgressUpdate(String... msg) {
mDialog.setMessage(msg[0]);
}
protected void onPostExecute(Void result) {
mDialog.dismiss();
}
}
Thanks again, Jason.
You should use an Async Task, Define a custom Async Task which receives the context (this) of the original activity.
Then keep that context for later Dismissing the dialog.
From your doInBackground() method you can call postProgress( int progress) which will cause onProgressUpdate() to be called in the async task , this method is on the UI thread so it will not cause cross thread errors.
Once doInBackground() is complete the method onComplete() will also be called on the UI thread, this is where you can use your saved context and dissmiss the dialog (context.dissmissDialog()
Take a look at Android's Handler class. If you create the Handler in the onCreate method of your activity, Runnables that are sent to the post method of the handler are then run on the UI thread of your activity:
Handler h;
protected void onCreate(Bundle bundle) {
h = new Handler;
new Thread() {
public void run() {
// your run code
h.post(new Runnable() { /* change dialog here */ });
}
}.start();
}
I'm not sure that's the best option, but worth a try.
In AsyncTask
You should do you work which need time in doInBackground and calling intent like things, that you need to do after this task should be in onPostExecute
public class ThreadPreLoader extends AsyncTask<Object, String, Void> {
private Activity mActivity;
private ProgressDialog mDialog;
public ThreadPreLoader(Activity activity) {
mActivity = activity;
}
protected void onPreExecute() {
mDialog = new ProgressDialog(mActivity);
mDialog.setMessage("Loading...");
mDialog.show();
}
protected Void doInBackground(Object... args) {
//do more
publishProgress("Loading something and reached somewhere..");
//do more
publishProgress("Loading something and reached somewhere..");
//do more
return null;
}
protected void onProgressUpdate(String msg) {
mDialog.setMessage(msg);
}
protected void onPostExecute() {
Intent intent = new Intent(BookmarkActivity.this, ThreadActivity.class);
BookmarkActivity.this.startActivity(intent);
mDialog.dismiss();
}
}

Categories

Resources