Android 踩坑记Android最佳实践android适配

AndroidX 踩坑指南

2021-04-24  本文已影响0人  Android轮子哥

本文章已授权鸿洋微信公众号转载

官方文档

转 AndroidX 的原因

转成 AndroidX 的步骤

Studio 帮我们做了什么事?

import android.support.v7.app.AppCompatActivity;
import androidx.appcompat.app.AppCompatActivity;
<android.support.v7.widget.RecyclerView />
<androidx.recyclerview.widget.RecyclerView />
implementation 'com.android.support:appcompat-v7:28.0.0'
implementation 'com.android.support:design:28.0.0'
implementation 'androidx.appcompat:appcompat:1.0.0'
implementation 'com.google.android.material:material:1.0.0'
# 表示使用 AndroidX
android.useAndroidX = true
# 表示将第三方库迁移到 AndroidX
android.enableJetifier = true

坑一:找不到约束布局

implementation 'androidx.constraintlayout:constraintlayout:2.0.0'

坑二:导包报错

坑三:第三方库的坑

implementation 'com.jakewharton:butterknife:9.0.0'
annotationProcessor 'com.jakewharton:butterknife-compiler:9.0.0'

implementation 'com.github.bumptech.glide:glide:4.7.1'
annotationProcessor 'com.github.bumptech.glide:compiler:4.7.1'
implementation 'com.jakewharton:butterknife:10.2.1'
annotationProcessor 'com.jakewharton:butterknife-compiler:10.2.1'

implementation 'com.github.bumptech.glide:glide:4.11.0'
annotationProcessor 'com.github.bumptech.glide:compiler:4.11.0'

坑四:替换不干净

Class.forName("android.support.design.widget.Snackbar");
Class.forName("android.support.design.widget.BottomSheetDialog");

-keep class android.support.**{*;}

坑五:Fragment 崩溃

public abstract class BaseFragment extends Fragment {

    @Override
    public void onDetach() {
        super.onDetach();
        try {
            Field childFragmentManager = Fragment.class.getDeclaredField("mChildFragmentManager");
            childFragmentManager.setAccessible(true);
            childFragmentManager.set(this, null);
        } catch (NoSuchFieldException e) {
            throw new RuntimeException(e);
        } catch (IllegalAccessException e) {
            throw new RuntimeException(e);
        }
    }
}

坑六:WebView 崩溃

android.view.InflateException: Binary XML file line #20: Error inflating class android.webkit.WebView
    at android.view.LayoutInflater.createView(LayoutInflater.java:633)
    at com.android.internal.policy.impl.PhoneLayoutInflater.onCreateView(PhoneLayoutInflater.java:55)
    at android.view.LayoutInflater.onCreateView(LayoutInflater.java:682)
    at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:741)
    at android.view.LayoutInflater.rInflate(LayoutInflater.java:806)
    at android.view.LayoutInflater.rInflate(LayoutInflater.java:809)
    at android.view.LayoutInflater.inflate(LayoutInflater.java:504)
    at android.view.LayoutInflater.inflate(LayoutInflater.java:414)
implementation 'androidx.appcompat:appcompat:1.1.0'
implementation 'com.google.android.material:material:1.1.0'
implementation 'androidx.appcompat:appcompat:1.2.0'
implementation 'com.google.android.material:material:1.2.0'
public class LollipopFixedWebView extends WebView {
    
    public LollipopFixedWebView(Context context) {
        super(getFixedContext(context));
    }

    public LollipopFixedWebView(Context context, AttributeSet attrs) {
        super(getFixedContext(context), attrs);
    }

    public LollipopFixedWebView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(getFixedContext(context), attrs, defStyleAttr);
    }

    @TargetApi(Build.VERSION_CODES.LOLLIPOP)
    public LollipopFixedWebView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
        super(getFixedContext(context), attrs, defStyleAttr, defStyleRes);
    }

    public LollipopFixedWebView(Context context, AttributeSet attrs, int defStyleAttr, boolean privateBrowsing) {
        super(getFixedContext(context), attrs, defStyleAttr, privateBrowsing);
    }

    /**
     * 修复原生 WebView 和 AndroidX 在 Android 5.x 上面崩溃的问题
     *
     * doc:https://stackoverflow.com/questions/41025200/android-view-inflateexception-error-inflating-class-android-webkit-webview
     */
    private static Context getFixedContext(Context context) {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP && Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
            // 为什么不用 ContextImpl,因为使用 ContextImpl 获取不到 Activity 对象,而 ContextWrapper 可以
            // 这种写法返回的 Context 是 ContextImpl,而不是 Activity 或者 ContextWrapper
            // return context.createConfigurationContext(new Configuration());
            // 如果使用 ContextWrapper 还是导致崩溃,因为 Resources 对象冲突了
            // return new ContextWrapper(context);
            // 如果使用 ContextThemeWrapper 就没有问题,因为它重写了 getResources 方法,返回的是一个新的 Resources 对象
            return new ContextThemeWrapper(context, context.getTheme());
        }
        return context;
    }
}

常见误区:FileProvider

<provider
    android:name="android.support.v4.content.FileProvider"
    android:authorities="${applicationId}.provider"
    android:exported="false"
    android:grantUriPermissions="true">

    <meta-data
        android:name="android.support.FILE_PROVIDER_PATHS"
        android:resource="@xml/file_paths" />
</provider>
<provider
    android:name="androidx.core.content.FileProvider"
    android:authorities="${applicationId}.provider"
    android:exported="false"
    android:grantUriPermissions="true">

    <meta-data
        android:name="android.support.FILE_PROVIDER_PATHS"
        android:resource="@xml/file_paths" />
</provider>
<provider
    ....
    <meta-data
        android:name="android.support.FILE_PROVIDER_PATHS" />
</provider>
<provider
    ....
    <meta-data
        android:name="androidx.core.FILE_PROVIDER_PATHS" />
</provider>
 java.lang.IllegalArgumentException: Missing android.support.FILE_PROVIDER_PATHS meta-data
    at androidx.core.content.FileProvider.parsePathStrategy(FileProvider.java:613)
    at androidx.core.content.FileProvider.getPathStrategy(FileProvider.java:579)
    at androidx.core.content.FileProvider.attachInfo(FileProvider.java:392)
package androidx.core.content;

public class FileProvider extends ContentProvider {

    private static final String
            META_DATA_FILE_PROVIDER_PATHS = "android.support.FILE_PROVIDER_PATHS";

    private static PathStrategy parsePathStrategy(Context context, String authority) {
        final XmlResourceParser in = info.loadXmlMetaData(
            context.getPackageManager(), META_DATA_FILE_PROVIDER_PATHS);
        if (in == null) {
            throw new IllegalArgumentException(
                    "Missing " + META_DATA_FILE_PROVIDER_PATHS + " meta-data");
        }
    }
}

灰度小插曲

异常名称 发生次数 影响设备数
java.lang.ClassNotFoundException:
android.support.constraint.ConstraintLayout
14 7

后续情况汇报

Android 技术讨论 Q 群:10047167

上一篇下一篇

猜你喜欢

热点阅读