Android数据绑定-无法通知视图更改

Android数据绑定-无法通知视图更改,android,data-binding,timer,Android,Data Binding,Timer,我尝试使用数据绑定是有目的的。我有一个我创建的项目,它启动了一个倒计时计时器。如果时间是一个质数,它应该在xml布局中更新TextView。计时器工作正常,但textview从未更新 这是我的计时器,工作正常: public class MyCountDownTimer { private CountDownTimer countDownTimer; private boolean isExecuting =false; private ICountDownListener listener;

我尝试使用数据绑定是有目的的。我有一个我创建的项目,它启动了一个倒计时计时器。如果时间是一个质数,它应该在xml布局中更新TextView。计时器工作正常,但textview从未更新

这是我的计时器,工作正常:

public class MyCountDownTimer {
private CountDownTimer countDownTimer;
private boolean isExecuting =false;
private ICountDownListener listener;
private final String TAG = getClass().getSimpleName();

public MyCountDownTimer(ICountDownListener listener){
this.listener = listener;
}

public void startTimer(long timeLeftMillis) {
if (!isExecuting) {
    isExecuting = true;
    countDownTimer = new CountDownTimer(timeLeftMillis, 1000) {
        @Override
        public void onTick(long millisUntilFinished) {
           ;
           if(isPrime(millisUntilFinished/1000)){
            listener.doSomethingWithPrimeCountDown(millisUntilFinished / 1000);

           }
        }

        @Override
        public void onFinish() {
            isExecuting = false;
            listener.doSomethingWithPrimeCountDown(0L);
        }
    };
    countDownTimer.start();
} else {
    Log.i(TAG, "Timer already started");
}
}m

}

我实际绑定到数据的主要活动类如下所示:

public class MainActivity extends FragmentActivity {
CountdownBinder mCountdownBinder;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    //setContentView(R.layout.activity_main);

   mCountdownBinder = DataBindingUtil.setContentView(this, R.layout.activity_main);

    //Lets reference our textview just for fun
    mCountdownBinder.tvGreen.setText("initial text");


     ViewModel vModel = ViewModel.instance();
//now tell databinding about your viewModel below
    mCountdownBinder.setViewModel(viewModel);
    vModel.startCounting(200000L); //start a countdown

}
}

这是我创建的ViewModel中非常重要的部分。它是一个单例类,它扩展了BaseObservable并实现了ICountDownListener,因此它可以侦听滴答声:

    package com.databindingexample.mycompany.databindingexample.ViewModels;


import android.databinding.BaseObservable;
import android.databinding.Bindable;
import android.databinding.BindingAdapter;
import android.graphics.Color;
import android.util.Log;
import android.widget.TextView;

import com.databindingexample.mycompany.databindingexample.Interfaces.ICountDownListener;
import com.databindingexample.mycompany.databindingexample.MyCountDownTimer;

//notice we are subclassing BaseObservable
public class ViewModel extends BaseObservable implements ICountDownListener{

    private static ViewModel instance;
    private long countDownTime;
    private MyCountDownTimer mCountDownTimer;

    //lock the constructor as this is a singleton
    private ViewModel(){
        mCountDownTimer=new MyCountDownTimer(this);

    }

    public static ViewModel instance() {
        if (instance == null) {
            instance = new ViewModel();
        }
        return instance;
    }

    @Bindable
    public long getCountDownTime() {
        return countDownTime;
    }

    public void setCountDownTime(long countDownTime) {
        this.countDownTime = countDownTime;

        //this seems to not notify the UI, nothings changing
        notifyPropertyChanged((int) countDownTime);

        //this log prints out
        Log.d("TAG","prime tick:"+countDownTime);
    }

    @BindingAdapter({"app:primeColor"})
    public static void setTextColor(TextView view, String color) {

        if("green".equals(color))
            view.setTextColor(Color.parseColor("#63f421"));

        else  if("pink".equals(color))
            view.setTextColor(Color.parseColor("#ffc0cb"));
    }

    public void startCounting(Long milli){
        mCountDownTimer.restartTimer(milli);
    }

    @Override
    public void doSomethingWithPrimeCountDown(Long count) {
        setCountDownTime(count);
    }
}
注意:app:primeColor属性bindableAdapter工作正常,只是bindable getCountdownTime()不起作用

以下是xml文件:

    <?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    xmlns:app="http://schemas.android.com/apk/res-auto">
    <data class="CountdownBinder">
        <variable name="viewModel" type="com.databindingexample.mycompany.databindingexample.ViewModels.ViewModel"/>
    </data>

    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:paddingBottom="@dimen/activity_vertical_margin"
        android:paddingLeft="@dimen/activity_horizontal_margin"
        android:paddingRight="@dimen/activity_horizontal_margin"
        android:paddingTop="@dimen/activity_vertical_margin"
        app:layout_behavior="@string/appbar_scrolling_view_behavior"
        tools:context="com.databindingexample.mycompany.databindingexample.MainActivity"
        tools:showIn="@layout/activity_main">

        <TextView
            android:id="@+id/tv_green"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            app:primeColor='@{"pink"}'
            android:text="@{Long.toString(viewModel.getCountDownTime)}" />
    </RelativeLayout>

