2016-08-16 222 views
3

雙向數據綁定我有這樣的對象中的EditText

ObservableInt someNumber; 

public ObservableInt getSomeNumber() 
{ 
    return someNumber; 
} 

public void setSomeNumber(ObservableInt number) 
{ 
    this.someNumber = number; 
} 

和我AppCompatEditText是像這樣的XML代碼:

<android.support.v7.widget.AppCompatEditText 
     android:layout_width="0dp" 
     android:layout_height="@dimen/agro_item_height" 
     android:layout_weight="1" 
     android:inputType="numberDecimal" 
     android:text="@={String.valueOf(myObject.someNumber)}" 
     android:gravity="center_horizontal"/> 

我有此錯誤:

Error:Execution failed for task ':app:compileDebugJavaWithJavac'. 
java.lang.RuntimeException: failure, see logs for details. 
cannot generate view binders java.lang.NullPointerException 
at android.databinding.tool.expr.MethodCallExpr.generateCode(MethodCallExpr.java:69) 
at android.databinding.tool.expr.Expr.toFullCode(Expr.java:745) 
at android.databinding.tool.expr.Expr.assertIsInvertible(Expr.java:767) 
at android.databinding.tool.BindingTarget.addInverseBinding(BindingTarget.java:68) 
at android.databinding.tool.LayoutBinder.<init>(LayoutBinder.java:228) 
at android.databinding.tool.DataBinder.<init>(DataBinder.java:52) 
at android.databinding.tool.CompilerChef.ensureDataBinder(CompilerChef.java:83) 
at android.databinding.tool.CompilerChef.sealModels(CompilerChef.java:168) 
at android.databinding.annotationprocessor.ProcessExpressions.writeResourceBundle(ProcessExpressions.java:149) 
at android.databinding.annotationprocessor.ProcessExpressions.onHandleStep(ProcessExpressions.java:82) 
at android.databinding.annotationprocessor.ProcessDataBinding$ProcessingStep.runStep(ProcessDataBinding.java:154) 
at android.databinding.annotationprocessor.ProcessDataBinding$ProcessingStep.access$000(ProcessDataBinding.java:139) 
at android.databinding.annotationprocessor.ProcessDataBinding.process(ProcessDataBinding.java:66) 
at com.sun.tools.javac.processing.JavacProcessingEnvironment.callProcessor(JavacProcessingEnvironment.java:794) 
at com.sun.tools.javac.processing.JavacProcessingEnvironment.discoverAndRunProcs(JavacProcessingEnvironment.java:705) 
at com.sun.tools.javac.processing.JavacProcessingEnvironment.access$1800(JavacProcessingEnvironment.java:91) 
at com.sun.tools.javac.processing.JavacProcessingEnvironment$Round.run(JavacProcessingEnvironment.java:1035) 
at com.sun.tools.javac.processing.JavacProcessingEnvironment.doProcessing(JavacProcessingEnvironment.java:1176) 
at com.sun.tools.javac.main.JavaCompiler.processAnnotations(JavaCompiler.java:1170) 
at com.sun.tools.javac.main.JavaCompiler.compile(JavaCompiler.java:856) 
at com.sun.tools.javac.main.Main.compile(Main.java:523) 
at com.sun.tools.javac.api.JavacTaskImpl.doCall(JavacTaskImpl.java:129) 
at com.sun.tools.javac.api.JavacTaskImpl.call(JavacTaskImpl.java:138) 
at org.gradle.api.internal.tasks.compile.JdkJavaCompiler.execute(JdkJavaCompiler.java:46) 
at org.gradle.api.internal.tasks.compile.JdkJavaCompiler.execute(JdkJavaCompiler.java:33) 
at org.gradle.api.internal.tasks.compile.NormalizingJavaCompiler.delegateAndHandleErrors(NormalizingJavaCompiler.java:104) 
at org.gradle.api.internal.tasks.compile.NormalizingJavaCompiler.execute(NormalizingJavaCompiler.java:53) 
at org.gradle.api.internal.tasks.compile.NormalizingJavaCompiler.execute(NormalizingJavaCompiler.java:38) 
at org.gradle.api.internal.tasks.compile.CleaningJavaCompilerSupport.execute(CleaningJavaCompilerSupport.java:35) 
at org.gradle.api.internal.tasks.compile.CleaningJavaCompilerSupport.execute(CleaningJavaCompilerSupport.java:25) 
at org.gradle.api.tasks.compile.JavaCompile.performCompilation(JavaCompile.java:163) 
at org.gradle.api.tasks.compile.JavaCompile.compile(JavaCompile.java:145) 
at org.gradle.api.tasks.compile.JavaCompile.compile(JavaCompile.java:93) 
at com.android.build.gradle.tasks.factory.AndroidJavaCompile.compile(AndroidJavaCompile.java:49) 
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) 
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) 
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) 
at java.lang.reflect.Method.invoke(Method.java:498) 
at org.gradle.internal.reflect.JavaMethod.invoke(JavaMethod.java:75) 
at org.gradle.api.internal.project.taskfactory.AnnotationProcessingTaskFactory$IncrementalTaskAction.doExecute(AnnotationProcessingTaskFactory.java:245) 
at org.gradle.api.internal.project.taskfactory.AnnotationProcessingTaskFactory$StandardTaskAction.execute(AnnotationProcessingTaskFactory.java:221) 
at org.gradle.api.internal.project.taskfactory.AnnotationProcessingTaskFactory$IncrementalTaskAction.execute(AnnotationProcessingTaskFactory.java:232) 
at org.gradle.api.internal.project.taskfactory.AnnotationProcessingTaskFactory$StandardTaskAction.execute(AnnotationProcessingTaskFactory.java:210) 
at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.executeAction(ExecuteActionsTaskExecuter.java:80) 
at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.executeActions(ExecuteActionsTaskExecuter.java:61) 
at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.execute(ExecuteActionsTaskExecuter.java:46) 
at org.gradle.api.internal.tasks.execution.PostExecutionAnalysisTaskExecuter.execute(PostExecutionAnalysisTaskExecuter.java:35) 
at org.gradle.api.internal.tasks.execution.SkipUpToDateTaskExecuter.execute(SkipUpToDateTaskExecuter.java:66) 
at org.gradle.api.internal.tasks.execution.ValidatingTaskExecuter.execute(ValidatingTaskExecuter.java:58) 
at org.gradle.api.internal.tasks.execution.SkipEmptySourceFilesTaskExecuter.execute(SkipEmptySourceFilesTaskExecuter.java:52) 
at org.gradle.api.internal.tasks.execution.SkipTaskWithNoActionsExecuter.execute(SkipTaskWithNoActionsExecuter.java:52) 
at org.gradle.api.internal.tasks.execution.SkipOnlyIfTaskExecuter.execute(SkipOnlyIfTaskExecuter.java:53) 
at org.gradle.api.internal.tasks.execution.ExecuteAtMostOnceTaskExecuter.execute(ExecuteAtMostOnceTaskExecuter.java:43) 
at org.gradle.execution.taskgraph.DefaultTaskGraphExecuter$EventFiringTaskWorker.execute(DefaultTaskGraphExecuter.java:203) 
at org.gradle.execution.taskgraph.DefaultTaskGraphExecuter$EventFiringTaskWorker.execute(DefaultTaskGraphExecuter.java:185) 
at org.gradle.execution.taskgraph.AbstractTaskPlanExecutor$TaskExecutorWorker.processTask(AbstractTaskPlanExecutor.java:66) 
at org.gradle.execution.taskgraph.AbstractTaskPlanExecutor$TaskExecutorWorker.run(AbstractTaskPlanExecutor.java:50) 
at org.gradle.execution.taskgraph.DefaultTaskPlanExecutor.process(DefaultTaskPlanExecutor.java:25) 
at org.gradle.execution.taskgraph.DefaultTaskGraphExecuter.execute(DefaultTaskGraphExecuter.java:110) 
at org.gradle.execution.SelectedTaskExecutionAction.execute(SelectedTaskExecutionAction.java:37) 
at org.gradle.execution.DefaultBuildExecuter.execute(DefaultBuildExecuter.java:37) 
at org.gradle.execution.DefaultBuildExecuter.access$000(DefaultBuildExecuter.java:23) 
at org.gradle.execution.DefaultBuildExecuter$1.proceed(DefaultBuildExecuter.java:43) 
at org.gradle.execution.DryRunBuildExecutionAction.execute(DryRunBuildExecutionAction.java:32) 
at org.gradle.execution.DefaultBuildExecuter.execute(DefaultBuildExecuter.java:37) 
at org.gradle.execution.DefaultBuildExecuter.execute(DefaultBuildExecuter.java:30) 
at org.gradle.initialization.DefaultGradleLauncher$4.run(DefaultGradleLauncher.java:153) 
at org.gradle.internal.Factories$1.create(Factories.java:22) 
at org.gradle.internal.progress.DefaultBuildOperationExecutor.run(DefaultBuildOperationExecutor.java:91) 
at org.gradle.internal.progress.DefaultBuildOperationExecutor.run(DefaultBuildOperationExecutor.java:53) 
at org.gradle.initialization.DefaultGradleLauncher.doBuildStages(DefaultGradleLauncher.java:150) 
at org.gradle.initialization.DefaultGradleLauncher.access$200(DefaultGradleLauncher.java:32) 
at org.gradle.initialization.DefaultGradleLauncher$1.create(DefaultGradleLauncher.java:98) 
at org.gradle.initialization.DefaultGradleLauncher$1.create(DefaultGradleLauncher.java:92) 
at org.gradle.internal.progress.DefaultBuildOperationExecutor.run(DefaultBuildOperationExecutor.java:91) 
at org.gradle.internal.progress.DefaultBuildOperationExecutor.run(DefaultBuildOperationExecutor.java:63) 
at org.gradle.initialization.DefaultGradleLauncher.doBuild(DefaultGradleLauncher.java:92) 
at org.gradle.initialization.DefaultGradleLauncher.run(DefaultGradleLauncher.java:83) 
at org.gradle.launcher.exec.InProcessBuildActionExecuter$DefaultBuildController.run(InProcessBuildActionExecuter.java:99) 
at org.gradle.tooling.internal.provider.runner.BuildModelActionRunner.run(BuildModelActionRunner.java:46) 
at org.gradle.launcher.exec.ChainingBuildActionRunner.run(ChainingBuildActionRunner.java:35) 
at org.gradle.tooling.internal.provider.runner.SubscribableBuildActionRunner.run(SubscribableBuildActionRunner.java:58) 
at org.gradle.launcher.exec.ChainingBuildActionRunner.run(ChainingBuildActionRunner.java:35) 
at org.gradle.launcher.exec.InProcessBuildActionExecuter.execute(InProcessBuildActionExecuter.java:48) 
at org.gradle.launcher.exec.InProcessBuildActionExecuter.execute(InProcessBuildActionExecuter.java:30) 
at org.gradle.launcher.exec.ContinuousBuildActionExecuter.execute(ContinuousBuildActionExecuter.java:81) 
at org.gradle.launcher.exec.ContinuousBuildActionExecuter.execute(ContinuousBuildActionExecuter.java:46) 
at org.gradle.launcher.daemon.server.exec.ExecuteBuild.doBuild(ExecuteBuild.java:52) 
at org.gradle.launcher.daemon.server.exec.BuildCommandOnly.execute(BuildCommandOnly.java:36) 
at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:120) 
at org.gradle.launcher.daemon.server.exec.WatchForDisconnection.execute(WatchForDisconnection.java:37) 
at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:120) 
at org.gradle.launcher.daemon.server.exec.ResetDeprecationLogger.execute(ResetDeprecationLogger.java:26) 
at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:120) 
at org.gradle.launcher.daemon.server.exec.RequestStopIfSingleUsedDaemon.execute(RequestStopIfSingleUsedDaemon.java:34) 
at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:120) 
at org.gradle.launcher.daemon.server.exec.ForwardClientInput$2.call(ForwardClientInput.java:74) 
at org.gradle.launcher.daemon.server.exec.ForwardClientInput$2.call(ForwardClientInput.java:72) 
at org.gradle.util.Swapper.swap(Swapper.java:38) 
at org.gradle.launcher.daemon.server.exec.ForwardClientInput.execute(ForwardClientInput.java:72) 
at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:120) 
at org.gradle.launcher.daemon.server.health.DaemonHealthTracker.execute(DaemonHealthTracker.java:47) 
at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:120) 
at org.gradle.launcher.daemon.server.exec.LogToClient.doBuild(LogToClient.java:60) 
at org.gradle.launcher.daemon.server.exec.BuildCommandOnly.execute(BuildCommandOnly.java:36) 
at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:120) 
at org.gradle.launcher.daemon.server.exec.EstablishBuildEnvironment.doBuild(EstablishBuildEnvironment.java:72) 
at org.gradle.launcher.daemon.server.exec.BuildCommandOnly.execute(BuildCommandOnly.java:36) 
at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:120) 
at org.gradle.launcher.daemon.server.health.HintGCAfterBuild.execute(HintGCAfterBuild.java:41) 
at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:120) 
at org.gradle.launcher.daemon.server.exec.StartBuildOrRespondWithBusy$1.run(StartBuildOrRespondWithBusy.java:50) 
at org.gradle.launcher.daemon.server.DaemonStateCoordinator$1.run(DaemonStateCoordinator.java:237) 
at org.gradle.internal.concurrent.ExecutorPolicy$CatchAndRecordFailures.onExecute(ExecutorPolicy.java:54) 
at org.gradle.internal.concurrent.StoppableExecutorImpl$1.run(StoppableExecutorImpl.java:40) 
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142) 
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) 
at java.lang.Thread.run(Thread.java:745) 

