Show dialog from fragment? - android

I have some fragments that need to show a regular dialog. On these dialogs the user can choose a yes/no answer, and then the fragment should behave accordingly.
Now, the Fragment class doesn't have an onCreateDialog() method to override, so I guess I have to implement the dialogs outside, in the containing Activity. It's ok, but then the Activity needs to report back the chosen answer somehow to the fragment. I could of course use a callback pattern here, so the fragment registers itself at the Activity with a listener class, and the Activity would report back the answer thru that, or something like that.
But this seems to be quite a big mess for a simple task as displaying a "simple" yes-no dialog in a fragment. Also, this way my Fragment would be less self-contained.
Is there some cleaner way to do this?
Edit:
The answer to this question doesn't really explain in detail how one should use DialogFragments to display dialogs from Fragments. So AFAIK, the way to go is:
Display a Fragment.
When needed, instantiate a DialogFragment.
Set the original Fragment as the target of this DialogFragment, with .setTargetFragment().
Show the DialogFragment with .show() from the original Fragment.
When the user chooses some option on this DialogFragment, notify the original Fragment about this selection (e.g. the user clicked 'yes'), you can get the reference of the original Fragment with .getTarget().
Dismiss the DialogFragment.

I must cautiously doubt the previously accepted answer that using a DialogFragment is the best option. The intended (primary) purpose of the DialogFragment seems to be to display fragments that are dialogs themselves, not to display fragments that have dialogs to display.
I believe that using the fragment's activity to mediate between the dialog and the fragment is the preferable option.

You should use a DialogFragment instead.

Here is a full example of a yes/no DialogFragment:
The class:
public class SomeDialog extends DialogFragment {
#Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
return new AlertDialog.Builder(getActivity())
.setTitle("Title")
.setMessage("Sure you wanna do this!")
.setNegativeButton(android.R.string.no, new OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
// do nothing (will close dialog)
}
})
.setPositiveButton(android.R.string.yes, new OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
// do something
}
})
.create();
}
}
To start dialog:
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
// Create and show the dialog.
SomeDialog newFragment = new SomeDialog ();
newFragment.show(ft, "dialog");
You could also let the class implement onClickListener and use that instead of embedded listeners.
Callback to Activity
If you want to implement callback this is how it is done
In your activity:
YourActivity extends Activity implements OnFragmentClickListener
and
#Override
public void onFragmentClick(int action, Object object) {
switch(action) {
case SOME_ACTION:
//Do your action here
break;
}
}
The callback class:
public interface OnFragmentClickListener {
public void onFragmentClick(int action, Object object);
}
Then to perform a callback from a fragment you need to make sure the listener is attached like this:
#Override
public void onAttach(Activity activity) {
super.onAttach(activity);
try {
mListener = (OnFragmentClickListener) activity;
} catch (ClassCastException e) {
throw new ClassCastException(activity.toString() + " must implement listeners!");
}
}
And a callback is performed like this:
mListener.onFragmentClick(SOME_ACTION, null); // null or some important object as second parameter.

