我已将我的应用程序转换为MultiDex以承受64k dex限制。现在它看起来像这样:
public class App extends MultiDexApplication {
private AppWrapper instance;
@Override
protected void attachBaseContext(Context base) {
super.attachBaseContext(base);
MultiDex.install(base);
}
@Override
public void onCreate() {
super.onCreate();
if (instance == null) {
instance = new AppWrapper(this);
}
}
}
我已将所有常用逻辑从App移至AppWidget
以使MultiDex
正常工作。它在其他队友的电脑上运行正常。但不是和我在一起。它不断在应用程序创建java.lang.NoClassDefFoundError
上投掷:
I/dalvikvm﹕ Failed resolving Lcom/playday/app/core/AppWrapper; interface 8940 'Lretrofit/ErrorHandler;'
W/dalvikvm﹕ Link of class 'Lcom/playday/app/core/AppWrapper;' failed
I/dalvikvm﹕ Failed resolving Lcom/playday/app/core/AppWrapper; interface 8940 'Lretrofit/ErrorHandler;'
W/dalvikvm﹕ Link of class 'Lcom/playday/app/core/AppWrapper;' failed
E/dalvikvm﹕ Could not find class 'com.playday.app.core.AppWrapper', referenced from method com.playday.app.core.App.onCreate
W/dalvikvm﹕ VFY: unable to resolve new-instance 7076 (Lcom/playday/app/core/AppWrapper;) in Lcom/playday/app/core/App;
D/dalvikvm﹕ VFY: replacing opcode 0x22 at 0x0007
I/dalvikvm﹕ Failed resolving Lcom/playday/app/core/AppWrapper; interface 8940 'Lretrofit/ErrorHandler;'
W/dalvikvm﹕ Link of class 'Lcom/playday/app/core/AppWrapper;' failed
D/dalvikvm﹕ DexOpt: unable to opt direct call 0xc21b at 0x09 in Lcom/playday/app/core/App;.onCreate
I/MultiDex﹕ VM with version 1.6.0 does not have multidex support
I/MultiDex﹕ install
I/MultiDex﹕ MultiDexExtractor.load( /data/app/com.playdayteam.playday.debug-1.apk, false)
I/MultiDex﹕ Detected that extraction must be performed.
I/MultiDex﹕ Trying to delete old file /data/data/com.playdayteam.playday.debug/code_cache/secondary-dexes/com.playdayteam.playday. debug-2.apk.classes2.dex of size 1484912
I/MultiDex﹕ Deleted old file /data/data/com.playdayteam.playday.debug/code_cache/secondary-dexes/com.playdayteam.playday.debug-2 .apk.classes2.dex
I/MultiDex﹕ Trying to delete old file /data/data/com.playdayteam.playday.debug/code_cache/secondary-dexes/com.playdayteam.playday. debug-2.apk.classes2.zip of size 540964
I/MultiDex﹕ Deleted old file /data/data/com.playdayteam.playday.debug/code_cache/secondary-dexes/com.playdayteam.playday.debug-2 .apk.classes2.zip
D/dalvikvm﹕ GC_CONCURRENT freed 186K, 11% free 3245K/3640K, paused 2ms+4ms, total 28ms
D/dalvikvm﹕ WAIT_FOR_CONCURRENT_GC blocked 5ms
D/dalvikvm﹕ GC_CONCURRENT freed 156K, 8% free 3593K/3904K, paused 3ms+2ms, total 22ms
I/MultiDex﹕ Extraction is needed for file /data/data/com.playdayteam.playday.debug/code_cache/secondary-dexes/com.playdayteam. playday.debug-1.apk.classes2.zip
I/MultiDex﹕ Extracting /data/data/com.playdayteam.playday.debug/code_cache/secondary-dexes/com.playdayteam.playday.debug-1 .apk.classes576886388.zip
I/MultiDex﹕ Renaming to /data/data/com.playdayteam.playday.debug/code_cache/secondary-dexes/com.playdayteam.playday.debug-1 .apk.classes2.zip
I/MultiDex﹕ Extraction success - length /data/data/com.playdayteam.playday.debug/code_cache/secondary-dexes/com.playdayteam.playday. debug-1.apk.classes2.zip: 540964
I/MultiDex﹕ load found 1 secondary dex files
D/dalvikvm﹕ DexOpt: --- BEGIN 'com. playdayteam.playday.debug-1.apk.classes2.zip' (bootstrap=0) ---
D/dalvikvm﹕ DexOpt: --- END 'com. playdayteam.playday.debug-1.apk.classes2.zip' (success) ---
D/dalvikvm﹕ DEX prep '/data/data/com .playdayteam.playday.debug/code_cache/secondary-dexes/com.playdayteam.playday.debug-1.apk.classes2. zip': unzip in 28ms, rewrite 387ms
I/MultiDex﹕ install done
I/MultiDex﹕ install
D/AndroidRuntime﹕ Shutting down VM
W/dalvikvm﹕ threadid=1: thread exiting with uncaught exception (group=0x41c1d930)
E/AndroidRuntime﹕ FATAL EXCEPTION: main
java.lang.NoClassDefFoundError: com.playday.app.core.AppWrapper
at com.playday.app.core.App.onCreate(App.java:22)
at android.app.Instrumentation.callApplicationOnCreate(Instrumentation.java:1006)
at android.app.ActivityThread.handleBindApplication(ActivityThread.java:4457)
at android.app.ActivityThread.access$1300(ActivityThread.java:142)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1332)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:137)
at android.app.ActivityThread.main(ActivityThread.java:5105)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:511)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:793)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:560)
at dalvik.system.NativeStart.main(Native Method)
我有相同的Android Studio,gradle,sdk,jdk版本,相同的代码。我甚至尝试格式化硬盘并重新安装操作系统以确保环境相同。造成这个奇怪问题的原因是什么?
这是我的build.gradle
:
apply plugin: 'com.android.application'
repositories {
maven { url 'http://dl.bintray.com/populov/maven' }
mavenCentral()
maven { url 'https://oss.sonatype.org/content/repositories/snapshots/' }
}
android {
compileSdkVersion project.api_level
buildToolsVersion project.build_tools_version
defaultConfig {
minSdkVersion 14
targetSdkVersion project.api_level
}
sourceSets {
instrumentTest.setRoot('src/test')
}
packagingOptions {
exclude 'META-INF/LICENSE.txt'
exclude 'META-INF/LICENSE'
exclude 'META-INF/NOTICE.txt'
exclude 'META-INF/NOTICE'
exclude 'META-INF/ASL2.0'
exclude 'AndroidManifest.xml'
}
defaultConfig {
versionName "0.3.2"
versionCode 23
}
buildTypes {
debug {
debuggable true
applicationIdSuffix ".debug"
}
beta {
debuggable true
signingConfig signingConfigs.release
applicationIdSuffix ".beta"
}
release {
signingConfig signingConfigs.release
runProguard false
proguardFile file('proguard-rules.txt')
proguardFile getDefaultProguardFile('proguard-android-optimize.txt')
}
}
dexOptions {
incremental false
preDexLibraries false
}
}
dependencies {
compile "com.android.support:support-v13:$project.support_lib_version"
compile "com.android.support:support-v4:$project.support_lib_version"
compile "com.android.support:appcompat-v7:$project.support_lib_version"
compile 'com.google.android.gms:play-services:6.1.11'
compile('de.keyboardsurfer.android.widget:crouton:1.8.5@aar') {
exclude group: 'com.google.android', module: 'support-v4'
}
compile('com.octo.android.robospice:robospice:1.4.14'){
exclude group: 'commons-io', module: 'commons-io'
}
compile('com.octo.android.robospice:robospice-retrofit:1.4.14'){
exclude group: 'commons-io', module: 'commons-io'
}
compile 'com.squareup.retrofit:retrofit:1.6.1'
compile 'com.google.code.gson:gson:2.3'
compile 'com.viewpagerindicator:library:2.4.1@aar'
compile 'com.squareup.picasso:picasso:2.3.3'
compile 'com.squareup.okhttp:okhttp:2.0.0'
compile 'com.squareup.okhttp:okhttp-urlconnection:2.0.0'
compile 'com.etsy.android.grid:library:1.0.5'
compile 'com.squareup:otto:1.3.4'
compile 'com.darwinsys:hirondelle-date4j:1.5.1'
compile 'com.github.chrisbanes.photoview:library:1.2.3'
compile 'me.grantland:autofittextview:0.2.0'
compile 'it.sephiroth.android.library.horizontallistview:library:1.2.1'
compile 'org.ocpsoft.prettytime:prettytime:3.2.4.Final'
compile 'com.google.guava:guava:18.0'
compile 'com.github.castorflex.smoothprogressbar:library:0.5.2'
compile 'com.makeramen:roundedimageview:1.3.0'
compile 'org.lucasr.twowayview:twowayview:0.1.1'
compile 'com.michaelpardo:activeandroid:3.1.0-SNAPSHOT'
compile project(':libs:LoopingViewPager')
compile project(':libs:PhotoView-2.2.1')
compile files('libs/localytics.jar')
compile files('libs/android-support-multidex.jar')
compile 'net.hockeyapp.android:HockeySDK:3.0.2'
}
afterEvaluate {
tasks.matching {
it.name.startsWith('dex')
}.each { dx ->
if (dx.additionalParameters == null) {
dx.additionalParameters = []
}
dx.additionalParameters += '--multi-dex' // enable multidex
dx.additionalParameters += "--main-dex-list=$projectDir/multidex.keep".toString()
}
}
更新。我的multidex.keep
文件:
android/support/multidex/BuildConfig.class
android/support/multidex/MultiDex$V14.class
android/support/multidex/MultiDex$V19.class
android/support/multidex/MultiDex$V4.class
android/support/multidex/MultiDex.class
android/support/multidex/MultiDexApplication.class
android/support/multidex/MultiDexExtractor$1.class
android/support/multidex/MultiDexExtractor.class
android/support/multidex/ZipUtil$CentralDirectory.class
android/support/multidex/ZipUtil.class
com/playday/app/models/notification/Badge.class
com/playday/app/models/User.class
com/playday/app/core/AppWrapper.class
com/playday/app/core/App.class
答案 0 :(得分:12)
您的 AppWrapper 类无法加载,因为 retrofit.ErrorHandler 接口未包含在主dex文件中。
如何计算要放在main-dex-list文件中的类?
有script可以为您生成它。我写了一篇blogpost来说明如何使用它。
更新(2014年10月31日):
Gradle插件v0.14.0现在自动完成。请参阅我的回答here。
更新(2017年4月24日):
developer guide解释了如果选择具有gradle选项的特定类,如果它没有自动选择所有正确的类。
答案 1 :(得分:7)
如果一切正常,但会出现此错误,
尝试停用即时运行!!!
当我禁用它时,所有类都已正确加载。
答案 2 :(得分:6)
如果您正在扩展MultiDexApplication,则不需要进行MultiDex.install(context)调用,因为它已经发生(请参阅源链接)。如果你需要使用attachBaseContext,那么只需确保调用super.attachBaseContext(context)。
我们刚刚更新了developers.android.com,其中包含有关如何将支持库与Android gradle插件配合使用的说明,其中包括用于快速开发构建周期时间的开发优化。
答案 3 :(得分:6)
如果有人因为他们的应用程序类没有在Lollipop之前的设备上找到,但是应用程序在Lollipop及以上版本上运行正常,那么这似乎是Jack和Multidex的一个已知问题。
答案 4 :(得分:3)
NoClassDefFound
可能发生在任何没有加载到早于Lollipop且启用了multidex的API的设备上的任意类。如果您正确设置了ProGuard,那么您可以轻松使用,而不会产生MultiDex开销,从而使您的应用程序在发布版本中启动缓慢,尤其是在旧设备上。但是,在调试模式下开发应用程序时,您不希望ProGuard减慢速度。如果您尝试在禁用ProGuard的情况下启动调试版本,则会开始出现com.android.dex.DexIndexOverflowException: Cannot merge new index 72118 into a non-jumbo instruction!
等构建错误
所以真正想要的是启用ProGuard并且仅在发布版本上禁用multidex,而调试版本应与禁用Proguard和启用multidex相反。当然,您还必须挑剔并使用较少的依赖项,因为您的发布版本将受到64K限制。
这需要将build.gradle设置为具有buildTypes
配置,并且仅为调试编译multidex支持库依赖项。
还必须将Application子类设置为从不同的子类派生,具体取决于您是否处于multidex模式。这可以使用gradle manifest merger原则,通过为调试版本定义覆盖清单,然后以不同方式指定Application类来实现。
这是相关的app模块build.gradle:
android {
...
buildTypes {
debug {
minifyEnabled false //Disabled Proguard
multiDexEnabled true // Enabling multi-dex support.
}
release {
minifyEnabled true //Enabled Proguard
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
multiDexEnabled false // Disable multi-dex support.
}
}
dependencies {
debugCompile 'com.android.support:multidex:1.0.1' //debugCompile makes it included only for debug builds
...
}
}
如果您不使用Application子类,那么您需要做的就是指定应用程序子类android.support.multidex.MultiDexApplication
的名称,如https://developer.android.com/studio/build/multidex.html中所述,但您想要这样做仅用于您的调试版本。
为此,您必须在调试和发布变体文件夹层次结构中指定覆盖文件,如下所示:
src
- main
- AndroidManifest.xml
- java/com/yourcompany/MyApplication.java (extends from BaseApplication)
- release
- java/com/yourcompany/BaseApplication.java (extends from Application)
- debug
- AndroidManifest.xml
- java/com/yourcompany/BaseApplication.java (extends from MultiDexApplication)
是的,您在主模块的文件夹旁边创建了debug
和release
个文件夹。在以下文件中添加以下文件:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
>
<application
android:name="com.yourcompany.MyApplication"
tools:replace="android:name"/>
</manifest>
此清单仅包含在调试版本中,并且将在您的版本1中被忽略。
public class BaseApplication extends Application {
}
public class BaseApplication extends MultiDexApplication {
}
public class MyApplication extends BaseApplication {
@Override
public void onCreate() {
super.onCreate();
//Init database, etc. etc.;
}
}
通过这种方式,您可以将App的功能添加到MyApplication.java
,同时具有不同的基类。
答案 5 :(得分:1)
我也遇到过这种问题。我的解决方案是:
在我的build.gradle文件中,依赖项中有多个compile 'com.android.support:multidex:1.0.0'
条目。像:
dependencies {
compile 'com.android.support:multidex:1.0.0'
compile 'com.android.support:multidex:1.0.0'
// other dependencies ........
}
只放一个编译'com.android.support:multidex:1.0.0'之类的:
dependencies {
compile 'com.android.support:multidex:1.0.0'
// other dependencies ........
}
答案 6 :(得分:0)
我终于解决了!原因不在onCreate()
方法中。来自logcat的这条线引起了我的注意:
I/dalvikvm﹕ Failed resolving Lcom/playday/app/core/AppWrapper; interface 8940 'Lretrofit/ErrorHandler;'
W/dalvikvm﹕ Link of class 'Lcom/playday/app/core/AppWrapper;' failed
此行在所有MultiDex日志之前触发。问题的根源是Retrofit ErrorHandler
接口,AppWrapper
实现了该接口。
正如@AlexLipov在回答中所说,Dalvik无法找到ErrorHandler
课程而无法加载AppWrapper
。
无论如何,解决方案不是直接由ErrorHandler
实现AppWrapper
,而是将其拉入私有变量。
答案 7 :(得分:0)
我尝试了很多解决方案,但没人为我工作。终于,我找到了:
public class MyApplication extends Application {
@Override
protected void attachBaseContext(Context base) {
super.attachBaseContext(base);
MultiDex.install(this);
}
}
这是解决我的问题的唯一方法。也许有人遇到相同的问题,这可能会有所帮助:)
答案 8 :(得分:0)
在gradle中添加以下依赖
implementation 'com.android.support:multidex:1.0.3'
在应用级 build.gradle 中,添加如下参数。
defaultConfig {
multiDexEnabled = true
}
在应用程序类中,添加以下行
MultiDex.install(this);