web-dev-qa-db-fra.com

Comment utiliser la liaison de données avec Fragment

J'essaie de suivre un exemple de liaison de données tiré de Google Doc officiel https://developer.Android.com/tools/data-binding/guide.html

sauf que j'essaie d'appliquer une liaison de données à un fragment, pas à une activité.

l'erreur que je reçois actuellement lors de la compilation est

Error:(37, 27) No resource type specified (at 'text' with value '@{marsdata.martianSols}.

onCreate pour fragment ressemble à ceci:

@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    MartianDataBinding binding = MartianDataBinding.inflate(getActivity().getLayoutInflater());
    binding.setMarsdata(this);
}

onCreateView pour fragment ressemble à ceci:

@Nullable
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
    return inflater.inflate(R.layout.martian_data, container, false);
}

et des parties de mon fichier de mise en page pour fragment ressemblent à ceci:

<?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>

je soupçonne que MartianDataBinding ne sait pas à quel fichier de mise en page il est supposé être lié - d'où l'erreur. Aucune suggestion?

114
dark_ruby

L'implémentation de la liaison de données doit figurer dans la méthode onCreateView du fragment. Supprimez toutes les liaisons de données existant dans votre méthode OnCreate, Votre onCreateView devrait ressembler à ceci:

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;
}
245
hdioui abdeljalil

Vous êtes réellement encouragé à utiliser la méthode inflate de votre liaison générée et non la méthode 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();
}

Docs for DataBindingUtil.inflate () :

Utilisez cette version uniquement si layoutId est inconnu à l’avance. Sinon, utilisez la méthode de gonflage de Binding générée pour garantir un gonflage conforme au type.

38
Till

Essayez ceci dans 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;
}

On peut simplement récupérer un objet de vue comme mentionné ci-dessous

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;

}
6

Même les autres réponses peuvent bien fonctionner, mais je veux dire la meilleure approche.

Utilisez Binding class's inflate comme recommandé dans Documentation Android.

Une option consiste à gonfler de DataBindingUtilmais seulement si vous ne le savez pas, avez généré la classe de liaison.

--Vous avez généré automatiquement binding class, utilisez cette classe au lieu de DataBindingUtil.

En Java 

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
    HomeFragmentBinding binding = HomeFragmentBinding.inflate(inflater, container, false);
    //set binding variables here
    return binding.getRoot();
}

À Kotlin

lateinit var binding: HomeFragmentBinding 
override fun onCreateView(inflater: LayoutInflater?, container: ViewGroup?, savedInstanceState: Bundle?): View? {
    binding = HomeFragmentBinding.inflate(inflater, container, false)
    return binding.root
}

Dans DataBindingUtil, vous pouvez voir la classe documentation.

gonfler

T inflate (LayoutInflater inflater, 
                int layoutId, 
                ViewGroup parent, 
                boolean attachToParent)

Utilisez cette version uniquement si layoutId est inconnu à l'avance. Sinon, utilisez la méthode de gonflage de Binding générée pour garantir la sécurité du type inflation.

Si votre classe de mise en page n'est pas générée @Voir cette réponse.

6
Khemraj

travailler dans mon code.

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();
}
5
UJWAL GHONGADE

Un exemple complet dans les fragments de liaison de données

FragmentMyProgramsBinding est une classe de liaison générée pour 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);

    }
}
4
vivek yadav

Tout comme la plupart l'ont dit, mais n'oubliez pas de définir LifeCycleOwner
échantillon en Java i.e

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();
}
3
Lefty

Syntaxe 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
}
2
muneikh

Si vous utilisez ViewModel et LiveData Ceci est la syntaxe suffisante

Syntaxe de Kotlin:

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
}
0
Saman Sattari

Un autre exemple à 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
}

Notez que le nom "MartianDataBinding" dépend du nom du fichier de mise en page. Si le fichier s'appelle "martian_data", le nom correct serait MartianDataBinding.

0
akohout

Tout le monde dit à propos de inflate(), mais que se passe-t-il si nous voulons l’utiliser dans onViewCreated()?

Vous pouvez utiliserbind(view)méthode de la classe de liaison concrète pour obtenir une instance ViewDataBinding pour la view.


Habituellement nous écrivons BaseFragment quelque chose comme ceci (simplifié):

// BaseFragment.kt
abstract fun layoutId(): Int

override fun onCreateView(inflater, container, savedInstanceState) = 
    inflater.inflate(layoutId(), container, false)

Et utilisez-le dans un fragment d'enfant.

// 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 tous les fragments utilisent la liaison de données, vous pouvez même simplifier l'utilisation du paramètre type.

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)
    }
}

Je ne sais pas si je peux affirmer que non-null est valide ici, mais vous voyez l'idée. Si vous voulez que ce soit nul, vous pouvez le faire.

0
Tura