For me, it was the following-
MyFragment:
public class MyFragment extends Fragment implements MyDialog.Callback
{
ShowDialog activity_showDialog;
#Override
public void onAttach(Activity activity)
{
super.onAttach(activity);
try
{
activity_showDialog = (ShowDialog)activity;
}
catch(ClassCastException e)
{
Log.e(this.getClass().getSimpleName(), "ShowDialog interface needs to be implemented by Activity.", e);
throw e;
}
}
#Override
public void onClick(View view)
{
...
MyDialog dialog = new MyDialog();
dialog.setTargetFragment(this, 1); //request code
activity_showDialog.showDialog(dialog);
...
}
#Override
public void accept()
{
//accept
}
#Override
public void decline()
{
//decline
}
#Override
public void cancel()
{
//cancel
}
}
MyDialog:
public class MyDialog extends DialogFragment implements View.OnClickListener
{
private EditText mEditText;
private Button acceptButton;
private Button rejectButton;
private Button cancelButton;
public static interface Callback
{
public void accept();
public void decline();
public void cancel();
}
public MyDialog()
{
// Empty constructor required for DialogFragment
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
View view = inflater.inflate(R.layout.dialogfragment, container);
acceptButton = (Button) view.findViewById(R.id.dialogfragment_acceptbtn);
rejectButton = (Button) view.findViewById(R.id.dialogfragment_rejectbtn);
cancelButton = (Button) view.findViewById(R.id.dialogfragment_cancelbtn);
acceptButton.setOnClickListener(this);
rejectButton.setOnClickListener(this);
cancelButton.setOnClickListener(this);
getDialog().setTitle(R.string.dialog_title);
return view;
}
#Override
public void onClick(View v)
{
Callback callback = null;
try
{
callback = (Callback) getTargetFragment();
}
catch (ClassCastException e)
{
Log.e(this.getClass().getSimpleName(), "Callback of this class must be implemented by target fragment!", e);
throw e;
}
if (callback != null)
{
if (v == acceptButton)
{
callback.accept();
this.dismiss();
}
else if (v == rejectButton)
{
callback.decline();
this.dismiss();
}
else if (v == cancelButton)
{
callback.cancel();
this.dismiss();
}
}
}
}
Activity:
public class MyActivity extends ActionBarActivity implements ShowDialog
{
..
#Override
public void showDialog(DialogFragment dialogFragment)
{
FragmentManager fragmentManager = getSupportFragmentManager();
dialogFragment.show(fragmentManager, "dialog");
}
}
DialogFragment layout:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:orientation="vertical" >
<TextView
android:id="#+id/dialogfragment_textview"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="20dp"
android:layout_centerHorizontal="true"
android:layout_marginBottom="10dp"
android:text="#string/example"/>
<Button
android:id="#+id/dialogfragment_acceptbtn"
android:layout_width="200dp"
android:layout_height="wrap_content"
android:layout_marginTop="20dp"
android:layout_centerHorizontal="true"
android:layout_below="#+id/dialogfragment_textview"
android:text="#string/accept"
/>
<Button
android:id="#+id/dialogfragment_rejectbtn"
android:layout_width="200dp"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:layout_alignLeft="#+id/dialogfragment_acceptbtn"
android:layout_below="#+id/dialogfragment_acceptbtn"
android:text="#string/decline" />
<Button
android:id="#+id/dialogfragment_cancelbtn"
android:layout_width="200dp"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:layout_marginBottom="20dp"
android:layout_alignLeft="#+id/dialogfragment_rejectbtn"
android:layout_below="#+id/dialogfragment_rejectbtn"
android:text="#string/cancel" />
<Button
android:id="#+id/dialogfragment_heightfixhiddenbtn"
android:layout_width="200dp"
android:layout_height="20dp"
android:layout_marginTop="10dp"
android:layout_marginBottom="20dp"
android:layout_alignLeft="#+id/dialogfragment_cancelbtn"
android:layout_below="#+id/dialogfragment_cancelbtn"
android:background="#android:color/transparent"
android:enabled="false"
android:text=" " />
</RelativeLayout>
As the name dialogfragment_heightfixhiddenbtn shows, I just couldn't figure out a way to fix that the bottom button's height was cut in half despite saying wrap_content, so I added a hidden button to be "cut" in half instead. Sorry for the hack.

I am a beginner myself and I honestly couldn't find a satisfactory answer that I could understand or implement.
So here's an external link that I really helped me achieved what I wanted. It's very straight forward and easy to follow as well.
http://www.helloandroid.com/tutorials/how-display-custom-dialog-your-android-application
THIS WHAT I TRIED TO ACHIEVE WITH THE CODE:
I have a MainActivity that hosts a Fragment. I wanted a dialog to appear on top of the layout to ask for user input and then process the input accordingly.
See a screenshot
Here's what the onCreateView of my fragment looks
#Nullable
#Override
public View onCreateView(LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_home_activity, container, false);
Button addTransactionBtn = rootView.findViewById(R.id.addTransactionBtn);
addTransactionBtn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Dialog dialog = new Dialog(getActivity());
dialog.setContentView(R.layout.dialog_trans);
dialog.setTitle("Add an Expense");
dialog.setCancelable(true);
dialog.show();
}
});
I hope it will help you
Let me know if there's any confusion. :)

