Is there a way to attach bindings to a setContentView activity - android

Currently if I want attach bindings I do
DataBindingUtil.setContentView(this, R.layout.main_activity);
I'm having troubles with a custom third-party Activity that needs to call
setContentView(R.layout.main_activity);
How I can attach binding to an activity where the layout was set with setContentView

You need to inflate you layout first, call setContentView(inflatedView) and set the DataBinding:
/* I don't know if passing 'null' as parent breaks something in your layout, I tested it in
mine and it did work.*/
View rootView = LayoutInflater.from(this).inflate(R.layout.activity_main, null);
setContentView(rootView);
ActivityMainBinding binding = DataBindingUtil.bind(rootView);

Related

Presenter is not called in onClick

When trying to inflate and set my presenter to my databinding component in this way my presenter methods are not called.
val fragmentBinding = FragmentListEditBinding.inflate(layoutInflater)
fragmentBinding.presenter = ListEditorPresenter(this, requireContext())
but when using this
val fragmentBinding = DataBindingUtil.setContentView<FragmentListEditBinding(requireActivity(), R.layout.fragment_list_edit)
fragmentBinding.presenter = ListEditorPresenter(this, requireContext())
It works fine, but then the layout is covering the full screen.
Any ideas how to fix this issue?
Please tell me if more context is needed.
The second method is for activity, not for the fragment, For fragment, you have to do it in the first method.
Before DataBinding and ViewBinding, In and activity we call setContentView(R.layout.activity_main) to set the view for the activity, but for fragment, we override the onCreateView method and inflate a view and return it.
So the way of setting view for activity and fragment is different from the beginning.
So the DataBindingUtil.setContentView is made for activity, while the FragmentListEditBinding.inflate custom/manual inflation is made for fragment. As i have already mentioned it above.

What is the difference between `bind`, `inflate` and `setContentView` in `DataBindingUtil`

I have seen DataBindingUtil used with all three methods, and it is not clear from the documentation (https://developer.android.com/reference/android/databinding/DataBindingUtil) what the difference is between the three.
bind takes an already inflated view hierarchy and returns a ViewDataBinding for it.
inflate takes a layout resource ID, inflates a view hierarchy from it and returns a ViewDataBinding for it. It's essentially equal to
val layoutInflater = LayoutInflater.from(context)
val view = layoutInflater.inflate(R.layout.some_layout, ...)
val binding = DataBindingUtil.bind<SomeLayoutBinding>(view)
setContentView takes a layout resource ID, inflates a view hierarchy from it, sets it as an activity content and returns a ViewDataBinding for the inflated view hierarchy. It's essentially equal to
setContentView(R.layout.some_layout)
val view = findViewById<View>(android.R.id.content)
val binding = DataBindingUtil.bind<SomeLayoutBinding>(view)
Generaly setContentView () will be displayed in the activity.
but fragments have a lifecycle method called onCreateView which returns a view. The most common way to do this is to inflate a view in XML and return it(as may you see in fragment's java code). In this case you need to inflate it yourself. Fragments don't have a setContentView method. so inflate use for fragments.
and binding just bind a view to a layout.

Turning multiple pre-created Android activities to a single activity with fragments

As a preamble; I have an Android app containing 4 activities, and I wish to transfer these into a single activity containing Fragments (two extending ListActivity, and two extending Activity), with navigation between Fragments enabled by a Navigation Drawer . I have attempted to turn these Activities into ones extending ListFragment and Fragment, however much of the code within the activity ceases to function: for example, getSystemService(NOTIFICATION_SERVICE), the unbindService and the 'registerReciever', and primarily the different onCreateOptionsMenus contained within the disparate activities.
Therefore I ask, would it be possible to port any separate Activities to a single fragmented one, but still retaining the same function as with the separate focused activities, with minimal editing?
Also, regarding the transition process would one need to end a previous Fragment within the main Activity to display another Fragment in the same space?
Yes it is possible, fragments have a very similar lifecycle to activities (See here). You'll find it is probably a case of copy/paste from your activity classes to your fragment classes with very minor tweaks to have them work as they were as separate activities. The only legwork you will have to do is swapping these fragments from your activities.
For example, an activity with its onCreate function that looks like this:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_home);
// Find views
homeMessagesButton = (Button) v.findViewById(R.id.homeMessagesButton);
homeCreateMatchButton = (Button) v.findViewById(R.id.homeCreateMatchButton);
homeMyMatchesButton = (Button) v.findViewById(R.id.homeMyMatchesButton);
homeMyTeamsButton = (Button) v.findViewById(R.id.homeMyTeamsButton);
homeSquadButton = (Button) v.findViewById(R.id.homeSquadButton);
homeSettingsButton = (Button) v.findViewById(R.id.homeSettingsButton);
// Set click listeners
homeMessagesButton.setOnClickListener(this);
homeCreateMatchButton.setOnClickListener(this);
homeMyMatchesButton.setOnClickListener(this);
homeMyTeamsButton.setOnClickListener(this);
homeSquadButton.setOnClickListener(this);
homeSettingsButton.setOnClickListener(this);
}
Will now look like this in a fragment (note the fragment uses the onCreateView lifecycle method to inflate its view inside the activity the fragment will appear in)
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
// Inflate the layout for this fragment
View v = inflater.inflate(R.layout.fragment_home, container, false);
// Find views
homeMessagesButton = (Button) v.findViewById(R.id.homeMessagesButton);
homeCreateMatchButton = (Button) v.findViewById(R.id.homeCreateMatchButton);
homeMyMatchesButton = (Button) v.findViewById(R.id.homeMyMatchesButton);
homeMyTeamsButton = (Button) v.findViewById(R.id.homeMyTeamsButton);
homeSquadButton = (Button) v.findViewById(R.id.homeSquadButton);
homeSettingsButton = (Button) v.findViewById(R.id.homeSettingsButton);
// Set click listeners
homeMessagesButton.setOnClickListener(this);
homeCreateMatchButton.setOnClickListener(this);
homeMyMatchesButton.setOnClickListener(this);
homeMyTeamsButton.setOnClickListener(this);
homeSquadButton.setOnClickListener(this);
homeSettingsButton.setOnClickListener(this);
return v;
}
Changing fragments within the activity is done through the use of the fragmentTransaction manager as shown in the android training site here
Since your service requires to be bound to a activity, rather than a fragment. This becomes trivial as fragments can retrieve the activity they are bound to. For example, the code below used in a fragment will automatically get the activity they exist within.
getActivity().getSystemService(Context.LOCATION_SERVICE);
If you want to use getSystemService(NOTIFICATION_SERVICE) in your fragments you need to use the context of your activity. Context.getSystemService(NOTIFICATION_SERVICE). Some methods work on Activities and if you want to use them elsewhere you need to get the context.
Moving your code from Activity is fairly simple. For example onCreateOptionsMenu is also available in Fragments and as for your methods that require a context or Activity, you can call getActivity() from your Fragment to get a reference to the parent Activity.
EDIT : to replace a Fragment, there's also a method for that from the FragmentTransaction class, taking the id of the container View in argument.

