ViewModelProviders java.lang.RuntimeException试图实例化继承AndroidViewModel的类

问题描述 投票:3回答:2

我正在使用架构组件创建应用程序。

调试版本运行正常,但在测试版本APK时,应用程序崩溃了下面的堆栈跟踪。

奇怪的是,我有6个视图模型的片段以相同的方式设置。其中2个崩溃,其中4个按预期工作。

该项目没有进行任何进展。

我正在使用具有以下依赖项的体系结构组件:

compile "android.arch.lifecycle:runtime:${arch}"
compile "android.arch.lifecycle:extensions:${arch}"
annotationProcessor "android.arch.lifecycle:compiler:${arch}"

架构组件的版本是'1.0.0-beta2'(arch ='1.0.0-beta2')。如果我尝试架构组件的版本是'1.0.0-rc1'(arch ='1.0.0-rc1'),我会遇到同样的问题。

我从片段中实例化我的viewmodel,如下所示:

@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    otherWorkViewModel = ViewModelProviders.of(this).get(OtherWorkViewModel.class);

    if (savedInstanceState == null) {

        // Check for arguments to fragment (section object and position in list)
        if (getArguments() != null) {
            OtherWork otherWork = (OtherWork) getArguments().get("otherWork");
            otherWorkViewModel.setOtherWork(otherWork);

            int position = getArguments().getInt("position");
            otherWorkViewModel.setPosition(position);
        } 
    }
}

在运行库代码以实例化viewmodel时,应用程序崩溃时出现以下异常:

10-20 08:41:03.555 2102-2102/no.example.thisapp E/AndroidRuntime: FATAL EXCEPTION: main
     Process: no.example.thisapp, PID: 2102
     java.lang.RuntimeException: Cannot create an instance of class no.example.thisapp.ui.job.pavingreport.OtherWorkViewModel
         at android.arch.lifecycle.ViewModelProviders$DefaultFactory.create(ViewModelProviders.java:149)
         at android.arch.lifecycle.ViewModelProvider.get(ViewModelProvider.java:128)
         at android.arch.lifecycle.ViewModelProvider.get(ViewModelProvider.java:96)
         at no.example.thisapp.ui.job.pavingreport.PavingReportDialogOtherWork.onCreate(PavingReportDialogOtherWork.java:57)
         at android.support.v4.app.Fragment.performCreate(Fragment.java:2339)
         at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1377)
         at android.support.v4.app.FragmentTransition.addToFirstInLastOut(FragmentTransition.java:1109)
         at android.support.v4.app.FragmentTransition.calculateFragments(FragmentTransition.java:996)
         at android.support.v4.app.FragmentTransition.startTransitions(FragmentTransition.java:99)
         at android.support.v4.app.FragmentManagerImpl.executeOpsTogether(FragmentManager.java:2364)
         at android.support.v4.app.FragmentManagerImpl.removeRedundantOperationsAndExecute(FragmentManager.java:2322)
         at android.support.v4.app.FragmentManagerImpl.execPendingActions(FragmentManager.java:2229)
         at android.support.v4.app.FragmentManagerImpl$1.run(FragmentManager.java:700)
         at android.os.Handler.handleCallback(Handler.java:751)
         at android.os.Handler.dispatchMessage(Handler.java:95)
         at android.os.Looper.loop(Looper.java:154)
         at android.app.ActivityThread.main(ActivityThread.java:6077)
         at java.lang.reflect.Method.invoke(Native Method)
         at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:866)
         at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:756)
      Caused by: java.lang.NoSuchMethodException: <init> [class android.app.Application]
         at java.lang.Class.getConstructor0(Class.java:2204)
         at java.lang.Class.getConstructor(Class.java:1683)
         at android.arch.lifecycle.ViewModelProviders$DefaultFactory.create(ViewModelProviders.java:147)
         at android.arch.lifecycle.ViewModelProvider.get(ViewModelProvider.java:128) 
         at android.arch.lifecycle.ViewModelProvider.get(ViewModelProvider.java:96) 
         at no.example.thisapp.ui.job.pavingreport.PavingReportDialogOtherWork.onCreate(PavingReportDialogOtherWork.java:57) 
         at android.support.v4.app.Fragment.performCreate(Fragment.java:2339) 
         at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1377) 
         at android.support.v4.app.FragmentTransition.addToFirstInLastOut(FragmentTransition.java:1109) 
         at android.support.v4.app.FragmentTransition.calculateFragments(FragmentTransition.java:996) 
         at android.support.v4.app.FragmentTransition.startTransitions(FragmentTransition.java:99) 
         at android.support.v4.app.FragmentManagerImpl.executeOpsTogether(FragmentManager.java:2364) 
         at android.support.v4.app.FragmentManagerImpl.removeRedundantOperationsAndExecute(FragmentManager.java:2322) 
         at android.support.v4.app.FragmentManagerImpl.execPendingActions(FragmentManager.java:2229) 
         at android.support.v4.app.FragmentManagerImpl$1.run(FragmentManager.java:700) 
         at android.os.Handler.handleCallback(Handler.java:751) 
         at android.os.Handler.dispatchMessage(Handler.java:95) 
         at android.os.Looper.loop(Looper.java:154) 
         at android.app.ActivityThread.main(ActivityThread.java:6077) 
         at java.lang.reflect.Method.invoke(Native Method) 
         at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:866) 
         at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:756) 

