2017-10-20 6 views
0

私はアーキテクチャコンポーネントを使用してアプリケーションを作成しています。ViewModelProviders java.lang.RuntimeException AndroidViewModelを継承するクラスをインスタンス化しようとしています

デバッグビルドはうまく動作しますが、リリース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-β2'(アーチ= '1.0.0-β2')です。アーキテクチャコンポーネントのバージョンを '1.0.0-rc1'(arch = '1.0.0-rc1')にしようとすると、同じ問題が発生します。

私はこのようなフラグメントからの私の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)  

いくつかのより多くのコード:

@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をインスタンス化するために、ライブラリのコードを実行すると、以下の例外を除いて、アプリがクラッシュします:

viewmodel:

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

} 
+0

「OtherWorkViewModel」コードを投稿してください。 – MatPag

+0

@MatPag完了! :-) –

+0

'OtherWorkViewModel'コンストラクタ内の' Application'パラメータを削除しようとしています(デフォルトの空のコンストラクタで終わり、numberFormatをコメントアウトします)。私はFactoryが 'Application'値を取る場所を知らないので、この方法でViewModelを初期化することができないと思います。試してみてください、それが問題なら私はより詳細な解決策を投稿します。 – MatPag

答えて

2

あなたOtherWorkViewModelコンストラクタpublicを作成し、それが助けかどうかを確認します。

+0

ハレイ!それが助けになった! :-) ありがとう! –

関連する問題