Je crée une application en utilisant des composants d'architecture.ViewModelProviders java.lang.RuntimeException essayant d'instancier une classe qui hérite AndroidViewModel
La version de débogage fonctionne correctement, mais lors du test de la version APK, l'application se bloque avec la trace de la pile vue ci-dessous. Ce qui est étrange, c'est que j'ai 6 fragments avec viewmodels qui sont configurés de la même manière. 2 d'entre eux s'écrasent, 4 d'entre eux fonctionnent comme prévu.
Le projet ne fait aucune minoration proguard.
J'utilise des composants d'architecture avec les dépendances suivantes:
compile "android.arch.lifecycle:runtime:${arch}"
compile "android.arch.lifecycle:extensions:${arch}"
annotationProcessor "android.arch.lifecycle:compiler:${arch}"
version des composants d'architecture est 'beta2-1.0.0' (arch = 'beta2-1.0.0). Si j'essaie la version des composants de l'architecture est '1.0.0-rc1' (arch = '1.0.0-rc1') je reçois le même problème.
J'instancier mon viewmodel du fragment comme celui-ci:
@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);
}
}
}
Lors de l'exécution du code de la bibliothèque pour instancier le viewmodel les application se bloque à l'exception suivante:
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)
code plus: Le mode de vue:
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);
}
}
Et le 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);
}
}
Vous devriez publier le code 'OtherWorkViewModel' pour aider – MatPag
@MatPag Done! :-) –
Essayant de supprimer le paramètre 'Application' dans le constructeur' OtherWorkViewModel' (pour finir avec un constructeur vide par défaut et commenter numberFormat). Je suppose que l'Usine n'est pas capable d'initier un ViewModel de cette manière car elle ne sait pas où prendre la valeur 'Application'. Essayez et laissez-moi savoir si cela fonctionne, si c'est le problème, je vais poster une solution plus détaillée. – MatPag