我已經試過

android:text="@={myObject.someNumber}" 

,但我有此錯誤:

Error:Execution failed for task ':app:compileDebugJavaWithJavac'. 
java.lang.RuntimeException: Found data binding errors. 
****/ data binding error ****msg:Cannot find the getter for attribute  'android:text' with value type int on android.support.v7.widget.AppCompatEditText. 
file:C:\Users\Moviit\AndroidStudioProjects\pbbchile-android\app\src\main\res\layout\row_agro_tab.xml 
loc:51:8 - 60:48 
****\ data binding error **** 

任何人對如何做到這一點的例子嗎?

+1

你的第一個表達式將無法正常工作,因爲沒有反向表達。你的第二個表達式不起作用,因爲Android將它視爲字符串資源。我的猜測是,您需要切換視圖模型,以使用'ObservableField '而不是'ObservableInt'。 – CommonsWare

回答

1

感謝來自@LongRanger綁定適配器我能提前了很多在我的解決方案,但我不得不做出對適配器和在我的代碼一些變化。首先我必須初始化這樣的ObservableInt成員:

ObservableInt someNumber; 

public ObservableInt getSomeNumber() 
{ 
    return someNumber; 
} 

public void setSomeNumber(ObservableInt number) 
{ 
    this.someNumber = number; 
} 

