通过引用视图模型中的片段,Android ClassCastException

时间:2018-07-02 02:36:00

标签: java android fragment viewmodel

在尝试引用我的viewmodel类中的片段时遇到了一些问题。这是我的片段称为视图模型的部分:

@Click(R.id.buttonExport)
void buttonExportClicked(View v){
    SummaryViewModel summaryViewModel = ViewModelProviders.of(this).get(SummaryViewModel.class);
    summaryViewModel.export(webViewResult);
}

在我试图访问上下文和活动的视图模型中:

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() {
        ....
}

以及我收到的错误消息:

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)

有什么想法吗?谢谢!

修改

@Inject
public SummaryViewModel(@NonNull Application application) {
    super(application);
}

4 个答案:

答案 0 :(得分:0)

该错误表明已足够清楚,您无法将Application强制转换为Activity

您正在做的是获取应用程序上下文,它将返回一个Application类:

Activity context = (Activity) getApplication().getApplicationContext();

如果您位于片段中,只需使用fragment.getActivity()

答案 1 :(得分:0)

由于尝试将应用程序强制转换为Activity,所以您收到ClassCastException。

Activity context = (Activity) getApplication().getApplicationContext();

getApplication()方法返回App类,getApplicationContext()方法也返回,该方法不能用于获取Activity。

永远不要在ViewModel中使用对Activity或Fragment的引用。绝对不要从ViewModel修改UI。 ViewModel应该只包含用于修改UI的数据。

例如:

片段/活动:

 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() {
             ....
            }
  })

在您的ViewModel中:

public LiveData<WebResult> getWebViewDataInBackgroundThread() {
    // getdata and return as LiveData
}

详细了解LiveDataViewModel

答案 2 :(得分:0)

使用Context和与活动生命周期相关的人员专门查看ViewModel内是一个好习惯。 ViewModel将仅保存数据并在数据和视图之间建立连接。在ProgressDialogActivity中创建Fragment。使用ViewModel作为您的业务逻辑。在LiveData中为ProgressDialog状态创建一个ViewModle。更改LiveData的值并在ActivityFragment中观察它。因此,您可以决定何时显示ProgressDialog或何时隐藏它。您的视图位于ActivityFragment内部,并且没有MemoryLeak的可能性。

正如@ tam-huynh提到的那样,您的问题是您试图将Application Context强制转换为无效的Activity

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) 
}

ActivityFragment中观察

   viewModel.getProgressDialogStateAsObservable().observe(getActivity(), state -> {
        if (state == 1) {
          // .....
           // show  
        }else if(state == 0){
           // hide
        }
    });

从这里了解Android Architecture Components

答案 3 :(得分:0)

或者,您也可以通过父视图来访问“活动”:

Activity act = (Activity) webViewResult.getParent().getParent().....so on