0

I am new to MVVM architecture, I have tried with different options but still getting same exception "cannot able to create an instance ViewModel". I am using Android Studio Iguana

below is my VideoActivity:

class VideoActivity : AppCompatActivity() {
    private lateinit var viewModel: VideoViewModel
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        viewModel = ViewModelProvider(this).get(VideoViewModel::class.java)
        
        val videos= listOf(
            Video(id = 1, url = "url1.mp4"),
            Video(id = 1, url = "url2.mp4"),
            Video(id = 1, url = "url3.mp4"),
            Video(id = 1, url = "url4.mp4"),
            Video(id = 1, url = "url5.mp4"),
        )

        viewModel.downloadVideos(videos)

        viewModel.videos.observe(this) { downloadedVideos ->
            if (downloadedVideos.isNotEmpty()) {
                viewModel.playNextVideo()
            }
        }
    }
}

below is my VideoRepository class

    class VideoRepository(private val context: Context) {
       
        suspend fun downloadVideos(videos: List<Video>): List<Video> {
            val downloadedVideos = mutableListOf<Video>()
            for (video in videos) {
                val filePath = downloadVideo(video.url)
                if (filePath.isNotBlank()) {
                    video.downloadStatus = DownloadStatus.DOWNLOADED
                    video.filePath = filePath
                    downloadedVideos.add(video)
                }
            }
            return downloadedVideos
        }
    
        private suspend fun downloadVideo(videoUrl: String): String = withContext(Dispatchers.IO) {
            try {
                val url = URL(videoUrl)
                val connection = url.openConnection() as HttpURLConnection
                connection.connect()
    
                val inputStream: InputStream = connection.inputStream
                val file = File(context.getExternalFilesDir(Environment.DIRECTORY_MOVIES), "video_${System.currentTimeMillis()}.mp4")
                val outputStream = FileOutputStream(file)
    
                val buffer = ByteArray(1024)
                var bytesRead: Int
                while (inputStream.read(buffer).also { bytesRead = it } != -1) {
                    outputStream.write(buffer, 0, bytesRead)
                }
    
                outputStream.flush()
                outputStream.close()
                inputStream.close()
    
                file.absolutePath
            } catch (e: Exception) {
                e.printStackTrace()
                ""
            }
        }
    
        fun playVideo(video: Video) {
            val videoView = (context as VideoActivity).findViewById<VideoView>(R.id.video_view)
            videoView.setVideoURI(Uri.parse(video.filePath))
            videoView.start()
        }
    }

class VideoViewModel(var repository: VideoRepository) : ViewModel(){

    private val _videos = MutableLiveData<List<Video>>()
    val videos:LiveData<List<Video>> = _videos

    private lateinit var videoView: VideoView

    private var currentVideoIndex = 0
    fun downloadVideos(videos: List<Video>){
        viewModelScope.launch {
            val downloadVideos = repository.downloadVideos(videos)
            _videos.postValue(downloadVideos)
        }
    }

    fun playNextVideo(){
        currentVideoIndex = (currentVideoIndex + 1) % (videos.value?.size ?: 1)
        val video = videos.value?.get(currentVideoIndex)
        video?.let{
            repository.playVideo(it)
        }
    }  
}

App Gradle Dependencies:

implementation(libs.androidx.core.ktx)
implementation(libs.androidx.lifecycle.runtime.ktx)
implementation(libs.androidx.activity.compose)
implementation(platform(libs.androidx.compose.bom))
implementation(libs.androidx.ui)
implementation(libs.androidx.ui.graphics)
implementation(libs.androidx.ui.tooling.preview)
implementation(libs.androidx.material3)

implementation("androidx.lifecycle:lifecycle-viewmodel-ktx:2.3.1")
implementation("androidx.lifecycle:lifecycle-livedata-ktx:2.3.1")
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.6.0")
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.6.0")
implementation(libs.androidx.appcompat)

Below is the exception which I am getting

