Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/android/189.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/vue.js/6.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Android MVVM LiveData和数据绑定_Android_Android Databinding_Android Mvvm_Android Livedata - Fatal编程技术网

Android MVVM LiveData和数据绑定

Android MVVM LiveData和数据绑定,android,android-databinding,android-mvvm,android-livedata,Android,Android Databinding,Android Mvvm,Android Livedata,我正在研究体系结构组件,现在我正在学习LiveData和数据绑定。我可以将LiveData与布局绑定为整数值,但无法找到用户列表 这是一个使用数据绑定的LiveData的工作示例 <?xml version="1.0" encoding="utf-8"?> <layout> <data> <variable name="viewModel" type="com.example.tu

我正在研究体系结构组件,现在我正在学习LiveData和数据绑定。我可以将LiveData与布局绑定为整数值,但无法找到用户列表

这是一个使用数据绑定的LiveData的工作示例

<?xml version="1.0" encoding="utf-8"?>
<layout>

    <data>
        <variable
            name="viewModel"
            type="com.example.tutorial3livedataanddatabinding.viewmodel.CounterViewModel" />
    </data>

    <android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        xmlns:tools="http://schemas.android.com/tools"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:context=".MainActivity">

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@{String.valueOf(viewModel.counter)}"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintLeft_toLeftOf="parent"
            app:layout_constraintRight_toRightOf="parent"
            app:layout_constraintTop_toTopOf="parent" />

    </android.support.constraint.ConstraintLayout>
</layout>
编辑:我在Blackbelt的回答之后编辑了MyViewModel类 现在我得到的原因是:java.lang.NullPointerException:尝试在空对象引用上调用虚拟方法'void android.arch.lifecycle.LiveData.ObserveForReverAndroid.arch.lifecycle.Observer' 未调用应用内的System.out.println,将调用其他2,并且不会为users和users.getValue返回null

在android中:text=@{viewModel.getUserRecords}getUserRecords返回一个字符串,而不是LiveData对象。您应该改为绑定到LiveData对象

例如


在您的布局中,android:text=@{viewModel.userStringLiveData}。这样,当您向用户发布新值时,将调用map并更新UI

看起来用户在创建对象时(即首次计算userStringLiveData时)将为空。因此Transformations.map将被传递一个null作为其第一个参数,而不是您希望它在以后操作的LiveData

以下是我的建议:

public class r_RealTulipCoin {

  private LiveData<List<User>> users;

  public LiveData<String> userStringLiveData;

  public void onCreate() {
    getUsersLiveDataFromRoomOrSomething();
    prepareUserStringLiveData();
  }

  private void prepareUserStringLiveData() {
    userStringLiveData = Transformations.map(users, new android.arch.core.util.Function<List<User>, String>() {
          @Override
          public String apply(List<User> input) {
            System.out.println("userStringLiveData users: " + users);
            return getUserRecordsAsSingleStringFromThisParticularList(input);
          }
        });
  }

  private String getUserRecordsAsSingleStringFromThisParticularList(List<User> a_list_of_users) {
    return "i concatenated them or something";
  }

  private class User {
    String a_name_or_something;
  }

}
这是一个模型,但我希望它能说明我的观点。你会注意到我做了几件事。。。 在我尝试将其传递到Transformations.map之前,我确保用户实际上是非null的。 我使用map提供的输入参数。我很感激您已经知道它指的是什么,这就是为什么您的代码依赖于使用users字段,但是思考它来自何处以及转换类试图做什么可能会对您有所帮助

在您的情况下,我建议您这样做:

public LiveData<List<User>> getUsers() {
        if (users == null) {
            users = new MutableLiveData<>();
            // this is the first time the users pointer is not null
            loadUsers();
            prepareUserStringLiveData();
        }
        return users;
    }
最后一个选项是,当您第一次构造转换时,返回原始代码并使用getUsers而不是users:

public LiveData<String> userStringLiveData = Transformations.map(getUsers(), blah...)

这不是最简洁的解决方案,但它再次说明了为什么我一直坚持要将null传递给Transformations.map。

