फ्रेगमेंट के साथ डेटा-बाइंडिंग का उपयोग कैसे करें


182

मैं आधिकारिक Google doc 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पता नहीं है कि यह किस लेआउट फ़ाइल के साथ बाध्य होना चाहिए - इसलिए त्रुटि। कोई सुझाव?

जवाबों:


354

डेटा बाइंडिंग क्रियान्वयन 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;
}

मुझे अपने बाइंडिंग वर्ग उत्पन्न करने के लिए कॉल को सुपर में जोड़ना था।
joey_g216

3
मैं इस मुद्दे पर घंटों संघर्ष करता हूं। समस्या यह थी कि मैंने गलत दृष्टिकोण लौटा दिया। +1
थारकनिरामन

1
View view = binding.getRoot(); मैं इस पर इतने लंबे समय से अटका हुआ हूं कि मैं वैध रूप से बहुत परेशान हूं कि मैं इसके बारे में कोई भी दस्तावेज डेवलपर.android.com पर नहीं पा सका ... समस्या का समाधान किया। धन्यवाद!
विक्टर उडे

1
यदि आप LiveData और ViewModel का उपयोग कर रहे हैं, तो इस उत्तर को पढ़ना सुनिश्चित करें ।
बिग मैकलारेग्यूज

1
सेटर्माडेटा () क्या है? मुझे लगता है कि यहाँ हम setViewModel () का उपयोग करते हैं ??
suv

59

आपको वास्तव inflateमें अपने उत्पन्न बाइंडिंग की विधि का उपयोग करने के लिए प्रोत्साहित किया जाता है न कि डेटाबाइंडिंगबिल:

@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 के लिए डॉक्स () :

इस संस्करण का उपयोग केवल तभी करें जब लेआउटआईड पहले से अज्ञात हो। अन्यथा, टाइपिंग-सुरक्षित मुद्रास्फीति सुनिश्चित करने के लिए उत्पन्न बाइंडिंग के इनफ्लो विधि का उपयोग करें।


दुर्भाग्य से यह मुझे cannot be resolved to a typeनिर्माण पर त्रुटि के साथ मार रहा है । यह मेरी राय में विश्वसनीय नहीं है। अगर मैं इसके साथ पहले जाता हूं DataBindingUtil.inflate(inflater, R.layout.fragment_camera, container, false);और फिर इसे बदल देता हूं FragmentCameraBinding.inflate(inflater, container, false);, तो यह काम करता है, लेकिन इसके पुनर्निर्माण के बाद यह फिर से त्रुटि देता है।
एलेक्स बुरडुलस

बहुत अच्छा काम करता है। वास्तव में लेआउट रेस आईडी (जो मैं पहले सोच रहा था) को निर्दिष्ट करने की आवश्यकता नहीं है क्योंकि यह स्वचालित रूप से उत्पन्न बाइंडिंग फ़ाइल से चुनता है।
5

2
आपने इस उदाहरण में खंड लेआउट id (जैसे। R.layout.fragment_) कहां सेट की है?
लेनिन राज राजसेकरन

यह स्वीकृत उत्तर होना चाहिए। लेआउट जनरेट बाइंडिंग का उपयोग करने के लिए प्रोत्साहित किया जाता है, इसके बजायDataBindingUtil.inflate
मोचडवी

@LeninRajRajasekaran लेआउट आईडी को MainFragmentBindingवर्ग के उपयोग के माध्यम से निहित किया गया है । वह वर्ग लेआउट फ़ाइल से उत्पन्न होता है इसलिए वांछित लेआउट स्वचालित रूप से लागू होता है।
एमिल एस

19

यहां तक ​​कि अन्य उत्तर भी अच्छी तरह से काम कर सकते हैं, लेकिन मैं सबसे अच्छा तरीका बताना चाहता हूं।

Android प्रलेखनBinding class's inflate में अनुशंसित के रूप में उपयोग करें ।

एक विकल्प के लिए फुलाया जाता है, DataBindingUtil लेकिन जब आप केवल यह नहीं जानते कि बाध्यकारी वर्ग उत्पन्न होता है

- आपके पास ऑटो जनरेट है 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)

इस संस्करण का उपयोग केवल तभी करें जब लेआउटआईड पहले से अज्ञात हो। अन्यथा, टाइपिंग-सुरक्षित मुद्रास्फीति सुनिश्चित करने के लिए उत्पन्न बाइंडिंग के इनफ्लो विधि का उपयोग करें।

यदि आपका लेआउट बिनाइडिंग क्लास इस उत्तर पर @See उत्पन्न नहीं करता है ।


उस inflateपद्धति का उपयोग क्यों न करें जो LayoutInflaterइसके एकमात्र तर्क के रूप में लेती है?
फ्लोरियन वाल्थर

@FlorianWalther बिना उस काम करता है ViewGroup container?
खेमराज

खैर, मुझे नहीं पता था कि मैंने यह टिप्पणी कब लिखी है। लेकिन मुझे यहाँ कुछ अच्छा जवाब मिला: stackoverflow.com/questions/61571381/…
फ्लोरियन वाल्थर

1
@FlorianWalther ठीक है, मैंने जवाब पढ़ा है, containerजब जरूरत attachToRootहै true
खेमराज

16

यदि आप ViewModel और LiveData का उपयोग कर रहे हैं तो यह पर्याप्त वाक्यविन्यास है

कोटलिन सिंटेक्स:

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 में यह प्रयास करें

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

जैसा कि नीचे उल्लेख किया गया है, केवल एक वस्तु को पुनः प्राप्त कर सकते हैं

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

कोटलीन वाक्य रचना:

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
}

6

बस के रूप में सबसे अधिक कहा है, लेकिन सेट करने के लिए न भूलें LifeCycleOwner
जावा में नमूना यानी

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

मेरे कोड में काम कर रहा है।

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

डेटा बाइंडिंग फ़्रैगमेंट्स में एक पूर्ण उदाहरण

FragmentMyProgramsBinding Res / लेआउट / 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);

    }
}

2

Databinding के बारे में बहुत उपयोगी ब्लॉग: 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 में इस तरह बाध्यकारी घाटी घोषित करें:

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

इस टुकड़े में लिखना मत भूलना

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

1

कोटलिन में एक और उदाहरण:

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 होगा।


0

हर कोई कहता है 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)
    }
}

मुझे नहीं पता कि वहाँ गैर-अशक्त करना ठीक है, लेकिन .. आप विचार प्राप्त करते हैं। यदि आप चाहते हैं कि यह अशक्त हो, तो आप इसे कर सकते हैं।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.