public void showAlert(){
AlertDialog.Builder alertDialog = new AlertDialog.Builder(getActivity());
LayoutInflater inflater = getActivity().getLayoutInflater();
View alertDialogView = inflater.inflate(R.layout.test_dialog, null);
alertDialog.setView(alertDialogView);
TextView textDialog = (TextView) alertDialogView.findViewById(R.id.text_testDialogMsg);
textDialog.setText(questionMissing);
alertDialog.setPositiveButton("Ok", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
dialog.cancel();
}
});
alertDialog.show();
}
where .test_dialog is of xml custom

public static void OpenDialog (Activity activity, DialogFragment fragment){
final FragmentManager fm = ((FragmentActivity)activity).getSupportFragmentManager();
fragment.show(fm, "tag");
}

Related

How to stop Activity attached AlertDialog keep reappearing over Activity after Activity paused and recreated?

I am working on project, which simply validates through username and password.
I made some progress with using DialogFragments and AlertDialog. AlertDialog appears after starting the app over the mainactivity asking for username and password.
I must set the Alertdialog's setCanceledOnTouchOutside(false) and DialogFragment's setCancelable(false) because I don't want the users to dismiss it with pressing android's back button.
The problem is, after dismissing it programatically on successful login, if the activity becomes invisible and visible again , the Alertdialog's OnShowListener called, showing this AlertDialog again.
Can I somehow "detach" this AlertDialog from Activity? This popups also happen after unlocking the screen and getting back to activity which makes it very annoying...
Here is the code of interest:
MainActivity
public class MainActivity extends AppCompatActivity implements NoticeDialogFragment.NoticeDialogListener {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
if(GlobalInformations.getInstance().getUsername()==null){
shownoticeDialog();
}
}
public void shownoticeDialog(){
DialogFragment dialogFragment = new NoticeDialogFragment();
dialogFragment.show(getFragmentManager(), "NoticeDialogFragment");
}
#Override
public void onDismiss(DialogFragment dialog) {
//set the username on a TextView instance, etc...
}
NoticeDialogFragment extends DialogFragment
public class NoticeDialogFragment extends DialogFragment {
public interface NoticeDialogListener{
public void onDialogPositiveClick(DialogFragment dialog);
public void onDialogNegativeClick(DialogFragment dialog);
public void onDismiss(DialogFragment dialog);
}
NoticeDialogListener mListener;
static Activity activity = null;
//static String username;
#Override
public void onAttach(Context context) {
super.onAttach(context);
try{
activity = (Activity) context;
mListener = (NoticeDialogListener) activity;
} catch (ClassCastException e){
throw new ClassCastException(activity.toString() + "must implement NoticeDialogListener");
}
}
#Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
LayoutInflater inflater = getActivity().getLayoutInflater();
View view = inflater.inflate(R.layout.dialog_signin, null);
final AutoCompleteTextView actv_username = (AutoCompleteTextView) view.findViewById(R.id.username);
final EditText password = (EditText) view.findViewById(R.id.password);
getavailableusernames(actv_username);
final AlertDialog dialog = new AlertDialog.Builder(new ContextThemeWrapper(getContext(), R.style.AlertDialogCustom))
.setView(view)
.setTitle("Login")
.setPositiveButton("OK", null)
//.setNegativeButton("Cancel", null)
.create();
dialog.setOnShowListener(new DialogInterface.OnShowListener() {
#Override
public void onShow(DialogInterface dialogInterface) {
final Button button =((AlertDialog) dialog).getButton(AlertDialog.BUTTON_POSITIVE);
button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
String passw = password.getText().toString();
String user = actv_username.getText().toString();
try{
if(user.length()<4 || passw.length()<4){
Toast.makeText(getContext(), "Username/password too short", Toast.LENGTH_SHORT).show();
dialog.show();
}
else {
//login to account, if success dismiss.
login(user, passw,dialog);
}
} catch(Exception e){
}
// dialog.dismiss();
}
});
}
});
dialog.setCanceledOnTouchOutside(false);
// set the DialogFragment to make the dialog unable to dismiss with back button
// (because not working if called on the dialog directly)
this.setCancelable(false);
return dialog;
}
public void login(final String username, String password, final AlertDialog dialog){
boolean login_success = false;
//query the credentials
login_success = dosomesqlquery(username, password);
if(login_success){
dialog.dismiss();
}
}
//passing the handling to activity...
#Override
public void onDismiss(DialogInterface dialog) {
mListener.onDismiss(NoticeDialogFragment.this);
}
}
Thank you for your help and patience.
Well this is that kind of situation where I end up heading my desk continously.
The source of the problem was I called dialog.dismiss() which dismisses the dialog, BUT not the dialogfragment itself, so will never, ever dismissed, even if the dialog disappeared from screen. Placing this.dismiss() in NoticeDialogFragment's onDismiss or anywhere else after login succeded will let the application act as it should.
#Override
public void onDismiss(DialogInterface dialog) {
mListener.onDismiss(NoticeDialogFragment.this);
this.dismiss(); //will dismiss the DialogFragment. Yeeey!
}
Thank you for your time and answers as they helped me point out the real problem. I will modify the code based on your suggestions.
An easier way is to use a static variable in your activity using two steps.
Declare a global static boolean
private static boolean session = false;
Check if the boolean has changed and if not, set the boolean to true when the dialog is shown
public void shownoticeDialog(){
if(session)return;
DialogFragment dialogFragment = new NoticeDialogFragment();
dialogFragment.show(getFragmentManager(), "NoticeDialogFragment");
session = true;
}
Set the value when the activity goes background
#Override
protected void onSaveInstanceState(Bundle outState) {
outState.putBoolean("authUser", GlobalInformations.getInstance().getUsername()==null)
}
and read it when it comes back
#Override
protected void onCreate(Bundle savedInstanceState) {
if(savedInstanceState != null && savedInstanceState.containsKey("authUser")) {
boolean authUser = savedInstanceState.getBoolean("authUser", false);
if(authUser) {
//show or don't show dialog
}
}
}

