How to use Databinding with DialogFragment - java

In my app I have an ElementListFragment of items represented by a code object Element. I've data-bound these elements to the list and they display the correct information.
However, to continue filling in the information in each item I put a button on each element that shows a Dialog with additional fields.
But when the Dialog opens the fields are all blank (where one at least ought to be filled) and any fields I fill don't save the data (and don't effect changes on the list).
Appart from the values not being bound (displayed or written), the application works fine. I've essentially tried multiple variations of the sugestions in this question. Here is the code:
public class ElementDialogFragment extends DialogFragment {
private Element mElement;
private Dialog dialog;
#Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
// Use the Builder class for convenient dialog construction
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
LayoutInflater inflater = getActivity().getLayoutInflater();
View v = inflater.inflate(R.layout.dialog_element, null);
final DialogSkillelementBinding binding = DialogElementBinding.inflate(LayoutInflater.from(getContext()));
builder.setView(v)
// Add action buttons
.setPositiveButton(R.string.save, new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int id) {
//this was just an attempt to make it work
binding.executePendingBindings();
dialog.dismiss();
}
});
TextView Title = v.findViewById(R.id.skill_e_dialog_title);
Title.setText(ResourceLocator.getSkillName(mElement.getSkill()));
dialog = builder.create();
dialog.setContentView(binding.getRoot());
binding.setElement(mElement);
binding.executePendingBindings();
return dialog;
}
}
When debuging I've confirmed that mElement is correctly attributed, however it's also bound to the list shown beneath the dialog. The title is also displayed correctly.
Is there a problem double-binding an object?
Are some of the steps on the function maybe out of order?
Is the DialogBuilder somehow incompatible with databinding?

You should set LyfecycleOwner for your binding class for data updating.
binding.setLifecycleOwner(requireActivity())

Related

Star Rating in Dialogbox won't change saved value

// Custom Dialog Box
final AlertDialog.Builder mBuilder = new AlertDialog.Builder(MainActivity.this, R.style.Theme_AppCompat_Dialog_Alert);
final View mView = getLayoutInflater().inflate(R.layout.completed, null);
ImageButton imgForm = (ImageButton) mView.findViewById(R.id.RateButton);
mBuilder.setCancelable(false);
mBuilder.setView(mView);
final AlertDialog dialog = mBuilder.create();
dialog.getWindow().setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));
dialog.show(); // Dialogbox appears
// Interest Rating
final AlertDialog.Builder nBuilder = new AlertDialog.Builder( MainActivity.this, R.style.Theme_AppCompat_Light_Dialog_Alert);
final View nView = getLayoutInflater().inflate(R.layout.intrst, null);
Save_Intrst = (Button) nView.findViewById(R.id.SaveIntrst);
nBuilder.setCancelable(false);
nBuilder.setView(nView);
final AlertDialog dilog = nBuilder.create();
// LongPress Image Button
imgForm.setOnLongClickListener(new View.OnLongClickListener(){
#Override
public boolean onLongClick(View view){
dialog.dismiss();
dilog.getWindow().setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));
dilog.show(); // Dialogbox appears
return true;
}
});
Save_Intrst.setOnClickListener(new View.OnClickListener(){
String IntrstLvl;
#Override
public void onClick(View v){
RatingBar rBar = (RatingBar)nView.findViewById(R.id.ratingStar);
IntrstLvl = Integer.toString(rBar.getNumStars());
addData(IntrstLvl);
dilog.dismiss();
Log.d(TAG,"Dismissed");
}
});
Whenever I select "save" within the Save_Intrst it saves 5 stars regardless of what I choose. I'm still fairly new to Android development and have been java coding for a bit now.
This is just a snippet of code of the project and I believe it will be enough, it shows my submit button, the submit button will launch a dialog box that will have a secret button in an image (ImgForm) the image doesn't show but that's not the problem, after long pressing it will launch another dialog that has a 5 Star Rating Bar and a Save button, this is used for rating after the person completes the previous requirements. The rating will always save "5" regardless of what was inserted, even after a reinstall of app onto the device.
getNumStars() will tell you the maximum number of stars shown and will always be 5 as you have defined it. If you want the actual selected rating, you will need getRating(). See this documentation.
You need to use the rBar.getRating()
RatingBar rBar = (RatingBar)nView.findViewById(R.id.ratingStar);
IntrstLvl = Integer.toString(rBar.getRating());
https://developer.android.com/reference/android/widget/RatingBar.html
You are calling getNumStars() which according to the documentation "Returns the number of stars shown." which means the total number of stars a user can select. You should instead be checking getRating() which returns the number of stars currently selected.
https://developer.android.com/reference/android/widget/RatingBar.html#getRating()

