Android ClassCastException by referencing fragment in viewmodel
Android ClassCastException by referencing fragment in viewmodel
I was having some problem when trying to reference the fragment in my viewmodel class. Here is the part where my fragment call the viewmodel:
@Click(R.id.buttonExport)
void buttonExportClicked(View v){
SummaryViewModel summaryViewModel = ViewModelProviders.of(this).get(SummaryViewModel.class);
summaryViewModel.export(webViewResult);
}
In the viewmodel where I tried to access the context as well as Activity:
public void exportSelfTestSummary(WebView webViewResult) {
Activity context = (Activity) getApplication().getApplicationContext();
final ProgressDialog progressDialog=new ProgressDialog(context);
progressDialog.show();
PdfView.createWebPrintJob(context, webViewResult, directory, fileName, new PdfView.Callback() {
....
}
And the error message I am getting:
07-02 02:34:01.922 3563-3563/com.mainapp E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.mainapp, PID: 3563
java.lang.ClassCastException: com.mainapp.App cannot be cast to android.app.Activity
at com.mainapp.viewmodel.SummaryViewModel.export(SummaryViewModel.java:218)
at android.view.View.performClick(View.java:6294)
at android.view.View$PerformClick.run(View.java:24770)
at android.os.Handler.handleCallback(Handler.java:790)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:164)
at android.app.ActivityThread.main(ActivityThread.java:6494)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:438)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:807)
Any ideas? Thanks!
Edit
@Inject
public SummaryViewModel(@NonNull Application application) {
super(application);
}
4 Answers
4
The error says it clear enough, you cannot cast Application
to Activity
Application
Activity
What you are doing is get the application context, which will return an Application
class:
Application
Activity context = (Activity) getApplication().getApplicationContext();
If you are inside a fragment, just simply use fragment.getActivity()
fragment.getActivity()
How do you construct your
ViewModel
now? Post part of its code. Besides, where is the method getApplication
come from? As far as I know, getApplication
method only available in Activity
– Tam Huynh
Jul 2 at 2:50
ViewModel
getApplication
getApplication
Activity
Edited question!
– hyperfkcb
Jul 2 at 3:01
You are getting a ClassCastException because you are trying to cast the application into an Activity.
Activity context = (Activity) getApplication().getApplicationContext();
getApplication() method returns the App class and so does the getApplicationContext() method, which cannot be used to get the Activity.
You should never use a reference to an Activity or Fragment in your ViewModel. Your UI should never be modified from your ViewModel. ViewModel should only contain data used to modify your UI.
As an example:
Fragment/Activity:
SummaryViewModel summaryViewModel = ViewModelProviders.of(this).get(SummaryViewModel.class);
LiveData<WebResult> data = summaryViewModel.getWebViewDataInBackgroundThread();
//observe on this data for changes in your activity/fragment
data.observe(this, Observer {
@Override
public void onChanged(@Nullable final WebResult result) {
// Update the UI,
Activity context = (Activity) getApplication().getApplicationContext();
final ProgressDialog progressDialog=new ProgressDialog(context);
progressDialog.show();
PdfView.createWebPrintJob(context, webViewResult, directory, fileName, new PdfView.Callback() {
....
}
})
In your ViewModel:
public LiveData<WebResult> getWebViewDataInBackgroundThread() {
// getdata and return as LiveData
}
Read more on LiveData and ViewModel
Alternatively you can reach the Activity digging through parent views:
Activity act = (Activity) webViewResult.getParent().getParent().....so on
It not a good practice to use Context
and Activity Lifecycle related staff specially view inside ViewModel
. ViewModel
will only hold data and make a connection between data and view. Create ProgressDialog
inside Activity
or Fragment
. Use ViewModel
for your business logic. Create a LiveData
for ProgressDialog
state in ViewModle
. Change LiveData
value and observe it in Activity
or Fragment
. So you can decide when to show ProgressDialog
or when to hide it. Your view is inside Activity
or Fragment
and there is no possibility of MemoryLeak.
Context
ViewModel
ViewModel
ProgressDialog
Activity
Fragment
ViewModel
LiveData
ProgressDialog
ViewModle
LiveData
Activity
Fragment
ProgressDialog
Activity
Fragment
As @tam-huynh mentioned your problem is you trying to cast Application Context to Activity
that is not valid.
Activity
Create LiveData
in ViewModel
LiveData
ViewModel
private MutableLiveData<Integer> progressDialogState;
public LiveData<Integer> getProgressDialogStateAsObservable(){
return progressDialogState;
}
public void setProgressDialogState(int value){
progressDialogState.setValue(value);
}
public void exportSelfTestSummary(WebView webViewResult) {
//Activity context = (Activity) getApplication().getApplicationContext();
//final ProgressDialog progressDialog=new ProgressDialog(context);
//progressDialog.show();
setProgressDialogState(1)
PdfView.createWebPrintJob(context, webViewResult, directory, fileName, new PdfView.Callback() {
....
// after work done set value to 0
//setProgressDialogState(0)
}
Observe it in Activity
or Fragment
Activity
Fragment
viewModel.getProgressDialogStateAsObservable().observe(getActivity(), state -> {
if (state == 1) {
// .....
// show
}else if(state == 0){
// hide
}
});
Learn about Android Architecture Components from here
By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.
How can I change this line: Activity context = (Activity) getApplication().getApplicationContext(); to fragment.getActivity? As in I do not want to pass the fragment as parameter into that function
– hyperfkcb
Jul 2 at 2:45