该博文用来整理开源项目 Android-References 迁移到 AndroidX 过程中遇到的各种问题。

Android-References 是一个 Android 示例程序项目:包含了 MVP, MVVM, 组件化, ARouter, RxJava, EventBus, ButterKnife, 视频播放, 视频直播, 网络访问, 布局和控件整理等,感性却可以到 Gihub:https://github.com/Shouheng88/Android-references 参考源码。

因为该项目包含了各种 support 包控件,并且各种组件化、架构模式和各种常见的功能一应俱全,因此,比较具有代表性。这里我们使用它来作为一个示例来将我们的项目迁移到 AndroidX。

1、关于 AndroidX

关于 AndroidX,可以参考: Hello world AndroidX

AndroidX 用来统一 Android 中的 support 包,之前我们通过引入 support 包的各个版本来使用支持包,现在我们可以通过使用 AndroidX 来使用支持包。从长远来看这当然是大有好处的,可以避免使用支持包中遇到的版本冲突、升级带来的各种问题。

不过,如果项目完全迁移到 AndroidX 风险还是太大。如果项目紧急的话,引入 AndroidX 成本都有些高,主要是因为一些三方库的原因。虽然一些使用特别多的三方库,比如 Glide 等都已经开始支持 AndroidX。当然,还有一些潜在的问题,比如使用字符串来获取类的 Behavior 等,迁移的时候可能就不会被照顾到。

为了迁移到 AndroidX,Google 给开发者提供了一个工具:在 AS 的 Refactor 中提供了一项 Migrate to AndroidX 的选项。但选择了迁移之后,出现一些问题还需要开发者自己手动解决。

2、着手迁移

2.1 第一个问题:Execution failed for task ‘:app:transformClassesWithMultidexlistForAlphaDebug’

这里我们迁移之后在 build 的时候出现了标题的问题:

* What went wrong:Execution failed for task ':app:transformClassesWithMultidexlistForAlphaDebug'.> com.android.build.api.transform.TransformException: Error while generating the main dex list.

显然是将 class 转换成 dex 的过程中出现了一些问题,不过只是上面的这行日志我们无法定位问题。所以,我们需要让 gradle 输出更多的错误信息,于是我们执行:

gradlew build --stacktrace

来让 Gradle 输出错误栈信息:

Caused by: com.android.builder.multidex.D8MainDexList$MainDexListException: com.android.tools.r8.errors.CompilationError: Program type already present: com.alibaba.android.arouter.routes.ARouter$$Group$$library        at com.android.builder.multidex.D8MainDexList.generate(D8MainDexList.java:87)        at com.android.build.gradle.internal.transforms.D8MainDexListTransform.transform(D8MainDexListTransform.kt:131)        ... 54 more

显然是 ARouter$$Group$$library 类的问题,我们使用 Ctrl+N 来搜索这个类,发现出现了两个同样的类。这个类是使用阿里的 ARouter 的时候在编译期间生成的:

按照上面的错误提示,该类同时出现在了我们的两个模块 librarieslayout 下面,因而类冲突了。所以,接下来的问题就是要发现为什么会出现类冲突。

经过一层层排查发现是一个地方写错了:

这个是 layout 模块下面的冲突的类,我们发现它的路由地址是 /library/swipe_back,所以因为路由的地址是 library 的原因它在 layout 的模块下面生成了 ARouter$$Group$$Library。按照正确的写法它应该是出现在 layout 模块下面,并且路由的地址是 /layout/swipe_back,那样就应该被生成到 ARouter$$Group$$Layout 下面,就不会多出一个类 ARouter$$Group$$Library 了。

虽然,最终问题的原因很简单,但是我们看到,发现问题的过程中需要自己有思路的去排查,而不是除了问题立刻 Google 或者 SOF。

2.2 android.view.InflateException: Binary XML file line #14: Error inflating class

修改了上面的问题之后,我们的程序可以编译并且安装了。

然后,我们又遇到下面的问题:

android.view.InflateException: Binary XML file line #14: Error inflating class

