I want to display a sum of favcount from NoteDao, so I make it in Livedata and ViewModel like this
@Dao
public interface NoteDao {
@Query("SELECT * FROM notes ORDER BY id DESC")
List<Note> getAllNotes();
@Insert(onConflict = OnConflictStrategy.REPLACE)
void insertNote(Note note);
@Delete
void deleteNote(Note note);
@Query("SELECT SUM(fav_count) as favSum FROM notes")
LiveData<String> getFavSum();
}
This is my entity "notes" that has the fav_count
@Entity(tableName = "notes")
@ColumnInfo(name = "fav_count")
private String favCount;
public Note() {}
public String getFavCount() { return favCount; }
public void setFavCount(String favCount) { this.favCount = favCount;}
This is my repository
public class totalRepository {
NoteDao noteDao;
public LiveData<String> getTotal() {
return noteDao.getFavSum();
}
}
And this is my ViewModel
public class NoteViewModel extends ViewModel {
public final totalRepository repository;
public LiveData<String> getmTotal(){
return repository.getTotal();
}
public NoteViewModel(totalRepository repository) {
this.repository = repository;
}
}
This is my activity where I want to display the data
public class Statistics extends AppCompatActivity {
TextView syukrsum;
String favSum = "0";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_statistics);
NoteViewModel noteViewModel;
syukrsum = findViewById(R.id.syukrSum);
noteViewModel = new ViewModelProvider(this).get(NoteViewModel.class);
noteViewModel.getmTotal().observe(Statistics.this, new Observer<String>() {
@Override
public void onChanged(String string) {
if (string == null) {
favSum = "0";
syukrsum.setText(0);
} else {
favSum = string;
syukrsum.setText(string);
}
}
});
}
}
When I open the Statistics activity, my app crashes and give the following errors:
2020-12-04 14:40:01.630 26822-26822/com.rhlab.syukr5 E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.rhlab.syukr5, PID: 26822
java.lang.RuntimeException: Unable to start activity ComponentInfo{com.rhlab.syukr5/com.rhlab.syukr5.Activities.Statistics}: java.lang.RuntimeException: Cannot create an instance of class com.rhlab.syukr5.NoteViewModel
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3170)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3307)
at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:78)
at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:113)
at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:71)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2036)
at android.os.Handler.dispatchMessage(Handler.java:106)
at android.os.Looper.loop(Looper.java:224)
at android.app.ActivityThread.main(ActivityThread.java:7081)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:604)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:928)
Caused by: java.lang.RuntimeException: Cannot create an instance of class com.rhlab.syukr5.NoteViewModel
at androidx.lifecycle.ViewModelProvider$NewInstanceFactory.create(ViewModelProvider.java:221)
at androidx.lifecycle.ViewModelProvider$AndroidViewModelFactory.create(ViewModelProvider.java:278)
at androidx.lifecycle.SavedStateViewModelFactory.create(SavedStateViewModelFactory.java:106)
at androidx.lifecycle.ViewModelProvider.get(ViewModelProvider.java:185)
at androidx.lifecycle.ViewModelProvider.get(ViewModelProvider.java:150)
at com.rhlab.syukr5.Activities.Statistics.onCreate(**Statistics.java:31**)
at android.app.Activity.performCreate(Activity.java:7258)
at android.app.Activity.performCreate(Activity.java:7249)
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1271)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3150)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3307)
at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:78)
at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:113)
at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:71)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2036)
at android.os.Handler.dispatchMessage(Handler.java:106)
at android.os.Looper.loop(Looper.java:224)
at android.app.ActivityThread.main(ActivityThread.java:7081)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:604)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:928)
Caused by: java.lang.InstantiationException: java.lang.Class<com.rhlab.syukr5.NoteViewModel> has no zero argument constructor
at java.lang.Class.newInstance(Native Method)
at androidx.lifecycle.ViewModelProvider$NewInstanceFactory.create(ViewModelProvider.java:219)
at androidx.lifecycle.ViewModelProvider$AndroidViewModelFactory.create(ViewModelProvider.java:278)
at androidx.lifecycle.SavedStateViewModelFactory.create(SavedStateViewModelFactory.java:106)
at androidx.lifecycle.ViewModelProvider.get(ViewModelProvider.java:185)
at androidx.lifecycle.ViewModelProvider.get(ViewModelProvider.java:150)
**at com.rhlab.syukr5.Activities.Statistics.onCreate(Statistics.java:31)**
at android.app.Activity.performCreate(Activity.java:7258)
at android.app.Activity.performCreate(Activity.java:7249)
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1271)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3150)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3307)
at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:78)
at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:113)
at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:71)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2036)
at android.os.Handler.dispatchMessage(Handler.java:106)
at android.os.Looper.loop(Looper.java:224)
at android.app.ActivityThread.main(ActivityThread.java:7081)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:604)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:928)
The error points out at Statistics.java line 31
noteViewModel = new ViewModelProvider(this).get(NoteViewModel.class);
QUESTION IS : What is my mistake? Sorry if my question is not clear, keep in mind that I am a novice, maybe I did make huge or stupid mistake, please bear with me and kindly explain the solution!
It is crashing because it is unable to create an instance of your Viewmodel. Why?
Because by default it only create instance of your viewmodel, if it has zeo constructor parameter. But your viewmodel do have one constructor parameter.
Your NoteViewModel, needs TotalRepository instance as a constructor parameter, which you're not telling it where to get from.
Therefore the solution is create a ViewModelFactory.
Here is sample code:
import androidx.lifecycle.ViewModel;
import androidx.lifecycle.ViewModelProvider;
public class NoteViewModelFactory extends ViewModelProvider.NewInstanceFactory {
private final TotalRepository totalRepository;
public NoteViewModelFactory(TotalRepository totalRepository) {
this.totalRepository = totalRepository;
}
@Override
public <T extends ViewModel> T create(Class<T> modelClass) {
return (T) new NoteViewModel(totalRepository);
}
}
From your Fragment, you need to create viewModel like below:
NoteDao noteDao = // Initialize your NoteDao object and pass it to Total Repository
TotalRepository totalRepository = new TotalRepository(noteDao);
NoteViewModelFactory noteViewModelFactory = new NoteViewModelFactory(totalRepository);
NoteViewModel noteViewModel = ViewModelProviders.of(this, noteViewModelFactory).get(NoteViewModel.class);