LiveData не уведомляет пользовательский интерфейс об изменениях при использовании с привязкой данных - PullRequest
0 голосов
/ 27 сентября 2018

Я хочу изменить пользовательский интерфейс при изменении LiveData при использовании с привязкой данных.Но поскольку LiveData меняется, оно не отражает изменений в пользовательском интерфейсе.

MainViewModel.java

public class MainViewModel extends AndroidViewModel {
    /**
     * Boolean variable to see whether user is ClockedIn or ClockedOut
     */
    public MutableLiveData<Boolean> isClockedIn;

    public MainViewModel(Application application) {
        super(application);
        isClockedIn = new MutableLiveData<>();
        //...
        calculateClockedInOrNot(PreferencesManager.getString(mContext,PreferencesManager.CLOCK_STATUS_KEY));
    }

    /**
     * An utility function to calculate whether user is clocked in or clocked out,
     * this function is also called within this ViewModel after an api hit
     *
     * if string == "CLOCKED_OUT" or string == "mobileEventType.CLOCK_OUT" => user is clocked out
     * else user is clocked in
     */
    private void calculateClockedInOrNot(String string) {
        if (string.equals("CLOCKED_OUT") || string.equals("mobileEventType.CLOCK_OUT")) {
            //user is clocked out
            isClockedIn.setValue(false);
        } else {
            //user is clocked in
            isClockedIn.setValue(true);
        }
    }
    //getter function
    public MutableLiveData<Boolean> isClockedIn() {
        return isClockedIn;
    }
    //other function left for brevity
}

MainActivity.java

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    // Obtain the ViewModel component.
    mainViewModel = ViewModelProviders.of(this).get(MainViewModel.class);
    // Inflate view and obtain an instance of the binding class.
    ActivityMainBinding binding = DataBindingUtil.setContentView(this, R.layout.activity_main);
    // Assign the component to a property in the binding class.
    binding.setData(mainViewModel);
}

activity_main.xml

<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:bind="http://schemas.android.com/apk/res-auto"

xmlns:tools="http://schemas.android.com/tools">

<data>

    <variable
        name="data"
        type="com.app.bidunity.viewmodel.MainViewModel" />
</data>

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

        <ImageView
            android:id="@+id/imageView"
            android:layout_width="wrap_content"
            android:layout_height="@dimen/img_hight_location"
            android:adjustViewBounds="true"
            android:src="@{data.clockedIn ? @drawable/ic_location_on : @drawable/ic_location_off}"/>
        <!--Other view left for brevity-->
 </LinearLayout>
</layout>

build.gradle

apply plugin: 'com.android.application'

android {
    compileSdkVersion 28
    defaultConfig {
        applicationId "com.app.bidunity"
        minSdkVersion 17
        targetSdkVersion 28
        versionCode 1
        versionName "1.0"
        testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
        vectorDrawables.useSupportLibrary = true
    }
buildTypes {
    release {
        minifyEnabled false
        proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
    }
}
dataBinding {
    enabled = true
}
compileOptions {
    sourceCompatibility = '1.8'
    targetCompatibility = '1.8'
}


}

dependencies {
def arch_version = "2.0.0-rc01"

implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation 'androidx.appcompat:appcompat:1.0.0'
implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
//material library
implementation 'com.google.android.material:material:1.0.0'
// ViewModel and LiveData
implementation "androidx.lifecycle:lifecycle-extensions:$arch_version"

testImplementation 'junit:junit:4.12'
androidTestImplementation 'androidx.test:runner:1.1.0-alpha4'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.1.0-alpha4'
}

Я использую Android-студия 3.3 Canary 11 с gradle 4.10.1 и onclick с привязкой данных прекрасно работает в viewmodel, но даже после изменения isClockedIn ImageView не меняется, его можно нарисовать.Я перепробовал все, я даже отладил, чтобы увидеть, меняется ли isClockedIn или нет в середине цикла, и да, это значение меняется

1 Ответ

0 голосов
/ 27 сентября 2018

Вам нужно сделать переменную isClockedIn Наблюдаемое поле ,

Поэтому замените его с

public boolean isClockedIn = false;

на

public ObservableBoolean isClockedIn = new ObservableBoolean();

Примечание: также убедитесь, что xml имеет то же имя переменной, что и в вашей ViewModel

См. здесь

Редактировать:

Если вы не хотите делать ObservableField , тогда потребуются некоторые другие изменения.

Несмотря на ObservableField , вам необходимо увеличить наблюдаемое расширение BaseObservable и в ваших livingata вам потребуется позвонить notifyPropertyChanged(BR.isClockedIn); после изменения логического значения.


Если вы хотите использовать LiveData в качестве наблюдателя, сначала необходимо предоставить привязке жизненный цикл

// Specify the current activity as the lifecycle owner (in your activity/fragment).
binding.setLifecycleOwner(this);

В вашем ViewModel возьмите объект LiveDataчтобы наблюдать за изменениями и применить Преобразование к нему:

MutableLiveData<Boolean> dataToBeObserve = new MutableLiveData<>();
LiveData booleanDataChange = Transformations.map(dataToBeObserve, dataToBeObserve-> dataToBeObserve.value);

Теперь, используйте это booleanDataChange для xml и измените значение MutableLiveDataсоблюдать данные ссобытие hange.

Примечание. Вы можете использовать одни и те же LiveData для событий изменения, просто нужно разделить определение на вызов конструктора.

...