Object in Kotlin/Singleton -> different instance (?) - object

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?

Related

How to test navigation from DialogFragment to another DialogFragment?

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?

Dialog values with MvvmCross, ActionBarSherlock and DialogFragment

I have a bunch of different libraries trying to work together and I'm pretty close but there's just one issue.
I have created a class called SherlockDialogFragment inheriting from SherlockFragment (rather than using the SherlockListFragment - this is because of the issue with the keyboard that's covered here). Here is my code:
public class SherlockDialogFragment : SherlockFragment
{
public RootElement Root
{
get { return View.FindViewById<LinearDialogScrollView>(Android.Resource.Id.List).Root; }
set { View.FindViewById<LinearDialogScrollView>(Android.Resource.Id.List).Root = value; }
}
public override View OnCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
var ignored = base.OnCreateView(inflater, container, savedInstanceState);
var layout = new LinearLayout(Activity) { Orientation = Orientation.Vertical };
var scroll_view = new LinearDialogScrollView(Activity)
{
Id = Android.Resource.Id.List,
LayoutParameters = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.FillParent, ViewGroup.LayoutParams.FillParent)
};
layout.AddView(scroll_view);
return layout;
}
}
I then do the regular thing of creating an eventsource class which inherits from this but also uses IMvxEventSourceFragment, then the actual fragment class (which I call MvxSherlockDialogFragment) which inherits the eventsource class, as well as IMvxFragmentView.
That all works fine (and indeed I've created a SherlockDialogActivity the same way and it's fine), however the one issue is when I use this fragment on a screen with tabs (i'm using a class I made similarly to above called MvxSherlockFragmentActivity). When switching to the tab with the dialog, the view appears fine, even with pre-populated data. However the issue is when I switch away from that fragment/tab, and then back to it, the dialog elements all have the same value.
In my particular example, it's a login page with a username and password. When I first go into the fragment, everything is fine. When I go out and back in, the password value is in both the username field and the password field.
I'm sure it's got something to do with the SherlockDialogFragment class - in the SherlockDialogActivity class I also have this bit:
public override void OnContentChanged()
{
base.OnContentChanged();
var list = FindViewById<LinearDialogScrollView>(Android.Resource.Id.List);
if (list == null)
{
throw new RuntimeException("Your content must have a ViewGroup whose id attribute is Android.Resource.Id.List and is of type LinearDialogScrollView");
}
list.AddViews();
}
However this doesn't work in a fragment because there's no OnContentChanged event. Also, another difference is that in the SherlockDialogActivity, the layout is being created ONCE in the OnCreate event - however in the SherlockFragmentActivity I've got it being created each time the fragment is viewed. I know that's probably not the best way, but I tried to do it in OnCreate and save it in a variable and then return that variable in OnCreateView, but android didn't like that...
Ok I feel like an idiot. I was creating/binding on OnViewCreated - however I need to do all my binding in OnStart - I think I was following some (possibly old) sample code from Stuart.
Obviously for a regular activity I'm using OnCreate but this doesn't work on a fragment, because the view is not initialised there - it's initialised at OnCreateView.
So for future reference - do all binding in OnStart!

getText from one layout and (setting it) setText in an other layout

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.

Extend View and Custom Dialogs

I am working on a game where I am extending the view and performing operations in the class. I need to have a popup in the game which will have 3 buttons inside it. I have managed to have the popup show-up using custom dialogs but when I configure the onClick as follows:
private void popUp() {
Context mContext = getContext();
Dialog dialog = new Dialog(mContext);
dialog.setContentView(R.layout.custom_fullimage_dialog);
dialog.setTitle("Cheese Market");
Button one = (Button)findViewById(R.id.firstpack);
one.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
cheeseLeft = cheeseLeft + 10;
masterMoveLock = false;
return;
}
});
}
It force closes giving a nullpointerexeption even though it is defined in the custom_fullimage_dialog layout.
Can someone help me figure out how to have the button click detected in this scenario?
Thank you.
Try calling dialog.findViewById instead.
You're setting the contentView for the dialog, but by calling findViewById you're looking for it under your activity's content view.

MFC menu item checkbox behavior

I'm trying to add a menu item such that it acts like a check mark where the user can check/uncheck, and the other classes can see that menu item's check mark status. I received a suggestion of creating a class for the menu option (with a popup option), however, I can't create a class for the menu option when I'm in the resource layout editor in Visual Studio 2005. It would be great to hear suggestions on the easiest way to create menu items that can do what I have described.
You should use the CCmdUI::SetCheck function to add a checkbox to a menu item, via an ON_UPDATE_COMMAND_UI handler function, and the ON_COMMAND handler to change the state of the checkbox. This method works for both for your application's main menu and for any popup menus you might create.
Assuming you have an MDI or SDI MFC application, you should first decide where you want to add the handler functions, for example in the application, main frame, document, or view class. This depends on what the flag will be used for: if it controls application-wide behaviour, put it in the application class; if it controls view-specific behaviour, put it in your view class, etc.
(Also, I'd recommend leaving the menu item's Checked property in the resource editor set to False.)
Here's an example using a view class to control the checkbox state of the ID_MY_COMMAND menu item:
// MyView.h
class CMyView : public CView
{
private:
BOOL m_Flag;
afx_msg void OnMyCommand();
afx_msg void OnUpdateMyCommand(CCmdUI* pCmdUI);
DECLARE_MESSAGE_MAP()
};
// MyView.cpp
BEGIN_MESSAGE_MAP(CMyView, CView)
ON_COMMAND(ID_MY_COMMAND, OnMyCommand)
ON_UPDATE_COMMAND_UI(ID_MY_COMMAND, OnUpdateMyCommand)
END_MESSAGE_MAP()
void CMyView::OnMyCommand()
{
m_Flag = !m_Flag; // Toggle the flag
// Use the new flag value.
}
void CMyView::OnUpdateMyCommand(CCmdUI* pCmdUI)
{
pCmdUI->SetCheck(m_Flag);
}
You should ensure the m_Flag member variable is initialised, for example, in the CMyView constructor or OnInitialUpdate function.
I hope this helps!
#ChrisN's approach doesn't quite work for MFC Dialog applications (the pCmdUI->SetCheck(m_Flag); has no effect). Here is a solution for Dialog apps:
// MyView.h
class CMyView : public CView
{
private:
BOOL m_Flag;
CMenu * m_menu;
virtual BOOL OnInitDialog();
afx_msg void OnMyCommand();
DECLARE_MESSAGE_MAP()
};
// MyView.cpp
BEGIN_MESSAGE_MAP(CMyView, CView)
ON_COMMAND(ID_MY_COMMAND, OnMyCommand)
END_MESSAGE_MAP()
BOOL CMyView::OnInitDialog()
{
m_menu = GetMenu();
}
void CMyView::OnMyCommand()
{
m_Flag = !m_Flag; // Toggle the flag
if (m_flag) {
m_menu->CheckMenuItem(ID_MENUITEM, MF_CHECKED | MF_BYCOMMAND);
} else {
m_menu->CheckMenuItem(ID_MENUITEM, MF_UNCHECKED | MF_BYCOMMAND);
}
}
References:
http://www.codeguru.com/forum/showthread.php?t=322261
I ended up retrieving the menu from the mainframe using GetMenu() method, and then used that menu object and ID numbers to call CheckMenuItem() with the right flags, as well as GetMenuState() function.

Resources