Calling a method in a Fragment from an AlertDialog

Could you please help with the below:
I am trying to call the method deletePlayer inside the fragment PlayersActivityFragment from the alertdialog NameAlertDialogFragment.
The code is below:
public static class PlayersActivityFragment extends Fragment {
ArrayList<Player> arrayPlayers;
ListView listViewPlayers;
//PlayerAdapter adapter;
public PlayersActivityFragment() {
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
arrayPlayers = new ArrayList<Player>();
View rootView = inflater.inflate(R.layout.fragment_activity_players, container, false);
Button buttonAddPlayer = (Button) rootView.findViewById(R.id.button_addplayers);
buttonAddPlayer.setOnClickListener(new View.OnClickListener(){
public void onClick(View view) {
arrayPlayers.add(new Player("Player", 0));
Player selectedPlayer = arrayPlayers.get(arrayPlayers.size()-1);
((PlayersActivity)getActivity()).showNameDialogFragment(selectedPlayer);
}
});
listViewPlayers = (ListView) rootView.findViewById(R.id.listView_playername);
return rootView;
}
public void deletePlayer(){
arrayPlayers.remove(arrayPlayers.size()-1);
}
}
void showNameDialogFragment(Player player) {
mDialog = NameAlertDialogFragment.newInstance(player);
mDialog.show(getFragmentManager(),"SCORE DIALOG");
}
// Class that creates the AlertDialog
public static class NameAlertDialogFragment extends DialogFragment {
static Player selectedPlayer;
public static NameAlertDialogFragment newInstance(Player player) {
selectedPlayer = player;
return new NameAlertDialogFragment();
}
// Build AlertDialog using AlertDialog.Builder
#Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
// Get the layout inflater
LayoutInflater inflater = getActivity().getLayoutInflater();
final View view = inflater.inflate(R.layout.alertdialog_name, null);
final EditText editTextName = (EditText) view.findViewById(R.id.edittext_name);
return new AlertDialog.Builder(getActivity())
// Inflate and set the layout for the dialog
// Pass null as the parent view because its going in the dialog layout
.setView(view)
.setMessage("Enter Player's Name:")
//Set up Yes Button
.setPositiveButton("Done", new DialogInterface.OnClickListener() {
public void onClick(final DialogInterface dialog, int id) {
mName = editTextName.getText().toString().trim();
selectedPlayer.setName(mName);
}
})
.setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
//PlayersActivityFragment playersActivityFragment = (PlayersActivityFragment) getFragmentManager().findFragmentById(R.id.container);
//playersActivityFragment.deletePlayer();
//((PlayersActivityFragment)getTargetFragment()).deletePlayer();
NameAlertDialogFragment.this.getDialog().cancel();
}
})
.create();
}
}
The two different ways I have tried to call the methods are commented out in the .setNegativeButton onClickListener:
PlayersActivityFragment playersActivityFragment = (PlayersActivityFragment) getFragmentManager().findFragmentById(R.id.container);
playersActivityFragment.deletePlayer();
and
((PlayersActivityFragment)getTargetFragment()).deletePlayer();
Thank you!
First of all, why are all of your classes static? Anyway, here's an answer that should work...
Try using an interface as a callback. For example:
First create an interface.
public interface NameAlertDialogListener {
public void onNegativeClick();
}
Then have PlayersFragment implement NameAlertDialogListener.
public static class PlayersActivityFragment extends Fragment implements NameAlertDialogListener
Next, in the PlayersFragment, create a method called onNegativeClick.
#Override
public void onNegativeClick() {
//delete or whatever you want to do.
}
Create a member variable for the listener:
static Player selectedPlayer;
static NameAlertDialogListener mCallBack;
Next create a method in the dialog fragment called setListener.
public void setListener(NameAlertDialogListener callback) {
try {
mCallBack = callback;
} catch (ClassCastException e){
throw new ClassCastException(callback.toString() + " must implement NameAlertDialogListener" );
}
}
Then, when you create the dialog fragment call the setListener method.
void showNameDialogFragment(Player player) {
mDialog = NameAlertDialogFragment.newInstance(player);
mDialog.setListener(this);
mDialog.show(getFragmentManager(),"SCORE DIALOG");
}
Lastly, in your negative click listener:
.setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
mCallBack.onNegativeClick() ;
NameAlertDialogFragment.this.getDialog().cancel();
}
})
I am not sure if this is the correct way of doing things, but I have come to a working solution.
First I moved ArrayList<Player> arrayPlayers; outside of the PlayersActivityFragment fragment.
Then I moved the method:
public void deletePlayer(){
arrayPlayers.remove(arrayPlayers.size()-1);
}
outside of the PlayersActivityFragment fragment.
I then called the deletePlayer() method inside the alertdialog with the line ((PlayersActivity)getActivity()).deletePlayer();.
Actually, I have a little hack, it's not really good, but it's easy to implement: declare PlayersActivityFragment variable in your DialogFragment. Then change your constructor to:
public static NameAlertDialogFragment newInstance(Player player,PlayersActivityFragment fragment ){
selectedPlayer = player;
NameAlertDialogFragment test = new NameAlertDialogFragment();
test.playerActivityFragment = fragment;
return test;
}
Then you can call playerActivityFragment.deletePlayer() everywhere in your DialogFragment.
P/s: The best way is implement interface, but for lazy coder like me, the method above is better lol!

