How to use asynctask to display a progress bar that counts down? - android-asynctask

In my application i want the user to press a button and then wait 5 mins. i know this sounds terrible but just go with it. The time remaining in the 5 min wait period should be displayed in the progress bar.
I was using a CountDownTimer with a text view to countdown but my boss wants something that looks better. hence the reasoning for a progress bar.

You can do something like this..
public static final int DIALOG_DOWNLOAD_PROGRESS = 0;
private ProgressDialog mProgressDialog;
#Override
protected Dialog onCreateDialog(int id) {
switch (id) {
case DIALOG_DOWNLOAD_PROGRESS:
mProgressDialog = new ProgressDialog(this);
mProgressDialog.setMessage("waiting 5 minutes..");
mProgressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
mProgressDialog.setCancelable(false);
mProgressDialog.show();
return mProgressDialog;
default:
return null;
}
}
Then write an async task to update progress..
private class DownloadZipFileTask extends AsyncTask<String, String, String> {
#Override
protected void onPreExecute() {
super.onPreExecute();
showDialog(DIALOG_DOWNLOAD_PROGRESS);
}
#Override
protected String doInBackground(String... urls) {
//Copy you logic to calculate progress and call
publishProgress("" + progress);
}
protected void onProgressUpdate(String... progress) {
mProgressDialog.setProgress(Integer.parseInt(progress[0]));
}
#Override
protected void onPostExecute(String result) {
dismissDialog(DIALOG_DOWNLOAD_PROGRESS);
}
}
This should solve your purpose and it wont even block UI tread..

Related

Toast is shown every time when device is rotate

In my Android app I use AAC.
Here my activity:
public class AddTraderActivity extends AppCompatActivity {
AddTraderViewModel addTraderViewModel;
private static final String TAG = AddTraderActivity.class.getName();
#Override
protected void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
AddTraderActivityBinding binding = DataBindingUtil.setContentView(this, R.layout.add_trader_activity);
binding.setHandler(this);
init();
}
private void init() {
ViewModelProvider viewViewModelProvider = ViewModelProviders.of(this);
addTraderViewModel = viewViewModelProvider.get(AddTraderViewModel.class);
Observer<String> () {
#Override
public void onChanged (String message){
Debug.d(TAG, "onChanged: message = " + message);
Toast.makeText(AddTraderActivity.this, message, Toast.LENGTH_LONG).show();
}
});
}
public void onClickStart() {
EditText baseEditText = findViewById(R.id.baseEditText);
EditText quoteEditText = findViewById(R.id.quoteEditText);
addTraderViewModel.doClickStart(baseEditText.getText().toString(), quoteEditText.getText().toString());
}
}
Here my ViewModel:
public class AddTraderViewModel extends AndroidViewModel {
private MutableLiveData<String> messageLiveData = new MutableLiveData<>();
private static final String TAG = AddTraderViewModel.class.getName();
public AddTraderViewModel(#NonNull Application application) {
super(application);
}
public void doClickStart(String base, String quote) {
Debug.d(TAG, "doClickStart: ");
if (base.trim().isEmpty() || quote.trim().isEmpty()) {
String message = getApplication().getApplicationContext().getString(R.string.please_input_all_fields);
messageLiveData.setValue(message);
return;
}
}
public LiveData<String> getMessageLiveData() {
return messageLiveData;
}
}
So when I click on button on Activity call method onClickStart()
If any fields is empty the show toast. In the activity call method:
onChanged (String message)
Nice. It's work fine.
But the problem is, when I rotate the device in the activity method onChanged(String message) is called AGAIN and as result show toast. This happened on every rotation.
Why?
This is the expected behaviour. If you want to avoid this you must set message = "" and keep an empty check before showing the toast.
A better way to use it is something like Event Wrapper or SingleLiveEvent
Highly recommend you to read this article. This explains why you are facing this and what are your options in detail.

Application crashes when I press back button using AsyncTask

