DialogFragment back button closes to main activity - java

I can't figure out why pressing the hardware back button (or the dialog OK button for that matter) doesn't return me to the initial DialogFragment at times.
I have a DeductionListDialog fragment that is called from the options menu of MainActivity as such:
public boolean onOptionsItemSelected(MenuItem item) {
...
case R.id.action_deduction_list:
DialogFragment newFragment = new DeductionListDialog();
newFragment.show(getFragmentManager(), "dialog");
return true;
default:
return super.onOptionsItemSelected(item);
}
DeductionListDialog then has a couple of onClickListeners within its onCreateDialog method:
// the listview that holds the deduction list
ListView listview = (ListView) view.findViewById(android.R.id.list);
listview.setOnItemClickListener(new OnItemClickListener() {
#Override
// set a short click listener
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
// create a new dialog fragment
DialogFragment deduction_specifics = new DeductionSpecificsDialog();
// / bundle database row so we can get the correct info
// for our specific listing
Bundle arguments = new Bundle();
arguments.putLong("database_row", id);
deduction_specifics.setArguments(arguments);
deduction_specifics.show(getFragmentManager(), "dialog");
}
});
// set the long click listener
listview.setOnItemLongClickListener(new OnItemLongClickListener() {
// on long click we want to open the edit fragment
#Override
public boolean onItemLongClick(AdapterView<?> parent, View view, int position, long id) {
DialogFragment deduction_edit = new DeductionEditFragment();
Bundle arguments = new Bundle();
arguments.putLong("database_id", id);
deduction_edit.setArguments(arguments);
deduction_edit.show(getFragmentManager(), "dialog");
/*Intent deduction_edit_intent = new Intent(getActivity(), DeductionEditActivity.class);
deduction_edit_intent.putExtra("database_id", id);
startActivity(deduction_edit_intent);*/
return true;
}
});
When the listview onItemClick & onItemLongClick listeners are clicked, another dialog pops up with various pieces of information. When I press the back button, or the dialog's OK button, I return to the initial DeductionListDialog fragment as expected.
The DeductionListDialog also has within its onCreateDialog method:
AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(getActivity());
...
alertDialogBuilder.setView(view);
alertDialogBuilder.setTitle("Deductions: ");
alertDialogBuilder.setMessage("Long press to update or delete");
alertDialogBuilder.setPositiveButton("Ok", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
// User clicked OK button
dialog.dismiss();
}
});
alertDialogBuilder.setNegativeButton("Add", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
// User clicked Add button
DialogFragment deduction_edit = new DeductionEditFragment();
Bundle arguments = new Bundle();
deduction_edit.setArguments(arguments);
deduction_edit.show(getFragmentManager(), "dialog");
/*Intent deduction = new Intent(getActivity(), DeductionEditActivity.class);
startActivity(deduction);*/
}
});
When I click the "Add" button, a new DeductionEditFragment is created. When I click back (or the dialog's cancel & accept buttons) I expect the view to go back to the original DeductionListDialog fragment, but clicks simply result in the fragment closing back to the MainActivity.
1) Why is this the case as I'd like to learn how to prevent this in the future.
2) What's the quickest way to resolve this issue?
3) What's the 'proper' way of resolving this issue if differenct from #2?
A pastebin of the entire three classes (DeductionListDialog, DeductionEditDialog, DeductionSpecificsDialog) can be found here: http://pastebin.com/AJQ6KCEN
Thanks all.

Related

Creating a different activity within main activity triggered by a button

