web-dev-qa-db-ja.com

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がどのレイアウトファイルにバインドされることになっているのかわからないということです - それゆえエラーです。助言がありますか?

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

DataBindingUtilではなく、生成されたBindingの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()のドキュメント

このバージョンは、layoutIdが事前に不明な場合にのみ使用してください。それ以外の場合は、生成されたBindingのinflateメソッドを使用して、タイプセーフなインフレーションを確保します。

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

下記のようにビューオブジェクトを取得するだけです。

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;

}

他の答えでもうまくいくかもしれませんが、私は最善のアプローチを教えてほしいのです。

Androidのドキュメントで推奨されているようにBinding class's inflateを使用してください。

1つのオプションは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のinflateメソッドを使用して、タイプセーフなインフレーションを確保します。

あなたのレイアウトビニングクラスが生成されていない場合@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/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

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

コトリンの構文:

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
}
3
muneikh

ほとんどの人が言ったように、LifeCycleOwnerを設定することを忘れないでください
Javaのサンプルつまり

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

コトリンのもう一つの例:

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()でそれを使用したいとしたらどうでしょうか。

ViewDataBindingviewインスタンスを取得するには、具象バインディングクラスのbind(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)
}


すべてのフラグメントがデータバインディングを使用している場合は、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)
    }
}

私はそれがnull以外を主張しても大丈夫かどうかわかりませんが、..あなたはアイデアを得ます。それをNULL可能にしたい場合は、それを実行できます。

0
Tura