How to pass object through activities by reference?

this is my first post here so be gentle :p
Here is the thing, I'm facing a really though issue and after several research i did not manage to figure out a clean solution. Let me explain:
I'm actually developing an android app for restaurant management.
In activity A, i'm able to create some articles with different parameters (picture, name, price ..).
I can also create a menu in which i indicate which articles are included. To do so i run Activity B that contains a dynamic list of the available articles (the ones i created) to be chosen. After picking up some of them the customised chosen objects are sent to Activity A through Parcel. And the chosen article list is updated in the menu.
But here is the thing, as far as i know, using Parcels create another instance of the object. As a result, if i modify or delete an article, the article list included in the menu does not change, and obviously i would like the list in the menu to be automatically updated.
Is there a way to simply pass customised objects through activities by reference?
What could be a clean solution to make the article list in the menu dynamic?
Here is some code:
In Activity A, in the menu interface i click + button to add an article, which run Activity B (the extras is the list of articles already included in the menu before, so in the beginning it's empty).
//Add article
FloatingActionButton addArticleButton = (FloatingActionButton)parentActivity.findViewById(R.id.addArticleButton);
addArticleButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
showMenuDetails(menuListView,menuAdapter,currentMenu);
parentActivity.startActivityForResult(new Intent(parentActivity.getApplicationContext(),ChooseArticleActivity.class).putParcelableArrayListExtra("menuArticleList",currentMenu.getArticles()),PICK_ARTICLES);
}
});
In activity B: I select Articles in a list of available Articles (the ones i created). After picking up i press OK button to put the list of chosen articles in result Intent as Parcelable Extras
protected void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.choose_article_layout);
initializeLists();
this.resultIntent = new Intent();
}
private void initializeLists(){
final ListView articleToChoose = (ListView)findViewById(R.id.articleToChoose);
final ListView articleChosen = (ListView)findViewById(R.id.articleChosen);
final ArrayList<Article> articleToChooseList = (ArrayList<Article>)MainActivity.model.getArticleList().getArticleList().clone();
final ArrayList<Parcelable> articleChosenListParcelable = (ArrayList<Parcelable>)this.getIntent().getParcelableArrayListExtra("menuArticleList");
final ArticleAdapter articleToChooseAdapter = new ArticleAdapter(getApplicationContext(), articleToChooseList);
articleToChoose.setAdapter(articleToChooseAdapter);
ArrayList<Article> articleChosenListTemp = new ArrayList<>();
ArrayList<Article> articleToRemove = new ArrayList<>();
for(Parcelable a:articleChosenListParcelable){
articleChosenListTemp.add((Article)a);
for(Article article:articleToChooseList){
if(article.getName().equals(((Article) a).getName())){
articleToRemove.add(article);
}
}
}
articleToChooseList.removeAll(articleToRemove);
articleToChooseAdapter.notifyDataSetChanged();
final ArrayList<Article> articleChosenList = articleChosenListTemp;
final ArticleAdapter articleChosenAdapter = new ArticleAdapter(getApplicationContext(),articleChosenList);
articleChosen.setAdapter(articleChosenAdapter);
articleChosen.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
Article articleClicked = articleChosenAdapter.getItem(position);
articleChosenList.remove(articleClicked);
articleToChooseList.add(articleClicked);
articleChosenAdapter.notifyDataSetChanged();
articleToChooseAdapter.notifyDataSetChanged();
}
});
articleToChoose.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
Article articleClicked = articleToChooseAdapter.getItem(position);
if(!articleChosenList.contains(articleClicked)){
articleChosenList.add(articleClicked);
articleToChooseList.remove(articleClicked);
articleToChooseAdapter.notifyDataSetChanged();
articleChosenAdapter.notifyDataSetChanged();
}
}
});
Button okButton = (Button)findViewById(R.id.okButton);
okButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
chosenArticleListAttr = articleChosenList;
resultIntent.putParcelableArrayListExtra("articleList",chosenArticleListAttr);
setResult(RESULT_OK,resultIntent);
finish();
}
});
Button cancelButton = (Button)findViewById(R.id.cancelButton);
cancelButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
finish();
}
});
}
In activity A, in onActivityResult i catch the result and update the list, but the added Articles here are not the same instance as the article list in the model
if(requestCode==PICK_ARTICLES && resultCode==RESULT_OK){
ArticleAdapter articleAdapter = (ArticleAdapter) gestionMenusLayout.getMenuArticleListView().getAdapter();
ArrayList<Parcelable> chosenArticleList = (ArrayList<Parcelable>)data.getParcelableArrayListExtra("articleList");
gestionMenusLayout.getCurrentMenu().getArticles().clear();
for(Parcelable a:chosenArticleList){
gestionMenusLayout.getCurrentMenu().addArticle((Article)a);
}
articleAdapter.notifyDataSetChanged();
}
For debugging purpose only, I suggest that you use a public static List<Article> articleList and call it directly from whether activity A or B
A better but take-alittle-more-effort solution is that you store the list in a database, and every updates, queries, ... come through it.You can use the server's database (where people usually get articles from), or a offline database like Realm here
I figured it out with a quite easy and simple solution finally.
I keep passing my Article objects through intents by parcels.
But as it creates a new instance, instead of adding this instance i add the original one (the one from the model) after an equality key check (the name of the article). By doing so i keep the reference on my Article.
Thank you for helping!
Edit:
Here is the code:
if(requestCode==PICK_ARTICLES && resultCode==RESULT_OK){
ArticleAdapter articleAdapter = (ArticleAdapter) gestionMenusLayout.getMenuArticleListView().getAdapter();
ArrayList<Parcelable> chosenArticleList = (ArrayList<Parcelable>)data.getParcelableArrayListExtra("articleList");
gestionMenusLayout.getCurrentMenu().getArticles().clear();
ArrayList<Article> modelArticles = MainActivity.model.getArticleList().getArticleList();
for(Parcelable a:chosenArticleList){
for(Article modelArticle:modelArticles){
if(((Article)a).getName().equals(modelArticle.getName())){
gestionMenusLayout.getCurrentMenu().addArticle(modelArticle);
}
}
}
articleAdapter.notifyDataSetChanged();
}

