ProgressDialog does not disappear after executing dismiss, hide or cancel? - android

I have an Overlay extension which has 2 dialogs as private attributes - one Dialog and one ProgressDialog. After clicking on the Overlay in the MapView, the Dialog object appears. When the user clicks a button in the Dialog it disappears and the ProgressDialog is shown. Simultaneously a background task is started by notifying a running Service. When the task is done, a method (buildingLoaded) in the Overlay object is called to switch the View and to dismiss the ProgressDialog. The View is being switched, the code is being run (I checked with the debugger) but the ProgressDialog is not dismissed. I also tried hide() and cancel() methods, but nothing works. Can somebody help me?
Android version is 2.2
Here is the code:
public class LODOverlay extends Overlay implements OnClickListener {
private Dialog overlayDialog;
private ProgressDialog progressDialog;
..............
#Override
public void onClick(View view) {
.......
final Context ctx = view.getContext();
this.progressDialog = new ProgressDialog(ctx);
ListView lv = new ListView(ctx);
ArrayAdapter<String> adapter = new ArrayAdapter<String>(ctx, R.layout.layerlist, names);
lv.setAdapter(adapter);
final LODOverlay obj = this;
lv.setOnItemClickListener(new OnItemClickListener() {
public void onItemClick(AdapterView<?> parent, View view,
int position, long id) {
String name = ((TextView) view).getText().toString();
Intent getFloorIntent = new Intent(Map.RENDERER);
getFloorIntent.putExtra("type", "onGetBuildingLayer");
getFloorIntent.putExtra("id", name);
view.getContext().sendBroadcast(getFloorIntent);
overlayDialog.dismiss();
obj.waitingForLayer = name;
progressDialog.show(ctx, "Loading...", "Wait!!!");
}
});
.......
}
public void buildingLoaded(String id) {
if (null != this.progressDialog) {
if (id.equals(this.waitingForLayer)) {
this.progressDialog.hide();
this.progressDialog.dismiss();
............
Map.flipper.showNext(); // changes the view
}
}
}
}

Not sure if this is the cause of your issue, but the method you are calling on ProgressDialog is static, but you are calling it on an instance of the class. Here's the method definition:
public static ProgressDialog show (Context context, CharSequence title, CharSequence message)
As you can see, the method returns a ProgressDialog, it does not perform the show operation on your instance of the class. Update your code to use one of these:
progressDialog.setTitle("Loading...");
progressDialog.setMessage("Wait!!!");
progressDialog.show();
or
progressDialog = ProgressDialog.show(ctx, "Loading...", "Wait!!!");

ProgressDialog.show(...) methods do in fact perform a show() on the dialog before returning it. Here is Android.jar source:
public static ProgressDialog show(Context context, CharSequence title,
CharSequence message, boolean indeterminate,
boolean cancelable, OnCancelListener cancelListener) {
ProgressDialog dialog = new ProgressDialog(context);
dialog.setTitle(title);
dialog.setMessage(message);
dialog.setIndeterminate(indeterminate);
dialog.setCancelable(cancelable);
dialog.setOnCancelListener(cancelListener);
dialog.show();
return dialog;
}
All the overloads of this method refer to this one.

Related

Dialog pops up very slow

