IT

Fragment와 함께 데이터 바인딩을 사용하는 방법

lottoking 2020. 6. 8. 08:05
반응형

Fragment와 함께 데이터 바인딩을 사용하는 방법


공식 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그것이 어떤 레이아웃 파일을 바인딩해야하는지 모르기 때문에 오류입니다. 어떤 제안?


데이터 바인딩 구현이 있어야합니다 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;
}

실제로 inflateDataBindingUtil이 아니라 생성 된 Binding 메소드 를 사용하는 것이 좋습니다 .

@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를 미리 알 수없는 경우에만이 버전을 사용하십시오. 그렇지 않으면 생성 된 바인딩의 팽창 방법을 사용하여 형식이 안전한 팽창을 보장하십시오.


당신이 사용하는 경우 의 ViewModel을 하고 LiveData 이 충분한 구문입니다

코 틀린 구문 :

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
}

다른 답변조차 잘 작동 할 수 있지만 최선의 방법을 말하고 싶습니다.

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
}

In DataBindingUtil class documentation you can see.

inflate

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

Use this version only if layoutId is unknown in advance. Otherwise, use the generated Binding's inflate method to ensure type-safe inflation.

If your layout biniding class is not generated @See this answer.


One can simply retrieve view object as mentioned below

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;

}

Try this in 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;
}

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

Kotlin syntax:

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
}

A complete example in data binding Fragments

FragmentMyProgramsBinding is binding class generated for 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);

    }
}

Just as most have said, but dont forget to set LifeCycleOwner
Sample in 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();
}

Another example in 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
}

Note that the name "MartianDataBinding" depends on the name of the layout file. If the file is named "martian_data" then the correct name would be MartianDataBinding.


Everyone says about inflate(), but what if we want to use it in onViewCreated()?

You can use bind(view) method of concrete binding class to get ViewDataBinding instance for the view.


Usually we write BaseFragment something like this (simplified):

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

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

And use it in child fragment.

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


If all Fragments uses data binding, you can even make it simpler using type parameter.

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

I don't know it's okay to assert non-null there, but.. you get the idea. If you want it to be nullable, you can do it.

참고URL : https://stackoverflow.com/questions/34706399/how-to-use-data-binding-with-fragment

반응형