Process: com.android, PID: 4717
                                                                                                    java.lang.RuntimeException: Unable to start activity ComponentInfo{com.android/com.android.main.VideoActivity}: java.lang.RuntimeException: Cannot create an instance of class com.android.main.VideoViewModel
                                                                                                        at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3825)
                                                                                                        at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3971)
                                                                                                        at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:101)
                                                                                                        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:2389)
                                                                                                        at android.os.Handler.dispatchMessage(Handler.java:106)
                                                                                                        at android.os.Looper.loopOnce(Looper.java:210)
                                                                                                        at android.os.Looper.loop(Looper.java:299)
                                                                                                        at android.app.ActivityThread.main(ActivityThread.java:8261)
                                                                                                        at java.lang.reflect.Method.invoke(Native Method)
                                                                                                        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:559)
                                                                                                        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:954)
                                                                                                    Caused by: java.lang.RuntimeException: Cannot create an instance of class com.android.main.VideoViewModel
                                                                                                        at androidx.lifecycle.ViewModelProvider$NewInstanceFactory.create(ViewModelProvider.kt:201)
                                                                                                        at androidx.lifecycle.ViewModelProvider$AndroidViewModelFactory.create(ViewModelProvider.kt:320)
                                                                                                        at androidx.lifecycle.ViewModelProvider$AndroidViewModelFactory.create(ViewModelProvider.kt:302)
                                                                                                        at androidx.lifecycle.ViewModelProvider$AndroidViewModelFactory.create(ViewModelProvider.kt:276)
                                                                                                        at androidx.lifecycle.SavedStateViewModelFactory.create(SavedStateViewModelFactory.kt:128)
                                                                                                        at androidx.lifecycle.ViewModelProvider.get(ViewModelProvider.kt:184)
                                                                                                        at androidx.lifecycle.ViewModelProvider.get(ViewModelProvider.kt:150)
                                                                                                        at com.android.main.VideoActivity.onCreate(VideoActivity.kt:20)
                                                                                                        at android.app.Activity.performCreate(Activity.java:8516)
                                                                                                        at android.app.Activity.performCreate(Activity.java:8480)
                                                                                                        at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1418)
                                                                                                        at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3806)
                                                                                                        at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3971) 
                                                                                                        at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:101) 
                                                                                                        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:2389) 
                                                                                                        at android.os.Handler.dispatchMessage(Handler.java:106) 
                                                                                                        at android.os.Looper.loopOnce(Looper.java:210) 
                                                                                                        at android.os.Looper.loop(Looper.java:299) 
                                                                                                        at android.app.ActivityThread.main(ActivityThread.java:8261) 
                                                                                                        at java.lang.reflect.Method.invoke(Native Method) 
                                                                                                        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:559) 
                                                                                                        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:954) 
                                                                                                    Caused by: java.lang.NoSuchMethodException: com.android.adbeets.main.VideoViewModel.<init> []
                                                                                                        at java.lang.Class.getConstructor0(Class.java:3325)
                                                                                                        at java.lang.Class.getDeclaredConstructor(Class.java:3063)
                                                                                                        at androidx.lifecycle.ViewModelProvider$NewInstanceFactory.create(ViewModelProvider.kt:199)
                                                                                                        at androidx.lifecycle.ViewModelProvider$AndroidViewModelFactory.create(ViewModelProvider.kt:320) 
                                                                                                        at androidx.lifecycle.ViewModelProvider$AndroidViewModelFactory.create(ViewModelProvider.kt:302) 
                                                                                                        at androidx.lifecycle.ViewModelProvider$AndroidViewModelFactory.create(ViewModelProvider.kt:276) 
                                                                                                        at androidx.lifecycle.SavedStateViewModelFactory.create(SavedStateViewModelFactory.kt:128) 
                                                                                                        at androidx.lifecycle.ViewModelProvider.get(ViewModelProvider.kt:184) 
                                                                                                        at androidx.lifecycle.ViewModelProvider.get(ViewModelProvider.kt:150) 
                                                                                                        at com.android.adbeets.main.VideoActivity.onCreate(VideoActivity.kt:20) 
                                                                                                        at android.app.Activity.performCreate(Activity.java:8516) 
                                                                                                        at android.app.Activity.performCreate(Activity.java:8480) 
                                                                                                        at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1418) 
                                                                                                        at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3806) 
                                                                                                        at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3971) 
                                                                                                        at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:101) 
                                                                                                        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:2389) 
                                                                                                        at android.os.Handler.dispatchMessage(Handler.java:106) 
                                                                                                        at android.os.Looper.loopOnce(Looper.java:210) 
                                                                                                        at android.os.Looper.loop(Looper.java:299) 
                                                                                                        at android.app.ActivityThread.main(ActivityThread.java:8261) 
                                                                                                        at java.lang.reflect.Method.invoke(Native Method) 
                                                                                                        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:559) 
                                                                                                        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:954) 
2024-04-09 12:06:35.424 24478-30209 ActivityManagerWrapper  com.miui.home                        E

Could anyone help me on this issue, Thanks inAdvance

2 Answers 2

2

Your viewModel definition is an old one, try to use the new approach to initialize your viewModel.

Add these dependencies to your project;

