From an activity, I can easily setup the onActivityResult() and call startActivityForResult() and everything works fine.
Now, I need to call startActivityForResult() from the Dialog. But I can't setup the onActivityResult(), I believe Dialog is not an Activity.
How do I get the result?
I try something like this inside a dialog but it failed.
//create new Intent
Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
intent.putExtra(MediaStore.EXTRA_OUTPUT, m_PicUri);
((Activity) getContext()).startActivityForResult(intent, Const.TAKE_PIC_ACTIVITY_RET_CODE);
You can declare your Activity to have a Dialog theme. Look into this SO question: Android Activity as a dialog
You would change this in your AndroidManifest.xml file:
<activity android:theme="#android:style/Theme.Dialog" />
You should be able to use startActivityForResult() like normal. I know the BluetoothChat example Android program uses something similar to return the Bluetooth device that you choose from a Dialog list.
if your dialog is a dialog fragment you can use
getActivity().startActivityForResult(intent);
in this way the result is sent to the activity that created the dialog
You can use DialogFragment instead of Dialog. Because The dialog is secondary to its activity. When you start the activity with startActivityForResult(), your dialog gets dismissed
Another Example Use Callback
Create Interface
public interface DialogCallback {
void getResults(String results);
}
Create DialogFragment
public class DialogFragment extends DialogFragment {
DialogCallback dialogCallback;
public DialogFragment setCallBack(DialogCallback dialogCallback){
this.dialogCallback = dialogCallback;
return this;
}
#NonNull
#Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
return super.onCreateDialog(savedInstanceState);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.your_layout, container, false);
return view;
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
#Override
public void onDismiss(DialogInterface dialog) {
super.onDismiss(dialog);
dialogCallback.getResults("hello");
}
}
In your Activity
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
new DialogFragment().setCallBack(dialogCallback).show(getFragmentManager(),"");
}
DialogCallback dialogCallback = new DialogCallback() {
#Override
public void getResults(String results) {
if(results!=null){
Log.e(TAG,results);
}
}
};
Output
When you dismiss the DialogFragment you will see the "hello" Log in your Activity
Use the compatibility package then build your dialog using DialogFragment
On the dialog constructor pass the reference of parent Activity, then you can use in the dialog like this,
parentActivity.startActivityForResult(intent, CODE);
Related
I'm trying to load fragment after alert Dialog response but when i attempt to load logcat shows "IllegalStateException: Fragment not attached to Activity". Generally IllegalStateException comes when you try to perform work after the Fragment is no longer attached to the Activity. but in my case every thing is fine i don't understand why fragment is not attached to an activity.
this is my MainActivity:
using this class i call DilogCreate which extends DialogFragment.
public class MainActivity extends AppCompatActivity {
Button btn;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
btn= (Button) findViewById(R.id.button);
btn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
new DilogCreate(view.getContext(),R.string.tilte,R.string.no,R.string.yes);
}
});
}
this is my DilogCreate class:
on the basis of dialog response decide fragment can be loaded or not if dialog response yes i call another activity name Second.java under this class i try to load fragment.
public class DilogCreate extends DialogFragment {
AlertDialog alertDialog;
public DilogCreate(final Context context, int tilte, int no, int yes) {
AlertDialog.Builder mAlertDilog = new AlertDialog.Builder(context);
mAlertDilog.setNegativeButton(yes, new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialogInterface, int i) {
Intent intent = new Intent(context, second.class);
startActivity(intent);
}
});
alertDialog = mAlertDilog.create();
alertDialog.show();
}
}
this is my my Second.java class:
this class is appear because of dialog response and under this class i tried to load fragment.
public class Second extends AppCompatActivity {
FragmentManager fragmentManager;
FragmentTransaction fragmentTransaction;
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.loadFragment);
fragmentManager=getSupportFragmentManager();
fragmentTransaction=fragmentManager.beginTransaction();
Myfragment myfragment=new Myfragment();
fragmentTransaction.replace(R.id.cont,myfragment);
fragmentTransaction.commit();
}
}
this is MyFragment.java extends Fragment :
public class Myfragment extends Fragment{
#Nullable
#Override
public View onCreateView(LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
return inflater.inflate(R.layout.frag,container,false);
}
}
Logcat status:
java.lang.IllegalStateException: Fragment DilogCreate{8aea1d4} not attached to Activity
please help me guys i have no idea why this error is coming.
new DilogCreate(view.getContext(),R.string.tilte,R.string.no,R.string.yes);
pass MainActivity.this instead of view.getContext().You need to pass activity context here.
fragment is load on the activity and one activity switch to another by using base reference that's why i need to call startActivity() method using base Activity refrence.
so i change startActivit() method in the DilogCreate class like this:
Intent intent=new Intent(context,Second.class);
context.startActivity(intent);//make sure context is the refrence of the base context
I'm trying to create an AlertDialog where both a message (in a TextView, for instance) and a MultiChoice-list can be displayed at the same time, but I'm a bit lost as to how to do it.
Will I have to create my own subclass of AlertDialog, or is there an easier way to do it?
You could create a normal AlertDialog but, instead of using the setMessage() method, you could just use a custom layout (you can inflate it in a View or even create a custom view) and use then the setView() method of the AlertDialog class.
Use DialogFragment for customization
public class ResponseDialog extends DialogFragment implements View.OnClickListener{
#Override
public void onActivityCreated(Bundle arg0) {
super.onActivityCreated(arg0);
getDialog().getWindow()
.getAttributes().windowAnimations = R.style.DialogAnimationFromDown;
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setStyle(DialogFragment.STYLE_NO_TITLE, android.R.style.Theme_Black_NoTitleBar);
}
#Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
Dialog dialog = super.onCreateDialog(savedInstanceState);
dialog.getWindow().setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));
return dialog;
}
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.YOUR_CUSTOM_LAYOUT, null);
//implement in layout what you want
return v;
}
public void onDismiss(DialogInterface dialog) {
super.onDismiss(dialog);
}
public void onCancel(DialogInterface dialog) {
super.onCancel(dialog);
}
}
}
for more info https://developer.android.com/reference/android/app/DialogFragment.html
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.
Is it possible to show multiple Dialogs one over another? Is there something like Dialog Z-Level?
I am using DialogFragment where user chooses elements, when he comfirms his choice, it is saved to database and sent on server. if the save action fails I would like to inform user with ... another dialog is it possible? And will it not clear off my first dialog?
Thanks in advance.
Indeed, it's possible to show multiple dialog Fragments one inside another one. The z-order depends on the order they are created.
In the code below there is an example of a FragmentActivity with the behavior that you require.
public class MyActivity extends FragmentActivity {
#Override
public void onCreate(Bundle savedInstanceState) {
//...
}
public void onSave(View view) {
Intent intent = getIntent();
this.setResult(RESULT_OK, intent);
finish();
}
public void onCancel(View view) {
finish();
}
public void SelectWeekDay(View view) {
DialogFragment selectWeekDayFragment = new SelectWeekDayFragment();
selectWeekDayFragment.show(getSupportFragmentManager(), "WeekDayDialog");
}
public class SelectWeekDayFragment extends DialogFragment {
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.week_day_dialog, container, true);
Button saveButton = (Button) view.findViewById(R.id.button_save);
saveButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
CheckBox checkboxMonday = (CheckBox) getDialog().findViewById(R.id.checkBox_monday);
if (!checkboxMonday.isChecked()) {
DialogFragment saveErrorFragment = new SaveErrorFragment();
saveErrorFragment.show(getSupportFragmentManager(), "SaveErrorFragment");
}
else {
SaveToDb(); //Perform actions to store on db or what you wish
dismiss();
}
}
});
Button cancelButton = (Button) view.findViewById(R.id.button_cancel);
cancelButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
dismiss();
}
});
return view;
}
}
public class SaveErrorFragment extends DialogFragment {
#Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
return new AlertDialog.Builder(getActivity())
.setMessage("You must select Monday").setPositiveButton("Ok", null).create();
}
}
}
My advice is to use a custom layout with a ViewFlipper inside your dialog so you can easily switch between a progress-bar or whatever different layouts you want to show. If you want to show multiple Dialogs my guess is that the z-order depends on the order they were created the latest beeing shown on top.
You usually can, however, just be a little careful. Use the dialog's lifecycle to your advantage to avoid side-effects. For example: you can do a check on a function like onStop() to see if the child dialog is open, and if so, close it.
Ideally, cutting down on the amount of layers of dialogs you have is ideal, as long as it's sane (for example: doing it ends up being hundreds of lines of code more)
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");
}