DataBinding Binder doesn't work on 2 identical layouts with different qualifiers

216 views Asked by At

I have 2 layout files. One is the default one, and the other is sw720dp. Obviously, they both share the same model:

<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:fresco="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools">

<data>

    <import type="java.lang.String" />

    <variable
        name="product"
        type="com.test.test.test.test.Product" />
</data>

<ScrollView
    android:layout_width="match_parent"
    android:layout_height="wrap_content">

    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="@color/white"
        android:orientation="vertical"
        tools:context="com.test.test.test.test.ProductDetailsFragment">

        <RelativeLayout
            android:id="@+id/ll_custome_action_bar"
            android:layout_width="match_parent"
            android:layout_height="56dp"
            android:background="@color/light_blue_900"
            android:orientation="horizontal">

            <TextView
                android:id="@+id/tv_back_button"
                android:layout_width="wrap_content"
                android:layout_height="match_parent"
                android:layout_alignParentLeft="true"
                android:layout_alignParentStart="true"
                android:gravity="center_vertical"
                android:padding="16dp"
                android:text="@string/fa_arrow_left"
                android:textColor="@color/white"
                android:textSize="22sp" />

            <TextView
                android:id="@+id/tv_product_name"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_centerInParent="true"
                android:ellipsize="end"
                android:gravity="center"
                android:maxLines="1"
                android:paddingLeft="46dp"
                android:paddingRight="46dp"
                android:text="@{product.name}"
                android:textColor="@color/white"
                android:textSize="18sp" />
        </RelativeLayout>

        <com.facebook.drawee.view.SimpleDraweeView
            android:id="@+id/vp_product_images"
            android:layout_width="match_parent"
            android:layout_height="150dp"
            android:layout_below="@+id/ll_custome_action_bar"
            fresco:actualImageScaleType="centerCrop"
            fresco:placeholderImage="@drawable/placeholder2" />

        <Button
            android:id="@+id/btn_add_to_card"
            android:layout_width="232dp"
            android:layout_height="wrap_content"
            android:layout_below="@+id/btn_wishlist"
            android:layout_centerHorizontal="true"
            android:layout_marginBottom="16dp"
            android:background="@drawable/selector_button_green"
            android:text="@string/add_to_cart"
            android:textColor="@color/white"
            android:textSize="16sp" />

        <Button
            android:id="@+id/btn_wishlist"
            android:layout_width="232dp"
            android:layout_height="wrap_content"
            android:layout_below="@+id/ll_price_holder"
            android:layout_centerHorizontal="true"
            android:layout_marginBottom="16dp"
            android:layout_marginLeft="16dp"
            android:layout_marginRight="16dp"
            android:background="@drawable/selector_button_red"
            android:text="@string/wishlist"
            android:textColor="@color/white"
            android:textSize="16sp" />

        <LinearLayout
            android:id="@+id/ll_product_info_holder"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_below="@+id/ll_product_images"
            android:layout_marginLeft="16dp"
            android:layout_marginRight="16dp"
            android:layout_marginTop="5dp"
            android:background="@drawable/drawable_border"
            android:orientation="vertical">

            <TextView
                android:id="@+id/tv_product_description_title"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:background="@color/light_blue_900"
                android:gravity="center"
                android:padding="3dp"
                android:text="@string/description"
                android:textColor="@color/white"
                android:textSize="16sp" />

            <TextView
                android:id="@+id/tv_product_description_value"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:padding="16dp"
                android:text="@{product.description}"
                android:textColor="@color/gray_800"
                android:textSize="12sp" />
        </LinearLayout>

        <LinearLayout
            android:id="@+id/ll_price_holder"
            android:layout_width="264dp"
            android:layout_height="wrap_content"
            android:layout_below="@+id/ll_product_info_holder"
            android:layout_centerHorizontal="true"
            android:gravity="center"
            android:orientation="horizontal">

            <LinearLayout
                android:id="@+id/ll_total_price_holder"
                android:layout_width="100dp"
                android:layout_height="wrap_content"
                android:layout_margin="@dimen/screen_edge_margin"
                android:background="@drawable/drawable_border"
                android:orientation="vertical">

                <TextView
                    android:id="@+id/tv_total_price_title"
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:background="@color/light_blue_900"
                    android:gravity="center"
                    android:padding="3dp"
                    android:paddingLeft="8dp"
                    android:paddingRight="8dp"
                    android:text="@string/basePrice"
                    android:textColor="@color/white"
                    android:textSize="16sp" />

                <LinearLayout
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:orientation="horizontal"
                    android:padding="16dp">

                    <TextView
                        android:id="@+id/tv_total_price_value"
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:gravity="center"
                        android:text="@{product.normalPrice}"
                        android:textColor="@color/gray_800"
                        android:textSize="14sp" />

                    <TextView
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:text="@string/blank_space"
                        android:textColor="@color/white"
                        android:textSize="12sp" />

                    <TextView
                        android:id="@+id/tv_total_price_currency"
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:gravity="center"
                        android:text="@{product.productionData}"
                        android:textColor="@color/gray_800"
                        android:textSize="14sp" />

                </LinearLayout>


            </LinearLayout>

            <LinearLayout
                android:id="@+id/ll_your_price_holder"
                android:layout_width="100dp"
                android:layout_height="wrap_content"
                android:layout_margin="@dimen/screen_edge_margin"
                android:layout_marginLeft="8dp"
                android:layout_marginStart="8dp"
                android:background="@drawable/drawable_border"
                android:orientation="vertical">

                <TextView
                    android:id="@+id/tv_your_price_title"
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:background="@color/light_blue_900"
                    android:gravity="center"
                    android:padding="3dp"
                    android:paddingLeft="8dp"
                    android:paddingRight="8dp"
                    android:text="@string/yourPrice"
                    android:textColor="@color/white"
                    android:textSize="16sp" />

                <LinearLayout
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:orientation="horizontal"
                    android:padding="16dp">

                    <TextView
                        android:id="@+id/tv_your_price_value"
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:gravity="center"
                        android:text="@{product.specialPrice}"
                        android:textColor="@color/gray_800"
                        android:textSize="14sp" />

                    <TextView
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:text="@string/blank_space"
                        android:textColor="@color/white"
                        android:textSize="12sp" />

                    <TextView
                        android:id="@+id/tv_your_price_currency"
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:gravity="center"
                        android:text="@{product.productionData}"
                        android:textColor="@color/gray_800"
                        android:textSize="14sp" />

                </LinearLayout>


            </LinearLayout>
        </LinearLayout>

        <LinearLayout
            android:id="@+id/ll_product_images"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_below="@+id/vp_product_images"
            android:layout_marginLeft="16dp"
            android:layout_marginRight="16dp"
            android:layout_marginTop="20dp"
            android:orientation="horizontal">

            <com.facebook.drawee.view.SimpleDraweeView
                android:id="@+id/vp_product_image_1"
                android:layout_width="100dp"
                android:layout_height="70dp"
                android:layout_margin="5dp"
                android:layout_weight="1"
                fresco:actualImageScaleType="centerCrop"
                fresco:placeholderImage="@drawable/placeholder2" />

            <com.facebook.drawee.view.SimpleDraweeView
                android:id="@+id/vp_product_image_2"
                android:layout_width="100dp"
                android:layout_height="70dp"
                android:layout_margin="5dp"
                android:layout_weight="1"
                fresco:actualImageScaleType="centerCrop"
                fresco:placeholderImage="@drawable/placeholder2" />

            <com.facebook.drawee.view.SimpleDraweeView
                android:id="@+id/vp_product_image_3"
                android:layout_width="100dp"
                android:layout_height="70dp"
                android:layout_margin="5dp"
                android:layout_weight="1"
                fresco:actualImageScaleType="centerCrop"
                fresco:placeholderImage="@drawable/placeholder2" />

        </LinearLayout>

    </RelativeLayout>