I have rather simple task to complete, but I can't get my head around it, I have my main class here, I choosing between screens using buttons, My task is to create a About page just explaing the rules of the game (my application).
public class Hashi_Main extends Activity implements OnClickListener {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
// Set up click listeners for all the buttons
View continueButton = findViewById(R.id.continue_button);
continueButton.setOnClickListener(this);
View newButton = findViewById(R.id.new_button);
newButton.setOnClickListener(this);
View aboutButton = findViewById(R.id.about_button);
aboutButton.setOnClickListener(this);
View exitButton = findViewById(R.id.exit_button);
exitButton.setOnClickListener(this);
}
// click handling
public void onClick(View view) {
switch (view.getId()) {
case R.id.exit_button:
finish();
break;
case R.id.new_button:
NewGame();
break;
case R.id.about_button:
NewGame();
break;
}
}
And here i create a my NewGame activity this all works.
public void NewGame() {
// We first ask for the difficulty level.
new AlertDialog.Builder(this)
.setTitle(R.string.new_game_title)
// we provide a char array with the on click listener.
.setItems(R.array.difficulty,
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialoginterface, int hardness) {
Intent intent = new Intent(Hashi_Main.this, HashiGame.class);
intent.putExtra(HashiGame.KEY_DIFFICULTY, hardness);
startActivity(intent);
}
})
.show();
}
What I want to do is the same thing but to use it for about page, I want to use TextView for the rules, this activity will have nothing else except text and a back to main menu button. I tried something like this.
public void About() {
LinearLayout lheader = new LinearLayout(this);
lheader.setOrientation(LinearLayout.HORIZONTAL);
TextView about_rules = new TextView(this);
about_rules.setId(about_id);
lheader.addView(about_rules);
}
But I am stuck for a while now, how can i trigger this activity?
Create an about activity and use an intent to launch your newly created activity. like so:
Intent intent = new Intent(Hashi_Main.this, AboutActivity.class);
startActivity(intent);
I cannot see any Activity in the About() method. It is just a local LinearLayout with a TextView.
You need to learn more about Android development before making any app.

Returning Data from a Dialog Fragment to the Activity that Called It