Object created from layout xml file is null

I have two classes that extend the activity class. Each class has it's own layout class, main.xml and compose.xml.
In my main activity I try to access a layout element that is in compose.xml. So:
EditText smsBody = (EditText)findViewById(R.id.smsBody);
But smsBody is null. Why? How can I access it?
Did you set the content view in the onCreate() method?
Like in this example:
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
}
Well, your main activity has a main.xml layout. Your compose activity has a compose.xml layout. Assuming your "smsBody" EditText is in the compose.xml layout, then this will be only accesible in your compose activity, since that widget doesn't exist in your main.xml layout.
when main activity have layout main.xml, how you can expect that you can access component of compose.xml ?? you suppose to play with view inside layout you set using setContentView() .
in exceptional cases we need to use other layouts as well , so you can use LayoutInflater for this

Setting global Button and EditText objects

I'm getting null pointer exceptions when I try to initialize Button and EditText objects in global scope, can't figure it out. I've commented out everything but the bare minimum for the app to display my layout, but this still causes a crash:
private EditText addmoney = (EditText)findViewById(R.id.addmoney);
R.id.addmoney definitely, definitely exists. So what the heck? Is it impossible to declare EditText in global scope? I need to be able to call it from both onCreate and onPause in a class extending Activity, is there maybe another way I should be doing this?
EDIT:
I tried using shade's method of inflating the layout first but it causes errors, apparently your not allowed to use system services before onCreate() has been called and inflating a view requires one.
You have to execute findViewById only after you have set the content for your current activity.
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.home);
addmoney = (EditText)findViewById(R.id.addmoney);//it knows in which file to search for the id
}
Alternatively, you could do something like this:
private View dummy = (View) View.inflate(this, R.layout.dummy, null);
private EditText addmoney = (EditText) dummy.findViewById(R.id.addmoney);
... and in the onCreate (or wherever else):
setContentView (dummy);
Since you already have the parent of the EditText view instantiated, you can reference it without having a NPE.
NOTE: The first parameter of inflate is a Context. Therefore, you need a Context that is alive for this to work.
Ooops, wrong class :D

Categories

Resources