更多代码:

视图模型:

package no.example.thisapp.ui.job.pavingreport;

import android.app.Application;
import android.databinding.Bindable;
import android.util.Log;

import com.android.databinding.library.baseAdapters.BR;

import java.text.NumberFormat;
import java.text.ParseException;

import no.inforte.android.databinding.BaseObservableViewModel;
import no.inforte.android.validation.Misc;
import no.example.thisapp.R;
import no.example.thisapp.model.pavingreport.OtherWork;


public final class OtherWorkViewModel extends BaseObservableViewModel {

    @SuppressWarnings("unused")
    private static final String TAG = "OtherWorkViewModel";

    private OtherWork otherWork;
    private int position;

    private NumberFormat numberFormat;

    // Shadow fields for otherArea model object

    private String areaGluedString;
    private String handPavedTonString;
    private String nightWorkTonString;




    OtherWorkViewModel(Application application) {
        super(application);

        numberFormat = Misc.getNumberFormat(application);
    }




    // Used when:
    // - accessing values from layout
    // - Returning values to PavingReportListFragment
    public OtherWork getOtherWork() {
        return otherWork;
    }




    // Used when:
    // - Returning values to PavingReportListFragment
    public int getPosition() {
        return position;
    }




    public void setOtherWork(OtherWork otherWork) {
        this.otherWork = otherWork;
        this.areaGluedString = (otherWork.getAreaGlued() != null && !otherWork.getAreaGlued().isNaN()) ? numberFormat.format(otherWork.getAreaGlued()) : "";
        this.handPavedTonString = (otherWork.getHandPavedTon() != null && !otherWork.getHandPavedTon().isNaN()) ? numberFormat.format(otherWork.getHandPavedTon()) : "";
        this.nightWorkTonString = (otherWork.getHandPavedTon() != null && !otherWork.getHandPavedTon().isNaN()) ? numberFormat.format(otherWork.getHandPavedTon()) : "";
    }




    public void setPosition(int position) {
        this.position = position;
    }




    public boolean isValidInput() {
        boolean tmpIsValid = true;

        if (!validDrains()) tmpIsValid = false;
        if (!validManHoles()) tmpIsValid = false;
        if (!validOther()) tmpIsValid = false;
        if (!validHandPavedTon()) tmpIsValid = false;
        if (!validNightWorkTon()) tmpIsValid = false;
        if (!validAreaGlued()) tmpIsValid = false;

        return tmpIsValid;
    }


    // Shadow for otherWork.areaGlued (Double)




    @Bindable
    public String getAreaGluedString() {
        return areaGluedString;
    }




    @Bindable
    public String getAreaGluedStringError() {
        return Misc.validateDecimalNumberString(areaGluedString, this.getApplication());
    }




    public void setAreaGluedString(String areaGluedString) {
        this.areaGluedString = areaGluedString;

        if (Misc.isValidDecimalNumber(this.areaGluedString, this.getApplication())) {
            try {
                Number number = numberFormat.parse(this.areaGluedString);
                otherWork.setAreaGlued(number.doubleValue());
            } catch (ParseException e) {
                e.printStackTrace();
            }
        }

        notifyPropertyChanged(BR.areaGluedString);
        notifyPropertyChanged(BR.areaGluedStringError);
    }




    private boolean validAreaGlued() {
        return (otherWork.getAreaGlued() != null && !otherWork.getAreaGlued().isNaN());
    }


    // Shadow for otherWork.handPavedTon (Double)




    @Bindable
    public String getHandPavedTonString() {
        return handPavedTonString;
    }




    @Bindable
    public String getHandPavedTonStringError() {
        return Misc.validateDecimalNumberString(handPavedTonString, this.getApplication());
    }




    public void setHandPavedTonString(String handPavedTonString) {
        this.handPavedTonString = handPavedTonString;

        if (Misc.isValidDecimalNumber(this.handPavedTonString, this.getApplication())) {
            try {
                Number number = numberFormat.parse(this.handPavedTonString);
                otherWork.setHandPavedTon(number.doubleValue());
            } catch (ParseException e) {
                e.printStackTrace();
            }
        }

        notifyPropertyChanged(BR.handPavedTonString);
        notifyPropertyChanged(BR.handPavedTonStringError);
    }




    private boolean validHandPavedTon() {
        return (otherWork.getHandPavedTon() != null && !otherWork.getHandPavedTon().isNaN());
    }


    // Shadow for otherWork.nightWorkTon (Double)




    @Bindable
    public String getNightWorkTonString() {
        return nightWorkTonString;
    }




    @Bindable
    public String getNightWorkTonStringError() {
        return Misc.validateDecimalNumberString(nightWorkTonString, getApplication());
    }