def activity_version = "1.8.2"
implementation "androidx.activity:activity-ktx:$activity_version"

Remove your viewModel = ViewModelProvider(this).get(VideoViewModel::class.java) line

Update your private lateinit var viewModel: VideoViewModel to private val viewModel: VideoViewModel by viewModels()

Hope this helps.

Sign up to request clarification or add additional context in comments.

3 Comments

Mustafa,Thanks for your response, when I try to add above dependency getting exception Execution failed for task ':app:checkDebugAarMetadata'. > Could not resolve all files for configuration ':app:debugRuntimeClasspath'. > Could not find activityx.activity:activity-ktx:1.8.2.
You should copy&paste the artifact from the answer. activityx.activity:activity-ktx is not what was suggested.
Please follow this page to implement the library developer.android.com/jetpack/androidx/releases/activity
2

Reason is that default viewModel providers cannot construct viewModel which contains properties in primary constructor (excepts for application class). I would recommend you some DI library (hilt for example).

Solution without DI

If you don't want to implement DI right now just change your viewModel's like this:

class VideoViewModel(
application: Application
) : AndroidViewModel(application) {
   val repository: VideoRepository = VideoRepository(application)
}

This is just quick workaround but i recommend using DI.

Solution with DI

Add plugin into your root build.gradle.kts:

plugins {
  //Plugin is taken from google() repository
  id("com.google.dagger.hilt.android") version "2.51.1" apply false
  
  //Keep in mind to use compatible versions of ksp and kotlin
  id("org.jetbrains.kotlin.android") version "1.9.23" apply false
  id("com.google.devtools.ksp") version "1.9.23-1.0.20" apply false
}

then update your app's build.gradle.kts, keep in mind you have to use same version of hilt:

plugins {
  id("com.google.dagger.hilt.android")
  id("com.google.devtools.ksp")
}

android {
  ...
}

dependencies {
    val hiltVersion = "2.51.1"
    val hiltCompilerVersion = "1.2.0"
    implementation("com.google.dagger:hilt-android:$hiltVersion")
    implementation("androidx.hilt:hilt-common:$hiltCompilerVersion")
    
    //using ksp but it's still possible to use kapt
    ksp("com.google.dagger:hilt-android-compiler:$hiltVersion")
    ksp("androidx.hilt:hilt-compiler:$hiltCompilerVersion")
}

After you sync your gradle you have to adjust your code for dependency injection, follow the docs i mentioned.

Annotate your application class with @HiltAndroidApp and also don't forget to declare it in Manifest.xml:

@HiltAndroidApp
class ExampleApplication : Application() { ... }

Manifest:

<application
    android:name=".ExampleApplication"/>

After that annotate your VideoActivity with @AndroidEntryPoint annotation and update how you are constructing the viewModel:

@AndroidEntryPoint
class VideoActivity : AppCompatActivity() { 
   private val viewModel: VideoViewModel by viewModels()
}

Update your viewModel with annotations to tell the hilt how to construct it:

@HiltViewModel
class VideoViewModel @Inject constructor(
val repository: VideoRepository
) : ViewModel(){ ... }

And for your VideoRepository too to tell the hilt how to construct it:

///In case you want only one single instance of repository
@Singleton
class VideoRepository @Inject constructor(
@ApplicationContext private val context: Context
) { ... }

With this you are able to have clean MVVM architecture using dependency injection for better dependencies management. I didn't explained all the details because it's all in the documentation.

Hope this helps.

12 Comments

You should use ksp instead of kapt. Also, you need to annotate the Application with @HiltAndroidApp. And while you're at it you should use the newest hilt version.
Thanks for your response, what we need to add in Application class, please do let me know
@Naveen I updated the DI solution in my answer. @Leviathan Thanks, didn't know that hilt has support for ksp too.
@MiroslavHýbler, thanks for updating the code, I am getting below exception after updating the code java.lang.NoSuchMethodError: 'void org.jetbrains.kotlin.incremental.IncrementalCompilationContext.<init>(org.jetbrains.kotlin.incremental.storage.FileToPathConverter, org.jetbrains.kotlin.incremental.storage.FileToPathConverter, boolean, org.jetbrains.kotlin.incremental.CompilationTransaction, org.jetbrains.kotlin.build.report.ICReporter, boolean, boolean, int, kotlin.jvm.internal.DefaultConstructorMarker)'
@Naveen Try clean and rebuild your project, and also make sure to use compatible ksp and kotlin versions, i used newest ones in my answer. I didn't experienced this build crash myself, i believe it's just some temporary crash which can be solved by rebuild, or after clearing Android Studio cache and restart.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.