In my app I have implemented this custom dialog (which has a fairly complex layout) by extending DialogFragment. I expect this dialog to pop up when I click a button in my layout. (Which I have successfully achieved). But the problem is that the dialog shows up in a janky manner.
My custom dialog class:
public class CustomizeDialog extends DialogFragment implements AdapterView.OnItemSelectedListener {
// field declarations go here
#NonNull
#Override
public Dialog onCreateDialog(#Nullable Bundle savedInstanceState) {
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
LayoutInflater inflater = getActivity().getLayoutInflater();
View view = inflater.inflate(R.layout.customize_dialog, null);
builder.setView(view)
.setTitle("Customize")
.setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
}
})
.setPositiveButton("Let's go!", new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
Intent intent = new Intent();
intent.setAction("fromDialog");
intent.putExtra("ratio",getRatio(paperSizeSpinner.getSelectedItem().toString()));
if(isOrientationSpinnerVisible){
intent.putExtra("isCustom",false);
intent.putExtra("orientation",orientationSpinner.getSelectedItem().toString());
} else {
intent.putExtra("isCustom",true);
}
intentProvider.getIntent(intent);
}
});
widthEditText = view.findViewById(R.id.width_et);
heightEditText = view.findViewById(R.id.height_et);
widthEditText.setEnabled(false);
heightEditText.setEnabled(false);
paperSizeSpinner = view.findViewById(R.id.paper_size_spinner);
orientationSpinner = view.findViewById(R.id.orientation_spinner);
// ArrayList for populating paperSize spinner via paperSizeAdapter
ArrayList<String> paperSizes = new ArrayList<>();
paperSizes.add("A0");
paperSizes.add("A1");
paperSizes.add("A2");
paperSizes.add("A3");
paperSizes.add("A4");
paperSizes.add("A5");
paperSizes.add("Custom");
// ArrayList for populating orientation spinner via orientationAdapter
ArrayList<String> orientation = new ArrayList<>();
orientation.add("Portrait");
orientation.add("Landscape");
// arrayAdapters containing arraylists to populate spinners
ArrayAdapter paperSizeAdapter = new ArrayAdapter(getActivity(), android.R.layout.simple_spinner_dropdown_item, paperSizes);
ArrayAdapter orientationAdapter = new ArrayAdapter(getActivity(), android.R.layout.simple_spinner_dropdown_item, orientation);
paperSizeSpinner.setAdapter(paperSizeAdapter);
orientationSpinner.setAdapter(orientationAdapter);
paperSizeSpinner.setSelection(4);
paperSizeSpinner.setOnItemSelectedListener(this);
orientationSpinner.setOnItemSelectedListener(this);
return builder.create();
}
// These are some important complex ui functionalities
#Override
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
if (parent.getId() == R.id.paper_size_spinner) {
if (position == 6) {
widthEditText.setEnabled(true);
heightEditText.setEnabled(true);
orientationSpinner.setEnabled(false);
isOrientationSpinnerVisible = false;
} else {
widthEditText.setEnabled(false);
heightEditText.setEnabled(false);
orientationSpinner.setEnabled(true);
isOrientationSpinnerVisible = true;
}
}
}
#Override
public void onNothingSelected(AdapterView<?> parent) {
}
// interface used to communicate with the parent activity
public interface IntentProvider {
// this method is used to provide the intent to the parent activity
void getIntent(Intent intent);
}
// instantiating the interface object and throwing error if parent activity does not implement this interface
#Override
public void onAttach(#NonNull Context context) {
super.onAttach(context);
try {
intentProvider = (IntentProvider) context;
} catch (ClassCastException e) {
throw new ClassCastException(context.toString() + " must implement IntentProvider");
}
}
}
MainActivity class:
public class MainActivity extends AppCompatActivity implements CustomizeDialog.IntentProvider {
// field declarations go here
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
imageView = findViewById(R.id.image);
// instantiating the dialog
final CustomizeDialog dialog = new CustomizeDialog();
findViewById(R.id.button).setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
// showing the dialog on click
dialog.show(getSupportFragmentManager(),"");
}
});
}
// via this method I receive the intent from the dialog
// I know intent might not be the best option for this function but let's let it be here for now
#Override
public void getIntent(Intent intent) {
ratio = intent.getFloatExtra("ratio",3);
isCustom = intent.getBooleanExtra("isCustom",false);
orientation = intent.getStringExtra("orientation");
launchChooser();
}
}
Let me know in the comments if you want the layout code for the dialog.
What I tried:
Implementing threading so that my dialog is ready in a background thread and show it onButtonClick. But this is not allowed in general as any other thread except UI thread aren't supposed to touch UI related events.
Using onCreateView instead of onCreateDialog to inflate the layout directly.
Making the dialog a global variable, initialized it in onCreate and then show the dialog onButtonClick.
Switched to CONSTRAINT LAYOUT
Using an activity as a dialog by setting the dialog theme to the activity in the manifest file.
Launched my app in a device with better hardware than mine.
BUT NOTHING WORKED
What I want:
Why is my dialog janky? and what I need to do to make the dialog pop up faster?
In case anybody wants here's the link to my app repo on github.
AlertDialog and DialogFragment frameworks are slow because they need to some time to do calculations and fragment stuffs. So a solution to this problem is, using the Dialog framework straight away.
Use the Dialog framework's constructor to initialize a Dialog object like this:
Dialog dialog = new Dialog(context, R.style.Theme_AppCompat_Dialog);
// the second parameter is not compulsory and you can use other themes as well
Define the layout and then use dialog.setContentView(R.layout.name_of_layout).
Use dialog.findViewById(R.id.name_of_view) to reference views from the dialog's layout file
And then implement the logic just like anyone would do in an activity class. Find out the best implementation for your use case by reading the official documentation.

