I'm using the Navigation component for my two DialogFragments and when I press a button on the first DialogFragment it is dismissed and then the second one is shown. I need to test that clicking this button will take me to the second dialog. I have a simple home fragment that is overlayed by the first DialogFragment at the start of the app. The following code is from the first DialogFragment.
/**
* Redirects users to another dialog after pressing button
*/
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
button.setOnClickListener {
if (findNavController().currentDestination?.id == R.id.firstDialogFragment) {
findNavController().navigateUp()
val action = HomeFragmentDirections.actionHomeFragmentToSecondDialogFragment()
findNavController().navigate(action)
}
}
}
This next bit of code comes from the developer's guide and only checks for the behavior of dismissing a DialogFragment back to the previous Fragment.
#RunWith(AndroidJUnit4::class)
class MyTestSuite {
#Test fun testDismissDialogFragment() {
// Assumes that "MyDialogFragment" extends the DialogFragment class.
with(launchFragment<MyDialogFragment>()) {
onFragment { fragment ->
assertThat(fragment.dialog).isNotNull()
assertThat(fragment.requireDialog().isShowing).isTrue()
fragment.dismiss()
fragment.requireFragmentManager().executePendingTransactions()
assertThat(fragment.dialog).isNull()
}
// Assumes that the dialog had a button
// containing the text "Cancel".
onView(withText("Cancel")).check(doesNotExist())
}
}
}
I need some way to test the behavior of a DialogFragment's button and see that it dismisses itself and starts the second DialogFragment.
When I test for the button being clicked, the first DialogFragment is correctly dismissed, but the second DialogFragment is not launched. I've used both Espresso and UiAutomator and the click does occur, but reading the code snippet's explanation for testing DialogFragments it says,
"Even though dialogs are instances of graphical fragments, you use the launchFragment() method so that the dialog's elements are populated in the dialog itself, rather than in the activity that launches the dialog".
Is the reason that I am unable to check if the second DialogFragment exists or not, because it is an instance of a graphical fragment and my click listener for the button on the first DialogFragment cannot implement launchFragment() for the second DialogFragment?
Related
I have an Android application with a dialog and a few buttons inside.
I want to reuse the dialog for different purposes and looking for a way to call the button from a separate class and define an action event for it.
Creating a test class, I managed to define an action event for a button inside a form, but the same code does not work for a button inside a dialog, and I can't get my head around why it is not working for the dialog.
Below is what I already have. Any suggestions would be appreciated.
public Class One {
Test test = new Test();
test.testOne(); // this is working : button prints
test.testTwo(); // this is not working : button does not print
buttonTest = test.getTestButton();
buttonTest.setText("Hello World"); // not working for a button in a dialog
buttonTest.addActionListener(l-> { // prints when the button in a Form
System.out.println("try"); // does not print when the button is in a dialog
});
}
public class Test {
Dialog dialog = new Dialog();
Form form = new Form();
Button button;
public void testOne() {
button = new Button("Test");
form.add(button);
form.show();
}
public void testTwo() {
button = new Button("Testing");
dialog.add(button);
dialog.show();
}
public Button getTestButton () {
return button;
}
}
You add the action listener after showing the form and dialog. This isn't a problem for the form since the forms show method will continue. But a dialogs show() method will block.
Two solutions:
Move the listener binding higher in the code (before the show) that would be a problem since the button doesn't exist yet so you will need some refactoring.
Change the show() call on the dialog to showModless()
I have an app with a bottom navigation and a toolbar.
The bottom navigation opens different fragments and the toolbar is suppose to change depending on the fragment (not implemented yet).
The toolbar is initialized in the main activity and depending on which fragment will be opened the menu of the toolbar will be inflated differently. There are different methods in the main activity which inflate the menu and set up the onClickListeners.
Inside OnCreate in MainActivity
if (savedInstanceState == null) {
supportFragmentManager
.beginTransaction()
.replace(R.id.main_container, QuickNPangFragment.QuickNPangFragment.newInstance(), "activitySelection")
.addToBackStack("navigation_quick")
.commit()
supportFragmentManager.executePendingTransactions()
}
[...]
val toolbar: Toolbar = findViewById(R.id.toolbarNew)
when (supportFragmentManager.getBackStackEntryAt(supportFragmentManager.backStackEntryCount-1).name) {
"navigation_quick" -> setQuickMenu(toolbar)
"navigation_location" -> setLocationMenu(toolbar)
"navigation_friends" -> setFriendsMenu(toolbar)
}
[...]
private fun setQuickMenu(toolbar: Toolbar) {
toolbar.inflateMenu(R.menu.menu_main)
toolbar.setOnMenuItemClickListener {
QuickNPangFragment.QuickNPangFragment.newInstance().setQuickMenuItemClickListener(it.itemId)
true
}
}
Inside QuickNPangFragment
object QuickNPangFragment {
fun newInstance() = QuickNPangFragment()
}
There is something wrong in my understanding of this concept of the singleton: I think that only ONE instance of this fragment will be created, so whenever I call the newInstance() method of the fragment, it will return the same instance.
When running the debugger though it shows that the reference to the QuickNPangFragment object that is added when calling onCreate (this = {QuickNPangFragment#10915}... << this is the address, correct?) is different from the one when setting up the onClickListener in the setQuickMenu method (this = {QuickNPangFragment#11154}).
1) What am making wrong? and/or Where is the misunderstanding of that concept?
2) Is it ok to change the toolbar menu depending on the fragment?
I'm programming a J(2)ME app (actually a MIDlet) where more commands than command buttons available are shown on the screen and I'm stuck with this situation:
The mapping to concrete user interface constructs may also depend on
the total number of the commands. For example, if an application asks
for more abstract commands than can be mapped onto the available
physical buttons on a device, then the device may use an alternate
human interface such as a menu. For example, the abstract commands
that cannot be mapped onto physical buttons are placed in a menu and
the label "Menu" is mapped onto one of the programmable buttons.
http://docs.oracle.com/javame/config/cldc/ref-impl/midp2.0/jsr118/javax/microedition/lcdui/Command.html
So in this situation a Menu is auto-generated and a 'Select' and 'Back' choice added. The 'Back' choice is supposed to exit the menu and go back to the previous screen. This works in principle, problem is I need to catch it somehow and trigger a redraw, otherwise the screen goes blank.
So my question is: Is there a way to catch this 'implicit' (automatically added 'Back' command ?
Code example and result:
public class HelloWorld extends MIDlet
{
private Form helloFrm;
private Display display;
public HelloWorld() {
Command command1 = new Command("Cmd 1", Command.SCREEN, 1);
Command command2 = new Command("Cmd 2", Command.SCREEN, 0);
Command command3 = new Command("Cmd 3", Command.SCREEN, 0);
Command command4 = new Command("Cmd 4", Command.SCREEN, 0);
helloFrm = new Form("Hello World");
helloFrm.addCommand(command1);
helloFrm.addCommand(command2);
helloFrm.addCommand(command3);
helloFrm.addCommand(command4);
}
public void startApp()
{
display = Display.getDisplay(this);
display.setCurrent(helloFrm);
}
public void pauseApp()
{
}
public void destroyApp(boolean unconditional)
{
}
}
edit to add more detail:
As per my comment, I'm going back from a Form to Canvas in my app, that's where the screen blanking happens.
I've already added my own 'Back' command, this one works correctly as I can catch easily with CommandListener and treat accordingly (trigger a redraw). But now I have two 'Back' commands, the implicit one (blanking) and mine.
So the alternative version of the question is: Can I prevent the adding of the implicit 'Back' command somehow ?
You can't prevent the adding of the implicit 'Back' command, but you can redraw the screen from the call to Canvas.showNotify:
The implementation calls showNotify() immediately prior to this Canvas
being made visible on the display. Canvas subclasses may override this
method to perform tasks before being shown, such as setting up
animations, starting timers, etc. The default implementation of this
method in class Canvas is empty.
I would like to create a dialog without the OK/Cancel buttons. I know that if you override the createButton method, this can be achieved.
What do you think of overriding the createButtonBar method to return null if the button bar is not required at all? This would save some code.
Overriding createButtonBar is going to produce errors if you return null for the result composite as the Dialog code expects it to not be null.
You can override createButtonsForButtonBar and not create any buttons. It looks like Dialog always checks that individual buttons exist.
You can remove the space used by the buttons composite like this:
#Override
protected void createButtonsForButtonBar(final Composite parent)
{
GridLayout layout = (GridLayout)parent.getLayout();
layout.marginHeight = 0;
}
If you want to have the only one "Close" button on your dialog, you can do it so:
#Override
public void create() {
super.create();
getButton(IDialogConstants.OK_ID).setVisible(false);
getButton(IDialogConstants.CANCEL_ID).setText("Close");
}
i call this method SolveUpdation (from button- onclickAction Listener) from mainAcitivity with main layout. i use other layout to get value from user and set it as button title in the main layout and that is only instruction that does not works for me
private void SolveUpdation() { //this function call is generated from the main Activity with main layout
setContentView(R.layout.updateappliance); //this is 2nd layout to get values from user and use them as buttonText in the main layout
btnSaveApp = (Button) findViewById(R.id.Bupdatenow);
btnSaveApp.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
// TODO Auto-generated method stub
mOutEditText = (EditText) findViewById(R.id.edit_text_1);
TextView view1 = (TextView) findViewById(R.id.edit_text_1);
final String TitleApp1 = view1.getText().toString(); //the value is read properly here
// if (App1.length() > 0) {
// byte[] send = App1.getBytes();
// }
btnSaveApp.setText(TitleApp1); //this works fine
startActivity(new Intent(HomeScreen.this, HomeScreen.class));//this the main activity for main layout
setContentView(R.layout.main); //this is the main layout and this instruction works
buttonLED1.setText(TitleApp1); //buttonLED1 (a Togglebutton or can be simple) is defined in main layout and this does not works and this is what i am stuck with
SaveAppNamesToast(TitleApp1); //this is just to toast the value and it works fine.
}});
So plz can any one guide me why this instruction buttonLED1.setText(TitleApp1); does not works ??? Any help will be appreciatable.. thanks
No offense, but the way you write your code is not a good practice.
My advise: Stop calling another setContentView in your Main Activity. You should rather implement all needed Buttons and EditTexts in one layout and set their visiblity to gone or visible depending on which button was clicked.
If you don't wanna do this you should create a second class that handles the input of the user. After pressing the save button you initialize your intent for the main activity and give it via intent.putExtra("KEY", value) the input of the user.
Your Main Activity can receive this value via getIntent().getExtras().getInt("KEY").
By the way: I think your current code doesn't work because of the new Activity you start. Through this everything gets initialized again so the buttonLED1 that you see isn't the same buttonLED1 that gets the text.