    public void setNightWorkTonString(String nightWorkTonString) {
        this.nightWorkTonString = nightWorkTonString;

        if (Misc.isValidDecimalNumber(this.nightWorkTonString, this.getApplication())) {
            try {
                Number number = numberFormat.parse(this.nightWorkTonString);
                otherWork.setNightWorkTon(number.doubleValue());
            } catch (ParseException e) {
                e.printStackTrace();
            }
        }

        notifyPropertyChanged(BR.nightWorkTonString);
        notifyPropertyChanged(BR.nightWorkTonStringError);
    }




    private boolean validNightWorkTon() {
        return (otherWork.getNightWorkTon() != null && !otherWork.getNightWorkTon().isNaN());
    }




    @Bindable
    public String getDrainsString() {
        if (otherWork.getDrains() != null && otherWork.getDrains() == (int) otherWork.getDrains()) {
            return otherWork.getDrains().toString();
        } else return "";
    }




    private boolean validDrains() {
        return (otherWork.getDrains() != null && otherWork.getDrains() == (int) otherWork.getDrains());
    }




    @Bindable
    public String getDrainsStringError() {
        if (validDrains())
            return null;
        return getApplication().getString(R.string.error_value_required);
    }




    public void setDrainsString(String drainsString) {
        try {
            int drains = Integer.parseInt(drainsString);
            otherWork.setDrains(drains);
            notifyPropertyChanged(BR.drainsStringError);
        } catch (NumberFormatException ex) {
            Log.d(TAG, "Could not parse integer value...");
        }
    }




    @Bindable
    public String getManHolesString() {
        if (otherWork.getManHoles() != null && otherWork.getManHoles() == (int) otherWork.getManHoles()) {
            return otherWork.getManHoles().toString();
        } else return "";
    }




    private boolean validManHoles() {
        return (otherWork.getManHoles() != null && otherWork.getManHoles() == (int) otherWork.getManHoles());
    }




    @Bindable
    public String getManHolesStringError() {
        if (validManHoles()) return null;
        return getApplication().getString(R.string.error_value_required);
    }




    public void setManHolesString(String manHolesString) {
        try {
            int manHoles = Integer.parseInt(manHolesString);
            otherWork.setManHoles(manHoles);
            notifyPropertyChanged(BR.manHolesStringError);
        } catch (NumberFormatException ex) {
            Log.d(TAG, "Could not parse integer value...");
        }
    }




    private boolean validOther() {
        return (otherWork.getOther() != null && !otherWork.getOther().isEmpty());
    }




    @Bindable
    public String getOtherError() {
        return (validOther()) ? null : getApplication().getString(R.string.error_value_required);
    }
}

和BaseObservableViewModel:

package no.inforte.android.databinding;


import android.app.Application;
import android.arch.lifecycle.AndroidViewModel;
import android.databinding.Bindable;
import android.databinding.Observable;
import android.databinding.PropertyChangeRegistry;

public class BaseObservableViewModel extends AndroidViewModel implements Observable {
    private transient PropertyChangeRegistry mCallbacks;

    public BaseObservableViewModel(Application application) {
        super(application);
    }



    // Code below is copied from com.android.databinding.BaseObservable so we can use this ViewModel as our backing Databinding model
    // Solution came from twitter tip from Yigit Boyar and this article:
    // https://willowtreeapps.com/ideas/google-i-o-2017-the-viewmodel-is-nice-from-up-here

    @Override
    public void addOnPropertyChangedCallback(Observable.OnPropertyChangedCallback callback) {
        synchronized (this) {
            if (mCallbacks == null) {
                mCallbacks = new PropertyChangeRegistry();
            }
        }
        mCallbacks.add(callback);
    }

    @Override
    public void removeOnPropertyChangedCallback(Observable.OnPropertyChangedCallback callback) {
        synchronized (this) {
            if (mCallbacks == null) {
                return;
            }
        }
        mCallbacks.remove(callback);
    }

    /**
     * Notifies listeners that all properties of this instance have changed.
     */
    public void notifyChange() {
        synchronized (this) {
            if (mCallbacks == null) {
                return;
            }
        }
        mCallbacks.notifyCallbacks(this, 0, null);
    }

    /**
     * Notifies listeners that a specific property has changed. The getter for the property
     * that changes should be marked with {@link Bindable} to generate a field in
     * <code>BR</code> to be used as <code>fieldId</code>.
     *
     * @param fieldId The generated BR id for the Bindable field.
     */
    public void notifyPropertyChanged(int fieldId) {
        synchronized (this) {
            if (mCallbacks == null) {
                return;
            }
        }
        mCallbacks.notifyCallbacks(this, fieldId, null);
    }

}
android android-architecture-components
2个回答
11
投票

让你的OtherWorkViewModel构造函数public,看看是否有帮助。


1
投票

就我而言,问题是包类而不是公共类。

错误:

class MyViewModel extends ViewModel {

公开修正:

public class MyViewModel extends ViewModel {
© www.soinside.com 2019 - 2024. All rights reserved.