android - 在较旧的 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'
}
解决方案
“这是否意味着通过使用 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
属性决定的色调的圆形
推荐阅读
- c# - 如何签署 DLL 的文件版本和产品版本?
- spring-boot - 如何使用 @ApiModelProperty 添加多个数据类型
- python - 创建一个 python 脚本来模拟一个 Matlab 文件并存储结果
- php - 不同视频分辨率的理想比特率
- reactjs - React Redux TypeError:无法读取未定义的属性“地图”
- ruby-on-rails - Ruby:悲观锁的最大等待时间?
- angular - 如何在 ngrx/effects 中访问解析器数据?(v7)
- c++ - 为什么(仅)某些编译器对相同的字符串文字使用相同的地址?
- jquery - 在选择器附近找不到 div
- rust - 如何跨平台获取cargoregistry/src目录?