Hey fellow stackoverflowers!!!
I'm wondering what the best way to pass a string taken from a Dialog Fragment based on user input on the Dialog into the main activity which called the string?
Here's my specific example but it's really long so if you don't feel like going through it don't worry about everything below.
Here's my source code, I've ommitted the imports n stuff
public class GroupNameFragment extends AppCompatDialogFragment {
private EditText edittGroupName;
public static String GROUP_NAME = "com.example.mashu.walkinggroup.controller - groupName";
// When the views are inflated, get access to them
#Override
public void onViewCreated(View view, #Nullable Bundle savedInstanceState) {
edittGroupName = Objects.requireNonNull(getView()).findViewById(R.id.edittGroupName);
}
#NonNull
#Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
// Get reference to fragment's layout
View view = LayoutInflater.from(getActivity())
.inflate(R.layout.group_name_layout, null);
// OK button listener
DialogInterface.OnClickListener listener = (dialog, which) -> {
if (which == DialogInterface.BUTTON_POSITIVE) {
// If OK pressed, create bundle to be accessed in OnDismissListener in MapActivity,
// which contains the groupName user inputted
String groupName = edittGroupName.getText().toString();
Bundle bundle = new Bundle();
bundle.putString(GROUP_NAME, groupName);
setArguments(bundle);
}
};
// Build alert dialog
return new AlertDialog.Builder(getActivity())
.setTitle("Choose your Group Name!")
.setView(view)
.setPositiveButton(android.R.string.ok, listener)
.create();
}
// Extracts groupName from the bundle set up in the onClickListener above
public static String getGroupName(GroupNameFragment dialog) {
Bundle bundle = getArguments();
return bundle.getString(GROUP_NAME);
}
}
What I attempted to do was to this: First, I get access to the EditText that the user will type in their response. Then I set the Dialog Listener for the OK button which creates a bundle using the setArguments function which contains the groupName when the user is done, which will be accessed in the other activity later on by using the static getGroupName function. Here's the function in the main activity which creates the Dialog and sets the onDismissListener
private void createGroupNameDialog() {
// Instantiate Dialog
// Support Fragment Manager for backwards compatibility
FragmentManager manager = getSupportFragmentManager();
GroupNameFragment dialog = new GroupNameFragment();
dialog.show(manager, "GroupNameDialog");
// OnDismissListener callback function to be run whenever dialog dismissed.
dialog.getDialog().setOnDismissListener(new DialogInterface.OnDismissListener() {
#Override
public void onDismiss(DialogInterface dialogInterface) {
// Update groupName based on what user inputted and update marker name at origin
groupName = GroupNameFragment.getGroupName(dialog);
originMarker.setTitle(groupName);
}
});
}
I think the problem is in groupName = GroupNameFragment.getGroupName(dialog). I feel like theres a better way to get the bundle here, and it seems weird to use the function as static and then pass in specific instance of GroupNameFragment in order to get the bundle (wouldn't that instance be gone by then since it's being used in the "OnDismiss"?). Also, the app crashes the second createGroupNameDialog is called, but it doesn't crash and actually opens the dialog window if I comment out the OnDismissListener, so I'm sure the problems in there somewhere but I don't know why it crashes before the dialog box even opens since OnDismiss happens AFTER the user dismisses the Dialog Box.
Thanks!!!
I accomplished passing variables back using an interface and listeners. I'll show you how I handled it (although I used a DialogFragment, this should still work for AlertDialogs, and in this example I passed an integer, not a string, but it would work for any data type).
public class DialogFragmentOtherMedia extends DialogFragment {
int dialogResult;
//The interface is important!
public interface YesNoListener {
void onYesOtherMedia(int output);
void onNoOtherMedia(int output);
}
//Checking for ClassCastException is nice here.
#Override
public void onAttach(Activity activity) {
super.onAttach(activity);
if (!(activity instanceof YesNoListener)) {
throw new ClassCastException(activity.toString() + " must implement YesNoListener");
}
}
#Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
dialogResult = 0;
final String mediaType[] = {getString(R.string.Ringtones),getString(R.string.Music),getString(R.string.Alarms)};
return new AlertDialog.Builder(getActivity())
.setTitle(getString(R.string.Select_Other_Media_Type))
.setSingleChoiceItems(mediaType, dialogResult, new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
//Log.d("DialogFragmentOtherMedia.onCreateDialog","Item clicked: " + mediaType[which]);
dialogResult = which;
}
})
.setPositiveButton(android.R.string.yes, new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
//Casting the activity to YesNoListener is very important here!
//You'll register the listener in the activity later, by implementing the interface.
((YesNoListener) getActivity()).onYesOtherMedia(dialogResult);
}
})
.setNegativeButton(android.R.string.no, new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
//Same thing for your other callbacks.
((YesNoListener) getActivity()).onNoOtherMedia(dialogResult);
}
})
.create();
}
}
Then you just need to implement it in your activity where you called the dialog from:
public class AlarmDetailsActivity extends Activity
DialogFragmentOtherMedia.YesNoListener {
//All of your activity stuff here...
#Override
public void onYesOtherMedia(int result) {
Log.i("Tag", "onYes Result: " + result);
}
#Override
public void onNoOtherMedia(int result) {
Log.i("Tag", "onNo Result: " + result);
}
}
Sorry about all of the random strings and extra alert dialog. I just wanted to show some actual working code from my app. I tried to add comments next to the important stuff. Hope this helps!

How to fix automatic view another activity on spinner onItemSelected methods

I'm working on simple android project that require spinner widget in android studio. what i want to do is, when a user select choices from the spinner it will open another activity. while i'm in the middle of the coding. I decided to use switch case condition with Intent. The problem is whenever i run the application it will automatically go to the specific activity location that i declare. Even though I didn't select any choice on spinner.
Note: log cat doesn't show any error
Your help is very much appreciated to beginner like me.
public class CustomOnItemSelectedListener extends Activity implements
OnItemSelectedListener {
public void onItemSelected(AdapterView<?> parent, View view, int pos,
long id) {
// **************************** below here is where I start the new activity
switch (pos) {
case 0 :
Intent i = new Intent(app.this, home.class);
app.this.startActivity(i);
break;
case 1 :
//Intent intent = new Intent(app.this, about.class);
//app.this.startActivity(intent);
break;
case 2 :
//Intent intent1 = new Intent(app.this, home.class);
//app.this.startActivity(intent1);
break;
}
// **************************** above here is where I start the new activity
}
#Override
public void onNothingSelected(AdapterView<?> arg0) {
// TODO Auto-generated method stub
}
}
Try this
Declare an int in your class, e.g. before onCreate(), then in your onCreate() you assign it to 0. Use this variable to check if its bigger than 0 when selecting something with your spinner, example below.
public class ExampleActivity extends AppCompatActivity {
private int spinnerCheck;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mSpinnerCheck = 0;
mMySpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
#Override
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
int itemId = (int) id;
// For some reason this method is called during initialization, so increment counter once to prevent it from auto selecting first item when loading view
spinnerCheck += 1;
if (spinnerCheck > 1) {
switch (pos) {
case 0:
Intent i = new Intent(app.this, home.class);
app.this.startActivity(i);
break;
case 1:
//Intent intent = new Intent(app.this, about.class);
//app.this.startActivity(intent);
break;
case 2:
//Intent intent1 = new Intent(app.this, home.class);
//app.this.startActivity(intent1);
break;
}
}
}
#Override
public void onNothingSelected(AdapterView<?> parent) {
}
});
}
}
For some reason it selects the first item once created, not sure why, but this should work.
When the application is created by default the first option is selected in your spinner and your listener is called. To avoid this you can use the solution of #Simon
or you can use a button to confirm your selection and change your activity when this button is pressed and not when an item is selected in your spinner.
UPDATE
You can also populate the first entry of your spinner with a useless text which can be a title like "Select activity" and start your switch in the listener to 1 and not 0