</ScrollView>

Then, in my fragment I access the binder like this FragmentProductDetailsBinding mBinder and later on mBinder.setProduct(mProduct);.

public class ProductDetailsFragment extends BaseFragment implements ProductDetailsView {

private static final String ARG_PARAM1 = "param1";
private static final String ARG_PARAM2 = "param2";
public static final String ACTION_SHOW_ACTION_BAR = ProductDetailsFragment.class.getName() + ".show_action_bar";
public static final String ACTION_HIDE_ACTION_BAR = ProductDetailsFragment.class.getName() + ".hide_action_bar";
public static final String ACTION_BACK = ProductDetailsFragment.class.getName() + ".back";
public static final String ACTION_ADD_TO_CART = ProductDetailsFragment.class.getName() + ".add_to_cart";
public static final String ACTION_ADD_TO_WISHLIST = ProductDetailsFragment.class.getName() + ".add_to_wishlit";

FragmentProductDetailsBinding mBinder;
Shop mShop;
Product mProduct;
ProductDetailsPresenter mPresenter;
PreferenceAdapter mPreferenceAdapter;

public ProductDetailsFragment() {
    // Required empty public constructor
}

/**
 * Use this factory method to create a new instance of
 * this fragment using the provided parameters.
 *
 * @param product Parameter 1.
 * @return A new instance of fragment ProductDetailsFragment.
 */
public static ProductDetailsFragment newInstance(Shop shop, Product product) {
    ProductDetailsFragment fragment = new ProductDetailsFragment();
    Bundle args = new Bundle();
    args.putParcelable(ARG_PARAM1, Parcels.wrap(shop));
    args.putParcelable(ARG_PARAM2, Parcels.wrap(product));
    fragment.setArguments(args);
    return fragment;
}

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    if (getArguments() != null) {
        Parcelable parcelable;
        parcelable = getArguments().getParcelable(ARG_PARAM1);
        mShop = Parcels.unwrap(parcelable);
        parcelable = getArguments().getParcelable(ARG_PARAM2);
        mProduct = Parcels.unwrap(parcelable);
    }
}

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
    mBinder = DataBindingUtil.inflate(inflater, R.layout.fragment_product_details, container, false);
    setUIListeners();
    mPresenter = new ProductDetailsPresenterImpl(this);
    mPreferenceAdapter = new PreferenceAdapter(getContext());
    mBinder.setProduct(mProduct);
    setImages();
    setPriceVisibility();
    sendActionToActivity(ACTION_HIDE_ACTION_BAR);

    if (isUserLogged()) {
        mBinder.btnWishlist.setVisibility(View.VISIBLE);
    } else {
        mBinder.btnWishlist.setVisibility(View.GONE);
    }
    return mBinder.getRoot();
}