其次,我不得不改變由@LongRanger給出的適配器是這樣的:

@BindingAdapter("android:text") 
public static void bindIntegerInText(AppCompatEditText tv, int value) 
{ 
    tv.setText(String.valueOf(value));  

    // Set the cursor to the end of the text 
    tv.setSelection(tv.getText().length()); 
} 

@InverseBindingAdapter(attribute = "android:text") 
public static int getIntegerFromBinding(TextView view) 
{ 
    String string = view.getText().toString(); 

    return string.isEmpty() ? 0 : Integer.parseInt(string); 
} 

這樣,我避免了錯誤:當試圖對@InverseBindingAdapter執行Integer.parse(...)時,無效的int「」。在這之後,我必須用@BindingAdapter將光標放在EditText的末尾,否則光標會移動到開頭。

+0

InverseBindingAdapter是否會影響其他需要綁定到String的綁定? – gopalanrc

+0

是的@gopalanrc,每當你在「android:text」標籤中有「@ = {myObject.someNumber}」之類的東西時,綁定和反向綁定適配器都可以工作 –

1

@CommonsWare是對的,你應該使用ObservableField<Str‌​ing>而不是ObservableInt。如果你真的需要數字,只需解析它Integer.valueOf(stringNumber)

public ObservableField<Str‌​ing> someNumber; 

