5

I have an abstract BaseActivity in my library module:

 @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        //Normal method to inflate the layout
        mBinding = DataBindingUtil.setContentView(this, R.layout.base_view_stub_layout);
        AppCompatDelegate.setCompatVectorFromResourcesEnabled(true);
        if (mBinding != null && mBinding.viewStub != null && mBinding.viewStub.getViewStub() != null) {
            mBinding.viewStub.getViewStub().setLayoutResource(getLayoutId());
        }

        if (!hasStubInflated) {
            View inflatedView = mBinding.viewStub.getViewStub().inflate();
            //Abstract method
            onViewStubInflated(inflatedView, savedInstanceState);
            //Normal method to hide progress bar
            onViewStubInflated();
        }
        initControllers();
        handleViews();
        setListeners();
        restoreValues(savedInstanceState);
    }

The MainActivity from AppModule extends the BaseActivity of library module and hence, getting an abstract method to override:

MainActivity extends BaseActivity

private ActivityMainBinding mBinding;

@Override
    public int getLayoutId() {
        return R.layout.activity_main;
    }

@Override
    public void onViewStubInflated(View inflatedView, Bundle savedInstanceState) {
        if (mBinding == null || mBinding.getRoot() != inflatedView) {
            mBinding = ActivityMainBinding.bind(inflatedView);
        }
    }

When I run the app, I am getting:

 Caused by: java.lang.RuntimeException: view must have a tag
        at com.example.android.emailapp.DataBinderMapperImpl.getDataBinder(DataBinderMapperImpl.java:67)
        at androidx.databinding.MergedDataBinderMapper.getDataBinder(MergedDataBinderMapper.java:74)
        at androidx.databinding.DataBindingUtil.bind(DataBindingUtil.java:199)
        at androidx.databinding.ViewDataBinding.bind(ViewDataBinding.java:693)
        at com.example.android.emailapp.databinding.ActivityMainBinding.bind(ActivityMainBinding.java:99)
        at com.example.android.emailapp.databinding.ActivityMainBinding.bind(ActivityMainBinding.java:87)
        at com.example.android.emailapp.login.MainActivity.onViewStubInflated(MainActivity.java:86)
        at com.library.android.common.ui.baseui.BaseActivity.onCreate(BaseActivity.java:52)

Note that I have layout tag in both xml of BaseActivity and MainActivity.

I have tried this with no success.

Is mBinding.viewStub.getViewStub().setLayoutResource(getLayoutId()) an issue in BaseActivity as it will try to get the layout from AppModule? if it is that, how can I solve it?

If you know the answer, please try to explain why this is happening along with the solution...

Already tried

View must have a tag error

What does it mean by view must have a tag error

How to use databinding for viewstub

Sagar Patel
  • 506
  • 1
  • 8
  • 23

2 Answers2

0

If you are using the custom class as the root view of your_layout.xml then you must override all constructors of view

your class

class MyCustomView : FrameLayout {
    constructor(context: Context) : super(context){
        ...
    }

    constructor(context: Context, attrs: AttributeSet?) : super(context, attrs){
        ...
    }
    constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : super(context, attrs, defStyleAttr){
        ...
    }
}

your layout

<layout xmlns:android="http://schemas.android.com/apk/res/android">
    <data>
        <variable name="viewModel" type="......" />
    </data>

    <MyCustomView
        android:layout_width="match_parent"
        android:layout_height="match_parent">

    </MyCustomView>

</layout>
M--
  • 25,431
  • 8
  • 61
  • 93
jyun
  • 1
0

You must wrap your viewStub's layouts with <layout></layout> as well, which is what they are expecting : Either using DataBinding everywhere, or simply nowhere.


If you don't want DataBinding on the viewStub, then extra work needs to be done.

For example if itemData is the DataBindingImpl object for my listview, and I am to inflate some sort of more options overlay-ViewStub, then I need to store the inflated view myself, and avoid accessing the `mRoot field of the DataBinding's ViewStubProxy

ViewGroup inflated = (ViewGroup) itemData.someView.getTag();
if(inflated==null) {
    ViewStub stub = itemData.viewStubProxy.getViewStub();
    if(stub!=null) {
        stub.setOnInflateListener(null);
        inflated = (ViewGroup) stub.inflate();
        // what I need is simply to set onClickListener on all of it's children. (one for-loop inside)
        Utils.setOnClickListenersOneDepth(inflated, onClickListener, 3, null);
        itemData.someView.setTag(inflated);
    }
}
if(inflated!=null) {
    // what I need then is to animate the overlay. 
    View mRoot = inflated;
    int width = itemData.getRoot().getWidth();
    mRoot.setAlpha(0);
    mRoot.setTranslationX(width/3);
    mRoot.animate().alpha(1);
    mRoot.animate().translationX(0);
}

Never invoke itemData.viewStubProxy.getViewStub().getRoot().isInflated() or so because we are now storing the inflated outside of the DataBindingImpl object.

KnIfER
  • 712
  • 7
  • 13