Java自学者论坛

 找回密码
 立即注册

手机号码,快捷登录

恭喜Java自学者论坛(https://www.javazxz.com)已经为数万Java学习者服务超过8年了!积累会员资料超过10000G+
成为本站VIP会员,下载本站10000G+会员资源,会员资料板块,购买链接:点击进入购买VIP会员

JAVA高级面试进阶训练营视频教程

Java架构师系统进阶VIP课程

分布式高可用全栈开发微服务教程Go语言视频零基础入门到精通Java架构师3期(课件+源码)
Java开发全终端实战租房项目视频教程SpringBoot2.X入门到高级使用教程大数据培训第六期全套视频教程深度学习(CNN RNN GAN)算法原理Java亿级流量电商系统视频教程
互联网架构师视频教程年薪50万Spark2.0从入门到精通年薪50万!人工智能学习路线教程年薪50万大数据入门到精通学习路线年薪50万机器学习入门到精通教程
仿小米商城类app和小程序视频教程深度学习数据分析基础到实战最新黑马javaEE2.1就业课程从 0到JVM实战高手教程MySQL入门到精通教程
查看: 405|回复: 0

Android 65K问题之Multidex原理分析及NoClassDefFoundError的解决方法

[复制链接]
  • TA的每日心情
    奋斗
    2024-4-6 11:05
  • 签到天数: 748 天

    [LV.9]以坛为家II

    2034

    主题

    2092

    帖子

    70万

    积分

    管理员

    Rank: 9Rank: 9Rank: 9

    积分
    705612
    发表于 2021-7-9 06:40:35 | 显示全部楼层 |阅读模式

    Android 65K问题相信困惑了不少人,尽管AS的出来能够通过分dex高速解决65K问题,可是同一时候也easy由于某些代码没有打包到MainDex里引起NoClassDefFoundError

    随着5.0的推出,Android也放出了Multidex Support Library来解决问题。

    Multidex Support Library能够直接分包处理65K问题。而且不会发生NoClassDefFoundError的情况。

    1.使用的话。首先加入依赖库:
    //分包multiDexEnabled必须加入该依赖
    compile  'com.android.support:multidex:1.0.1'

    2.另外开启Multidex开关:
    buildTypes {
        release {
            minifyEnabled  false
            //分包
            multiDexEnabled  true
            proguardFiles  getDefaultProguardFile( 'proguard-android.txt'),  'proguard-rules.pro'
        }
    }

    3.这时候执行的话可能会报java堆内存错误,因此最好加入上:
    dexOptions {
        javaMaxHeapSize  "4g" 
        incremental  true
    }

    4.假设你有自己的Application,则改动一下Application使其继承MultiDexApplication:
    public class MyApplication  extends MultiDexApplication {
       
        ...
    }

    假设你的Application非常不幸已经继承了其它Application导致无法继承MultiDexApplication的话。那也是能够是,仅仅须要复写该方法并加上该代码:
    @Override
    protected void  attachBaseContext(Context base) {
        super.attachBaseContext(base) ;
        MultiDex. install(base) ;
    }
    这时候你就能够跑了,详细能够看官方文档,毕竟官方文档里面写得很清楚。


    以下我们主要来说下Multidex的实现方法 ,以下部分来源: http://blog.waynell.com/2015/04/19/android-multidex/ 的分析。

    Multidex的实现原理

    Multidex的实现原理是将class编译进不同的classes.dex文件里。普通情况下。一个APK文件里仅仅包括了一个classes.dex文件。

    分包之后就存在一个主的classes.dex,多个副的classes2.dex,classes3.dex…

    在要启动程序时,Android会先去载入主的classes.dex。然后在程序启动后再去载入其他副的dex。那哪些class应该被编译到主的classes.dex中呢?

    先来看下Multidex的编译过程,它由三个不同的gradle task组成:
    1
    
    collect{variant}MultiDexComponents task
    

    这个task会读取项目的AndroidManifest.xml文件里注冊的application、Activity、service、receiver、provider、instrumentation相关类,并将其class文件路径写到文件buidl/intermediates/multi-dex/${variant.dirName}/manifest_keep.txt

    1
    
    shrink{variant}MultiDexComponents task
    

    这个task会调用ProGuard并依据上一步生成的manifest_keep.txt文件内容去压缩class,剔除没实用到的class。生成一个精简的jar包buidl/intermediates/multi-dex/${variant.dirName}/componentClasses.jar

    1
    
    create{variant}MainDexClassList task
    

    这个task会依据上一步生成的componentClasses.jar去寻找这里面的各个class文字中依赖的class,比方一个class中有一成员变量X。那么X就是依赖的class,componentClasses.jar中全部的class和依赖的class路径都会被写入到文件buidl/intermediates/multi-dex/${variant.dirName}/maindexlist.txt中,这个文件里的类都会被编译进主的classes.dex中去。(详情能够查看ClassReferenceListBuilder的实现源代码

    NoClassDefFoundError

    Multidex固然是好的,不用再为方法数超过65536而苦恼了。

    可是有时往往会带来意想不到的bug。比方NoClassDefFoundError。之前我就在项目中遇到了这个问题。一启动程序就crash了,看log是因为某个类找不到引起的。


    通过上面的分析,我们已经得知Multidex的原理了,所以要解决一启动程序就NoClassDefFoundError的问题仅仅须要确定该类是否正确被编译到主classes.dex中去了。假设没有被编进去的话,仅仅要改动下maindexlist.txt文件。把这个类加入进去就可以。因为maindexlist.txt这个文件是每次编译时自己主动生成的,手动去改动它是无用的。所以我们能够在gradle编译中新加入一个task,在 create{variant}MainDexClassList这个task完毕之后再去改动maindexlist.txt文件加入丢失的class。 
    哎...今天够累的,签到来了1...
    回复

    使用道具 举报

    您需要登录后才可以回帖 登录 | 立即注册

    本版积分规则

    QQ|手机版|小黑屋|Java自学者论坛 ( 声明:本站文章及资料整理自互联网,用于Java自学者交流学习使用,对资料版权不负任何法律责任,若有侵权请及时联系客服屏蔽删除 )

    GMT+8, 2024-5-21 04:35 , Processed in 0.058853 second(s), 29 queries .

    Powered by Discuz! X3.4

    Copyright © 2001-2021, Tencent Cloud.

    快速回复 返回顶部 返回列表