//and in xml code: 

<EditText 
     android:layout_width="0dp" 
     android:layout_height="@dimen/agro_item_height" 
     android:layout_weight="1" 
     android:inputType="numberDecimal" 
     android:text="@={myObject.someNumber}" 
     android:gravity="center_horizontal"/> 

EDITED:或者,如前所述,編寫自定義@InverseBindingAdapter

public class MyEditTextBindingAdapters { 

    @BindingConversion 
    public static String intToStr(Integer value) { 
     return value != null ? String.valueOf(value) : ""; 
    } 

    @InverseBindingAdapter(attribute = "android:text") 
    public static Integer captureIntValue(EditText view) { 
     long value = 0; 
     try { 
      value = Integer.parseInt(view.getText().toString()); 
     } catch (NumberFormatException e) { 
      e.printStackTrace(); 
     } 
     return value; 
    } 
} 
6

沒有爲簡單的原始轉換的未公開招:

<android.support.v7.widget.AppCompatEditText 
    android:layout_width="0dp" 
    android:layout_height="@dimen/agro_item_height" 
    android:layout_weight="1" 
    android:inputType="numberDecimal" 
    android:text="@={`` + myObject.someNumber}" 
    android:gravity="center_horizontal"/> 

我相信這只是加在Android Studio 2.2中。

+0

它引發此錯誤: 錯誤:執行任務':app:compileDebugJavaWithJavac'失敗。 > java.lang.RuntimeException:發現數據綁定錯誤。 **** /數據綁定錯誤**** msg:表達式(「」)+(dosisAgrochemical)不能顛倒:在雙向綁定中不支持字符串連接運算符(+)。 文件:C:\ Users \ Moviit \ AndroidStudioProjects \ pbbchile-android \ app \ src \ main \ res \ layout \ item_agro_dosis.xml loc:23:29 - 23:51 **** \ data binding error ** ** –