</layout>

更新:
谢谢你的回答,所以我写了一篇文章来帮助别人

更新绑定当然需要某种通知

这就是notifyPropertyChanged的用武之地。 每个@Bindable注释属性都将在BR类中生成一个id(如果确实需要,可以更改此行为)

因此,调用notifyPropertyChanged(BR.fieldName)并不是触发变量本身

看一看位于或更好位置的文档,检查生成的代码以了解“魔力”是如何工作的

可观察对象应该(或者可以,因为您可以完全独立于赋值触发属性更改通知):


notifyPropertyChanged(BR.countDownTime);这不起作用,IDE说找不到BR。BR类应该在生成后通过数据绑定生成。添加BR可行,但似乎不符合逻辑。你能在一个正式的回答中解释为什么BR有效吗?为什么我需要使用生成的变量而不是POJO viewmodel变量?顺便谢谢你。但是如果你有时间的话,我需要一个解释。你知道为什么这个类是静态的吗
私有静态类用户extends BaseObservable
?是的:)我已经在一个打开的类中作为一个内部类攻击了这个被剪断的类,我已经放弃了在发布之前将其公开;)
    package com.databindingexample.mycompany.databindingexample.ViewModels;


import android.databinding.BaseObservable;
import android.databinding.Bindable;
import android.databinding.BindingAdapter;
import android.graphics.Color;
import android.util.Log;
import android.widget.TextView;

import com.databindingexample.mycompany.databindingexample.Interfaces.ICountDownListener;
import com.databindingexample.mycompany.databindingexample.MyCountDownTimer;

//notice we are subclassing BaseObservable
public class ViewModel extends BaseObservable implements ICountDownListener{

    private static ViewModel instance;
    private long countDownTime;
    private MyCountDownTimer mCountDownTimer;

    //lock the constructor as this is a singleton
    private ViewModel(){
        mCountDownTimer=new MyCountDownTimer(this);

    }

    public static ViewModel instance() {
        if (instance == null) {
            instance = new ViewModel();
        }
        return instance;
    }

    @Bindable
    public long getCountDownTime() {
        return countDownTime;
    }

    public void setCountDownTime(long countDownTime) {
        this.countDownTime = countDownTime;

        //this seems to not notify the UI, nothings changing
        notifyPropertyChanged((int) countDownTime);

        //this log prints out
        Log.d("TAG","prime tick:"+countDownTime);
    }

    @BindingAdapter({"app:primeColor"})
    public static void setTextColor(TextView view, String color) {

        if("green".equals(color))
            view.setTextColor(Color.parseColor("#63f421"));

        else  if("pink".equals(color))
            view.setTextColor(Color.parseColor("#ffc0cb"));
    }

    public void startCounting(Long milli){
        mCountDownTimer.restartTimer(milli);
    }

    @Override
    public void doSomethingWithPrimeCountDown(Long count) {
        setCountDownTime(count);
    }
}
    <?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    xmlns:app="http://schemas.android.com/apk/res-auto">
    <data class="CountdownBinder">
        <variable name="viewModel" type="com.databindingexample.mycompany.databindingexample.ViewModels.ViewModel"/>
    </data>

    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:paddingBottom="@dimen/activity_vertical_margin"
        android:paddingLeft="@dimen/activity_horizontal_margin"
        android:paddingRight="@dimen/activity_horizontal_margin"
        android:paddingTop="@dimen/activity_vertical_margin"
        app:layout_behavior="@string/appbar_scrolling_view_behavior"
        tools:context="com.databindingexample.mycompany.databindingexample.MainActivity"
        tools:showIn="@layout/activity_main">

        <TextView
            android:id="@+id/tv_green"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            app:primeColor='@{"pink"}'
            android:text="@{Long.toString(viewModel.getCountDownTime)}" />
    </RelativeLayout>

</layout>
public class User extends BaseObservable {
   private String firstName;
   private String lastName;
   @Bindable
   public String getFirstName() {
       return this.firstName;
   }
   @Bindable
   public String getLastName() {
       return this.lastName;
   }
   public void setFirstName(String firstName) {
       this.firstName = firstName;
       notifyPropertyChanged(BR.firstName);
   }
   public void setLastName(String lastName) {
       this.lastName = lastName;
       notifyPropertyChanged(BR.lastName);
   }
}