How to apply Back button pressed in fragment [duplicate]

This question already has answers here:
Android Fragment handle back button press [duplicate]
(25 answers)
Closed 7 years ago.
I am new on android. I cant handle onBackPressed method. I have an Activity class which has four fragment like A,B,C, D. When i lunched Activity by default Fragment A is active and there are link on fragment A to move another Fragment. I want when move another Fragment like B,C,D from Fragment A and pressed Back button it return to Fragment A and if i pressed Back button from Fragment A it show a dialog box.
I used onBackPressed() like below
public void onBackPressed() {
AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(
MainActivity.this);
// set title
alertDialogBuilder.setTitle("Exit");
// set dialog message
AlertDialog.Builder builder = alertDialogBuilder
.setMessage("Do you really want to exit?")
.setCancelable(false)
.setPositiveButton("Yes", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
// if this button is clicked, close
// current activity
MainActivity.this.finish();
}
})
.setNegativeButton("No", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
// if this button is clicked, just close
// the dialog box and do nothing
dialog.cancel();
}
});
// create alert dialog
AlertDialog alertDialog = alertDialogBuilder.create();
// show it
alertDialog.show();
}
But it work on all fragment and i want to work only Fragment A
You have to handle such requirements in the Activity's onBackPressed only. I usually follow the following approach:
I keep an enum having all the fragments defined and a parameter to track the current fragment:
enum FRAGMENTS{
fragmentA, fragmentB, fragmentC, fragmentD
}
FRAGMENTS mCurrentFragment;
Now the logic where you change the fragment should have:
public void changeFragment(FRAGMENTS newFragment){
//Your logic
mCurrentFragment = newFragment;
}
And finally the logic onBackPressed:
onBackPressed{
if(mCurrentFragment == FRAGMENTS.fragmentA){
//Your code here of asking the user if he/she really wants to quit
super.onBackPressed();
}else{
changeFragment(getPreviousFragment(mCurrentFragment));
}
}
If you dont want to use enum, you can have final int or any other string values to represent different fragments and a mCurrentFragment parameter to keep a track of the currentFragment being shown and then you can easily play with the code in your Activity's onBackPressed method
Let me know if you need more clarification.
Add fragment to backStack while replacing
Fragment newFragment = new ExampleFragment();
FragmentTransaction transaction = getFragmentManager().beginTransaction();
// Replace whatever is in the fragment_container view with this fragment,
// and add the transaction to the back stack if needed
transaction.replace(R.id.fragment_container, newFragment);
transaction.addToBackStack(null);
// Commit the transaction
transaction.commit();
And then override onBackPressed method inside an Activity
So Here is your answer which you are looking for :)
Method 1
#Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_BACK) {
// Your stuff here
AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(MainActivity.this);
// set title
alertDialogBuilder.setTitle("Exit");
// set dialog message
AlertDialog.Builder builder = alertDialogBuilder.setMessage("Do you really want to exit?")
.setCancelable(false).setPositiveButton("Yes", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
// if this button is clicked, close
// current activity
System.exit(0);
}
}).setNegativeButton("No", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
// if this button is clicked, just close
// the dialog box and do nothing
dialog.cancel();
}
});
// create alert dialog
AlertDialog alertDialog = alertDialogBuilder.create();
// show it
alertDialog.show();
}
}
//Tell me if you face any issue
Method 2 or in your case just paste this method in your main activity so you can also achieve it what you want :)
#Override
public void onBackPressed() {
// TODO Auto-generated method stub
AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(MainActivity.this);
// set title
alertDialogBuilder.setTitle("Exit");
// set dialog message
AlertDialog.Builder builder = alertDialogBuilder.setMessage("Do you really want to exit?").setCancelable(false)
.setPositiveButton("Yes", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
// if this button is clicked, close
// current activity
System.exit(0);
}
}).setNegativeButton("No", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
// if this button is clicked, just close
// the dialog box and do nothing
dialog.cancel();
}
});
// create alert dialog
AlertDialog alertDialog = alertDialogBuilder.create();
// show it
alertDialog.show();
}
If you want to override the onBack pressed method then add this code in your in onActivityCreated() method
getView().setFocusableInTouchMode(true);
getView().requestFocus();
getView().setOnKeyListener(new View.OnKeyListener() {
#Override
public boolean onKey(View v, int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_BACK) {
getFragmentManager().popBackStack();
return true;
}
return false;
}
});
Use the below code hope it helps.
//Always replace/add your fragment with a tag so that you can use that tag in future
Fragment fr = getSupportFragmentManager().findFragmentByTag("Fragment_Name");//Fragment Name is a tag to identify fragment
if (fr == null) {
getSupportFragmentManager().beginTransaction()
.replace(R.id.frame_container, new Demo_Fragment(), "Fragment_Name").commit();
}
//Now override onBackPressed method in MainActivity Only no need to do it in Fragment Class
#Override
public void onBackPressed() {
Fragment fr = getSupportFragmentManager().findFragmentByTag("FragmentA");
if(fr==null)
//replace FragmentA
else
//Show Alert Box
}
For that you need to do following
Create method on the BaseFragment or Activity that save the current fragment object
public void setCurrentFragment(Fragment currentFragment) {
this.currentFragment = currentFragment;
}
and also create a method that return your current fragment object
public Fragment getCurrentFragment() {
return currentFragment;
}
now just you need to call the getCurrentFragment Method and checked that if the Fragment is an instance of the A fragment or not
if (getCurrentFragment() instanceof AFragment) {
showAlert
} else {
super.onBackPressed()
}

