我一直在用头撞墙,我不明白为什么会这样。我正在使用适用于Android的新架构组件,并且在使用对象列表更新LiveData时遇到问题。 我有两个微调器。当我更改第一个选项时,第二个选项必须更改其内容。但最后一部分并没有发生。 谁能帮我?
状态.java
@Entity(tableName = "states")
public class State{
@PrimaryKey(autoGenerate = false)
private int id;
private String name;
@ColumnInfo(name = "countryId")
private String CountryId;
@Ignore
private Object geoCenter, geoLimit;
public State(){
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getCountryId() {
return CountryId;
}
public void setCountryId(String countryId) {
CountryId = countryId;
}
}
国家道
@Dao
public interface StateDao {
@Query("SELECT * FROM states")
LiveData<List<State>> getAllStates();
@Query("SELECT * FROM states WHERE countryId = :countryID")
LiveData<List<State>> getStatesFromCountry(String countryID);
@Query("SELECT COUNT(*) FROM states")
int getNrStates();
@Query("SELECT COUNT(*) FROM states WHERE countryId = :countryID")
int getNrStatesByCountry(String countryID);
@Insert(onConflict = IGNORE)
void insertAll(List<State> states);
@Delete
void delete(State state);
}
状态存储库
@Singleton
public class StatesRepository {
private final WebServices services;
private final StateDao stateDao;
private final Executor executor;
@Inject
public StatesRepository(Executor executor, StateDao stateDao, WebServices services) {
this.services = services;
this.stateDao = stateDao;
this.executor = executor;
}
public LiveData<List<State>> getStates(String token){
refreshStates(token);
return stateDao.getAllStates();
}
public LiveData<List<State>> getStatesFromCountry(String countryID){
return stateDao.getStatesFromCountry(countryID);
}
private void refreshStates(final String token){
executor.execute(() -> {
Log.d("oooooo", stateDao.getNrStates() + "");
if(stateDao.getNrStates() == 0){
try {
Response<List<State>> response = services.getStates("Bearer "+token).execute();
stateDao.insertAll(response.body());
} catch (IOException e) {
e.printStackTrace();
}
}
});
}
}
状态视图模型
public class StatesViewModel extends ViewModel {
private LiveData<List<State>> states;
private StatesRepository repo;
@Inject
public StatesViewModel(StatesRepository repository){
this.repo = repository;
}
public void init(String token){
states = repo.getStates(token);
}
public void getStatesFromCountry(String countryID){
states = repo.getStatesFromCountry(countryID);
}
public LiveData<List<State>> getStates(){
return this.states;
}
}
片段
public class EditAddressFragment extends LifecycleFragment implements View.OnClickListener, Injectable{
private Spinner country, city, state, zip_code;
private String token;
private List<Country> countries;
private List<City> cities;
private List<State> states;
@Inject ViewModelFactory viewModelFactory;
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.addresses_edit_layout, container, false);
city = view.findViewById(R.id.city);
state = view.findViewById(R.id.state);
country = view.findViewById(R.id.country);
...
countries = new ArrayList<>();
cities = new ArrayList<>();
states = new ArrayList<>();
return view;
}
@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
CountrySpinnerAdapter adapter = new CountrySpinnerAdapter(getActivity(), android.R.layout.simple_spinner_item, countries);
country.setAdapter(adapter);
CitySpinnerAdapter cityAdapter = new CitySpinnerAdapter(getActivity(), android.R.layout.simple_spinner_item, cities);
city.setAdapter(cityAdapter);
StateSpinnerAdapter stateAdapter = new StateSpinnerAdapter(getActivity(), android.R.layout.simple_spinner_item, states);
state.setAdapter(stateAdapter);
CountriesViewModel countriesViewModel = ViewModelProviders.of(this, viewModelFactory).get(CountriesViewModel.class);
countriesViewModel.init(token);
countriesViewModel.getCountries().observe(this, adapter::setValues);
CityViewModel cityViewModel = ViewModelProviders.of(this, viewModelFactory).get(CityViewModel.class);
cityViewModel.init(token);
cityViewModel.getCities().observe(this, cityAdapter::setValues);
StatesViewModel statesViewModel = ViewModelProviders.of(this, viewModelFactory).get(StatesViewModel.class);
statesViewModel.init(token);
statesViewModel.getStates().observe(this, states -> {
Log.d("called", states.toString());
stateAdapter.setValues(states); } );
country.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
@Override
public void onItemSelected(AdapterView<?> adapterView, View view, int i, long l) {
Country c = (Country) adapterView.getItemAtPosition(i);
Log.d("cd", c.getId());
//states = new ArrayList<State>();
statesViewModel.getStatesFromCountry(c.getId());
}
@Override
public void onNothingSelected(AdapterView<?> adapterView) {
}
});
....
适配器
public void setValues(List<State> states)
{
this.states = states;
Log.d("s", states.isEmpty()+" "+states.toString());
notifyDataSetChanged();
}
好吧,我已经找到了这个问题的解决方案,并发现了这个 LiveData 的东西是如何工作的。
感谢@MartinMarconcini在调试;)方面的帮助
因此,显然,观察者链接到您首先设置的对象。您不能替换对象(通过属性(,否则它将不起作用。 另外,如果变量的值要更改,则应使用MutableLiveData
所以必要的改变是:
1. 从 LiveData 更改为 MutableLiveData,并在需要更新时将该 MutableLiveData 传递给存储库
public class StatesViewModel extends ViewModel {
private MutableLiveData<List<State>> states; ;;CHANGED
private StatesRepository repo;
@Inject
public StatesViewModel(StatesRepository repository){
this.repo = repository;
}
public void init(String token){
states = repo.getStates(token);
}
public void getStatesFromCountry(String countryID){
repo.getStatesFromCountry(this.states, countryID); ;;CHANGED
}
public LiveData<List<State>> getStates(){
return this.states;
}
}
2. 在存储库中,使用 setValue 更新可变实时数据
@Singleton
public class StatesRepository {
private final WebServices services;
private final StateDao stateDao;
private final Executor executor;
@Inject
public StatesRepository(Executor executor, StateDao stateDao, WebServices services) {
this.services = services;
this.stateDao = stateDao;
this.executor = executor;
}
public MutableLiveData<List<State>> getStates(String token){
refreshStates(token);
final MutableLiveData<List<State>> data = new MutableLiveData<>();
data.setValue(stateDao.getAllStates());
return data;
}
;; CHANGED
public void getStatesFromCountry(MutableLiveData states, final String countryID){
states.setValue(stateDao.getStatesFromCountry(countryID));
}
private void refreshStates(final String token){
executor.execute(() -> {
if(stateDao.getNrStates() == 0){
try {
Response<List<State>> response = services.getStates("Bearer "+token).execute();
stateDao.insertAll(response.body());
} catch (IOException e) {
e.printStackTrace();
}
}
});
}
}
3. 将 DAO 更改为返回列表而不是 LiveData
@Dao
public interface StateDao {
@Query("SELECT * FROM states")
List<State> getAllStates();
@Query("SELECT * FROM states WHERE ctrId = :countryID")
List<State> getStatesFromCountry(String countryID);
@Query("SELECT COUNT(*) FROM states")
int getNrStates();
@Query("SELECT COUNT(*) FROM states WHERE ctrId = :countryID")
int getNrStatesByCountry(String countryID);
@Insert(onConflict = IGNORE)
void insertAll(List<State> states);
@Delete
void delete(State state);
}
4.最后允许在主线程中执行查询
应用模块.java
@Singleton @Provides
AppDatabase provideDb(Application app) {
return Room.databaseBuilder(app, AppDatabase.class,"unitail.db")
.allowMainThreadQueries()
.fallbackToDestructiveMigration()
.build();
}
Dao 在所有操作中都必须相同。 您使用不同的 Dao 实例进行插入和观察
一旦设置了实时数据引用并开始观察它,就不应更新它。相反,要使用存储库更新实时数据,您应该使用 MediatorLiveData。
在您的情况下,请执行以下更改:
private MediatorLiveData<List<State>> states; // change
.....
.....
states.addSource(repo.getStatesFromCountry(countryID), newData -> states.setValue(newData)); //change
写一个答案以便更好地讨论。
所以我有一个模型(在 Kotlin 中,sry(它是一个笔记列表(它只是一个沙盒应用程序来玩/所有这些(,这是我的架构:我没有存储库,但我有活动 -> ViewModel -> Dao。
于是道露出一个LiveData<MutableList<Note>>
@Query("SELECT * FROM notes")
fun loadAll(): LiveData<MutableList<Note>>
我的视图模型...通过以下方式公开它:
val notesList = database.notesDao().loadAll()
和我的活动(onCreate(确实...
viewModel.notesList.observe(this,
Observer<MutableList<Note>> { notes ->
if (notes != null) {
progressBar?.hide()
adapter.setNotesList(notes)
}
})
这行得通。适配器是一个 RecyclerView 适配器,它实际上什么都不做,但:
fun setNotesList(newList: MutableList<Note>) {
if (notes.isEmpty()) {
notes = newList
notifyItemRangeInserted(0, newList.size)
} else {
val result = DiffUtil.calculateDiff(object : DiffUtil.Callback() {
override fun getOldListSize(): Int {
return notes.size
}
override fun getNewListSize(): Int {
return newList.size
}
override fun areItemsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean {
return notes[oldItemPosition].id == newList[newItemPosition].id
}
override fun areContentsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean {
val (id, title, _, priority) = newList[newItemPosition]
val (id1, title1, _, priority1) = notes[oldItemPosition]
return id == id1
&& priority == priority1
&& title == title1
}
})
notes = newList
result.dispatchUpdatesTo(this)
}
}
如果应用程序的任何其他部分修改了该笔记列表,适配器会自动更新。我希望这能给你一个尝试简单(r?(方法的游乐场。