谢谢。我有这个想法,但我得到了这个错误:类转换中的方法映射不能应用于给定的类型;必需:LiveData,找到的函数:MutableLiveData,原因:推断的类型不符合推断的等式约束:列出等式约束S:List,其中X、Y是类型变量:X扩展方法mapLiveData中声明的对象,函数Y扩展方法mapLiveData中声明的对象,为什么LiveData计数器会在应用程序暂停时更新?LiveData不应该在未被观察到时停止更新吗?您导入了哪个函数?android.arch.core.util.Functionright,在您的例子中,输入是列表而不是字符串。我编辑了答案
public class MainActivity extends AppCompatActivity {

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


        MyViewModel myViewModel = ViewModelProviders.of(MainActivity.this).get(MyViewModel.class);
        myViewModel.getUsers();

        ActivityMainBinding binding = DataBindingUtil.setContentView(this, R.layout.activity_main);
        binding.setViewModel(myViewModel);
        // Required for  binding with LiveData
        binding.setLifecycleOwner(this);

    }
}
import android.arch.core.util.Function;
import android.arch.lifecycle.LiveData;
import android.arch.lifecycle.MutableLiveData;
import android.arch.lifecycle.Transformations;
import android.arch.lifecycle.ViewModel;

import com.example.tutorial3livedataanddatabinding2.model.User;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;


public class MyViewModel extends ViewModel {

    private MutableLiveData<List<User>> users;

    public LiveData<String> userStringLiveData = Transformations.map(users, new Function<List<User>, String>() {
        @Override
        public String apply(List<User> input) {
            System.out.println("userStringLiveData users: " + users);
            return getUserRecords();
        }
    });

    public LiveData<List<User>> getUsers() {
        if (users == null) {
            users = new MutableLiveData<>();
            loadUsers();
        }
        return users;
    }

    private void loadUsers() {
        // do async operation to fetch users
        List<User> userList = new ArrayList<>();

        User user = new User();
        user.setFirstName("Jack");
        user.setLastName("Daniels");
        userList.add(user);

        user = new User();
        user.setFirstName("Johnny");
        user.setLastName("Walker");
        userList.add(user);

        user = new User();
        user.setFirstName("James");
        user.setLastName("Jameson");
        userList.add(user);

        user = new User();
        user.setFirstName("Arthur");
        user.setLastName("Guinness");
        userList.add(user);

        users.setValue(userList);

        System.out.println("MyViewModel users " + users);
        System.out.println("MyViewModel users List" + users.getValue());

    }

    public void shuffleUsers() {
        if (users != null && users.getValue() != null && users.getValue().size() > 0) {
            Collections.shuffle(users.getValue());
            // Needed to update Live Data observers
            users.setValue(users.getValue());
        }
    }

    public void addUser() {
        if (users != null && users.getValue() != null) {

            User user = new User();
            user.setFirstName("Winston");
            user.setLastName("Whiskey");

            users.getValue().add(user);
            // Needed to update Live Data observers
            users.setValue(users.getValue());

        }
    }


    public String getUserRecords() {

        if (users != null && users.getValue() != null && users.getValue().size() > 0) {
            StringBuilder sb = new StringBuilder();
            for (User user : users.getValue()) {
                sb.append(user.getFirstName() + " " + user.getLastName() + "\n");
            }

            return sb.toString();
        }

        return "empty list";
    }
}
 public LiveData<String> userStringLiveData = Transformations.map(getUsers(), new Function<List<User>, String>() {
        @Override
        public String apply(List<User> input) {
            return getUserRecords();
        }
  });
public class r_RealTulipCoin {

  private LiveData<List<User>> users;

  public LiveData<String> userStringLiveData;

  public void onCreate() {
    getUsersLiveDataFromRoomOrSomething();
    prepareUserStringLiveData();
  }

  private void prepareUserStringLiveData() {
    userStringLiveData = Transformations.map(users, new android.arch.core.util.Function<List<User>, String>() {
          @Override
          public String apply(List<User> input) {
            System.out.println("userStringLiveData users: " + users);
            return getUserRecordsAsSingleStringFromThisParticularList(input);
          }
        });
  }

  private String getUserRecordsAsSingleStringFromThisParticularList(List<User> a_list_of_users) {
    return "i concatenated them or something";
  }

  private class User {
    String a_name_or_something;
  }

}
public LiveData<List<User>> getUsers() {
        if (users == null) {
            users = new MutableLiveData<>();
            // this is the first time the users pointer is not null
            loadUsers();
            prepareUserStringLiveData();
        }
        return users;
    }
public LiveData<String> userStringLiveData = Transformations.map(getUsers(), blah...)