【问题标题】:Android ClassCastException by referencing fragment in viewmodelAndroid ClassCastException 通过在视图模型中引用片段
【发布时间】:2018-07-02 02:36:00
【问题描述】:

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

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

在我尝试访问上下文以及 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() {
        ....
}

我收到的错误消息:

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

【问题讨论】:

    标签: java android fragment viewmodel


    【解决方案1】:

    错误说得很清楚,您不能将Application 转换为Activity

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

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

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

    【讨论】:

    • 如何更改这一行:Activity context = (Activity) getApplication().getApplicationContext();到fragment.getActivity?正如我不想将片段作为参数传递给该函数
    • 你现在如何构建你的ViewModel?贴出部分代码。此外,getApplication 的方法是从哪里来的?据我所知,getApplication 方法仅适用于Activity
    • 已编辑问题!
    【解决方案2】:

    您收到 ClassCastException 是因为您试图将应用程序转换为 Activity。

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

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

    您不应该在 ViewModel 中使用对 Activity 或 Fragment 的引用。您的 UI 不应该从您的 ViewModel 中修改。 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() {
                 ....
                }
      })
    

    在您的视图模型中:

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

    阅读更多关于LiveDataViewModel

    【讨论】:

      【解决方案3】:

      或者,您可以通过父视图挖掘 Activity:

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

      【讨论】:

        【解决方案4】:

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

        正如@tam-huynh 提到的,您的问题是您试图将应用程序上下文转换为无效的Activity

        ViewModel 中创建LiveData

        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

        【讨论】:

          猜你喜欢
          • 2014-07-28
          • 2020-05-18
          • 2021-02-11
          • 2013-11-04
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2021-08-14
          相关资源
          最近更新 更多