I have currently coded an app that uses the newer AndroidX library, which runs perfectly fine on an emulator running an SDK version of 29 and higher, however, when I try to run the same app on an emulator running SDK version 28 and lower, I get the following error message:
android.view.InflateException: Binary XML file line #17: Binary XML file line #17: Error inflating class androidx.appcompat.widget.Toolbar
Does this mean that by going to AndroidX I have closed off my chances of allowing this app to run on older devices? Or is this error showing up for different reasons? If is it because of the library change, is there by any chance I can get some advice as to how I could make my app compatible with some of the older SDKs. I'll gladly post any required code to give further clarity.
Edit
I added whatever I though could reproduce the error, as well as removed some of the database related code (you'll see the imports but not the code). It seems to have a problem for when it reaches the line setContentView(R.layout.activity_main)
in the MainActivity.java. Essentially all I have provided is a basic NavigationDrawer setup.
Manifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.fabricanddecor">
<uses-permission android:name="android.permission.INTERNET" />
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity android:name=".MainActivity"
android:configChanges="orientation|screenSize"
android:theme="@style/AppTheme.NoActionBar"
android:windowSoftInputMode="adjustPan">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
MainActivity.java
package com.example.fabricanddecor;
import androidx.annotation.NonNull;
import androidx.appcompat.app.ActionBarDrawerToggle;
import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.widget.Toolbar;
import androidx.drawerlayout.widget.DrawerLayout;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.preference.PreferenceManager;
import android.view.MenuItem;
import android.view.View;
import android.widget.ImageView;
import com.example.fabricanddecor.inventory.category.InventoryCategoryFragment;
import com.example.fabricanddecor.model.Sale;
import com.example.fabricanddecor.profile.ProfileMainFragment;
import com.example.fabricanddecor.reports.ReportMainFragment;
import com.example.fabricanddecor.sale.category.SaleCategoryFragment;
import com.example.fabricanddecor.suppliers.SupplierMainFragment;
import com.google.android.gms.tasks.OnCompleteListener;
import com.google.android.gms.tasks.Task;
import com.google.android.material.navigation.NavigationView;
import com.google.firebase.firestore.FirebaseFirestore;
import com.google.firebase.firestore.FirebaseFirestoreSettings;
import com.google.firebase.firestore.Query;
import com.google.firebase.firestore.QueryDocumentSnapshot;
import com.google.firebase.firestore.QuerySnapshot;
import com.google.gson.Gson;
public class MainActivity extends AppCompatActivity implements NavigationView.OnNavigationItemSelectedListener {
private DrawerLayout drawer;
private ImageView profilePicture;
private NavigationView navigationView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
profilePicture = findViewById(R.id.profile_picture);
Toolbar toolbar = findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
drawer = findViewById(R.id.drawer_layout);
navigationView = findViewById(R.id.nav_view);
navigationView.setNavigationItemSelectedListener(this);
ActionBarDrawerToggle toggle = new ActionBarDrawerToggle(this, drawer, toolbar, R.string.navigation_drawer_open, R.string.navigation_drawer_close);
drawer.addDrawerListener(toggle);
toggle.syncState();
}
@Override
public boolean onNavigationItemSelected(@NonNull MenuItem item) {
switch (item.getItemId())
{
case R.id.nav_sale:
getSupportFragmentManager().beginTransaction().replace(R.id.fragment_container, new SaleCategoryFragment()).addToBackStack("SaleCategory").commit();
break;
case R.id.nav_inventory:
getSupportFragmentManager().beginTransaction().replace(R.id.fragment_container, new InventoryCategoryFragment()).addToBackStack("InventoryCategory").commit();
break;
case R.id.nav_report:
getSupportFragmentManager().beginTransaction().replace(R.id.fragment_container, new ReportMainFragment()).addToBackStack("ReportMain").commit();
break;
case R.id.nav_suppliers:
getSupportFragmentManager().beginTransaction().replace(R.id.fragment_container, new SupplierMainFragment()).addToBackStack("SupplierMain").commit();
break;
}
drawer.close();
return true;
}
@Override
public void onBackPressed()
{
if (drawer.isOpen())
{
drawer.close();
}
else
{
super.onBackPressed();
}
}
public void profileClick(View view)
{
getSupportFragmentManager().beginTransaction().replace(R.id.fragment_container, new ProfileMainFragment()).addToBackStack("ProfileMain").commit();
drawer.close();
}
MainActivity.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.drawerlayout.widget.DrawerLayout 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"
android:id="@+id/drawer_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
tools:context=".MainActivity"
tools:openDrawer="start">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<androidx.appcompat.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="@android:color/secondary_text_dark"
android:elevation="4dp"
android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"
app:popupTheme="@style/ThemeOverlay.AppCompat.Light" />
<FrameLayout
android:id="@+id/fragment_container"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</LinearLayout>
<com.google.android.material.navigation.NavigationView
android:id="@+id/nav_view"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="start"
app:headerLayout="@layout/nav_drawer_header"
app:menu="@menu/nav_drawer_menu" />
</androidx.drawerlayout.widget.DrawerLayout>
Gradle (app)
apply plugin: 'com.android.application'
apply plugin: 'com.google.gms.google-services'
android {
compileSdkVersion 29
buildToolsVersion "29.0.3"
defaultConfig {
applicationId "com.example.fabricanddecor"
minSdkVersion 21
targetSdkVersion 29
versionCode 1
versionName "1.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
}
dependencies {
implementation fileTree(dir: "libs", include: ["*.jar"])
implementation 'androidx.appcompat:appcompat:1.2.0'
implementation 'com.hbb20:ccp:2.4.0'
implementation 'androidx.constraintlayout:constraintlayout:2.0.1'
implementation 'androidx.drawerlayout:drawerlayout:1.1.1'
implementation 'com.google.android.material:material:1.2.1'
implementation "androidx.swiperefreshlayout:swiperefreshlayout:1.1.0"
implementation 'com.google.firebase:firebase-firestore:21.6.0'
implementation 'com.google.firebase:firebase-storage:19.2.0'
implementation 'com.google.firebase:firebase-auth:19.4.0'
testImplementation 'junit:junit:4.12'
androidTestImplementation 'androidx.test.ext:junit:1.1.2'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0'
}
"Does this mean that by going to AndroidX I have closed off my chances of allowing this app to run on older devices?"
Definitely not, AFAIK the lowest supported API level today is 14
Your app crashes for lower API levels because there you can't set a ColorStateList
as background to a View
. It does not depend on whether it's a Toolbar
or a FrameLayout
or a TextView
...
Since @android:color/secondary_text_dark is a resource for a ColorStateList
, you should use android:backgroundTint
instead:
android:backgroundTint="@android:color/secondary_text_dark"
This will keep your app from crashing but unfortunately it is not sufficient to achieve the desired background color.
TL;DR you also need to set some background color:
android:background="#ff0000"
android:backgroundTint="@android:color/secondary_text_dark"
The reason is that the background tint will be applied to the non transparent parts of the background Drawable
:
If you set no background at all, then the background does not need to be drawn, and so there is nothing to apply the tint to. If you set a shape drawable with a round shape as background, then you will get a circle with the tint determined by the backgroundTint
attribute
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.