这种问题比较常见,是 XML 的某个地方写错了,经过排查发现有一行代码,当我们为控件添加 Behavior 的时候使用了字符串形式的类名。在迁移的时候没有被照顾到:

事实上在 Google 的新的 material 包下面的 values.xml 文件中定义了一些 Behavior,新的包中这些字符串的值已经被替换过。但是像我们上面的这种情况,因为使用的是字符串而不是引用的资源,所以就没有被替换过去。因此,引用非自定义的 Behavior 的时候需要注意使用字符串资源进行引用而不是使用字符串:

2.3 android.view.InflateException: Binary XML file line #12: Binary XML file line #12: Error inflating class com.google.android.material.button.MaterialButton

这里的类 Support28Activity 用来整理原来的 support-28 包里面的一些控件,迁移之后页面打开的时候立即崩溃。然后留下了一地鸡毛(异常):

 java.lang.RuntimeException: Unable to start activity ComponentInfo{me.shouheng.references/me.shouheng.layout.view.support28.Support28Activity}: android.view.InflateException: Binary XML file line #12: Binary XML file line #12: Error inflating class com.google.android.material.button.MaterialButton

我们尝试在程序中寻找 MaterialButton,发现确实能够找到这个类,但这里加载失败是什么原因呢?

于是我们继续查看输出的错误日志,从这里我们获取到了更多的信息。

    Process: me.shouheng.references, PID: 22961    java.lang.RuntimeException: Unable to start activity ComponentInfo{me.shouheng.references/me.shouheng.layout.view.support28.Support28Activity}: android.view.InflateException: Binary XML file line #12: Binary XML file line #12: Error inflating class com.google.android.material.button.MaterialButton        at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3037)        at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3172)        at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:78)        at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:108)        at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:68)        at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1906)        at android.os.Handler.dispatchMessage(Handler.java:106)        at android.os.Looper.loop(Looper.java:193)        at android.app.ActivityThread.main(ActivityThread.java:6863)        at java.lang.reflect.Method.invoke(Native Method)        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:537)        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:858)     Caused by: android.view.InflateException: Binary XML file line #12: Binary XML file line #12: Error inflating class com.google.android.material.button.MaterialButton     Caused by: android.view.InflateException: Binary XML file line #12: Error inflating class com.google.android.material.button.MaterialButton     Caused by: java.lang.reflect.InvocationTargetException        at java.lang.reflect.Constructor.newInstance0(Native Method)        at java.lang.reflect.Constructor.newInstance(Constructor.java:343)        at android.view.LayoutInflater.createView(LayoutInflater.java:647)        at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:790)        at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:730)        at android.view.LayoutInflater.rInflate(LayoutInflater.java:863)        at android.view.LayoutInflater.rInflateChildren(LayoutInflater.java:824)        at android.view.LayoutInflater.inflate(LayoutInflater.java:515)        at android.view.LayoutInflater.inflate(LayoutInflater.java:423)        at androidx.databinding.DataBindingUtil.inflate(DataBindingUtil.java:126)        at androidx.databinding.DataBindingUtil.inflate(DataBindingUtil.java:95)        at me.shouheng.commons.view.activity.CommonActivity.onCreate(CommonActivity.java:41)        at android.app.Activity.performCreate(Activity.java:7149)        at android.app.Activity.performCreate(Activity.java:7140)        at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1288)        at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3017)        at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3172)        at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:78)        at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:108)        at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:68)        at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1906)        at android.os.Handler.dispatchMessage(Handler.java:106)        at android.os.Looper.loop(Looper.java:193)        at android.app.ActivityThread.main(ActivityThread.java:6863)        at java.lang.reflect.Method.invoke(Native Method)        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:537)        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:858)     Caused by: java.lang.IllegalArgumentException: The style on this component requires your app theme to be Theme.MaterialComponents (or a descendant).        at com.google.android.material.internal.ThemeEnforcement.checkTheme(ThemeEnforcement.java:240)        at com.google.android.material.internal.ThemeEnforcement.checkMaterialTheme(ThemeEnforcement.java:215)        at com.google.android.material.internal.ThemeEnforcement.checkCompatibleTheme(ThemeEnforcement.java:143)2018-11-10 15:21:55.948 22961-22961/me.shouheng.references E/AndroidRuntime:     at com.google.android.material.internal.ThemeEnforcement.obtainStyledAttributes(ThemeEnforcement.java:78)        at com.google.android.material.button.MaterialButton.(MaterialButton.java:140)        at com.google.android.material.button.MaterialButton.(MaterialButton.java:133)        ... 27 more