@Override
public void onDestroyView() {
    super.onDestroyView();
    mPresenter.cleanup();
    sendActionToActivity(ACTION_SHOW_ACTION_BAR);
}

@Override
protected void setTypeface() {
    mBinder.tvBackButton.setTypeface(FontManager.getInstance().getFontAwesome());
}

private void setUIListeners() {
    mBinder.btnAddToCard.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            sendActionToActivity(ACTION_ADD_TO_CART, mShop, mProduct);
        }
    });
    mBinder.btnWishlist.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            sendActionToActivity(ACTION_ADD_TO_WISHLIST, mShop, mProduct);

        }
    });
    mBinder.tvBackButton.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            sendActionToActivity(ACTION_BACK);
        }
    });
}

private void setImages() {
    String imagePathMax = mPreferenceAdapter.readImagePathMax();
    String imagePathNormal = mPreferenceAdapter.readImagePathNormal();
    String imageExtension = mPreferenceAdapter.readImageExtension();

    String input = mProduct.getId();
    input = input.replace(" ", "");

    String image = imagePathMax + input + imageExtension;
    String image_01 = imagePathNormal + input + "_01" + imageExtension;
    String image_02 = imagePathNormal + input + "_02" + imageExtension;
    final Uri imageUri = Uri.parse(image);
    final Uri image_01Uri = Uri.parse(image_01);
    final Uri image_02Uri = Uri.parse(image_02);
    mBinder.vpProductImages.setImageURI(imageUri);
    mBinder.vpProductImage1.setImageURI(imageUri);
    mBinder.vpProductImage2.setImageURI(image_01Uri);
    mBinder.vpProductImage3.setImageURI(image_02Uri);

    mBinder.vpProductImage1.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            mBinder.vpProductImages.setImageURI(imageUri);
        }
    });

    mBinder.vpProductImage2.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            mBinder.vpProductImages.setImageURI(image_01Uri);
        }
    });

    mBinder.vpProductImage3.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            mBinder.vpProductImages.setImageURI(image_02Uri);
        }
    });
}

