I have a progress dialog I am trying to show when a user clicks a button to launch a new activity. The spinner should be displayed on the current page until the other activity appears. ( The activity can take sometimes up to 4-5 seconds to launch and without the spinner it just shows a pressed button that looks frozen )
This is what I have, it's only working if I remove hideProgressDialog();, but then the spinner will still be there when I back to the previous activity, obviously.
What am I doing wrong ?
Progress Dialog :
public void showProgressDialog(Context context) {
if(this.progressDialog != null) {
this.progressDialog.dismiss();
this.progressDialog = null;
}
this.progressDialog = ProgressDialog.show(context, "", "Chargement en cours, veuillez patienter");
}
public void hideProgressDialog() {
if(this.progressDialog != null) {
this.progressDialog.dismiss();
this.progressDialog = null;
}
}
Function :
public void startActivity(Context context, Class<? extends Activity> activityClass) {
try {
showProgressDialog(context);
Intent intent = new Intent(this, activityClass);
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
hideProgressDialog();
}
catch(Throwable e) {
e.printStackTrace();
}
}
Example of a button click where this calls the function to show the spinner :
#Override
public void onClick(View view) {
if(view.getId() == R.id.changeBannerButton) {
getBaseApplication().startActivity(this, BannerListActivity.class);
}...
Call hideProgressDialog() in the onResume() method. This way, if the user presses the back button, the onResume() method gets called and immediately hides the progress dialog.
Well First off you should use the new DialogFragment class with FragmentManager. Because showdialog() is deprecated from API level 8
Next you should use showdialog and removedialog for adding and removing the dialog.
And you should use the onCreateDialog to handle the dialog and the operations. Like start a new thread to run do the job when you are displaying the progressdialog.
Try to load data in a seperate thread on start of activity. But before start of that process show the progress dialog. Now once the process is done use runOnUI to hide the progress dialog..
Indicate the user that data is being loading
http://www.helloandroid.com/tutorials/using-threads-and-progressdialog
and this:
Android - using runOnUiThread to do UI changes from a thread
Related
So I'm trying to call a dialogFragment, it works perfectly until I call the onDismiss function from the activity to make an action...
I got a dialog fragment in the hangman game which says if you won or loose, there is a button in the dialog which says if "try again" or "next word", in case you won or loose,
it looks like this:
When the client clicks one of these buttons the dialog will disappear and a new word should appear and reset everything except the word if won...
So I've tried to set onDismiss listener to the dialogFragment inside the activity where the current game is running, but instead of setting dismiss listener, the app crashes with this error:
java.lang.IllegalStateException: Fragment already added: WonDialogFragment{db6bbec}
here is the code where I call the dialogFragment:
// in case the user won
if (isWon) {
// Disable all the buttons immediately.
setEnabledToEachButton(false);
// check if there is already a dialog.
if (!dialogFragment.isAdded() && !dialogFragment.isVisible()) {
// show the dialog
dialogFragment.show(getSupportFragmentManager(), WonDialogFragment.WON_TAG);
dialogFragment.onDismiss(new DialogInterface() {
#Override
public void cancel() {
}
#Override
public void dismiss() {
currentIndex++;
nextWordOrTryAgain();
updateTextView();
}
});
}
}
if I should provide more information to solve my problem let me know...
thank you for your time.
onDismiss is a lifecycle method of DialogFragment. You are not supposed to call it.
You have 2 options,
Try to use the OnDismissListener:
dialogFragment.getDialog().setOnDismissListener(new DialogInterface.OnDismissListener() {
#Override
public void onDismiss(DialogInterface dialogInterface) {
currentIndex++;
nextWordOrTryAgain();
updateTextView();
}
}
Or to Create a custom listener interface:
public interface DialogDismissed {
void onDialogDismissed();
}
Inside you dialog, have a setter and keep the listener interface:
public void setListener(DialogDismissed listener) {
mListener = listener;
}
When you call dismiss() inside you dialog use:
if (mListener != null) {
mListener.onDialogDismissed()
}
And when creating the Dialog, set the listener:
dialogFragment.setListener(new DialogDismissed {
#Override
void onDialogDismissed() {
currentIndex++;
nextWordOrTryAgain();
updateTextView();
}
});
I have this code to make an asynchronous call in the background, show a progress bar and start another activity when a button is clicked :
#Override
protected void onCreate(Bundle savedInstanceState) {
// ....
actionButton.setOnClickListener(this);
// call action here
}
#Override
public void onClick(View v) {
if (v.getId() == R.id.actionButton) {
setProgressVisibility(VISIBLE);
new MyActivity.ActionTask().execute(action);
}
}
private void getAction(Action action) {
try {
Call<Action> getAction = api.callAction(model, action);
Response<Action> response = getAction.execute();
setProgressVisibility(INVISIBLE);
if (response.isSuccessful() && response.body() != null) {
startAction(response.body());
} else {
runOnUiThread(() -> showToast(R.string.error, this));
logger.error(getResources().getString(R.string.error));
}
} catch (IOException e) {
runOnUiThread(() -> showToast(e.getMessage(), this));
logger.error(e.getMessage());
setProgressVisibility(INVISIBLE);
}
}
private void startAction(Action action) {
Intent intent = new Intent(this, ActionActivity.class);
intent.putExtra("action", action);
startActivity(intent);
}
private class ActionTask extends AsyncTask<Action, Void, Action> {
#Override
protected Action doInBackground(Action... action) {
getAction(action[0]);
return action[0];
}
}
I would like to start the asynchronous call as soon as the first activity is displayed in OnCreate to make it look faster for the user when he clicks on the button. So the asynchronous call starts as soon as the activity is created, then when the user clicks the button if the result is already available, the next activity starts, otherwise the progress bar is displayed until a result is available and once the result is ready the second activity starts. What's the best way to do that?
onCreate: start the task
AsyncTask: when the task finishes, check if the user has already clicked on the button. If so, start the next activity. If not, store the result of the task, or just a flag if no result needed.
onClick: Check if the task is done. If so, start the next activity. If not, show the progress indicator, and set a flag indicating the user has clicked the button.
This is my context: I have an activity which downloads a list of video and set them into an adapter. When user clicks on each item, application downloads and streams video in an external application.
So, let's see some code. Main activity has this:
new TvAsyncTask(getActivity(), gridView, progressBar).execute();
TvAsyncTask download video list and sets it like here:
protected void onPostExecute(ArrayList<VideoPreviewData> list) {
progressBar.setVisibility(View.INVISIBLE);
final TvListAdapter adapter = new TvListAdapter(activity.getApplicationContext(), R.layout.item_video_list, list);
videoGridView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, final View view, int position, long id) {
String videoUrl = adapter.getItem(position).getLink();
//Launch asyncTask to download video an load it into an external media player
new GetVideoAsyncTask(activity).execute(videoUrl);
}
});
if (videoGridView!=null) videoGridView.setAdapter(adapter);
}
GetVideoAsyncTask load video link and lauch an Intent in an external application to stream that video. In order to do this, during onLoading I set a ProgressDialog that shows to the user a loading message. After that loading is completed, intent is launched.
Problem
When ProgressDialog is shown and user click "back button" the dialog is cancelled but the asynctask continues to work. So when it finishes it launches intent.
I want to prevent this. I have a onPause method in MainActivity, but I don't have a reference of GetVideoAsyncTask launched from adapter. So I cannot call method AsyncTask.cancel(true) in order to deny intent launch.
Any suggestion?
Create an object of your async task class;
TvAsyncTask tvTask = new TvAsyncTask(getActivity(), gridView, progressBar);
tvTask.execute();
Then in the TvAsyncTask class override the onCanceled function
#Override
protected void onCancelled()
{
super.onCancelled();
}
In your back button code check:
if(tvTask != null)
tvTask.cancel(true);
in main activity you can keep a reference to GetVideoAsyncTask and TvAsyncTask and in onPause cancel both of them.
inActivity:
GetVideoAsyncTask getVideoAsyncTask;
TvAsyncTask tvAsyncTask;
in onCreate:
tvAsyncTask=new TvAsyncTask(getActivity(), gridView, progressBar);
tvAsyncTask.execute();
and in onItemClick
getVideoAsyncTask=new GetVideoAsyncTask(activity);
getVideoAsyncTask.execute(videoUrl);
in onPause:
if(tvAsyncTask!=null&&!tvAsyncTask.isCancelled())
tvAsyncTask.cancel(true);
if(getVideoAsyncTask!=null&&!getVideoAsyncTask.isCancelled())
getVideoAsyncTask.cancel(true);
I am working on a To Do List Android application (it happens to be for a class assignment, but that's not what I'm asking about--I've tried to leave out as much code as I could). The main screen displays a list of ToDo items with a button at the bottom to open the Add New ToDo Item screen.
On the Add New ToDo Item screen, there is a Cancel button.
Relevant ToDoManagerActivity.java snippet:
public void onCreate(Bundle savedInstanceState) {
// Init and setup adapter, etc.
footerView.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
Intent intent = new Intent(ToDoManagerActivity.this, AddToDoActivity.class);
startActivityForResult(intent, ADD_TODO_ITEM_REQUEST);
}
});
// Attach the adapter to this ListActivity's ListView
}
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
log("Entered onActivityResult()");
// Check result code and request code.
// If user submitted a new ToDoItem
// Create a new ToDoItem from the data Intent
// and then add it to the adapter
}
Relevant AddToDoActivity.java snippet:
protected void onCreate(Bundle savedInstanceState) {
// Initialize default view, handle other events, etc.
final Button cancelButton = (Button) findViewById(R.id.cancelButton);
cancelButton.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
setResult(RESULT_CANCELED, new Intent());
finish();
}
});
}
The above code works. Previously, I was trying this in the onClick handler for cancelButton:
public void onClick(View v) {
finishActivity(RESULT_CANCELED);
}
When I clicked the Cancel button, I could see that the onActivityResult was being reached in the logs, but the screen was not reverting back to the main ToDo list screen.
Why does the above code not return me to the previous screen, but the following code does return me to the previous screen? What am I misunderstanding about the task backstack/activities?
public void onClick(View v) {
setResult(RESULT_CANCELED, new Intent());
finish();
}
According to the documentation:
public void finish ()
Call this when your activity is done and should be closed. The ActivityResult is propagated back to whoever launched you via
onActivityResult().
and
public void finishActivity (int requestCode)
Force finish another activity that you had previously started with startActivityForResult(Intent, int).
You should call finish() to close the current activity and finishActivity() to close another activity you started using startActivityForResult(Intent intent, int requestCode). Calling finishActivity() on the current activity will not close it.
Also, there's no point in creating a new Intent for setResult() as you are not passing back any data. Doing this would be sufficient:
setResult(RESULT_CANCELED);
finish();
From Android Docs:
public void finishActivity (int requestCode)
Force finish another activity that you had previously started with startActivityForResult(Intent, int).
finishActivity does not finish the current activity but calls finish for an activity called with requestCode
If you look at the documentation for finishActivity() it says that it will force finish an activity started with startActivityForResult(), but you have to pass in the request code that you used to start the other activity. In your case it would be ADD_TODO_ITEM_REQUEST.
This is probably not the API you want to use. Your 2nd method is cleaner in that you don't need to force close the child activity, but let it finish in the normal way.
i have an activity or screen which contains mainly 3 views (ex.textview1,textview2,textview3) and a progress bar.
While progress bar running or loading if i click on either of textview1,textview2,textview3,
corresponding next activity or screen is opening.
But i want like while progress bar running relevant screen should disable(not tappable) or should not move to next screen if i click on any of these views.
please reply with an example
Just create a boolean for when the you have something in progress and then check for it in you onClickListener.
boolean isRunning;
#Override
public void onClick(View v) {
if(isRunning)
return;
//handle code normally
}
You can use AsyncTask class to do this
FYI, AsyncTask is known as Painless Threading in Android.
onCreate() {
...
MyTask task = new MyTask();
task.execute();
}
class MyTask extends AsyncTask
{
onPreExecute() {
// disable your views here
}
doInBackground() {
// do your loading here in background
}
onPostExecute() {
// enable your views to start activities
}
}