DialogFragment's weird behavior

I spent all day trying to make this up, but I can't..
This is the problem: I want an yes/no AlertDialog that doesn't disappear on orientation change, so I decided to use DialogFragment.
So I prepared the code and for the first use, everything with it is just perfect, but if I hit the button (that should show the dialog) once more (second, third and further times) the dialog doesn't show up! Though I can see from logs it actually makes instances and I have no errors, it's there, I just can't see it!
If I fold the app, or turn off / on the screen (I believe it's about calling onResume() method) the dialogs shows up, all of them (depending how much time I hit the button), it seems like a some displaying issue or refreshing problem maybe.. I don't know, so I came here hoping to get some help.
About my code:
I have a ListView with custom adapter, and in that adapter I have the code to show the an AlertDialog (DialogFragment) - as part of an ImageButton onClickListener.
The code for DialogFragment that I use:
public static class cMyDialogFragment extends DialogFragment {
public static cMyDialogFragment newInstance(int title) {
cMyDialogFragment frag = new cMyDialogFragment();
Bundle args = new Bundle();
args.putInt("title", title);
frag.setArguments(args);
return frag;
}
#Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
int title = getArguments().getInt("title");
this.setCancelable(true);
setRetainInstance(true);
return new AlertDialog.Builder(getActivity())
// .setIcon(R.drawable.alert_dialog_icon)
.setTitle(title)
.setPositiveButton(R.string.yes,
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int whichButton) {
((ActAudiorecords) getActivity()).doPositiveClick();
}
}
)
.setNegativeButton(R.string.no,
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int whichButton) {
((ActAudiorecords) getActivity()).doNegativeClick();
}
}
)
.create();
}
}
The code for calling the dialog to show up (within the custom ListView adapter):
public View getView(final int position, View convertView, ViewGroup parent) {
View vi = convertView;
if (vi == null)
vi = inflater.inflate(R.layout.recordings_row, null);
TextView tvDate = (TextView) vi.findViewById(R.id.tv_Recordings_r_date);
tvDate.setText(ainfo.get(position).getDate());
ImageButton ibtn_play = (ImageButton) vi.findViewById(R.id.ibtnPlay);
final String localPath = dPath + File.separator + ainfo.get(position).getFName();
ImageButton ibtn_remove = (ImageButton) vi.findViewById(R.id.ibtnRecordings_r_remove);
ibtn_remove.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
curFName = ainfo.get(position).getFName();
curID = ainfo.get(position).getID();
showDialog();
}
});
ibtn_play.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
play(localPath);
}
});
return vi;
}
The additional functions:
void showDialog() {
DialogFragment newFragment = cMyDialogFragment.newInstance(
R.string.do_you_want_to_remove_the_file);
newFragment.show(getFragmentManager(), "dialog");
}
public void doPositiveClick() {
// Do stuff here.
ps_db.delete(const_audiorecords_tname, "id = " + curID, null);
new File(dPath + File.separator + curFName).delete();
Toast.makeText(ActAudiorecords.this, getString(R.string.audiorecord_has_been_removed), Toast.LENGTH_LONG).show();
ActAudiorecords.this.onCreate(null); //Restarting the Activity to refresh the LV
Log.i("FragmentAlertDialog", "Positive click!");
}
public void doNegativeClick() {
// Do stuff here.
Toast.makeText(ActAudiorecords.this, getString(R.string.the_operation_has_been_cancelled), Toast.LENGTH_LONG).show();
Log.i("FragmentAlertDialog", "Negative click!");
}
I have no onResume() in my code.
I tried to use different codes for DialogFragment but it doesn't matter.
It was all due to the line:
ActAudiorecords.this.onCreate(null);
So after calling onCreate() with null as savedInstance it have been removing link to the DialogFragment (as I can understand), it was the line for refreshing the Activity, I solved the problem by splitting the code in onCreate() to which should be called only once (at a start of Activity) and the part that should be called in every refreshing point (such as GUI settings and etc).
I believe I could also save the current Bundle and pass it to onCreate() instead of null and it would work as good as now, but I thought that calling an function is much better for data updating than calling onCreate() over and over, so that's it, thank you all who wanted to help.