Custom AlertDialog disappears on back button press

Hi guys I have a custom alert dialog I created. In the builder I set cancelable to false yet it still disappears when I press the back button, any ideas?
This is the code for the dialog:
public final class HemisphereDialogFragment extends DialogFragment {
#Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
// Use the Builder class for convenient dialog construction
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
LayoutInflater inflater = getActivity().getLayoutInflater();
View customTitle = inflater.inflate(R.layout.hemisphere_dialog_custom_title, null);
builder.setCustomTitle(customTitle);
String[] entries = new String[2];
entries[0] = getResources().getString(R.string.northern_hemisphere);
entries[1] = getResources().getString(R.string.southern_hemisphere);
builder.setItems(entries, new DialogInterface.OnClickListener() {
//The 'which' argument contains the index position of the selected item
public void onClick(DialogInterface dialog, int which) {
if( which == 0 ) {
GlobalVariables.getShared().setIsInNorthernHemisphere(true);
} else if( which == 1 ) {
GlobalVariables.getShared().setIsInNorthernHemisphere(false);
}
ToolbarActivity.outfitsFragment.hemisphereSelected();
GlobalVariables.getShared().setHasAskedForHemisphere(true);
}
});
builder.setCancelable(false);
//Create the AlertDialog object and return it
return builder.create();
}
And this is how it's displayed:
new HemisphereDialogFragment().show(getSupportFragmentManager(), "hemisphereDialog");
Another small side question, is there a way to change the text size for the items in the dialog?
You set your alert dialog cancelable to false, but your fragment is still set to cancelable, you need to add setCancelable(false) to your fragment as well.
You should call setCancellable(false) in the Dialog fragment itself not the AlertDialog.Builder.