Update RecyclerView from Dialog

how to update recyclerview from a dialog which is in another class?
My dialog is as a separate class which is called from mainActivity. When I do changes in database, I would like to update recyclerview, which is on mainActivity.
Dialog:
public class Dialog {
DatabaseExecutor databaseExecutor = new DatabaseExecutor();
private final Activity activity;
private final List<Passenger> passengers;
private final int position;
public Dialog (final Activity activity, final List<Passenger> passengers, final int position){
this.activity = activity;
this.passengers = passengers;
this.position = position;
}
public void showDialog (){
final BottomSheetDialog dialog = new BottomSheetDialog(activity);
dialog.setContentView(R.layout.custom_dialog);
final AppCompatImageView dial, message, info, paid, edit, delete;
final AppCompatTextView name;
name = dialog.findViewById(R.id.dialog_name);
paid = dialog.findViewById(R.id.dialog_paid);
name.setText(passengers.get(position).getName());
if(passengers.get(position).isPaid())
paid.setImageResource(R.drawable.money_paid_72);
else
paid.setImageResource(R.drawable.money_unpaid_72);
paid.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Passenger passenger = passengers.get(position);
if (!passengers.get(position).isPaid()){
passenger.setPaid(true);
passenger.setTumblr(R.drawable.money_paid);
passenger.setUser(R.drawable.user_icon);
paid.setImageResource(R.drawable.money_paid_72);
}
else {
passenger.setPaid(false);
passenger.setTumblr(R.drawable.money_unpaid);
passenger.setUser(R.drawable.user_icon_unpaid);
paid.setImageResource(R.drawable.money_unpaid_72);
}
databaseExecutor.updatePassenger(activity, passenger);
}
});
dialog.show();
}
}
P.s. when this dialog was in mainActivity, I just called populateData method and it worked. But how to refresh it from this Dialog class?
You can use callback with dialog in MainActivity,
public interface DialogCallback {
public void onDialogCallback();
}
Your Dialog constructor should be,
DialogCallback callback;
public Dialog (final Activity activity, final List<Passenger> passengers, final int position, DialogCallback callback){
this.activity = activity;
this.passengers = passengers;
this.position = position;
this.callback = callback;
}
In your Dialog button click use below code,
paid.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Passenger passenger = passengers.get(position);
if (!passengers.get(position).isPaid()){
passenger.setPaid(true);
passenger.setTumblr(R.drawable.money_paid);
passenger.setUser(R.drawable.user_icon);
paid.setImageResource(R.drawable.money_paid_72);
}
else {
passenger.setPaid(false);
passenger.setTumblr(R.drawable.money_unpaid);
passenger.setUser(R.drawable.user_icon_unpaid);
paid.setImageResource(R.drawable.money_unpaid_72);
}
databaseExecutor.updatePassenger(activity, passenger);
callback.onDialogCallback(); // Add this line
}
});
In your MainActivity use below code,
Dialog dialog = new Dialog(this, passengers, position, new DialogCallback() {
#Override
public void onDialogCallback() {
// Update recycler view code here
}
});
dialog.showDialog();
In Dialog :
Have an interface
public interface onDialogFinishCallback
{
void refreshRecyclerView();
}
Now implement the above in your activity.
before dismiss the dialog or after the db change operation call
callback.refreshRecyclerView
A direct solution would be to call method on activity you passed to the dialog. There refresh data of recyclerview and notifyDataSetChanged() or appropriate.
A more general and imo better, architecture-related solution is to use Room or similar db, where you can observe data for changes. Let's say data in the db is changed anywhere. All the places where this data is observed (like with LiveData), data is refreshed. If you also use Paging library, data is refreshed and animated in recyclerview too.
Dialog shouldn't refresh RecyclverView directly. Instead you should pass listener from activity. Activity can refresh recycler if needed with notifyDataSetChanged.
Usually dialog should be 'dumb' ui and you shouldn't give it too much control, especially not over elements that are not shown inside dialog. Such approach will make your dialogs more reusable and easy to maintain.
Write an interface in your dialog
public interface onClickInterface{
public void updateRecyclerView(int position);
}
declare new variable for this interface in your dialog class
private onClickInterface mOnClickInterface;
then call method updateRecyclerView() from dialog class where you want to update recyclerview
mOnClickInterface.updateRecyclerView(position);
then implement your MainActivity for this interface and override this method
#override
public void updateRecyclerView(int position){
//alter your list which you are passing to your adapter
Passenger passenger = passengers.get(position);
passenger.setPaid(true);
rAdapter.notifyDatasetChanged();
}

