Fragment ile veri bağlama nasıl kullanılır


183

Resmi google doc'dan veri bağlama örneğini takip etmeye çalışıyorum https://developer.android.com/tools/data-binding/guide.html

dışında bir etkinliğe değil, bir parçaya veri ayırma uygulamak çalışıyorum dışında.

derlerken şu anda aldığım hata

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

onCreate fragman için şuna benzer:

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

onCreateView fragman için şuna benzer:

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

ve parça için benim düzen dosya bölümleri şöyle:

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

benim şüphe ile MartianDataBindinghangi düzen dosyası bağlı olması gerektiğini bilmiyor - bu nedenle hata. Baska öneri?

Yanıtlar:


354

Veri bağlama uygulaması onCreateView, parçanın yönteminde olmalı, yönteminizde mevcut olan tüm Veri Bağlamalarını silmeli OnCreate, onCreateViewşöyle görünmelidir:

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

Binding sınıf oluşturmak için süper çağrı eklemek zorunda kaldı.
joey_g216

3
Saatlerce bu sorunla mücadele ediyorum. Sorun yanlış görünümü döndü oldu. +1
TharakaNirmana

1
View view = binding.getRoot(); Bu kadar uzun süredir takıldım ki, developer.android.com'da bu konuda herhangi bir belge bulamadığım için oldukça üzgünüm. Sorun çözüldü. Teşekkür ederim!
Victor Ude

1
LiveData ve ViewModel kullanıyorsanız, bu yanıtı mutlaka okuyun .
Büyük McLargeHuge

1
setMarsdata () nedir? Burada setViewModel () kullandığımı düşünüyorum ??
suv

59

Aslında inflate, DataBindingUtil yerine oluşturduğunuz Binding yöntemini kullanmanız önerilir :

@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 () için dokümanlar :

Bu sürümü yalnızca layoutId önceden bilinmiyorsa kullanın. Aksi takdirde, tür güvenli enflasyonu sağlamak için oluşturulan Binding'ın şişirme yöntemini kullanın.


Ne yazık ki bu beni cannot be resolved to a typeyapı hatasıyla öldürüyor . Bence güvenilir değil. Ben ilk gidip DataBindingUtil.inflate(inflater, R.layout.fragment_camera, container, false);sonra değiştirmek FragmentCameraBinding.inflate(inflater, container, false);, çalışır, ancak yeniden sonra hata tekrar verir.
Alex Burdusel

Harika çalışıyor. Aslında, oluşturulan bağlama dosyasından otomatik olarak aldığı için (daha önce merak ettiğim) düzen res kimliğini belirtmeye gerek yoktur.
eC Droid

2
bu örnekte parça yerleşimi kimliğini (ör. R.layout.fragment_) nerede ayarlıyorsunuz?
Lenin Raj Rajasekaran

bu kabul edilen cevap olmalıdır. oluşturulan düzen cilt yerine kullanılması teşvik edilirDataBindingUtil.inflate
mochadwi

@LeninRajRajasekaran Yerleşim kimliği, MainFragmentBindingsınıfın kullanılmasıyla ima edilir . Bu sınıf mizanpaj dosyasından oluşturulur, böylece istenen mizanpaj otomatik olarak uygulanır.
Emil S.

19

Diğer cevaplar bile işe yarayabilir, ama en iyi yaklaşımı söylemek istiyorum.

Android Belgeleri'ndeBinding class's inflate önerildiği gibi kullanın .

Bir seçenek şişirmek DataBindingUtil ama sadece bilmediğinizde bağlayıcı sınıf oluşturdunuz .

--Otomatik olarak oluşturdunuz binding class, kullanmak yerine bu sınıfı kullanın DataBindingUtil.

Java dilinde

@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 bölgesinde

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

In DataBindingUtil sınıfı belgelerine görebilirsiniz.

şişirmek

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

Bu sürümü yalnızca layoutId önceden bilinmiyorsa kullanın. Aksi takdirde, tür güvenli enflasyonu sağlamak için oluşturulan Binding'ın şişirme yöntemini kullanın.

Düzen biniding sınıfınız oluşturulmamışsa @ Bu cevaba bakınız .


neden tek argüman olarak alan inflateyöntemi kullanmıyorsunuz LayoutInflater?
Florian Walther

@FlorianWalther olmadan çalışır ViewGroup container?
Khemraj

Bu yorumu ne zaman yazdığımı bilmiyordum. Ama burada iyi bir cevap aldım: stackoverflow.com/questions/61571381/…
Florian Walther

1
@FlorianWalther tamam, cevabı, okudum containerne zaman ihtiyaç vardır attachToRootolduğunu true.
Khemraj

17

ViewModel ve LiveData kullanıyorsanız Bu, yeterli sözdizimidir

Kotlin Sözdizimi:

override fun onCreateView(
    inflater: LayoutInflater,
    container: ViewGroup?,
    savedInstanceState: Bundle?
): View? {
    return MartianDataBinding.inflate(
        inflater,
        container,
        false
    ).apply {
        lifecycleOwner = viewLifecycleOwner
        vm = viewModel    // Attach your view model here
    }.root
}

10

Android DataBinding'da bunu deneyin

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

7

Sadece aşağıda belirtildiği gibi görüntüleme nesnesini alabilirsiniz

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;

}

7

Kotlin sözdizimi:

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
}

7

Sadece çoğu söylediler, fakat ayarlamayı unutmayın daha dont olarak LifeCycleOwner
Java Numune yani

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

5

benim kodumda çalışıyor.

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

Veri bağlama parçalarında tam bir örnek

FragmentMyProgramsBinding res / layout / fragment_my_programs için oluşturulan bağlayıcı sınıftır

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

    }
}

2

Veri Bağlama hakkında çok yararlı blog: https://link.medium.com/HQY2VizKO1

class FragmentBinding<out T : ViewDataBinding>(
    @LayoutRes private val resId: Int
) : ReadOnlyProperty<Fragment, T> {

    private var binding: T? = null

    override operator fun getValue(
        thisRef: Fragment,
        property: KProperty<*>
    ): T = binding ?: createBinding(thisRef).also { binding = it }

    private fun createBinding(
        activity: Fragment
    ): T = DataBindingUtil.inflate(LayoutInflater.from(activity.context),resId,null,true)
}

Fragment'ta şu şekilde bağlayıcı val bildir:

private val binding by FragmentBinding<FragmentLoginBinding>(R.layout.fragment_login)

Bunu bir parça halinde yazmayı unutma

override fun onCreateView(
    inflater: LayoutInflater,
    container: ViewGroup?,
    savedInstanceState: Bundle?
): View? {
    return binding.root
}

1

Kotlin'de bir başka örnek:

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" adının mizanpaj dosyasının adına bağlı olduğunu unutmayın. Dosya "martian_data" olarak isimlendirilirse, doğru isim MartianDataBinding olur.


0

Herkes inflate()ne diyor , ama eğer onu kullanmak istiyorsak onViewCreated()?

Örnek bind(view)almak ViewDataBindingiçin beton bağlama sınıfı yöntemini kullanabilirsiniz view.


Genellikle BaseFragment'ı böyle bir şey yazıyoruz (basitleştirilmiş):

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

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

Ve çocuk parçasında kullanın.

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


Tüm Parçalar veri bağlama kullanıyorsa, type parametresini kullanarak bunu daha da basitleştirebilirsiniz.

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

Orada null olmadığını iddia etmenin bir sakıncası olmadığını bilmiyorum ama ... Null edilebilir olmasını istiyorsanız, bunu yapabilirsiniz.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.