首页 > 解决方案 > 在较旧的 SDK 版本上运行较新的应用程序

问题描述

我目前编写了一个使用较新 AndroidX 库的应用程序,它在运行 SDK 版本 29 及更高版本的模拟器上运行得非常好,但是,当我尝试在运行 SDK 版本 28 及更低版本的模拟器上运行相同的应用程序时,我收到以下错误消息:

android.view.InflateException: Binary XML file line #17: Binary XML file line #17: Error inflating class androidx.appcompat.widget.Toolbar

这是否意味着通过使用 AndroidX 我已经关闭了允许该应用在旧设备上运行的机会?还是由于不同的原因出现此错误?如果是因为库的变化,我是否有机会获得一些关于如何使我的应用程序与一些较旧的 SDK 兼容的建议。我很乐意发布任何必需的代码以进一步说明问题。

编辑

我添加了任何可以重现错误的内容,并删除了一些与数据库相关的代码(您将看到导入但看不到代码)。当它到达setContentView(R.layout.activity_main)MainActivity.java 中的行时似乎有问题。基本上我提供的只是一个基本的 NavigationDrawer 设置。

清单.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>

摇篮(应用程序)

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'
}

标签: android

解决方案


“这是否意味着通过使用 AndroidX,我已经关闭了允许该应用在旧设备上运行的机会?”

绝对不是,AFAIK今天支持的最低 API 级别是 14

您的应用程序因较低的 API 级别而崩溃,因为您无法将 aColorStateList作为背景设置为View. 它不取决于它是aToolbar还是aFrameLayout还是a TextView...

由于 @android:color/secondary_text_dark 是 a 的资源ColorStateList,因此您应该android:backgroundTint改用:

android:backgroundTint="@android:color/secondary_text_dark"

这将防止您的应用程序崩溃,但不幸的是,它不足以实现所需的背景颜色。

TL;DR 你还需要设置一些背景颜色:

android:background="#ff0000"            
android:backgroundTint="@android:color/secondary_text_dark"  

原因是背景色调将应用于背景的非透明部分Drawable

如果您根本没有设置背景,则不需要绘制背景,因此无需应用色调。如果你设置一个圆形的可绘制形状作为背景,那么你会得到一个由backgroundTint属性决定的色调的圆形


推荐阅读