I am trying to use AsyncTask and the activity is working perfectly but I am facing a problem. The problem comes after I have pressed back button, because pressing this button my app crashes. I have seen other posts saying that I must cancel the task in onStop() and onDestroy() but still crashes. Does anyone have any idea how can I solve that?
private class MyAsyncTask extends AsyncTask<Void, Integer, Boolean> {
#Override
protected Boolean doInBackground(Void... args0) {
for(int i=1; i<=10; i++) {
try{
if(isCancelled())
break;
publishProgress(i*10);
Thread.sleep(1000);
}catch (InterruptedException e){}
}
return null;
}
/*
* it will update the publishProgress method and it will
* update the interface (if it's necessary)
*/
#Override
protected void onProgressUpdate(Integer... values) {
int progreso = values[0].intValue();
pbarProgreso.setProgress(progreso); // showing progress
pbarProgreso.setSecondaryProgress(progreso + 5);
}
/*
* Initializing progressBar
*/
#Override
protected void onPreExecute() {
pbarProgreso.setMax(100); // maximum value for process bar
pbarProgreso.setProgress(0); // minimum value to start
}
#Override
protected void onPostExecute(Boolean result) {
if(!this.isCancelled())
Toast.makeText(getApplicationContext(), "Task finished!",
Toast.LENGTH_SHORT).show();
}
#Override
protected void onCancelled() {
Toast.makeText(getApplicationContext(), "Task cancelled!",
Toast.LENGTH_SHORT).show();
}
}
#Override
protected void onStop() {
super.onStop();
if(task != null && task.getStatus() == Status.RUNNING){
task.cancel(true);
}
}
#Override
protected void onDestroy() {
super.onDestroy();
if(task != null && task.getStatus() == Status.RUNNING) {
task.cancel(true);
}
}
It's because when you press back button, AsyncTask continues to work, and when it do context related work, that context no longer exists, and a crash happens, it's better to use a "isResumed" boolean indicator variable inside an activity, and set it to false in onPause and set to true inside onResume, and inside an AsyncTask do context related things, inside an if condition.
Or if this code is inside a fragment, can use isAdded() method, to check if fragment is active or not. Cancel is also important, but there may be a delay, between an Activity pause and AsyncTask cancel, so keeping that variable is important.

Fatal Exception: java.lang.IllegalArgumentException occurs from ProgressDialog

I've 10 apps which uses AsyncTasks. As you know i show progressdialog in asynctasks to show progress of the task. But there is a problem that i couldn't solve so far about progressdialog.
Here is one of my AsyncTask class (which is not in a other class);
public class GetBalanceAsyncTask extends AsyncTask<Void, Void, String> {
Context context;
ProgressDialog pd;
public GetBakiyeAsyncTask(Context context) {
this.context = context;
}
#Override
protected String doInBackground(Void... arg0) {
String userAgent = HttpHelper.getRandomUserAgent(context);
return HttpHelper.post(PreferenceHelper.getBalanceQueryAPI(context), userAgent);
}
#Override
protected void onPreExecute() {
super.onPreExecute();
pd = ProgressDialog.show(context, "","Please wait...",true);
}
#Override
protected void onPostExecute(String result) {
try {
if (pd != null & pd.isShowing()) {
pd.dismiss();
pd = null;
}
} catch (IllegalArgumentException e) {
pd = null;
e.printStackTrace();
}
if (result != null & result.length() > 0) {
Utils.doTask(result);
} else {
Utils.ShowToast(context,
"An error has occurred, please try again.",
STYLE_CONFIRM, LENGTH_LONG);
}
super.onPostExecute(result);
}
}
and the execption is
java.lang.IllegalArgumentException: View not attached to window manager
at android.view.WindowManagerImpl.findViewLocked(WindowManagerImpl.java:381)
at android.view.WindowManagerImpl.removeView(WindowManagerImpl.java:226)
at android.view.Window$LocalWindowManager.removeView(Window.java:432)
at android.app.Dialog.dismissDialog(Dialog.java:278)
at android.app.Dialog.access$000(Dialog.java:71)
at android.app.Dialog$1.run(Dialog.java:111)
at android.app.Dialog.dismiss(Dialog.java:268)
at fragments.RuyalarFragment$getRuyalarAsyncTask.onPostExecute(GetBalanceAsyncTask.java:27)
at fragments.RuyalarFragment$getRuyalarAsyncTask.onPostExecute(GetBalanceAsyncTask.java:1)
at android.os.AsyncTask.finish(AsyncTask.java:417)
at android.os.AsyncTask.access$300(AsyncTask.java:127)
at android.os.AsyncTask$InternalHandler.handleMessage(AsyncTask.java:429)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:130)
at android.app.ActivityThread.main(ActivityThread.java:3691)
at java.lang.reflect.Method.invokeNative(Method.java)
at java.lang.reflect.Method.invoke(Method.java:507)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:907)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:665)
at dalvik.system.NativeStart.main(NativeStart.java)
I've searched the solution almost everywhere but there is no working results. Most of answers contain use isFinishing, onDestroy or something like this but no body is sure which is working.
Thanks for advice.
How to reproduce the bug:
Enable this option on your device: Settings -> Developer Options -> Don't keep Activities.
Press Home button while the 'AsyncTask' is executing and the ProgressDialog is showing.
The Android OS will destroy an activity as soon as it is hidden. When onPostExecute is called the Activity will be in "finishing" state and the ProgressDialog will be not attached to Activity.
How to fix it:
Check for the activity state in your onPostExecute method.
Dismiss the ProgressDialog in onDestroy method. Otherwise, android.view.WindowLeaked exception will be thrown. This exception usually comes from dialogs that are still active when the activity is finishing.
try this code :
public class YourActivity extends Activity {
<...>
private void showProgressDialog() {
if (pDialog == null) {
pDialog = new ProgressDialog(StartActivity.this);
pDialog.setMessage("Loading. Please wait...");
pDialog.setIndeterminate(false);
pDialog.setCancelable(false);
}
pDialog.show();
}
private void dismissProgressDialog() {
if (pDialog != null && pDialog.isShowing()) {
pDialog.dismiss();
}
}
#Override
protected void onDestroy() {
dismissProgressDialog();
super.onDestroy();
}
class LoadAllProducts extends AsyncTask<String, String, String> {
/**
* Before starting background thread Show Progress Dialog
* */
#Override
protected void onPreExecute() {
showProgressDialog();
}
/**
* getting All products from url
* */
protected String doInBackground(String... args)
{
doMoreStuff("internet");
return null;
}
/**
* After completing background task Dismiss the progress dialog
* **/
protected void onPostExecute(String file_url)
{
if (YourActivity.this.isDestroyed()) {
return;
}
dismissProgressDialog();
something(note);
}
}
}
Late to the party, but really this question has many duplicates on SO.
The most comprehensive summary of solutions I've found is here.
Basically use a retained Fragment to connect your AsyncTask to the new Activity.

Gridview onScroll method gets called always, without user scroll

I have a customized gridview where i'm checking onScroll method to find the end of the list. If the scroll reaches the end of the list, it will again add few elements in to the list.
gridview.setOnScrollListener(new OnScrollListener() {
#Override
public void onScrollStateChanged(AbsListView arg0, int arg1) {
}
#Override
public void onScroll(AbsListView arg0, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
// TODO Auto-generated method stub
int lastInScreen = firstVisibleItem + visibleItemCount;
//is the bottom item visible & not loading more already ? Load more !
if((lastInScreen == totalItemCount) && (!loadingMore))
{
new LoadDataTask().execute();
}
}
});
And this is my Asynchronous task class..
private class LoadDataTask extends AsyncTask<Void, Void, Void> {
#Override
protected Void doInBackground(Void... params) {
if (isCancelled()) {
return null;
}
loadingMore = true;
for (int i = 0; i < mNames.length; i++)
mListItems.add(mNames[i]);
return null;
}
#Override
protected void onPostExecute(Void result) {
mListItems.add("Added after load more");
loadingMore=false;
adapter.notifyDataSetChanged();
super.onPostExecute(result);
}
#Override
protected void onCancelled() {
}
}
Now the issue is that the onScroll method keep on calling. It doesn't stop even when the user not scrolling. Can anyone have a solution ?
Please check the answer for this question: onScroll gets called when I set listView.onScrollListener(this), but without any touch .
The same is true for the GridView, since it has AbsListView as superclass just as ListView does.