getWidth for a child view within DialogFragment

I have a DialogFragment class named DF.java which uses a linearlayout based layout named DF.xml.
The child elements (again linearlayouts) in DF.xml have their widths set to 0dp and are calculated using weights.
I plan to show the DialogFragment DF from an activity on a button click, which works fine and the DialogFragment loads fine.
Now, when the DialogFragment DF shows up, I need to get the width of one of its child elements (a linearlayout).
I have tried getWidth, getMeaseuredWidth, ViewTreeObserver etc in onCreateDialog but result is always zero.
Code to show DialogFragment
DF dialog = DF.newInstance(context, "DFInstance");
dialog.show(((Activity)context).getFragmentManager(), "DFInstance");
Code within DialogFragment DF.java class
public Dialog onCreateDialog(Bundle savedInstanceState) {
LayoutInflater inflater = LayoutInflater.from(context);
View dialog_layout = inflater.inflate(R.layout.dialog_DF,
null);
CurrentDialog = new Dialog(context, R.style.DFTheme);
CurrentDialog.setCanceledOnTouchOutside(true);
CurrentDialog.setContentView(dialog_layout);
CurrentDialog.getWindow().setBackgroundDrawable(
new ColorDrawable(android.graphics.Color.TRANSPARENT));
CurrentDialog.setOnShowListener(new OnShowListener() {
#Override
public void onShow(DialogInterface dialog) {
//Tried getting width here using many approaches, Ex:
int Width1 = (((Dialog)dialog).findViewById(R.Id.fieldForWidth)).getWidth();
// Also tried using MeasureSpec here and then getMeasuresWidth
// Also tried adding above code in ViewTreeObserver here.
}
});
Window window = CurrentDialog.getWindow();
window.setLayout(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT);
CurrentDialog.show();
return CurrentDialog;
}
But strangely, if I choose against DialogFragment, and I show the Dialog directly from my main activity, then same code returns width value perfectly within onShow, using getWidth().
But I really need to do this via DialogFragment for the sake of code organization.
Any assistance or pointers as to what I am doing wrong here will be really helpful.
To get the width of the child LinearLayout in the DialogFragment, you can use an OnShowListener together with getMeasuredWidth():
final int width;
myDialog.setOnShowListener(new DialogInterface.OnShowListener()
{
#Override
public void onShow(DialogInterface dialog)
{
width = ((Dialog)dialog).findViewById(R.id.field_for_width).getMeasuredWidth());
}
});
This works for a child View (just a plain View as well as a LinearLayout) with width set to match_parent or wrap_content.
Please note that in my test I did not call CurrentDialog.show() in onCreateDialog() but only used the following lines in the Activity code to show the dialog:
DialogFragment mDialog = DF.newInstance("x", "yz");
mDialog.show(getSupportFragmentManager(), "myCurrentDialog");

Custom style on DialogFragment

Possible duplicate here, sorry in that case...
I can't get my head around how to add a custom style to my DialogFragment. At the moment I have a class
public final class SelectFragment extends DialogFragment {
which I call from different parts of my app. E.g from my "CreateInvoice" class like this:
private void showFragment(int selectedIndex) {
SelectFragment fragment = SelectFragment.newInstance(selectedIndex, getOnOptionSelectListener());
fragment.setStyle(DialogFragment.STYLE_NO_TITLE, android.R.style.Theme_Holo_Light_Dialog);
fragment.show(getActivity().getSupportFragmentManager(), "");
}
What I want to do is to change the fragment.setStyle to a custom one, for example with my own color scheme as color on the border, background etc.. And I would really appreciate if someone could walk me through it since it's the first time I've worked with fragments. :-)
Thanks!
The way I would do it is to simply write your own layout for your dialog, then load it up when you show the fragment
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
// Get the layout inflater
LayoutInflater inflater = getActivity().getLayoutInflater();
// Inflate and set the layout for the dialog
// Pass null as the parent view because its going in the dialog layout
View v = inflater.inflate(R.layout.custom_dialog_layout, null, false);
builder.setView(v)
// Add action buttons
.setPositiveButton(R.string.save_note, new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int id) {
// do stuff
}
})
.setNegativeButton(R.string.note_cancel, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
//do stuff
}
});

Categories

Resources