Exception when showing a dialog after orientation change

I have an activity and a fragment inside it.inside fragment, there is a button, and on click of button a dialog shows.
Everything works, until user do a orientation change and click button after it.
IllegalStateException(cannot perform this action after onsaveinstancestate) occurs when user clicks button after orientation change. I'm using android support framework.
Anybody have any idea regarfing this?
Activity Code
public void openMoreDialog(String shareData, String link) {
DialogFragment dialog = new MoreDialog(shareData, link);
dialog.show(getSupportFragmentManager(), "MoreDialog");
}
Fragment Code
public void onAttach(Activity activity) {
super.onAttach(activity);
mControl = (ActivityControl)activity;
}
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_main, container, false);
ImageButton moreButton = (ImageButton)v.findViewById(R.id.moreButton);
moreButton.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
mControl.openMoreDialog(shareData, link);
}
});
return rootView;
}
FragmentDialog code
public class MoreDialog extends DialogFragment {
private String mShareData;
private String mLink;
public MoreDialog(String shareData, String link){
mShareData = shareData;
mLink = link;
}
#Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
// Get the layout inflater
LayoutInflater inflater = getActivity().getLayoutInflater();
View dialogView = inflater.inflate(R.layout.more_dialog, null);
Button openBtn = (Button)dialogView.findViewById(R.id.openBtn);
openBtn.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
openLink(mLink);
}
});
Button shareBtn = (Button)dialogView.findViewById(R.id.shareBtn);
shareBtn.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
shareNews(mShareData);
}
});
builder.setView(dialogView);
return builder.create();
}
private void openLink(String link){
}
private void shareNews(String data){
}
}
Helpful link & solution how to:
https://stackoverflow.com/a/17413324/619673 and btw, constructor in fragment must be empty! Documentation:
http://developer.android.com/reference/android/app/Fragment.html
public Fragment ()
Added in API level 11
Default constructor.
Every fragment must have an empty constructor, so
it can be instantiated when restoring its activity's state. It is
strongly recommended that subclasses do not have other constructors
with parameters, since these constructors will not be called when the
fragment is re-instantiated; instead, arguments can be supplied by the
caller with setArguments(Bundle) and later retrieved by the Fragment
with getArguments().
Applications should generally not implement a constructor. The first
place application code an run where the fragment is ready to be used
is in onAttach(Activity), the point where the fragment is actually
associated with its activity. Some applications may also want to
implement onInflate(Activity, AttributeSet, Bundle) to retrieve
attributes from a layout resource, though should take care here
because this happens for the fragment is attached to its activity.