Instant value change handler on a GWT textbox

I would like to update a text field instantly when typing in a GWT TextBox. My problem is that ValueChangeEvent and ChangeEvent handlers only fire when the TextBox loses focus. I thought about using the KeyPressEvent but then nothing would happen when performing a copy paste with the mouse.
What's the simplest way to do that ?
You could catch the ONPASTE event and manually fire a ValueChangeEvent. Something like this:
public void onModuleLoad() {
final Label text = new Label();
final ExtendedTextBox box = new ExtendedTextBox();
box.addValueChangeHandler(new ValueChangeHandler<String>() {
#Override
public void onValueChange(ValueChangeEvent<String> event) {
text.setText(event.getValue());
}
});
box.addKeyUpHandler(new KeyUpHandler() {
#Override
public void onKeyUp(KeyUpEvent event) {
text.setText(box.getText());
}
});
RootPanel.get().add(box);
RootPanel.get().add(text);
}
private class ExtendedTextBox extends TextBox {
public ExtendedTextBox() {
super();
sinkEvents(Event.ONPASTE);
}
#Override
public void onBrowserEvent(Event event) {
super.onBrowserEvent(event);
switch (DOM.eventGetType(event)) {
case Event.ONPASTE:
Scheduler.get().scheduleDeferred(new ScheduledCommand() {
#Override
public void execute() {
ValueChangeEvent.fire(ExtendedTextBox.this, getText());
}
});
break;
}
}
}
Tested on firefox 3.6.1.
As a general solution, what works for me (thx to gal-bracha comment):
Generally, GWT does not have classes to handle input event (described here
and here). So we need to implement it by ourselves:
Handler class:
import com.google.gwt.event.shared.EventHandler;
public interface InputHandler extends EventHandler {
void onInput(InputEvent event);
}
Event class:
import com.google.gwt.event.dom.client.DomEvent;
public class InputEvent extends DomEvent<InputHandler> {
private static final Type<InputHandler> TYPE = new Type<InputHandler>("input", new InputEvent());
public static Type<InputHandler> getType() {
return TYPE;
}
protected InputEvent() {
}
#Override
public final Type<InputHandler> getAssociatedType() {
return TYPE;
}
#Override
protected void dispatch(InputHandler handler) {
handler.onInput(this);
}
}
Usage:
box.addDomHandler(new InputHandler() {
#Override
public void onInput(InputEvent event) {
text.setText(box.getText());
}
},InputEvent.getType());
It works on every TextBox value change including pasting using context menu. It does not react on arrows, ctrl, shift etc...
This has been a major issue for me in the past. The keyupHandler wont work because the copy paste requires a second key press on the paste option which does not fire the event. the best i have been able to do is use the old changelistener not ideal but it does work.
I prefer use Elements than Widgets so this my way to handler.
Element input = Document.get().getElementById("my-input");
DOM.sinkBitlessEvent(input, "input");
DOM.setEventListener(input, event -> GWT.log("Event!"));
Why not use combination of both KeyUpHandler and a ChangeHandler on the TextBox?
Should take care of immediate feedback on each keystroke as well as copy paste case as well.
Just saw this question. Because I was facing the similar problem.
Did some hack and it worked for me.
You can use KeyUpHandler but use it with additional if block that checks
for length of textbox. If length of text box is > 0, do your thing.
Ex:
textBox.addKeyUpHandler(new KeyUpHandler() {
#Override
public void onKeyUp(KeyUpEvent keyUpEvent) {
if (textBox.getText().length() > 0) {
//do your stuff`enter code here`
}
}

Resources