android - uso - Cómo usar el enlace de datos con Fragment
navigation with fragments android (12)
Estoy tratando de seguir el ejemplo de enlace de datos del documento oficial de Google https://developer.android.com/tools/data-binding/guide.html
excepto que estoy tratando de aplicar la transferencia de datos a un fragmento, no a una actividad.
el error que obtengo actualmente al compilar es
Error:(37, 27) No resource type specified (at ''text'' with value ''@{marsdata.martianSols}.
onCreate
for fragment se ve así:
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
MartianDataBinding binding = MartianDataBinding.inflate(getActivity().getLayoutInflater());
binding.setMarsdata(this);
}
onCreateView
para fragmento se ve así:
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
return inflater.inflate(R.layout.martian_data, container, false);
}
y partes de mi archivo de diseño para fragmentos se ven así:
<?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>
mi sospecha es que
MartianDataBinding
no sabe con qué archivo de diseño debe estar vinculado, de ahí el error.
¿Alguna sugerencia?
Como la mayoría ha dicho, pero no se olvide de configurar
LifeCycleOwner
Muestra en Java
es decir
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();
}
En realidad, se le recomienda utilizar el método de
inflate
de su enlace generado y no el 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();
}
Documentos para DataBindingUtil.inflate () :
Use esta versión solo si layoutId es desconocido de antemano. De lo contrario, utilice el método de inflado de Binding generado para garantizar una inflación segura.
Incluso las otras respuestas pueden funcionar bien, pero quiero decir el mejor enfoque.
Utilice el
Binding class''s inflate
como se recomienda en la
documentación de Android
.
Una opción es inflar por
DataBindingUtil
pero cuando solo usted no sabe que ha generado la clase de enlace
.
- Tiene una
binding class
generada automáticamente, use esa clase en lugar de usar
DataBindingUtil
.
En java
lateinit var binding: HomeFragmentBinding
override fun onCreateView(inflater: LayoutInflater?, container: ViewGroup?, savedInstanceState: Bundle?): View? {
binding = HomeFragmentBinding.inflate(inflater, container, false)
return binding.root
}
En kotlin
T inflate (LayoutInflater inflater,
int layoutId,
ViewGroup parent,
boolean attachToParent)
En la documentation clase DataBindingUtil puede ver.
inflar
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; }
Use esta versión solo si layoutId es desconocido de antemano. De lo contrario, utilice el método de inflado de Binding generado para garantizar una inflación segura.
Si su clase de agrupación de diseño no se genera @Vea documentation .
La implementación del enlace de datos debe estar en el método
onCreateView
del fragmento, elimine cualquier enlace de datos que exista en su método
OnCreate
, su
onCreateView
debería verse así:
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;
}
Otro ejemplo en Kotlin:
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
}
Tenga en cuenta que el nombre "MartianDataBinding" depende del nombre del archivo de diseño. Si el archivo se llama "martian_data", el nombre correcto sería MartianDataBinding.
Prueba esto en Android DataBinding
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
return MartianDataBinding.inflate(
inflater,
container,
false
).apply {
setLifecycleOwner(this@MartianData)
vm = viewModel // Attach your view model here
}.root
}
Si está utilizando ViewModel y LiveData Esta es la sintaxis suficiente
Sintaxis de Kotlin:
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
HomeFragmentBinding binding = HomeFragmentBinding.inflate(inflater, container, false);
//set binding variables here
return binding.getRoot();
}
Todos dicen sobre
inflate()
, pero ¿qué pasa si queremos usarlo en
onViewCreated()
?
Puede usar el método de
bind(view)
de la clase de enlace concreto para obtener la instancia de
ViewDataBinding
para la
view
.
Por lo general, escribimos BaseFragment de esta manera (simplificado):
// BaseFragment.kt
abstract fun layoutId(): Int
override fun onCreateView(inflater, container, savedInstanceState) =
inflater.inflate(layoutId(), container, false)
Y úsalo en un fragmento infantil.
// 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)
}
Si todos los Fragmentos usan enlace de datos, incluso puede simplificarlo usando el parámetro tipo.
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)
}
}
No sé si está bien afirmar que no es nulo allí, pero ... entiendes la idea. Si quieres que sea anulable, puedes hacerlo.
Un ejemplo completo en Fragmentos de enlace de datos
FragmentMyProgramsBinding es una clase de enlace generada para res / layout / fragment_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);
}
}
Uno simplemente puede recuperar el objeto de vista como se menciona a continuación
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;
}
trabajando en mi código
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();
}
Sintaxis de 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
}