I'm trying to implement a simple Dialog into my code. But it does not work. I have searched every available tutorial, including the official developer guide but nothing works. The error I got from logcat is that I'm getting a nullPointerException, I'm guessing that's on the getActivity. Any help?
This is what I have: This is my Custom Dialog class.
public class SaveDialog extends DialogFragment {
public Dialog onCreateDialog(Bundle savedInstanceState) {
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
builder.setTitle("Save Password");
builder.setView(getContentView());
Dialog dialog = builder.create();
dialog.show();
return dialog;
}
private View getContentView() {
LayoutInflater inflater = getActivity().getLayoutInflater();
return inflater.inflate(R.layout.dialog, null);
}
}
and this is my main activity where the onclick occurs
private void savePassword() {
SaveDialog savePasswordDialog = new SaveDialog();
savePasswordDialog.show(savePasswordDialog.getSupportFragmentManager(), "tag");
}
Every single time I fire up the onClick, the app crashes. On top of that, currently I am trying to use getSupportFragmentManager, but it says it's undefined.
You should use getSupportFragmentManager(), which is only available in FragmentActivity.
You should change your activity to a fragment one.
Check this answer
Try this..works!!
((AppCompatActivity)activity).getSupportFragmentManager()
Just call getFragmentManager() from your android.support.v4.app.DialogFragment or android.support.v4.app.Fragment. It will return a android.support.v4.app.FragmentManager (this is, the support FragmentManager)
You don't have to manually show the dialog in onCreateDialog(), just returning it is sufficient for DialogFragment to work its magic (and show the dialog) when you call savePassword().
So remove this line from onCreateDialog :
dialog.show();
and it should work. Good luck!
Related
I have a custom dialog which extends AppCompatDialogFragment. I am calling it from within one Fragment of a BottomNavigationBar. It gets dismissed when a message is returned from a ListenerService. It all works well until I switch to a different fragment using one of the icons on the BottomNavigationBar and then back to the fragment with Dialog functionality. The next time I show the dialog the message does not dismiss it.
I have a member variable:
SendingMessageDialog sendingMessageDialog;
When I click a button it calls this to show the dialog:
sendingMessageDialog = new SendingMessageDialog();
sendingMessageDialog.show(getActivity().getSupportFragmentManager(), "Sending Message");
When the message is receive I call this:
sendingMessageDialog.dismiss();
sendingMessageDialog = null;
I have also tried it this way:
private void dismissDialog() {
Fragment prev = getActivity().getSupportFragmentManager().findFragmentByTag("Sending Message");
if (prev != null) {
Log.d(TAG, "dismissDialog: prev is not null");
SendingMessageDialog df = (SendingMessageDialog) prev;
df.dismiss();
}
}
My SendingMessageDialog which extends AppCompatDialogFragment, I have this code in my onCreateDialog:
#NonNull
#Override
public Dialog onCreateDialog(#Nullable Bundle savedInstanceState) {
Log.d(TAG, "onCreateDialog: starting");
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
LayoutInflater inflater = getActivity().getLayoutInflater();
View view = inflater.inflate(R.layout.send_message_dialog, null);
builder.setView(view)
.setTitle("Sending Token")
.setNegativeButton("cancel", new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialogInterface, int i) {
}
});
return builder.create();
}
I have looked up a few post on stackoverflow but none seem to address this specific issue. I saw this one, but there is no cancel() method available. I saw this one but I have to dismiss the dialog when I get a message from another part of the system, so I cannot just do this in-line sort of thing. This one just seemed like a simple mistake of calling show on the wrong dialog. I couldn't quite get a handle on this one, but it's 8 years old and seems to be about the coordination of two dialogs.
Many of the examples identify the dismiss is not working. In my case it is, until I switch fragments using the bottom navigation and then return to the fragment where the dialog process exists.
Nothing special happening in the navigation:
selectedFragment = new RunScenarioListFragment();
and:
getActivity().getSupportFragmentManager()
.beginTransaction()
.replace(R.id.frame_layout_run_scenario,selectedFragment)
.addToBackStack(null)
.commit();
So I have a fragment (WifiSetupFragment) that calls a DialogFragment, and that DialogFragment needs to pass a string back to the original fragment. I know to do this you have an interface in the activity that will send data to the original fragment like so, which I am already doing:
FragmentTransaction transaction = getFragmentManager().beginTransaction();
transaction.addToBackStack(null);
transaction.replace(R.id.content_frag, WifiSetupFragment.newInstance(password));
transaction.commit();
So the first time I call WifiSetupFragment, I haven't created a DialogFragment yet because I haven't clicked on an item to open the dialog. My question is should I just call
WifiSetupFragment.newInstance(null)
and have a null check for the password string in my fragment? Because I don't have a password unless the DialogFragment is open, and it's not always open. If this made no sense, please tell me and I'll try to explain more clearly. I guess it just seems strange to me to have a parameter for a string that might only be sent to this fragment occasionally since the data isn't constantly being passed in.
You don't need to communicate between these Fragments through the Activity. What you can do instead:
Make your WifiSetupFragment.newInstance() accept no parameters.
Make WifiSetupFragment implement a new interface, let's call it OnPasswordSuppliedListener.
Once you create your DialogFragment instance, attach it to a getChildFragmentManager() instead of getFragmentManager().
Now inside of your DialogFragment subclass you can reference WifiSetupFragment by calling getParentFragment().
Cast getParentFragment() to your interface and voila!
Note: I'm assuming you're using Fragments from the support library. Otherwise please be aware that nested Fragments feature was introduced in the API 17.
Your dialog can define an interface allowing to send input password back to parent fragment / activity:
public class TestDialog extends DialogFragment {
private TextView mPasswordView;
private OnPasswordDefinedCallback mCallback;
public static TestDialog newInstance() {
TestDialog dialog = new TestDialog();
return dialog;
}
#Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
// inflate layout for your dialog (it must include edit text for password)
LayoutInflater inflater = getActivity().getLayoutInflater();
View layout = inflater.inflate(R.layout.dialog_test, null);
// getting ui elements from layout
mPasswordView = (TextView) layout.findViewById(R.id.txt_password);
// building dialog
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
builder.setView(layout);
builder.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
try {
mCallback = (OnPasswordDefinedCallback) getTargetFragment();
} catch (ClassCastException e) {
throw new ClassCastException("must implement OnPasswordDefinedCallback");
}
if (mCallback != null) {
// send password back to parent
mCallback.doPasswordDefined(mPasswordView.getText().toString());
}
dismiss();
}
});
return builder.create();
}
public interface OnPasswordDefinedCallback {
void doPasswordDefined(String password);
}
}
Then in WifiSetupFragment you can proceed as follows for opening PasswordDialog:
TestDialog dialog = TestDialog.newInstance();
dialog.setTargetFragment(WifiSetupFragment.this, 1);
dialog.show(getChildFragmentManager(), null);
WifiSetupFragment must of course implement interface OnPasswordDefinedCallback.
I have searched for an answer to this question but none of the answers helped me.
The problem is that I have a DialogFragment that is displayed when a user add a widget (as part of the WidgetConfig). It looks like this:
The dialog is created like this;
Calling activity:
public class AppWidgetConfigure extends Activity {
private void setUp(){
//Config widget code removed
DialogFragment dialog = new ChooserDialog();
dialog.show(getFragmentManager(), "dialog");
}
}
the DialogFragment:
public class ChooserDialog extends DialogFragment {
#Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
choices = getResources().getStringArray(R.array.choices);
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
builder.setTitle(getResources().getString(R.string.widget_dialog_chooser_title));
builder.setPositiveButton(getResources().getString(R.string.widget_dialog_chooser_posBtn), this);
builder.setNegativeButton(getResources().getString(R.string.widget_dialog_chooser_negBtn), this);
builder.setSingleChoiceItems(choices, -1, this);
return builder.create();
}
}
I want the dialog to have a transparent background. Currently, as shown in the picture, there is the WidgetConfigure activity as background.
Thankful for any help.
Marcus
Using below code we can get transparent AlertDialog
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity(),android.R.style.Theme_Translucent);
But in your case you have some choices to be displayed in alert dialog. In that case you need to create a layout with transparent background with choice list and set that layout to dialog.
something like this
View view = getActivity().getLayoutInflater().inflate(R.layout.dialog, null);
builder.setView(view);
This is my static inner class for creating an AlertDialog inside my MainActivity class:
public static class AboutDialogFragment extends DialogFragment {
public static AboutDialogFragment newInstance() {
AboutDialogFragment frag = new AboutDialogFragment();
return frag;
}
#Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
return new AlertDialog.Builder(getActivity())
.setIcon(R.drawable.ic_dialog_about)
.setTitle(R.string.about)
.setMessage(R.string.about_message)
..........
.create();
}
}
And I'm showing it when you press a menu item which is inside MainActivity:
case R.id.about:
DialogFragment aboutFragment = AboutDialogFragment.newInstance();
aboutFragment.show(getSupportFragmentManager(), "about_dialog");
// Make links clickable
((TextView) aboutFragment.getDialog().findViewById(android.R.id.message)).setMovementMethod(LinkMovementMethod.getInstance());
return true;
I'm trying to make the links in the message text clickable using the commented line.
I found this method here and it has worked for me when using a regular Dialog (no fragments). However, this is the first time I have tried using it on a DialogFragment and I always get a NullPointerException when trying to find the view.
I've also tried aboutFragment.getView().findViewById(android.R.id.message) but that returns null as well.
Maybe I am calling the code too early/in the wrong place?
Any ideas would be great!
EDIT: Just tried ((TextView) v.getRootView().findViewById(android.R.id.message)).setMovementMethod(LinkMovementMethod.getInstance());
and
((TextView) v.findViewById(android.R.id.message)).setMovementMethod(LinkMovementMethod.getInstance()); in onCreateView() and also tried in onCreateDialog() without success.
Still getting null pointer exception...
Hopefully you've already figured this out but I just did this same thing and wanted to document it somewhere. Put this in your DialogFragment class:
#Override
public void onStart() {
super.onStart();
((TextView) getDialog().findViewById(android.R.id.message))
.setMovementMethod(LinkMovementMethod.getInstance());
}
Maybe I am calling the code too early/in the wrong place?
That's my suspicion. Is there any reason you can't do your "make links clickable" inside your onCreateDialog() method?
As the time progressed, adding some updated inputs to the query.
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
setupView(view)
}
private fun setupView(view: View) {
toolbar.setNavigationOnClickListener({ v -> dismiss() })
toolbar.title = "New Message"
view.tvTitle.text = arguments?.getString("title")
view.tvBody.autoLinkMask = Linkify.ALL
view.tvBody.text = arguments?.getString("body")
view.tvBody.movementMethod = LinkMovementMethod.getInstance()
}
Most important 2 steps in the above code (which can be used in any dialog textviews) are:
To Linkify
setMovementMethod
After this all links will work fine.
I am trying to get the Dialog I have created with an extended DialogFragment using DialogFragment.getDialog() but it returns null.
Basically I want to alter the text in the layout from the FragmentActivity which creates and shows the DialogFragment.
You're calling getDialog() too early in the DialogFragment's life cycle.
getDialog() simply returns the private variable mDialog from the DialogFragment.
When a DialogFragment is instantiated mDialog is null, and then it gets set when onCreateDialog is fired inside getLayoutInflater(Bundle savedInstanceState), so you have to call getDialog after onCreateDialog.
For example, the order of some common methods called is onCreate, onCreateDialog, and onCreateView, onStart. So, you can call getDialog and have it return something in onCreateView or onStart, but not in onCreate or onCreateDialog.
Even though onStart is called called when the Fragment is visible to the user, adjusting the layout of the fragment at that point looks fine.... for example setting the width and height using getDialog().getWindow().setLayout(..., ...); doesn't make the fragment appear to change size, but just appears to have the newly set size.
Try calling executePendingTransactions() from the available FragmentManager.
dialogFragment = new DialogFragment();
...
dialogFragment.show(mFragmentActivity.getSupportFragmentManager(), "Dialog");
mFragmentActivity.getSupportFragmentManager().executePendingTransactions();
Dialog d = dialogFragment.getDialog()
...
There is 2 way to show DialogFragment:
void showDialog() {
// Create the fragment and show it as a dialog.
DialogFragment newFragment = MyDialogFragment.newInstance();
newFragment.show(getFragmentManager(), "dialog");
}
And
FragmentTransaction ft = getFragmentManager().beginTransaction();
DialogFragment newFragment = MyDialogFragment.newInstance();
ft.add(R.id.embedded, newFragment);
ft.commit();
You can only get a nonNull dialog when using the first way.
public class Dialog extends DialogFragment {
private DialogListener dialogListener;
public void setDialogListener(DialogListener dialogListener) {
this.dialogListener = dialogListener;
}
#Nullable
#Override
public View onCreateView(LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
view = inflater.inflate(R.layout.layout_dialog, null);
return view;
}
#Override
public void onDismiss(DialogInterface dialog) {
super.onDismiss(dialog);
if (null != dialogListener) {
dialogListener.onDismiss();
}
}
public interface DialogListener {
void onDismiss();
}
}
in Activity
...
Dialog dialog= new Dialog();
dialog.setDialogListener(new Dialog.DialogListener() {
#Override
public void onDismiss() {
Foo()..
}
});
One reason for why getDialog() might return null after the dialog has been constructed and properly stored in mDialog is an accidental invocation of dismiss() on the DialogFragment.
When dismiss() is called, it will reset the mDialog field to null so that subsequent invocations of getDialog() will return null instead of the previously constructed dialog.
In my case, dismiss() was called to handle an error situation / side-case in the DialogFragment's onActivityCreated() method. Subsequently trying to use getDialog() from the onResume() method returned null.
Also refer to the source code of the DialogFragment class, specifically its dismissInternal(boolean allowStateLoss) method:
https://github.com/aosp-mirror/platform_frameworks_base/blob/pie-platform-release/core/java/android/app/DialogFragment.java