简体   繁体   中英

Running a newer app on an older SDK version

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM