Android P 适配

Android N 适配
Android O 适配

Android P (9.0)(API 28) 适配

最近将我们项目的targetSdkVersion升到28了,由于是从Android O (26)升到Android P(28)遇到的问题不算多,下面是一些需要适配的问题,后面遇到其他问题再补充:

一、适配,首先更改 build.gradle,我这边的更改如下:
android {
    compileSdkVersion 28
    buildToolsVersion 28.0.3
 
     defaultConfig {
        minSdkVersion 17
        targetSdkVersion 28
    }   
}

dependencies {
    implementation 'com.android.support:support-v4:28.0.0'
    implementation 'com.android.support:appcompat-v7:28.0.0'
    implementation 'com.android.support:design:28.0.0'
    implementation 'com.android.support:recyclerview-v7:28.0.0'
    implementation 'com.android.support:cardview-v7:28.0.0'
    implementation 'com.android.support:support-annotations:28.0.0'
}

编译过了就可以了,我们项目这边编译报错了,原因是 support 库依赖冲突了,有其他库依赖了其他版本的 support 库,解决方案如下:

通过下面命令查看下哪个库冲突了

gradlew :app:dependencies

1、然后在引入依赖的时候移除掉即可

implementation ('xxx') {
    exclude group: 'com.android.support'
}

2、强制设置都依赖某个版本

android {
    configurations.all {
        resolutionStrategy.force "com.android.support:support-v4:28.0.0"
    }
}
二、全面屏适配

全面屏适配使用的是github上面star比较多的 ImmersionBar 库,该库可以更改状态栏和导航栏的颜色等,具体使用方法可以去github上查看

三、Apache HTTP client 相关类找不到

将 compileSdkVersion 升级到 28 之后,如果在项目中用到了 Apache HTTP client 的相关类,就会抛出找不到这些类的错误。这是因为官方已经在 Android P 的启动类加载器中将其移除。我们项目中引用了科大讯飞的语音识别库会报下面错误。

java.lang.NoClassDefFoundError: Failed resolution of: Lorg/apache/http/util/ByteArrayBuffer;

解决方法为在AndroidManifest.xml的中加入以下代码

<uses-library android:name="org.apache.http.legacy" android:required="false"/>
四、前台Service适配

在 Android P 中,如果 targeSdkVersion 升级到 28,使用前台 Service 必须要申请 FOREGROUND_SERVICE 权限,如果没有申请该权限,系统会抛出 SecurityException,该权限为普通权限,申请自动授予应用。在AndroidManifest.xml中加入

<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
五、Only fullscreen opaque activities can request orientation 崩溃
1、崩溃信息

targetSdkVersion 升到28后,在 Android 8.0.0 版本的手机上程序会崩溃,报错如下

Caused by: java.lang.IllegalStateException: Only fullscreen opaque activities can request orientation
at android.app.Activity.onCreate(Activity.java:987)
at android.support.v4.app.SupportActivity.onCreate(SupportActivity.java:66)
at android.support.v4.app.FragmentActivity.onCreate(FragmentActivity.java:297)
at android.support.v7.app.AppCompatActivity.onCreate(AppCompatActivity.java:84)
at xxx.XXXActivity.onCreate(XXXActivity.java:xx)
2、崩溃分析

根据上面调用栈可以看出是自己 XXXActivity 调用 onCreate 后,最终在 Activity 的第987行报错,到 Activity中看下源码(注意 Android API 28 中已经没有下面代码了)如下:

protected void onCreate(@Nullable Bundle savedInstanceState) {
 	...
    if (getApplicationInfo().targetSdkVersion > O && mActivityInfo.isFixedOrientation()) {
        final TypedArray ta = obtainStyledAttributes(com.android.internal.R.styleable.Window);
        final boolean isTranslucentOrFloating = ActivityInfo.isTranslucentOrFloating(ta);
            ta.recycle();

        if (isTranslucentOrFloating) {
            throw new IllegalStateException(
                        "Only fullscreen opaque activities can request orientation");
        }
    }
    ...
    }
public static boolean isTranslucentOrFloating(TypedArray attributes) {
    final boolean isTranslucent =
                attributes.getBoolean(com.android.internal.R.styleable.Window_windowIsTranslucent,
                        false);

    final boolean isSwipeToDismiss = !attributes.hasValue(
                com.android.internal.R.styleable.Window_windowIsTranslucent)
                && attributes.getBoolean(
                com.android.internal.R.styleable.Window_windowSwipeToDismiss, false);

    final boolean isFloating =
                attributes.getBoolean(com.android.internal.R.styleable.Window_windowIsFloating,
                        false);

    return isFloating || isTranslucent || isSwipeToDismiss;
}
public boolean isFixedOrientation() {
    return isFixedOrientationLandscape() || isFixedOrientationPortrait()
                || screenOrientation == SCREEN_ORIENTATION_LOCKED;
}

通过源码可以看出下面三个条件都符合系统就抛出异常了。

  • targetSdkVersion > O targetSdkVersion 大于26;
  • isFixedOrientation 固定方向:横屏或竖屏或锁定
  • isTranslucentOrFloating 透明或漂浮:在 AndroidManifest 中设置 windowIsTranslucent 或 windowSwipeToDismiss 或 windowIsFloating为 true

我们这边报错是在 AndroidManifest 中设置了如下代码,我们项目侧滑返回时设置了 Activity 透明,然后又设置了 Activity 布局竖直,这两个条件共同作用时就崩溃了

    <activity
        android:name=".XXXActivity"
        android:screenOrientation="portrait"
        android:theme="@style/TranslucentTheme" />

    <style name="TranslucentTheme" parent="xxx">
       ...
        <item name="android:windowIsTranslucent">true</item>
    </style>

最终分析崩溃同时满足下面4点

  • Android 8.0.0 版本手机
  • targetSdkVersion 大于 26
  • 固定方向
  • 透明 Activity
3、解决方案

具体没有好的解决方案,源码中的代码也改不了,具体解决只能是规避了,如下:

1、将 targetSdkVersion 设置为26及以下

2、判断 Android 8.0.0 版本的手机不设置透明;或者非要设置透明的话,则不设置方向,此时这个透明 Activity 的方向是依赖其父Activity的

六、getCurrentFocus() 为空

隐藏软键盘时之前用的是下面代码:

((InputMethodManager) getSystemService(INPUT_METHOD_SERVICE)).hideSoftInputFromWindow(SearchActivity.this.getCurrentFocus().getWindowToken(), HIDE_NOT_ALWAYS);

然后空指针了如下,getCurrentFocus() 返回空了

java.lang.NullPointerException: Attempt to invoke virtual method 'android.os.IBinder android.view.View.getWindowToken()' on a null object reference
        xxx.SearchActivity.requestSearch(SearchActivity.java:762)
        at xxx.SearchActivity.access$200(SearchActivity.java:91)
        at xxx.SearchActivity$3.onItemClick(SearchActivity.java:199)

getCurrentFocus() 方法是获取当前焦点的 View,之前是能获取到输入的 EditText 的,现在有时候获取不到了就不用 getCurrentFocus() 获取了,直接写当前的 EditText即可

EditText editText = findViewById(R.id.edit_text);
((InputMethodManager) getSystemService(INPUT_METHOD_SERVICE)).hideSoftInputFromWindow(editText.getWindowToken(), HIDE_NOT_ALWAYS);

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值