In Android, how do I create a popup and submit data to the main view?

I've created a Main.xml with buttons. They all perform a certain action and this is all fine, but there should also be password protected buttons. So I also created a second xml (popup.xml). This should pop up if the user presses the button. In popup.xml there is just a textfield for user input and a button to submit.
At the moment I can press on the button and the popup appears, but I don't know how to submit the user input data to the main view or just go back to the main view by pressing the button.
public class BastiLauncherActivity extends Activity implements OnClickListener {
private Button b1;
// ...
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
// this b1 is a button in the main view where this pop up should appear
b1 = (Button) findViewById(R.id.b1Button);
b1.setOnClickListener(this);
// ...
}
#Override
public void onClick(View v) {
LayoutInflater inflater =
(LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
PopupWindow pw = new PopupWindow(inflater.inflate(R.layout.popup, null,
false), 200, 300, true);
pw.setOutsideTouchable(true);
if (v == b1) {
// opening the popup
pw.showAtLocation(findViewById(R.id.dateiButton), Gravity.CENTER, 0, 0);
} else if (...) {
}
}
}
I see you're using a PopupWindow - to remove it you invoke dismiss().
If you just want a pop up to capture some user input then return back to the Activity that spawned the pop up then I would suggest using a Custom Dialog. You can create whatever you like in the dialog, and add whatever buttons you need with handlers for each button. An example;
new AlertDialog.Builder(Main.this)
.setTitle("Enter password")
.setMessage("Password required for this function")
.setView(/* You view layout */)
.setPositiveButton("Ok", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int whichButton) {
Editable value = input.getText();
}
}).setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int whichButton) {
// Do nothing.
}
}).show();

Categories

Resources