+0

對不起,它不能在2.2發佈。我想它將不得不等待2.3。 –

+0

在AS 2.2.3上的工作方式像魅力 – miv

1

我嘗試使用了定製的setter作爲@George提到山(https://medium.com/google-developers/android-data-binding-custom-setters-55a25a7aea47#.vsry4d95w),以及靈感來自這個答案(Android two way binding with Integer type causes databinding does not exist

您仍然可以使用原來的代碼雙向綁定。

Model類

public class Age { 
    private ObservableInt someNumber; 
    private ObservableField<String> someStr; 
    public Age() { 
     someNumber = new ObservableInt(); 
     someStr = new ObservableField<>(); 
    } 
    public ObservableInt getSomeNumber() { 
     return someNumber; 
    } 
    public void setSomeNumber(ObservableInt pSomeNumber) { 
     someNumber.set(pSomeNumber.get()); 
    } 
    public ObservableField<String> getSomeStr() { 
     return someStr; 
    } 
    public void setSomeStr(ObservableField<String> pSomeStr) { 
     someStr.set(pSomeStr.get()); 
    } 
} 

自定義setter和getter在活動屬性

@BindingAdapter("android:text") 
public static void bindIntegerInText(AppCompatEditText tv, int value) { 
    tv.setText(String.valueOf(value)); 
} 
@InverseBindingAdapter(attribute = "android:text") 
public static int getIntegerFromBinding(TextView view) { 
    return Integer.parseInt(view.getText().toString()); 
} 

代碼

protected void onCreate(Bundle savedInstanceState) { 
    super.onCreate(savedInstanceState); 
    ActivityMain2Binding binding = DataBindingUtil.setContentView(this, R.layout.activity_main2); 
    mAge = new Age(); 
    mAge.setSomeNumber(new ObservableInt(3)); 
    mAge.setSomeStr(new ObservableField<>("Test")); 
    binding.setAge(mAge); 
    binding.btn.setOnClickListener(new View.OnClickListener() { 
     @Override 
     public void onClick(View v) { 
      mAge.setSomeNumber(new ObservableInt(4)); 
      mAge.setSomeStr(new ObservableField<>("Hello World")); 
     } 
    }); 
} 

我做4演示與ObservableInt,可觀察到,正常的字符串資源在XML中綁定字符串資源。

<string name="helloworld">Hello World</string> 

activity_main3.xml

<?xml version="1.0" encoding="utf-8"?> 
<layout xmlns:android="http://schemas.android.com/apk/res/android" 

    > 

    <data> 

     <variable 
      name="age" 
      type="example.com.testerapplication.Age"/> 
    </data> 

    <LinearLayout 
     android:layout_width="match_parent" 
     android:layout_height="match_parent" 
     android:orientation="vertical"> 

     <android.support.v7.widget.AppCompatEditText 
      android:layout_width="match_parent" 
      android:layout_height="wrap_content" 
      android:text="@={age.someNumber}"/> 

     <android.support.v7.widget.AppCompatEditText 
      android:layout_width="match_parent" 
      android:layout_height="wrap_content" 
      android:text="@={age.someStr}"/> 

     <android.support.v7.widget.AppCompatEditText 
      android:layout_width="match_parent" 
      android:layout_height="wrap_content" 
      android:text="@string/helloworld"/> 

     <android.support.v7.widget.AppCompatEditText 
      android:layout_width="match_parent" 
      android:layout_height="wrap_content" 
      android:text="@{@string/helloworld}"/> 

     <Button 
      android:id="@+id/btn" 
      android:layout_width="match_parent" 
      android:layout_height="wrap_content" 
      android:text="Test" 
      /> 
    </LinearLayout> 

</layout> 
+0

非常感謝您的解決方案,但它給我一個錯誤。 EditText從0開始,但是當你清除它時,錯誤:Invalid int:「」,因爲BindingAdapter試圖解析一個「」值。你有這個解決方案嗎? –

-1

只要做到這一點:

android:text="@={user.username}" 

全碼:

<EditText 
      android:id="@+id/username" 
      android:layout_width="match_parent" 
      android:layout_height="wrap_content" 
      android:hint="user name" 
      android:text="@={user.username}"/> 

和用戶類

public class User { 
public ObservableField<String> username = new ObservableField<>(); 
public ObservableField<String> password = new ObservableField<>(); 

public User() { 
    this("", ""); 
} 

public User(String username, String password) { 
    this.username.set(username); 
    this.password.set(password); 
} 
+0

我正在做的是使用ObservableInt和兩個在我的EditText上進行綁定。我沒有字符串問題 –