private void setPriceVisibility() {
    if (mBinder.getProduct().getNormalPrice().equals(mBinder.getProduct().getSpecialPrice())) {
        mBinder.llTotalPriceHolder.setVisibility(View.VISIBLE);
        mBinder.llYourPriceHolder.setVisibility(View.GONE);
    } else {
        mBinder.llTotalPriceHolder.setVisibility(View.VISIBLE);
        mBinder.llYourPriceHolder.setVisibility(View.VISIBLE);
    }
}

@Override
public void logoutShop(Shop shop) {

}

@Override
public void showError(Error error) {

}

@Override
public void showProgress(boolean show) {

}

private void sendActionToActivity(String action) {
    if (mListener == null) {
        return;
    }
    Bundle bundle = new Bundle();
    bundle.putString(Constants.ACTION_KEY, action);
    mListener.onFragmentInteraction(bundle);
}

private void sendActionToActivity(String action, Shop shop, Product product) {
    if (mListener == null) {
        return;
    }
    Bundle bundle = new Bundle();
    bundle.putString(Constants.ACTION_KEY, action);
    bundle.putParcelable(Constants.DATA_KEY_1, Parcels.wrap(shop));
    bundle.putParcelable(Constants.DATA_KEY_2, Parcels.wrap(product));
    mListener.onFragmentInteraction(bundle);
}

public void logoutShop() {
    AsyncExecutor.create().execute(new AsyncExecutor.RunnableEx() {
        @Override
        public void run() throws Exception {
            mPresenter.logoutShop(mShop);
            ShopRepository shopRepository;
            shopRepository = new ShopRepository();
            mShop.setLoginId(-1);
            mShop.setCustomerId(-1);
            mShop.setCartNumber(0);
            mShop.setLineNumber(0);
            mShop.setCartItems(0);
            shopRepository.updateLoginNumber(mShop);
            shopRepository.updateCart(mShop);
            notifyChanges();
        }
    });
}

private boolean isUserLogged() {
    return mShop != null && mShop.getLoginId() != -1;

}

private void notifyChanges() {
    AuthShopResult event;
    event = new AuthShopResult();
    event.setShop(mShop);
    EventBus.getDefault().post(event);
}
}

But when I try to run my app on tablet, and expect that the other layout is used, but I get an error at the binder.

C:\ProductDetailsFragment.java Error:(179, 65) error: cannot find symbol method getProduct() Error:(179, 20) error: cannot find symbol method getProduct() Error:Execution failed for task ':app:compileDebugJavaWithJavac'. Compilation failed; see the compiler error output for details. Information:BUILD FAILED Information:Total time: 6.231 secs Information:3 errors Information:0 warnings Information:See complete output in console

The getProduct() error can be found in setPriceVisibility() method.

According to me FragmentProductDetailsBinding mBinder refers only to the standard layout, but there's no binder for the sw720dp layout. How do I solve this?

EDIT: I've added the following:

FragmentProductDetailsBindingSw720dpImpl mBinder720;
mBinder720 = DataBindingUtil.inflate(inflater, R.layout.fragment_product_details, container, false);
mBinder720.setProduct(mProduct);
mBinder720.getProduct().getNormalPrice().equals(mBinder720.getProduct().getSpecialPrice())

This way I have two binders and it works, but there must be a better way.

EDIT 2: I've posted the question at the Android bug tracker, please feel free to correct me if you have any suggestion.

1

There are 1 answers

5
tynn On

For some reason the getter is not defined on the binding class FragmentProductDetailsBinding like it's documented:

The generated binding class will have a setter and getter for each of the described variables. The variables will take the default Java values until the setter is called — null for reference types, 0 for int, false for boolean, etc.

The *Impl classes extend this class and define this getter method while the setter is overridden. So I'd consider this to be a bug on the data binding generation side.

In your case you could work around this by using mProduct from your Fragment directly.