I want the activity to refresh/redraw after dialog fragment is dismissed.. How can I achieve that?

This is how it looks at first:
This is the dialog fragment that pops when "edit" is pressed and I want The change to be seen in the activity after the dialog fragment is dismissed.
public Dialog onCreateDialog(Bundle savedInstanceState) {
final View view = getActivity().getLayoutInflater().inflate(R.layout.edit_profile_dialog, new LinearLayout(getActivity()), false);
editProfile = (EditText) view.findViewById(R.id.changeProfile);
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
setupProgressDialog();
/*get value from Bundle*/
String editValue = getArguments().getString("value", "");
editProfile.setText(editValue);
String title = getArguments().getString("title", "");
builder.setTitle(title);
builder.setView(view);
builder.setCancelable(false);
builder.setPositiveButton("Ok!", new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
/*edit the value in shared preference*/
sharedPref = getActivity().getSharedPreferences(getString(R.string.sharedPref), 0);
editor = sharedPref.edit();
editor.putString(getArguments().getString("saved", ""), editProfile.getText().toString());
editor.apply();
ID= sharedPref.getString("id", null);
access_token=sharedPref.getString("token",null);
//Start of AsyncTask after this
If you only need to update the data which user inputs from your dialog you do not have to redraw whole layout.
You can only set the user name to the related textview and dismiss dialog fragment.
TextView yourNameTextView = (TextView)findViewById(R.id.your_textview);
public void setNameToTextView(String name){
yourNameTextView.setText(name);
}
And when user clicks to Ok button you can call:
((YourActivity)getActivity).setText(input);
Good luck.
In your dialog's onClickListener you should be able to invalidate the layout and force a redraw / refresh
check this: How to force an entire layout View refresh?
Thanks to all of you guys trying to help me out.I think I got the answer by doing this:
In my DialogFragment
public class DialogFragmentEditProfile extends DialogFragment {
...
/*Initialize Parent Activity*/
private ChangeProfileActivity cp;
/*Override onAttachMethod */
#Override
public void onAttach(Activity activity) {
super.onAttach(activity);
try {
cp = (ChangeProfileActivity) activity;
} catch (ClassCastException e) {
throw new ClassCastException(activity.toString() + " must implement FeedbackListener");
}
}
/*create a method to recreate the parent activity*/
public void onButtonPushed(View view) {
cp.recreate();
}
Then onPostExecute() Method of AsyncTask with in the DialogFragment
protected void onPostExecute(String result) {
super.onPostExecute(result);
...
/*Recreate activity after successful update by calling the onButtonPushed() method*/
onButtonPushed(getView());
}
}

how to create a custom dialog and receive results in android?

i have an activity that when user click on button , a dialog open. in this dialog there is a spinner that have 3 choices: Blue,Red,Green. and there is a submit button. i want that when user select a color and click on submit, in caller activity, its String color set to selected color in dialog. i try this: but not worked. please help me....
String color;
String dialogColor;
showDialog.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
final Dialog dialog = new Dialog(context);
dialog.setContentView(R.layout.custom_dialog);
dialog.setTitle("my dialog");
Spinner spinner = (Spinner) dialog.findViewById(R.id.spinner);
final TextView status = (TextView) dialog.findViewById(R.id.status);
Button submit = (Button) dialog.findViewById(R.id.submit);
spinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
#Override
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
dialogColor = parent.getItemAtPosition(position).toString();
status.setText("Color is: "+dialogColor);
color = dialogColor;
}
#Override
public void onNothingSelected(AdapterView<?> parent) {
}
});
submit.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Intent intent = new Intent();
intent.putExtra("Color",dialogColor);
dialog.dismiss();
}
});
dialog.show();
}
});
i use both of direct and with intent ways to assign my color String to selected value. but not worked. where i have mistake?
I think the best way to create custom dialogs now is the Dialog Fragment, because the simple dialog it's limited. For example it's the way to create a dialogs with material design. And you have a differents ways to take info from dialog fragment, the first and the second for example.
This is basic code to create a dialog fragment:
//Method to call and start dialog fragment class
public void ShowPhotoFilesDialog(Activity context,File photo){
//Declaration of classes
Custom_DialogFragment custom_dialogFragment = new Custom_DialogFragment ();
FragmentManager fragmentManager = context.getFragmentManager();
// The device is using a large layout, so show the fragment as a dialog
custom_dialogFragment.show(fragmentManager, "dialog");
}
And this is the basic dialog fragment class:
public class Custom_DialogFragment extends DialogFragment {
#Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
try {
// The only reason you might override this method when using onCreateView() is
// to modify any dialog characteristics. For example, the dialog includes a
// title by default, but your custom layout might not need it. So here you can
// remove the dialog title, but you must call the superclass to get the Dialog.
Dialog dialog = super.onCreateDialog(savedInstanceState);
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
//To hide action bar from layout
dialog.requestWindowFeature(Window.FEATURE_NO_TITLE);
//Declaration of controls
View v = getActivity().getLayoutInflater().inflate(R.layout.my_custom_layout);
builder.setView(v);
//My code
return builder.create();
}
catch (Exception ex){
Log.e("-- Custom_DialogFragment.onCreateDialog --","",ex);
return null;
}
}
}
Tell me if I helped you, good programming!

