it-swarm.com.ru

Как использовать привязку данных с фрагментом

Я пытаюсь следовать примеру привязки данных из официального документа 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 не знает, с каким файлом макета он должен быть связан - отсюда и ошибка. Какие-либо предложения?

138
dark_ruby

Реализация привязки данных должна быть в методе 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;
}
245
hdioui abdeljalil

На самом деле вам рекомендуется использовать метод inflate вашего сгенерированного Binding, а не 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();
}

Документы для DataBindingUtil.inflate () :

Используйте эту версию, только если layoutId заранее неизвестен. В противном случае используйте сгенерированный метод инфляции Binding, чтобы обеспечить безопасную инфляцию.

38
Till

Попробуйте это в 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;
}
6
Jirawat Harnsiriwatanakit

Можно просто получить вид объекта, как указано ниже

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
Imran Solanki - GSLab

Даже другие ответы могут работать хорошо, но я хочу сказать лучший подход.

Используйте Binding class's inflate, как рекомендовано в Документация Android.

Один из вариантов - накачать DataBindingUtil, но только если вы не знаете, что сгенерирован класс привязки.

- Вы автоматически сгенерировали binding class, используйте этот класс вместо DataBindingUtil.

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

В Котлине

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)

Используйте эту версию, только если layoutId заранее неизвестен. В противном случае используйте сгенерированный метод наложения Binding, чтобы обеспечить безопасность типов инфляция.

Если ваш класс связывания макета не сгенерирован @See этот ответ.

6
Khemraj

работает в моем коде.

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

Полный пример фрагментов привязки данных

FragmentMyProgramsBinding - это класс привязки, созданный для res/layout/frag_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

Синтаксис Котлина:

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

Если вы используете ViewModel и LiveData Это достаточный синтаксис

Синтаксис Котлина:

override fun onCreateView(
    inflater: LayoutInflater,
    container: ViewGroup?,
    savedInstanceState: Bundle?
): View? {
    return MartianDataBinding.inflate(
        inflater,
        container,
        false
    ).apply {
        setLifecycleOwner([email protected])
        vm = viewModel    // Attach your view model here
    }.root
}
0
Saman Sattari

Еще один пример в Котлине:

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
akohout

Все говорят о 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)
    }
}

Я не знаю, что это нормально утверждать ненулевое значение там, но .. вы поняли идею. Если вы хотите, чтобы это было обнуляемым, вы можете сделать это.

0
Tura