0

Maybe I am missing something small here, but I cannot get my binding to work. I set it up as follow:

public class Toolbar extends Fragment {

//Interaction handlers
//interface for interaction with Activity
public interface ToolBarInteraction{
    public void Search(String screenName);
}

private ToolbarBind modelData;
private ToolBarInteraction mListener;

public static Toolbar newInstance() {
    return new Toolbar();
}

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    FragmentToolbarBinding binding = DataBindingUtil.setContentView(getActivity(), R.layout.fragment_toolbar);
    modelData = ToolbarBind.newInstance();
    modelData.searchedText.set("Hello");
    binding.setModelData(modelData);
}

@Nullable
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
    checkMListener();

    View view = inflater.inflate(R.layout.fragment_toolbar, container, false);

    //get button to set onClick event
    Button button = (Button)view.findViewById(R.id.btnSearch);
    button.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {
            String hello = modelData.searchedText.get();
        }
    });

    return view;
}

public void OnSearchClicked(View view){
    mListener.Search(modelData.searchedText.get());
}

private void checkMListener(){
    try{
        mListener = (ToolBarInteraction) getActivity();
    } catch (ClassCastException ex) {
        throw new ClassCastException(getActivity().toString()
                + " must implement the ToolBarInteraction Interface");
    }
}
}

Here is the code for ToolbarBind:

public class ToolbarBind extends BaseObservable {
private String _searchText;

public final ObservableField<String> searchedText = new ObservableField<String>();

//factory method
public static ToolbarBind newInstance(){ return new ToolbarBind(); }
}

And in my fragment, I set the binding up as follow, all within the layout tag:

<data>
    <variable
        name="modelData"
        type="Common.CommonObjects.ToolbarBind"/>
</data>

And for binding to property:

<EditText
     android:layout_width="match_parent"
     android:layout_height="match_parent"
     android:hint="Search"
     android:text="@={modelData.searchedText}"/>

As can be seen, in the onCreate I set the text to "Hello", but even when the view displays on the phone, the EditText is not populated with this text. When I change the value, and click my button, the value I get back in the event is "Hello", not my new text entered while the app is running.

What am I missing?

Marcin Orlowski
  • 72,056
  • 11
  • 123
  • 141
monstertjie_za
  • 7,277
  • 8
  • 42
  • 73

1 Answers1

1

The problem with your code is that you set the Activity's content view to something in onCreate(...) but you inflate and use something different in onCreateView(...) as your fragment's view, which gets the model data (not the other one you created in onCreate(...)). I don't know exactly what you try to achieve, but I'm gonna guess that you don't want to change the Activity's content view to something from the fragment, so I'm just gonna show you a variation of what could you use, however, you should change it to whatever pleases you.

Remove onCreate(...) completely then use only onCreateView(...) to inflate the fragment_toolbar layout using data binding:

@Nullable
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
    checkMListener();

    FragmentToolbarBinding binding = DataBindingUtil.inflate(inflater, R.layout.fragment_toolbar, container, false);

    // FIXME you're losing data here; watch out: checking whether savedInstanceState == null is not enough because returning from backstack it will be null
    modelData = ToolbarBind.newInstance();

    // FIXME modify this so it sets the data from savedInstanceState when configuration changes
    modelData.searchedText.set("Hello");


    binding.setModelData(modelData);

    //get button to set onClick event
    binding.btnSearch.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {
            String hello = modelData.searchedText.get();
        }
    });

    return binding.getRoot();
}

Watch out for the FIXME parts. You could move the modelData init to onCreate(...) which would save it from the backstack-return thing, however, configuration change will still call onCreate(...) unless you call setRetainInstance(true) on the fragment (do not).

Gergely Kőrössy
  • 5,620
  • 3
  • 28
  • 44
  • Your solution provides the following: The specified child already has a parent. You must call removeView() on the child's parent first. The purpose of this exercise is to learn Android development, but so far the process has been painful and slow – monstertjie_za May 29 '17 at 13:19
  • Are you sure you are using `DataBindingUtil.inflate(inflater, R.layout.fragment_toolbar, container, false);`? Pay attention to the last `false` attribute as it tells the inflater not to attach the inflated view to the container. – Gergely Kőrössy May 29 '17 at 13:26
  • I seem to have missed that. Thanks for your help, really appreciate it... – monstertjie_za May 29 '17 at 15:25