按照后面几行的意思:

     Caused by: java.lang.IllegalArgumentException: The style on this component requires your app theme to be Theme.MaterialComponents (or a descendant).

这个错误是因为我们设置的主题照成的。按照上面的意思,我们需要更新自己的控件的主题到 Theme.MaterialComponents。除了切换控件的主题,我们可以更新应用的主题,我们可以让自己的应用主题继承 Material Components Bridge 主题:

可以根据自己的需要选择继承下面的几种主题:

Theme.MaterialComponents.BridgeTheme.MaterialComponents.Light.BridgeTheme.MaterialComponents.NoActionBar.BridgeTheme.MaterialComponents.Light.NoActionBar.BridgeTheme.MaterialComponents.Light.DarkActionBar.Bridge

或者在你之前的 AppCompact 主题之上增加一些新的属性:

显然,这里是要求你为了使自己的应用符合 Material 规范,需要预先定义一些属性值,然后会被应用到程序的控件中。

这里我们将主题稍做修改

        

按照上面的方式,我们成功地打开了该页面。

2.4 java.lang.IllegalArgumentException: Invalid Region.Op - only INTERSECT and DIFFERENCE are allowed

然而打开了页面不久就又发现了问题,这个问题出现在 MaterialButton 的点击的时候:

    Process: me.shouheng.references, PID: 5730    java.lang.IllegalArgumentException: Invalid Region.Op - only INTERSECT and DIFFERENCE are allowed        at android.graphics.Canvas.checkValidClipOp(Canvas.java:779)        at android.graphics.Canvas.clipRect(Canvas.java:826)        at com.google.android.material.shape.MaterialShapeDrawable.prepareCanvasForShadow(MaterialShapeDrawable.java:850)        at com.google.android.material.shape.MaterialShapeDrawable.draw(MaterialShapeDrawable.java:746)        at android.view.View.getDrawableRenderNode(View.java:20622)        at android.view.View.drawBackground(View.java:20558)        at android.view.View.draw(View.java:20357)        at android.view.View.updateDisplayListIfDirty(View.java:19241)        at android.view.View.draw(View.java:20094)        at android.view.ViewGroup.drawChild(ViewGroup.java:4337)        at androidx.coordinatorlayout.widget.CoordinatorLayout.drawChild(CoordinatorLayout.java:1246)        at android.view.ViewGroup.dispatchDraw(ViewGroup.java:4116)        at android.view.View.updateDisplayListIfDirty(View.java:19232)        at android.view.View.draw(View.java:20094)        at android.view.ViewGroup.drawChild(ViewGroup.java:4337)        at android.view.ViewGroup.dispatchDraw(ViewGroup.java:4116)        at android.view.View.updateDisplayListIfDirty(View.java:19232)        at android.view.View.draw(View.java:20094)        at android.view.ViewGroup.drawChild(ViewGroup.java:4337)        at android.view.ViewGroup.dispatchDraw(ViewGroup.java:4116)        at android.view.View.updateDisplayListIfDirty(View.java:19232)        at android.view.View.draw(View.java:20094)        at android.view.ViewGroup.drawChild(ViewGroup.java:4337)        at android.view.ViewGroup.dispatchDraw(ViewGroup.java:4116)        at android.view.View.updateDisplayListIfDirty(View.java:19232)        at android.view.View.draw(View.java:20094)        at android.view.ViewGroup.drawChild(ViewGroup.java:4337)        at android.view.ViewGroup.dispatchDraw(ViewGroup.java:4116)        at android.view.View.updateDisplayListIfDirty(View.java:19232)        at android.view.View.draw(View.java:20094)        at android.view.ViewGroup.drawChild(ViewGroup.java:4337)        at android.view.ViewGroup.dispatchDraw(ViewGroup.java:4116)        at android.view.View.draw(View.java:20369)        at com.android.internal.policy.DecorView.draw(DecorView.java:781)        at android.view.View.updateDisplayListIfDirty(View.java:19241)        at android.view.ThreadedRenderer.updateViewTreeDisplayList(ThreadedRenderer.java:690)        at android.view.ThreadedRenderer.updateRootDisplayList(ThreadedRenderer.java:696)        at android.view.ThreadedRenderer.draw(ThreadedRenderer.java:805)        at android.view.ViewRootImpl.draw(ViewRootImpl.java:3515)        at android.view.ViewRootImpl.performDraw(ViewRootImpl.java:3312)        at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:2681)        at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:1633)        at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:7786)        at android.view.Choreographer$CallbackRecord.run(Choreographer.java:1004)        at android.view.Choreographer.doCallbacks(Choreographer.java:816)        at android.view.Choreographer.doFrame(Choreographer.java:751)        at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:990)        at android.os.Handler.handleCallback(Handler.java:873)        at android.os.Handler.dispatchMessage(Handler.java:99)        at android.os.Looper.loop(Looper.java:193)        at android.app.ActivityThread.main(ActivityThread.java:6863)        at java.lang.reflect.Method.invoke(Native Method)        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:537)        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:858)

