I'm working on a multi-module app with Kotlin and Hilt, and my MainActivity crashes when starting with the following exception:
2022-07-29 09:32:00.547 23850-23850/com.myApp.myApp E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.myApp.myApp, PID: 23850
java.lang.RuntimeException: Unable to instantiate activity ComponentInfo{com.myApp.myApp/com.myApp.myApp.activities.main.MainActivity}: java.lang.InstantiationException: java.lang.Class<com.myApp.myApp.activities.main.MainActivity> has no zero argument constructor
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3365)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3601)
at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:85)
at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:135)
at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:95)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2066)
at android.os.Handler.dispatchMessage(Handler.java:106)
at android.os.Looper.loop(Looper.java:223)
at android.app.ActivityThread.main(ActivityThread.java:7656)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:592)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:947)
Caused by: java.lang.InstantiationException: java.lang.Class<com.myApp.myApp.activities.main.MainActivity> has no zero argument constructor
at java.lang.Class.newInstance(Native Method)
at android.app.AppComponentFactory.instantiateActivity(AppComponentFactory.java:95)
at androidx.core.app.CoreComponentFactory.instantiateActivity(CoreComponentFactory.java:45)
at android.app.Instrumentation.newActivity(Instrumentation.java:1253)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3353)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3601)
at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:85)
at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:135)
at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:95)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2066)
at android.os.Handler.dispatchMessage(Handler.java:106)
at android.os.Looper.loop(Looper.java:223)
at android.app.ActivityThread.main(ActivityThread.java:7656)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:592)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:947)
MainActivity:
@AndroidEntryPoint
class MainActivity
@Inject constructor(
private var awLocale: AWLocale,
private var awUtils: AWUtils,
private var awDate: AWDate,
private var awPreferences: AWPreferences) :
FragmentActivity(),
IActionListeners, IImageListeners, OnListFragmentInteractionListener
{
private var mainViewModel: MainViewModel = ViewModelProvider(this).get(MainViewModel::class.java)
...Body
}
build.gradle:
plugins {
id('dagger.hilt.android.plugin')
id('com.android.application')
id('kotlin-android')
id('kotlin-kapt')
}
android {
compileSdkVersion 32
def code
Properties versionProps = new Properties()
def versionPropsFile = file('version.properties')
if (versionPropsFile.exists())
versionProps.load(new FileInputStream(versionPropsFile))
code = (versionProps['VERSION_CODE'] ?: "0").toInteger() 1
versionProps['VERSION_CODE'] = code.toString()
versionProps.store(versionPropsFile.newWriter(), null)
packagingOptions {
resources {
pickFirsts = ['META-INF/LICENSE.txt']
excludes = ['META-INF/NOTICE.md', 'META-INF/LICENSE.md', 'META-INF/INDEX.LIST', 'META-INF/DEPENDENCIES', 'META-INF/io.netty.versions.properties']
}
}
defaultConfig {
applicationId 'com.myApp.myApp'
minSdkVersion 23
targetSdkVersion 32
versionCode code
versionName "2.0." code
// next ndk abifilters have to be disabled if spli apk is enabled.
// ndk.abiFilters 'armeabi', 'armeabi-v7a', 'arm64-v8a', 'x86', 'x86_64'//testing
multiDexEnabled true
compileOptions {
sourceCompatibility java_version
targetCompatibility java_version
}
}
compileOptions {
sourceCompatibility java_version
targetCompatibility java_version
}
splits {
// Configures multiple APKs based on ABI.
abi {
// Enables building multiple APKs per ABI.
enable true
// By default all ABIs are included, so use reset() and include to specify that we only
// want APKs for x86 and x86_64.
// Resets the list of ABIs that Gradle should create APKs for to none.
reset()
// Specifies a list of ABIs that Gradle should create APKs for.
include "armeabi-v7a"
include "arm64-v8a"
include "x86"
include "x86_64"
// Specifies that we do not want to also generate a universal APK that includes all ABIs.
universalApk false
}
}
buildTypes {
release {
/*signingConfig signingConfigs.release*/
minifyEnabled false
shrinkResources false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
// This next piece of code is used by apk Split
applicationVariants.all { variant ->
variant.outputs.all { output ->
project.ext { appName = 'myApp' }
def newName = 'myApp_' output.getFilter(com.android.build.OutputFile.ABI) '.apk'
outputFileName = new File("./", newName)
}
// assign different version code for each output
variant.outputs.each { output ->
output.versionCodeOverride =
//project.ext.versionCodes.get(output.getFilter(OutputFile.ABI)) * 1000 android.defaultConfig.versionCode
project.ext.versionCodes.get(output.getFilter(com.android.build.OutputFile.ABI)) * 1000 code - 1000
}
}
}
debug {
}
}
allprojects {
repositories {
jcenter()
mavenCentral()
def androidHome = System.getenv("ANDROID_HOME")
maven {
url "$androidHome/extras/android/m2repository/"
}
maven {
url "https://maven.java.net/content/groups/public/"
}
}
/*tasks.withType(JavaCompile) {
options.compilerArgs << "-Xlint:unchecked" << "-Xlint:deprecation"
}*/
}
productFlavors {
}
androidResources {
ignoreAssetsPattern '!*ffprobe'
}
lint {
abortOnError false
checkReleaseBuilds false
}
dataBinding{
enabled = true
}
namespace 'com.myApp.myApp'
}
// This next piece of code is used by apk Split
// map for the version code that gives each ABI a value. make sure to list all ABIs mentioned in splits block, an keep the order.
ext.versionCodes = ['armeabi-v7a': 1, 'arm64-v8a': 2, 'x86': 3, 'x86_64': 4]
//import com.android.build.OutputFile
dependencies {
//P7Zip
//implementation 'com.hzy:libp7zip:1.7.0'
//Apache Commons
//implementation 'commons-io:commons-io:2.6'
//ffmpeg
implementation 'com.arthenica:mobile-ffmpeg-min-gpl:4.2.2.LTS'
//implementation 'com.arthenica:mobile-ffmpeg-full:4.3.1'
//Google Guava
api 'com.google.guava:guava:31.1-jre'
//volley
api 'com.android.volley:volley:1.2.1'
//spotify
api 'com.github.kaaes:spotify-web-api-android:0.4.1'
//mail API 19
//api 'com.sun.mail:android-mail:1.6.4'
//api 'com.sun.mail:android-activation:1.6.4'
//mail API 16
//api 'com.sun.mail:android-mail:1.6.7'
//api 'com.sun.mail:android-activation:1.6.7'
//apache commons lang
//ppppapi 'org.apache.commons:commons-lang3:3.12.0'
implementation group: 'org.apache.commons', name: 'commons-text', version: '1.9'
//Font Selector List Preference
api 'com.vanniktech:vntfontlistpreference:1.0.0'
//Rate my app
api 'com.github.hotchemi:android-rate:1.0.1'
//Support
api 'androidx.appcompat:appcompat:1.4.2'
api 'androidx.legacy:legacy-support-v4:1.0.0'
//AlertDialog
implementation 'com.github.d-max:spots-dialog:1.1@aar'
//glide animated gifs
implementation 'com.github.bumptech.glide:glide:4.13.2'
implementation 'androidx.viewpager2:viewpager2:1.0.0'
implementation project(path: ':Common')
annotationProcessor 'com.github.bumptech.glide:compiler:4.13.2'
implementation 'androidx.recyclerview:recyclerview:1.2.1'
//preference
implementation 'androidx.preference:preference-ktx:1.2.0'
//
api 'com.rockerhieu:rv-adapter-endless:1.2'
implementation 'com.squareup.picasso:picasso:2.71828'
//flat-dialog
implementation 'com.github.mejdi14:Flat-Dialog-Android:1.0.5'
//Hilt
//implementation('com.google.dagger:hilt-android:2.40')
//annotationProcessor('com.google.dagger:hilt-android-compiler:2.40')
implementation 'com.google.dagger:hilt-android:2.42'
implementation 'androidx.navigation:navigation-fragment-ktx:2.5.1'
//implementation 'androidx.hilt:hilt-lifecycle-viewmodel:1.0.0-alpha03'
//annotationProcessor 'androidx.hilt:hilt-compiler:1.0.0'
kapt 'com.google.dagger:hilt-android-compiler:2.42'
kapt('org.jetbrains.kotlinx:kotlinx-metadata-jvm:0.5.0')
kapt 'androidx.hilt:hilt-compiler:1.0.0'
implementation project(':Common')
implementation project(':DTO')
implementation project(':Core')
}
// Allow references to generated code
kapt {
correctErrorTypes = true
}
Application class:
@HiltAndroidApp
class AWApplication : MultiDexApplication() {
}
Provider module:
@Module
@InstallIn(SingletonComponent::class)
class Dependencies {
@Provides
@Singleton
fun bindsAppSettings(): AppSettings {
return AppSettings()
}
@Provides
@Singleton
fun bindsAWFile(appSettings: AppSettings, context: Context,
awException: ExceptionHandler, awPermission: AWPermission, awUtils: AWUtils): AWFile {
return AWFile(appSettings, context, awException, awPermission, awUtils)
}
@Provides
@Singleton
fun bindsAWLocale(appSettings: AppSettings, context: Context): AWLocale {
return AWLocale(appSettings, context)
}
@Provides
@Singleton
fun bindsAWDate(awLocale: AWLocale, awUtils: AWUtils): AWDate {
return AWDate(awLocale, awUtils)
}
@Provides
@Singleton
fun bindsAWException(appSettings: AppSettings, context: Context,
awDate: AWDate, awJson: AWJson, awEmail: AWEmail,
awCryptography: Cryptography, awPreferences: AWPreferences): ExceptionHandler {
return ExceptionHandler(appSettings, context, awDate, awJson, awEmail,
awCryptography, awPreferences)
}
@Provides
@Singleton
fun bindsAWJson(): AWJson {
return AWJson()
}
@Provides
@Singleton
fun bindsAWEmail(app: AppSettings, context: Context,
//awException: ExceptionHandler,
awJson: AWJson,
awLocale: AWLocale, awPreferences: AWPreferences): AWEmail {
return AWEmail(app, context, awJson, awLocale, awPreferences)
}
@Provides
@Singleton
fun bindsAWCryptography(app: AppSettings,
awPreferences: AWPreferences): Cryptography {
return Cryptography(app, awPreferences)
}
@Provides
@Singleton
fun bindsAWUtils(appSettings: AppSettings, context: Context): AWUtils {
return AWUtils(appSettings, context)
}
@Provides
@Singleton
fun bindsSMTP(appSettings: AppSettings, awException: ExceptionHandler,
awPreferences: AWPreferences): SMTP {
return SMTP(appSettings, awException, awPreferences)
}
}
MainViewModel:
@HiltViewModel
class MainViewModel
@Inject
constructor(
private var context: Context,
private var awPreferences: AWPreferences,
private var paintingService: PaintingService,
private var thoughtService: ThoughtService): ViewModel() {
}
Any help?
CodePudding user response:
You shouldn't inject your dependencies into Activity constructor when you don't need it. Take a look at this article, for such cases you have to create a factory.
In your case it would be enough to inject it as class-level variables (it also explained here).
@AndroidEntryPoint
class MainActivity :
FragmentActivity(),
IActionListeners, IImageListeners, OnListFragmentInteractionListener
{
@Inject
lateinit var awLocale: AWLocale
@Inject
lateinit var awUtils: AWUtils
@Inject
lateinit var awDate: AWDate
@Inject
lateinit var awPreferences: AWPreferences
private var mainViewModel: MainViewModel = ViewModelProvider(this).get(MainViewModel::class.java)
...Body
}