ProgressDialog not showing up in activity

I am trying to include a ProgressDialog in my application. But it is not showing up.
Here's the code snippet where i use the ProgressDialog:
public class abcActivity extends Activity {
public boolean onOptionsItemSelected(MenuItem item) {
case XYZ:
ProgressDialog dialog = ProgressDialog.show(abcActivity.this, "", "Please wait for few seconds...", true);
callSomeFunction();
dialog.dismiss();
showToast(getString(R.string.SomeString));
break;
}
}
Does anyone know why the dialog is not showing up? Any clues?
I think your code is wrong in a sense that you do all in the UI thread. You have to put callsomefunction() into a background thread.
public void runSomething()
{
showDialog(BACKGROUND_ID);
Thread t = new Thread(new Runnable()
{
public void run()
{
//do something
handler.post(finishThread);
}
});
t.start();
// The progress wheel will only show up once all code coming here has been executed
}
And as well
protected Dialog onCreateDialog(int id)
{
if(progressDialog == null) progressDialog = new ProgressDialog(this);
return progressDialog;
}
#Override
protected void onPrepareDialog(int id, Dialog dialog)
{
if(id == BACKGROUND_ID)
{
progressDialog.setIndeterminate(true);
progressDialog.setCancelable(false);
progressDialog.setMessage("running for long ...");
}
}
Runnable finishThread = new Runnable()
{
public void run()
{
//long running
if(progressDialog != null) progressDialog.dismiss();
}
};
i think issue is in your switch condition pls verify it.
here is another method to display dialog in android try this.
public static final int DIALOG2_KEY = 1;
public static ProgressDialog dialog1;
showDialog(DIALOG2_KEY); // use it where you want to display dialog
dialog1.cancel(); // use it to cancel the dialog
#Override
public Dialog onCreateDialog(int id) {
if (id == 1) {
dialog1 = new ProgressDialog(this);
dialog1.setMessage("Please wait...");
dialog1.setIndeterminate(true);
dialog1.setCancelable(true);
}
return dialog1;
}
Ensure you have this code called by debugging or adding a log. The code seems right to me.
Also, if you want to perform some operations in background and show a progress dialog while the performing, please use AsyncTask with ProgressDialog bounded, like here.
ProgressDialog is deprecated in Android O , Use ProgressBar now.

Categories

Resources