Android: How to create a Detail alertdialog

I've been playing around with alert dialogs. I want to show a dialog that shows particular information about a list item in listview. Just like the android's file manager's detail dialog.
Picture: https://dl.dropbox.com/u/20856352/detailsbox.jpg
Interesting thing about this Details dialog is that it shows list items which are very similar to Preference item in a Preferences Screen. They can be clicked upon, they're showing a very nicely laid out two-line item listitem.
I need to create a similar dialog box but I've no clue how to accomplish this. I've played around a bit. Preference XML cannot be used as alertdialog's layout. And I'm unable to develop a layout that looks similar to the above pic. Need help / guideline how to achieve this.
Faraz Azhar
You probably don't want to use a custom dialog because it will be difficult to replicate the look of the AlertDialog. An AlertDialog can display a list of items using AlertDialog.setListAdapter. You can customize the list of items to show two rows of text per item by using a custom implementation of ListAdapter. The attached screenshot was produced by the below code and xml.
public class Temp extends Activity
{
private String[] listItemsFirstRow = {"item 1", "item 2", "item 3"};
private String[] listItemsSecondRow = {"item 1", "item 2", "item 3"};
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setAdapter(new MyAdapter(), null);
builder.setTitle("Title");
builder.setPositiveButton(android.R.string.ok, new OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
}
});
builder.show();
}
class MyAdapter extends BaseAdapter
{
#Override
public int getCount()
{
return listItemsFirstRow.length;
}
#Override
public Object getItem(int position)
{
//this isn't great
return listItemsFirstRow[position];
}
#Override
public long getItemId(int position)
{
return position;
}
#Override
public View getView(int position, View convertView, ViewGroup parent)
{
if(convertView == null)
{
convertView = getLayoutInflater().inflate(R.layout.main, null);
}
((TextView)convertView.findViewById(R.id.text1)).setText( listItemsFirstRow[position]);
((TextView)convertView.findViewById(R.id.text2)).setText( listItemsSecondRow[position]);
return convertView;
}
}
}
main.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:minHeight=![enter image description here][2]"?android:attr/listPreferredItemHeight"
android:orientation="vertical"
android:gravity="center_vertical"
android:paddingLeft="15dip"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<TextView
android:textAppearance="?android:attr/textAppearanceLarge"
android:id="#+id/text1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<TextView
android:textAppearance="?android:attr/textAppearanceSmall"
android:textColor="?android:attr/textColorSecondary"
android:id="#+id/text2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
</LinearLayout>
Just made your xml file same as regular screen/page
then put this code on your onCreate()
AlertDialog.Builder builder;
LayoutInflater inflater = getLayoutInflater();
View layout = inflater.inflate(R.layout.toast_info,
(ViewGroup) findViewById(R.id.toast_layout_root));
builder = new AlertDialog.Builder(this);
builder.setView(layout);
alertDialog = builder.create();
which r.layout.toast_info is your xml file
and r.id.toast_layout_root is your root xml id (eg. '<'linearlayout android:id="+#id...."'>' )
and when you want to show it just write this line
alertDialog.show();
My suggestion would be to use an Activity as a dialog. This way it is pretty easy to create a custom dialog. Here is a small example which I think you can build upon.
**Activity**
public class CustomDialogEx extends Activity implements OnClickListener {
private Button button;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.your_layout);
button = (Button) findViewById(R.id.button1);
button.setOnClickListener(this);
}
#Override
public void onClick(View v) { // pass your string data via this intent to the custom view
// show the custom dialog
Intent i = new Intent();
// i.putExtra(<your key/value pairs here>
i.setClass(this, DialogActivity.class);
startActivity(i);
}
}
****************************************************************************
**Custom Dialog**
// The Activity will serve as the Dialog
public class DialogActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.your_dialog_layout);
Intent i = new Intent();
Bundle b = getIntent().getExtras();
b.getString(<your key>)
}
}
*****************************************************************************
**AndroidManifest**
<activity
android:name="DialogActivity"
android:configChanges="keyboardHidden|orientation"
android:theme="#android:style/Theme.Dialog" >
</activity>
this may also help you
public class ShareDialog extends Dialog implements android.view.View.OnClickListener{
Context mcontContext;
Button btnok;
Listview lstview;
public ShareDialog(Context context) {
super(context);
mcontContext= context;
//pls replace with your dialog.xml file
setContentView(R.layout.sharedialog);
bindComponent();
addListener();
}
private void bindComponent() {
// TODO Auto-generated method stub
lstview=(Listview) findViewById(R.id.lstdetail);
btnok=(Button) findViewById(R.id.btnok);
//bind here listview with your adpter
}
private void addListener()
{
btnshareviwifi.setOnClickListener(this);
}
#Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.btnok:
dismiss();
break;
default:
break;
}
}
}
and where you want to show
ShareDialog shobje=new ShareDialog (context);
shobje.show()

Categories

Resources