Как использовать привязку данных с фрагментом
Я пытаюсь следовать примеру привязки данных из официального документа google https://developer.android.com/tools/data-binding/guide.html
за исключением того, что я пытаюсь применить данные, ожидающие фрагмента, а не активность.
ошибка, которую я получаю при компиляции,
Error:(37, 27) No resource type specified (at 'text' with value '@{marsdata.martianSols}.
onCreate
для фрагмента выглядит следующим образом:
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
MartianDataBinding binding = MartianDataBinding.inflate(getActivity().getLayoutInflater());
binding.setMarsdata(this);
}
onCreateView
для фрагмента выглядит следующим образом:
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
return inflater.inflate(R.layout.martian_data, container, false);
}
и части моего файла макета для фрагмента выглядят следующим образом:
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android">
<data>
<variable
name="marsdata"
type="uk.co.darkruby.app.myapp.MarsDataProvider" />
</data>
...
<TextView
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:text="@{marsdata.martianSols}"
/>
</RelativeLayout>
</layout>
Мое подозрение в том, что MartianDataBinding
не знает, какой файл макета он должен связывать, - следовательно, ошибка. Любые предложения?
Ответы
Ответ 1
Реализация привязки данных должна быть в методе onCreateView
фрагмента, удалить любые привязки данных, которые существуют в вашем методе OnCreate
, ваш onCreateView
должен выглядеть следующим образом:
public View onCreateView(LayoutInflater inflater,
@Nullable ViewGroup container,
@Nullable Bundle savedInstanceState) {
MartianDataBinding binding = DataBindingUtil.inflate(
inflater, R.layout.martian_data, container, false);
View view = binding.getRoot();
//here data must be an instance of the class MarsDataProvider
binding.setMarsdata(data);
return view;
}
Ответ 2
На самом деле вам рекомендуется использовать метод inflate
вашего сгенерированного связывания, а не DataBindingUtil:
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
MainFragmentBinding binding = MainFragmentBinding.inflate(inflater, container, false);
//set variables in Binding
return binding.getRoot();
}
Документы для DataBindingUtil.inflate():
Используйте эту версию, только если layoutId неизвестен заранее. В противном случае используйте сгенерированный метод накачивания Binding для обеспечения безопасной инфляции типа.
Ответ 3
Можно просто получить объект просмотра, как указано ниже
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
View view = DataBindingUtil.inflate(inflater, R.layout.layout_file, container, false).getRoot();
return view;
}
Ответ 4
Попробуйте это в Android DataBinding
FragmentMainBinding binding;
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
binding = DataBindingUtil.inflate(inflater, R.layout.fragment_main, container, false);
View rootView = binding.getRoot();
initInstances(savedInstanceState);
return rootView;
}
Ответ 5
Даже другие ответы могут работать хорошо, но я хочу сказать лучший подход.
Используйте Binding class inflate
как рекомендовано в документации Android.
Один из вариантов - использовать DataBindingUtil
но только если вы не знаете, что сгенерирован класс привязки.
--You имеет автоматически сгенерированный binding class
, используйте этот класс вместо DataBindingUtil
.
На яве
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
HomeFragmentBinding binding = HomeFragmentBinding.inflate(inflater, container, false);
//set binding variables here
return binding.getRoot();
}
В котлине
lateinit var binding: HomeFragmentBinding
override fun onCreateView(inflater: LayoutInflater?, container: ViewGroup?, savedInstanceState: Bundle?): View? {
binding = HomeFragmentBinding.inflate(inflater, container, false)
return binding.root
}
В документации класса DataBindingUtil вы можете увидеть.
раздувать
T inflate (LayoutInflater inflater,
int layoutId,
ViewGroup parent,
boolean attachToParent)
Используйте эту версию, только если layoutId заранее неизвестен. В противном случае используйте сгенерированный метод инфляции Binding, чтобы обеспечить безопасную инфляцию.
Если ваш класс связывания макета не сгенерирован @См. Этот ответ.
Ответ 6
работает в моем коде.
private FragmentSampleBinding dataBiding;
private SampleListAdapter mAdapter;
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
super.onCreateView(inflater, container, savedInstanceState);
dataBiding = DataBindingUtil.inflate(inflater, R.layout.fragment_sample, null, false);
return mView = dataBiding.getRoot();
}
Ответ 7
Синтаксис Kotlin:
lateinit var binding: MartianDataBinding
override fun onCreateView(inflater: LayoutInflater?, container: ViewGroup?, savedInstanceState: Bundle?): View? {
binding = DataBindingUtil.inflate(inflater, R.layout.martian_data, container, false)
return binding.root
}
Ответ 8
Полный пример фрагментов привязки данных
FragmentMyProgramsBinding - это класс привязки, созданный для res/layout/frag_my_programs
public class MyPrograms extends Fragment {
FragmentMyProgramsBinding fragmentMyProgramsBinding;
public MyPrograms() {
// Required empty public constructor
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
FragmentMyProgramsBinding fragmentMyProgramsBinding = DataBindingUtil.inflate(inflater, R
.layout.fragment_my_programs, container, false);
return fragmentMyProgramsBinding.getRoot();
}
@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
}
}
Ответ 9
Если вы используете ViewModel и LiveData Это достаточный синтаксис
Синтаксис Kotlin:
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
return MartianDataBinding.inflate(
inflater,
container,
false
).apply {
setLifecycleOwner([email protected])
vm = viewModel // Attach your view model here
}.root
}
Ответ 10
Еще один пример в Котлине:
override fun onCreateView(inflater: LayoutInflater?, container: ViewGroup?, savedInstanceState: Bundle?): View? {
val binding = DataBindingUtil
.inflate< MartianDataBinding >(
inflater,
R.layout.bla,
container,
false
)
binding.modelName = // ..
return binding.root
}
Обратите внимание, что имя "MartianDataBinding" зависит от имени файла макета. Если файл называется "martian_data", тогда правильное имя будет MartianDataBinding.
Ответ 11
Все говорят о inflate()
, но что если мы захотим использовать его в onViewCreated()
?
Вы можете использовать метод bind(view)
конкретного класса привязки, чтобы получить экземпляр ViewDataBinding
для view
.
Обычно мы пишем BaseFragment примерно так (упрощенно):
// BaseFragment.kt
abstract fun layoutId(): Int
override fun onCreateView(inflater, container, savedInstanceState) =
inflater.inflate(layoutId(), container, false)
И использовать его в дочернем фрагменте.
// ConcreteFragment.kt
override fun layoutId() = R.layout.fragment_concrete
override fun onViewCreated(view, savedInstanceState) {
val binding = FragmentConcreteBinding.bind(view)
// or
val binding = DataBindingUtil.bind<FragmentConcreteBinding>(view)
}
Если все фрагменты используют привязку данных, вы даже можете упростить их, используя параметр типа.
abstract class BaseFragment<B: ViewDataBinding> : Fragment() {
abstract fun onViewCreated(binding: B, savedInstanceState: Bundle?)
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
onViewCreated(DataBindingUtil.bind<B>(view)!!, savedInstanceState)
}
}
Я не знаю, хорошо ли утверждать ненулевое значение там, но... вы поняли идею. Если вы хотите, чтобы это было обнуляемым, вы можете сделать это.
Ответ 12
Точно так же, как большинство сказали, но не забудьте установить LifeCycleOwner
Образец в Java, т.е.
public View onCreateView(LayoutInflater inflater, ViewGroup container,Bundle savedInstanceState) {
super.onCreateView(inflater, container, savedInstanceState);
BindingClass binding = DataBindingUtil.inflate(inflater, R.layout.fragment_layout, container, false);
ModelClass model = ViewModelProviders.of(getActivity()).get(ViewModelClass.class);
binding.setLifecycleOwner(getActivity());
binding.setViewmodelclass(model);
//Your codes here
return binding.getRoot();
}