Search code examples
javaandroidkotlindata-bindingbottomnavigationview

Databinding not working with BaseActivity that overrides BottomNavActivity . setContentView called twice


Activity not working because setContentView is being called two times.

This is my activity_main layout:

<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools">

    <data>
        <import type="android.view.View"/>
       <variable
           name="viewmodel"
           type="com.project.viewmodel.MainViewModel" />
    </data>

    <androidx.constraintlayout.widget.ConstraintLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <androidx.swiperefreshlayout.widget.SwipeRefreshLayout
            android:id="@+id/pullToRefresh"
            android:layout_width="match_parent"
            android:layout_height="0dp"
            android:layout_marginTop="?attr/actionBarSize"
            android:background="@color/transparent"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="parent"
            app:layout_constraintBottom_toTopOf="@id/bottom_nav">

            <androidx.constraintlayout.widget.ConstraintLayout
                android:id="@+id/content_layout"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:orientation="vertical">
                  <androidx.viewpager.widget.ViewPager
                    android:id="@+id/view_pager"
                    android:layout_width="match_parent"
                    android:layout_height="0dp"
                    android:clipToPadding="false"
                    android:foregroundGravity="center"
                    android:overScrollMode="never"
                    app:layout_constraintBottom_toTopOf="@+id/tabLayout"
                    app:layout_constraintEnd_toEndOf="parent"
                    app:layout_constraintStart_toStartOf="parent"
                    app:layout_constraintTop_toBottomOf="@+id/search_image_view"
                    android:visibility="@{safeUnbox(viewmodel.dataLoading) ? View.VISIBLE : View.VISIBLE}"/>
         
            </androidx.constraintlayout.widget.ConstraintLayout>

        </androidx.swiperefreshlayout.widget.SwipeRefreshLayout>

        <com.google.android.material.bottomnavigation.BottomNavigationView
            android:id="@+id/bottom_nav"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_alignParentBottom="true"
            android:layout_marginTop="@dimen/_5sdp"
            android:background="@drawable/bottom_nav_background"
            android:clipChildren="false"
            android:visibility="visible"
            app:elevation="8dp"
            app:labelVisibilityMode="labeled"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintVertical_bias="1"
            app:menu="@menu/bottom_nav" />

    </androidx.constraintlayout.widget.ConstraintLayout>
</layout>

MainActivity.kt

class MainActivity : BottomNavActivity() {
    private lateinit var binding: ActivityWeatherNewBinding

    override fun getContentViewId(): Int {
        return R.layout.activity_main
    }

    override fun getNavigationMenuItemId(): Int {
        return R.id.nav_main
    }

    override fun onCreate(savedInstanceState: Bundle?) {

        binding = DataBindingUtil.setContentView(this, R.layout.activity_main)
        super.onCreate(savedInstanceState)
}
}

BottomNavigationActivity.java is being used to set BottomNavigation where setContentView gets called again.

 @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(getContentViewId());
        bottomNavigationView = findViewById(R.id.bottom_nav);
        bottomNavigationView.setOnNavigationItemSelectedListener(this);
    }
 @Override
    public boolean onNavigationItemSelected(@NonNull MenuItem item) {
        int itemId = item.getItemId();
        int currentItemId = getNavigationMenuItemId();
        if (itemId == currentItemId) {
            if (itemId == R.id.one) {
                
            }
            return false;
        }
        if (itemId == R.id.two) {
            startActivity(new Intent(this, TwoActivity.class));
        } 
        return true;
    }

    private void updateNavigationBarState() {
        int actionId = getNavigationMenuItemId();
        selectBottomNavigationBarItem(actionId);
    }

    void selectBottomNavigationBarItem(int itemId) {
        Menu menu = bottomNavigationView.getMenu();
        for (int i = 0, size = menu.size(); i < size; i++) {
            MenuItem item = menu.getItem(i);
            boolean shouldBeChecked = item.getItemId() == itemId;
            if (shouldBeChecked) {
                item.setChecked(true);
                break;
            }
        }
    }

    protected abstract int getContentViewId();

    protected abstract int getNavigationMenuItemId();

The issue is I can't modify BottomNavActivity and I was working on this new MainActivity where I have to extend BottomNavActivity for bottom navigation.

And when I call super.onCreate() in MainActivity after setting DataBinding then the bottom navigation works fine but Viewpager doesn't show. And when I set onCreate before binding then viewpager shows but Bottom Navigation doesn't work. I tried to look for alternate solution on the internet but I can't find anything and the issue still remains. I know I'm facing this issue because setContentView is getting called twice. But I can't find a work around.

Two possible solutions:

  1. I can either set the bottom navigation listener again on MainActivity but then BottomNavActivity won't make sense.
  2. Or I can just use the good old findViewById and remove Data Binding completely.

My question is Is there any way to fix this while still using Data Binding and making use of BottomNavActivity? Any suggestions or ideas would be of great help and would be appreciated.


Solution

  • Found the solution

    In MainActivity I set the binding variable first, then I sent the variable to BottomNavactivity

    binding = DataBindingUtil.setContentView(this, R.layout.activity_weather_new)
    setDataBinding(binding)
    super.onCreate(savedInstanceState)
    

    BottomNavActivity

     @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            if(binding == null){
                setContentView(getContentViewId());
                bottomNavigationView = findViewById(R.id.bottom_nav);
            }else {
                bottomNavigationView = binding.bottomNav;
    
            }
            bottomNavigationView.setOnNavigationItemSelectedListener(this);
        }
    public void setDataBinding(ActivityWeatherNewBinding activityWeatherNewBinding){
            binding = activityWeatherNewBinding;
        }
    

    getting bottomNav view using binding variable, thus preventing the second call to setContentView