经过排查发现,在 com.google.android.material.shape.MaterialShapeDrawable 中的 prepareCanvasForShadow() 方法中使用了 Region.Op.REPLACE

  private void prepareCanvasForShadow(Canvas canvas) {    // ... 无关代码    canvas.clipRect(canvasClipBounds, Region.Op.REPLACE);    // ... 无关代码  }

而在 support-28 中增加了下面的校验(这个校验在 support-27 上面是不存在的),显然是因为我们使用了 Region.Op.REPLACE 属性的原因:

    private static void checkValidClipOp(@NonNull Region.Op op) {        if (sCompatiblityVersion >= Build.VERSION_CODES.P                && op != Region.Op.INTERSECT && op != Region.Op.DIFFERENCE) {            throw new IllegalArgumentException(                    "Invalid Region.Op - only INTERSECT and DIFFERENCE are allowed");        }    }

在该方法上面有真么几行注释:

Region.Op values other than Region.Op.INTERSECT and Region.Op.DIFFERENCE have the ability to expand the clip. The canvas clipping APIs are intended to only expand the clip as a result of a restore operation. This enables a view parent to clip a canvas to clearly define the maximal drawing area of its children. The recommended alternative calls are clipRect(Rect) and clipOutRect(Rect)

大体意思是:Region.Op.INTERSECT和Region.Op.DIFFERENCE以外的Region.Op值可以展开 Clip。画布剪辑API仅用于在还原操作后展开Clip。这使视图父级能够剪切画布以清楚地定义其子画面的最大绘制区域。推荐调用clipRect(Rect)和clipOutRect(Rect).

虽然我们找到了问题的原因,但是这个类究竟是在哪里用到的我们还无法定位到,因此,我们还需要进一步进行排查。

经过排查,我们发现出现问题的原因是 material 包中的 BottomAppBar 控件。其实从上面的栈中我们也可以看出这一点:明显是在绘制 View 树的子 View 的时候出现的异常,而且是绘制 CoordinatorLayout。在 BottomAppBar 中使用了 materialShapeDrawable,该变量是 MaterialShapeDrawable。正是出现问题的罪魁祸首。

这个类MaterialShapeDrawable是用来实现 BottomBar 的阴影效果的,虽然它是 BottomBar 的内部类,但是如果不希望它调用上面的那个方法也是可以的。

首先,我发现它要先判断是否具有阴影再调用绘制阴影的方法:

    if (hasCompatShadow()) {      // Save the canvas before changing the clip bounds.      canvas.save();      prepareCanvasForShadow(canvas);  // ...无关代码    }

而这里的判断是否具有阴影的方法如下:

  private boolean hasCompatShadow() {    return shadowCompatMode != SHADOW_COMPAT_MODE_NEVER        && shadowCompatRadius > 0        && (shadowCompatMode == SHADOW_COMPAT_MODE_ALWAYS || requiresCompatShadow());  }

我们可以通过为 BottomBar 设置移除阴影效果来避免这个类调用绘制阴影的方法。于是,

        

虽然效果不好看,但是阴影解决了。

2.5 android.view.InflateException: Binary XML file line #24: Binary XML file line #24: Error inflating class com.google.android.material.floatingactionbutton.FloatingActionButton

在排查上面问题的过程中,我们同样发现了 FAB 的一个问题。这个 Material 包中的 FAB 与 Support-28 包中的相比做了一些调整。且看下面的异常信息。这里问题显然是类无法记载造成的。那么具体是因为什么呢?我们往下看到错误栈的最后几行,发现是有一个属性没有找到。

2018-11-10 16:56:48.408 27581-27581/me.shouheng.references E/AndroidRuntime: FATAL EXCEPTION: main    Process: me.shouheng.references, PID: 27581    java.lang.RuntimeException: Unable to start activity ComponentInfo{me.shouheng.references/me.shouheng.layout.view.support28.BottomAppBarActivity}: android.view.InflateException: Binary XML file line #24: Binary XML file line #24: Error inflating class com.google.android.material.floatingactionbutton.FloatingActionButton        at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3037)        at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3172)        at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:78)        at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:108)        at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:68)        at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1906)        at android.os.Handler.dispatchMessage(Handler.java:106)        at android.os.Looper.loop(Looper.java:193)        at android.app.ActivityThread.main(ActivityThread.java:6863)        at java.lang.reflect.Method.invoke(Native Method)        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:537)        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:858)     Caused by: android.view.InflateException: Binary XML file line #24: Binary XML file line #24: Error inflating class com.google.android.material.floatingactionbutton.FloatingActionButton     Caused by: android.view.InflateException: Binary XML file line #24: Error inflating class com.google.android.material.floatingactionbutton.FloatingActionButton     Caused by: java.lang.reflect.InvocationTargetException        at java.lang.reflect.Constructor.newInstance0(Native Method)        at java.lang.reflect.Constructor.newInstance(Constructor.java:343)        at android.view.LayoutInflater.createView(LayoutInflater.java:647)        at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:790)        at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:730)        at android.view.LayoutInflater.rInflate(LayoutInflater.java:863)        at android.view.LayoutInflater.rInflateChildren(LayoutInflater.java:824)        at android.view.LayoutInflater.inflate(LayoutInflater.java:515)        at android.view.LayoutInflater.inflate(LayoutInflater.java:423)        at androidx.databinding.DataBindingUtil.inflate(DataBindingUtil.java:126)        at androidx.databinding.DataBindingUtil.inflate(DataBindingUtil.java:95)        at me.shouheng.commons.view.activity.CommonActivity.onCreate(CommonActivity.java:41)        at android.app.Activity.performCreate(Activity.java:7149)        at android.app.Activity.performCreate(Activity.java:7140)        at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1288)        at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3017)        at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3172)        at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:78)        at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:108)        at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:68)        at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1906)        at android.os.Handler.dispatchMessage(Handler.java:106)        at android.os.Looper.loop(Looper.java:193)        at android.app.ActivityThread.main(ActivityThread.java:6863)        at java.lang.reflect.Method.invoke(Native Method)        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:537)        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:858)     Caused by: java.lang.UnsupportedOperationException: Failed to resolve attribute at index 0: TypedValue{t=0x2/d=0x7f0300b3 a=3}        at android.content.res.TypedArray.getColorStateList(TypedArray.java:565)        at com.google.android.material.resources.MaterialResources.getColorStateList(MaterialResources.java:65)        at com.google.android.material.floatingactionbutton.FloatingActionButton.(FloatingActionButton.java:204)2018-11-10 16:56:48.408 27581-27581/me.shouheng.references E/AndroidRuntime:     at com.google.android.material.floatingactionbutton.FloatingActionButton.(FloatingActionButton.java:190)        ... 27 more

根据错误的栈信息,我们到指定的方法下面去查看问题的原因,发现是设置背景着色的时候出现的问题:

    backgroundTint =        MaterialResources.getColorStateList(            context, a, R.styleable.FloatingActionButton_backgroundTint);

但我们并没有为 FAB 添加该属性,那么又是哪里出现的问题呢?原来是因为我们为 FAB 添加了一个 style:

style="@style/Widget.MaterialComponents.FloatingActionButton"

而该 style 的定义是:

      

这样刚好与我们的问题吻合,所以解决的方案就是移除这个属性。

2.6 java.net.UnknownServiceException: CLEARTEXT communication to baobab.kaiyanapp.com not permitted by network security policy

按照上面的方式对我们的项目做了调整之后,我们发现项目已经可以运行了。接下来出现的问题是网络访问过程中出现的。当我们访问网络的时候会遇到下面的这个异常:

java.net.UnknownServiceException: CLEARTEXT communication to baobab.kaiyanapp.com not permitted by network security policy

这个是因为 Android P 中新引入了网络安全规则,以上内容会对使用 http 的 URL 出现,默认会禁止访问 http 类型的地址。

当然,通常我们发布的时候会使用 Https 类型的网络协议,而当开发和调试的时候可能就没有那么严格了。所以,为了解决这个问题, Android 新引入了下面的解决方案:

首先,创建配置文件 res/xml/network_security_config.xml,内容如下:

<?xml version="1.0" encoding="utf-8"?>            localhost    

这里的 ``localhost是 host 的地址,比如我上面的出错的地址应该是kaiyanapp.com`。

然后,我们将其配置到 manifest.xml 中:

        

在我们的项目中使用了三个不同的地址,并且都是 http 的,所以就需要在该地址下面配置三个域名,然后再次访问网络,问题就解决了。

关于 Android 网络和安全的内容,建议参考官方文档:网络安全性配置 | Android Developers。

总结

显然迁移到 AndroidX 的过程中还是会出现许多问题的,大多数是与 Android 的支持包有关的。按照我们上面遇到的问题,主要包括以下几点内容:

  1. 主题
  2. 支持库的控件(控件属性,实现方式好像变了一些)
  3. 三方库,许多库并没有迁移,所以会导致程序内标红,但是编译和运行没有问题
  4. 网络安全,网络安全部分做了一些调整

好了,这篇文章大致到这里。也希望通过这篇文章来让你了解下迁移到 AndroidX 过程中可能会出现什么问题,并以此来考虑迁移的成本。

1.Getting started with Material Components for Android
2.网络安全性配置 | Android Developers


如果您喜欢我的文章,可以在以下平台关注我:

  • 个人主页:https://shouheng88.github.io/
  • 掘金:https://juejin.im/user/585555e11b69e6006c907a2a
  • Github:https://github.com/Shouheng88
  • CSDN:https://blog.csdn.net/github_35186068
  • 微博:https://weibo.com/u/5401152113

更多相关文章

  1. Android客制化------在设置中加入RAM flash计算
  2. android背景选择器总结
  3. Android学习笔记:布局
  4. Android(安卓)录制mp3使用mp3lame 库
  5. Android实战简易教程(自定义控件实现数字液晶时钟Demo)
  6. Android开发工程师个人简历
  7. Android(安卓)控件之GridView
  8. Android[初级教程]第十一章 TabHost控件
  9. 《Android》Lesson11-UI布局

随机推荐

  1. Android(安卓)GPS使用
  2. Android多分辨率适配框架(3)— 使用指南
  3. android 系统开发之开机动画
  4. android ndk log
  5. Android的selector,背景选择器
  6. Android多分辨率适配框架(2)— 原理剖析
  7. 性能优化之Java(Android)代码优化
  8. Android UI布局之RelativeLayout
  9. Android 第七课——UI布局
  10. Android(安卓)Studio 3.5 安装apk失败问